root / hw / versatile_pci.c @ 9f77c1cd
History | View | Annotate | Download (3.6 kB)
1 | 5fafdf24 | ths | /*
|
---|---|---|---|
2 | 502a5395 | pbrook | * ARM Versatile/PB PCI host controller
|
3 | 502a5395 | pbrook | *
|
4 | 502a5395 | pbrook | * Copyright (c) 2006 CodeSourcery.
|
5 | 502a5395 | pbrook | * Written by Paul Brook
|
6 | 502a5395 | pbrook | *
|
7 | 502a5395 | pbrook | * This code is licenced under the LGPL.
|
8 | 502a5395 | pbrook | */
|
9 | 502a5395 | pbrook | |
10 | 502a5395 | pbrook | #include "vl.h" |
11 | 502a5395 | pbrook | |
12 | 502a5395 | pbrook | static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr) |
13 | 502a5395 | pbrook | { |
14 | 80b3ada7 | pbrook | return addr & 0xffffff; |
15 | 502a5395 | pbrook | } |
16 | 502a5395 | pbrook | |
17 | 502a5395 | pbrook | static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr, |
18 | 502a5395 | pbrook | uint32_t val) |
19 | 502a5395 | pbrook | { |
20 | 502a5395 | pbrook | pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1);
|
21 | 502a5395 | pbrook | } |
22 | 502a5395 | pbrook | |
23 | 502a5395 | pbrook | static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr, |
24 | 502a5395 | pbrook | uint32_t val) |
25 | 502a5395 | pbrook | { |
26 | 502a5395 | pbrook | #ifdef TARGET_WORDS_BIGENDIAN
|
27 | 502a5395 | pbrook | val = bswap16(val); |
28 | 502a5395 | pbrook | #endif
|
29 | 502a5395 | pbrook | pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
|
30 | 502a5395 | pbrook | } |
31 | 502a5395 | pbrook | |
32 | 502a5395 | pbrook | static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr, |
33 | 502a5395 | pbrook | uint32_t val) |
34 | 502a5395 | pbrook | { |
35 | 502a5395 | pbrook | #ifdef TARGET_WORDS_BIGENDIAN
|
36 | 502a5395 | pbrook | val = bswap32(val); |
37 | 502a5395 | pbrook | #endif
|
38 | 502a5395 | pbrook | pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
|
39 | 502a5395 | pbrook | } |
40 | 502a5395 | pbrook | |
41 | 502a5395 | pbrook | static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr) |
42 | 502a5395 | pbrook | { |
43 | 502a5395 | pbrook | uint32_t val; |
44 | 502a5395 | pbrook | val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1);
|
45 | 502a5395 | pbrook | return val;
|
46 | 502a5395 | pbrook | } |
47 | 502a5395 | pbrook | |
48 | 502a5395 | pbrook | static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr) |
49 | 502a5395 | pbrook | { |
50 | 502a5395 | pbrook | uint32_t val; |
51 | 502a5395 | pbrook | val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
|
52 | 502a5395 | pbrook | #ifdef TARGET_WORDS_BIGENDIAN
|
53 | 502a5395 | pbrook | val = bswap16(val); |
54 | 502a5395 | pbrook | #endif
|
55 | 502a5395 | pbrook | return val;
|
56 | 502a5395 | pbrook | } |
57 | 502a5395 | pbrook | |
58 | 502a5395 | pbrook | static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr) |
59 | 502a5395 | pbrook | { |
60 | 502a5395 | pbrook | uint32_t val; |
61 | 502a5395 | pbrook | val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
|
62 | 502a5395 | pbrook | #ifdef TARGET_WORDS_BIGENDIAN
|
63 | 502a5395 | pbrook | val = bswap32(val); |
64 | 502a5395 | pbrook | #endif
|
65 | 502a5395 | pbrook | return val;
|
66 | 502a5395 | pbrook | } |
67 | 502a5395 | pbrook | |
68 | 502a5395 | pbrook | static CPUWriteMemoryFunc *pci_vpb_config_write[] = {
|
69 | 502a5395 | pbrook | &pci_vpb_config_writeb, |
70 | 502a5395 | pbrook | &pci_vpb_config_writew, |
71 | 502a5395 | pbrook | &pci_vpb_config_writel, |
72 | 502a5395 | pbrook | }; |
73 | 502a5395 | pbrook | |
74 | 502a5395 | pbrook | static CPUReadMemoryFunc *pci_vpb_config_read[] = {
|
75 | 502a5395 | pbrook | &pci_vpb_config_readb, |
76 | 502a5395 | pbrook | &pci_vpb_config_readw, |
77 | 502a5395 | pbrook | &pci_vpb_config_readl, |
78 | 502a5395 | pbrook | }; |
79 | 502a5395 | pbrook | |
80 | e69954b9 | pbrook | static int pci_vpb_irq; |
81 | e69954b9 | pbrook | |
82 | d2b59317 | pbrook | static int pci_vpb_map_irq(PCIDevice *d, int irq_num) |
83 | d2b59317 | pbrook | { |
84 | d2b59317 | pbrook | return irq_num;
|
85 | d2b59317 | pbrook | } |
86 | d2b59317 | pbrook | |
87 | d537cf6c | pbrook | static void pci_vpb_set_irq(qemu_irq *pic, int irq_num, int level) |
88 | 502a5395 | pbrook | { |
89 | d537cf6c | pbrook | qemu_set_irq(pic[pci_vpb_irq + irq_num], level); |
90 | 502a5395 | pbrook | } |
91 | 502a5395 | pbrook | |
92 | d537cf6c | pbrook | PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview) |
93 | 502a5395 | pbrook | { |
94 | 502a5395 | pbrook | PCIBus *s; |
95 | 502a5395 | pbrook | PCIDevice *d; |
96 | 502a5395 | pbrook | int mem_config;
|
97 | e69954b9 | pbrook | uint32_t base; |
98 | e69954b9 | pbrook | const char * name; |
99 | e69954b9 | pbrook | |
100 | e69954b9 | pbrook | pci_vpb_irq = irq; |
101 | e69954b9 | pbrook | if (realview) {
|
102 | e69954b9 | pbrook | base = 0x60000000;
|
103 | e69954b9 | pbrook | name = "RealView EB PCI Controller";
|
104 | e69954b9 | pbrook | } else {
|
105 | e69954b9 | pbrook | base = 0x40000000;
|
106 | e69954b9 | pbrook | name = "Versatile/PB PCI Controller";
|
107 | e69954b9 | pbrook | } |
108 | 80b3ada7 | pbrook | s = pci_register_bus(pci_vpb_set_irq, pci_vpb_map_irq, pic, 11 << 3, 4); |
109 | 502a5395 | pbrook | /* ??? Register memory space. */
|
110 | 502a5395 | pbrook | |
111 | 502a5395 | pbrook | mem_config = cpu_register_io_memory(0, pci_vpb_config_read,
|
112 | 502a5395 | pbrook | pci_vpb_config_write, s); |
113 | 502a5395 | pbrook | /* Selfconfig area. */
|
114 | 80b3ada7 | pbrook | cpu_register_physical_memory(base + 0x01000000, 0x1000000, mem_config); |
115 | 502a5395 | pbrook | /* Normal config area. */
|
116 | 80b3ada7 | pbrook | cpu_register_physical_memory(base + 0x02000000, 0x1000000, mem_config); |
117 | e69954b9 | pbrook | |
118 | e69954b9 | pbrook | d = pci_register_device(s, name, sizeof(PCIDevice), -1, NULL, NULL); |
119 | e69954b9 | pbrook | |
120 | e69954b9 | pbrook | if (realview) {
|
121 | e69954b9 | pbrook | /* IO memory area. */
|
122 | e69954b9 | pbrook | isa_mmio_init(base + 0x03000000, 0x00100000); |
123 | e69954b9 | pbrook | } |
124 | 502a5395 | pbrook | |
125 | 502a5395 | pbrook | d->config[0x00] = 0xee; // vendor_id |
126 | 502a5395 | pbrook | d->config[0x01] = 0x10; |
127 | e69954b9 | pbrook | /* Both boards have the same device ID. Oh well. */
|
128 | 502a5395 | pbrook | d->config[0x02] = 0x00; // device_id |
129 | 502a5395 | pbrook | d->config[0x03] = 0x03; |
130 | 502a5395 | pbrook | d->config[0x04] = 0x00; |
131 | 502a5395 | pbrook | d->config[0x05] = 0x00; |
132 | 502a5395 | pbrook | d->config[0x06] = 0x20; |
133 | 502a5395 | pbrook | d->config[0x07] = 0x02; |
134 | 502a5395 | pbrook | d->config[0x08] = 0x00; // revision |
135 | 502a5395 | pbrook | d->config[0x09] = 0x00; // programming i/f |
136 | 502a5395 | pbrook | d->config[0x0A] = 0x40; // class_sub = pci host |
137 | 502a5395 | pbrook | d->config[0x0B] = 0x0b; // class_base = PCI_bridge |
138 | 502a5395 | pbrook | d->config[0x0D] = 0x10; // latency_timer |
139 | 502a5395 | pbrook | |
140 | 502a5395 | pbrook | return s;
|
141 | 502a5395 | pbrook | } |