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