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