vmstate: port hpet device
[qemu] / hw / apb_pci.c
1 /*
2  * QEMU Ultrasparc APB PCI host
3  *
4  * Copyright (c) 2006 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 /* XXX This file and most of its contents are somewhat misnamed.  The
26    Ultrasparc PCI host is called the PCI Bus Module (PBM).  The APB is
27    the secondary PCI bridge.  */
28
29 #include "sysbus.h"
30 #include "pci.h"
31
32 /* debug APB */
33 //#define DEBUG_APB
34
35 #ifdef DEBUG_APB
36 #define APB_DPRINTF(fmt, ...) \
37 do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
38 #else
39 #define APB_DPRINTF(fmt, ...)
40 #endif
41
42 typedef target_phys_addr_t pci_addr_t;
43 #include "pci_host.h"
44
45 typedef struct APBState {
46     SysBusDevice busdev;
47     PCIHostState host_state;
48 } APBState;
49
50 static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
51                                          uint32_t val)
52 {
53     APBState *s = opaque;
54
55 #ifdef TARGET_WORDS_BIGENDIAN
56     val = bswap32(val);
57 #endif
58     APB_DPRINTF("config_writel addr " TARGET_FMT_plx " val %x\n", addr,
59                 val);
60     s->host_state.config_reg = val;
61 }
62
63 static uint32_t pci_apb_config_readl (void *opaque,
64                                             target_phys_addr_t addr)
65 {
66     APBState *s = opaque;
67     uint32_t val;
68
69     val = s->host_state.config_reg;
70 #ifdef TARGET_WORDS_BIGENDIAN
71     val = bswap32(val);
72 #endif
73     APB_DPRINTF("config_readl addr " TARGET_FMT_plx " val %x\n", addr,
74                 val);
75     return val;
76 }
77
78 static CPUWriteMemoryFunc * const pci_apb_config_write[] = {
79     &pci_apb_config_writel,
80     &pci_apb_config_writel,
81     &pci_apb_config_writel,
82 };
83
84 static CPUReadMemoryFunc * const pci_apb_config_read[] = {
85     &pci_apb_config_readl,
86     &pci_apb_config_readl,
87     &pci_apb_config_readl,
88 };
89
90 static void apb_config_writel (void *opaque, target_phys_addr_t addr,
91                                uint32_t val)
92 {
93     //PCIBus *s = opaque;
94
95     switch (addr & 0x3f) {
96     case 0x00: // Control/Status
97     case 0x10: // AFSR
98     case 0x18: // AFAR
99     case 0x20: // Diagnostic
100     case 0x28: // Target address space
101         // XXX
102     default:
103         break;
104     }
105 }
106
107 static uint32_t apb_config_readl (void *opaque,
108                                   target_phys_addr_t addr)
109 {
110     //PCIBus *s = opaque;
111     uint32_t val;
112
113     switch (addr & 0x3f) {
114     case 0x00: // Control/Status
115     case 0x10: // AFSR
116     case 0x18: // AFAR
117     case 0x20: // Diagnostic
118     case 0x28: // Target address space
119         // XXX
120     default:
121         val = 0;
122         break;
123     }
124     return val;
125 }
126
127 static CPUWriteMemoryFunc * const apb_config_write[] = {
128     &apb_config_writel,
129     &apb_config_writel,
130     &apb_config_writel,
131 };
132
133 static CPUReadMemoryFunc * const apb_config_read[] = {
134     &apb_config_readl,
135     &apb_config_readl,
136     &apb_config_readl,
137 };
138
139 static CPUWriteMemoryFunc * const pci_apb_write[] = {
140     &pci_host_data_writeb,
141     &pci_host_data_writew,
142     &pci_host_data_writel,
143 };
144
145 static CPUReadMemoryFunc * const pci_apb_read[] = {
146     &pci_host_data_readb,
147     &pci_host_data_readw,
148     &pci_host_data_readl,
149 };
150
151 static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
152                                   uint32_t val)
153 {
154     cpu_outb(NULL, addr & IOPORTS_MASK, val);
155 }
156
157 static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
158                                   uint32_t val)
159 {
160     cpu_outw(NULL, addr & IOPORTS_MASK, val);
161 }
162
163 static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
164                                 uint32_t val)
165 {
166     cpu_outl(NULL, addr & IOPORTS_MASK, val);
167 }
168
169 static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
170 {
171     uint32_t val;
172
173     val = cpu_inb(NULL, addr & IOPORTS_MASK);
174     return val;
175 }
176
177 static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
178 {
179     uint32_t val;
180
181     val = cpu_inw(NULL, addr & IOPORTS_MASK);
182     return val;
183 }
184
185 static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
186 {
187     uint32_t val;
188
189     val = cpu_inl(NULL, addr & IOPORTS_MASK);
190     return val;
191 }
192
193 static CPUWriteMemoryFunc * const pci_apb_iowrite[] = {
194     &pci_apb_iowriteb,
195     &pci_apb_iowritew,
196     &pci_apb_iowritel,
197 };
198
199 static CPUReadMemoryFunc * const pci_apb_ioread[] = {
200     &pci_apb_ioreadb,
201     &pci_apb_ioreadw,
202     &pci_apb_ioreadl,
203 };
204
205 /* The APB host has an IRQ line for each IRQ line of each slot.  */
206 static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
207 {
208     return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
209 }
210
211 static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
212 {
213     int bus_offset;
214     if (pci_dev->devfn & 1)
215         bus_offset = 16;
216     else
217         bus_offset = 0;
218     return bus_offset + irq_num;
219 }
220
221 static void pci_apb_set_irq(void *opaque, int irq_num, int level)
222 {
223     qemu_irq *pic = opaque;
224
225     /* PCI IRQ map onto the first 32 INO.  */
226     qemu_set_irq(pic[irq_num], level);
227 }
228
229 PCIBus *pci_apb_init(target_phys_addr_t special_base,
230                      target_phys_addr_t mem_base,
231                      qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
232 {
233     DeviceState *dev;
234     SysBusDevice *s;
235     APBState *d;
236
237     /* Ultrasparc PBM main bus */
238     dev = qdev_create(NULL, "pbm");
239     qdev_init(dev);
240     s = sysbus_from_qdev(dev);
241     /* apb_config */
242     sysbus_mmio_map(s, 0, special_base + 0x2000ULL);
243     /* pci_ioport */
244     sysbus_mmio_map(s, 1, special_base + 0x2000000ULL);
245     /* mem_config: XXX size should be 4G-prom */
246     sysbus_mmio_map(s, 2, special_base + 0x1000000ULL);
247     /* mem_data */
248     sysbus_mmio_map(s, 3, mem_base);
249     d = FROM_SYSBUS(APBState, s);
250     d->host_state.bus = pci_register_bus(NULL, "pci",
251                                          pci_apb_set_irq, pci_pbm_map_irq, pic,
252                                          0, 32);
253     pci_create_simple(d->host_state.bus, 0, "pbm");
254     /* APB secondary busses */
255     *bus2 = pci_bridge_init(d->host_state.bus, 8, PCI_VENDOR_ID_SUN,
256                             PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
257                             "Advanced PCI Bus secondary bridge 1");
258     *bus3 = pci_bridge_init(d->host_state.bus, 9, PCI_VENDOR_ID_SUN,
259                             PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
260                             "Advanced PCI Bus secondary bridge 2");
261
262     return d->host_state.bus;
263 }
264
265 static int pci_pbm_init_device(SysBusDevice *dev)
266 {
267
268     APBState *s;
269     int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
270
271     s = FROM_SYSBUS(APBState, dev);
272     /* apb_config */
273     apb_config = cpu_register_io_memory(apb_config_read,
274                                         apb_config_write, s);
275     sysbus_init_mmio(dev, 0x40ULL, apb_config);
276     /* pci_ioport */
277     pci_ioport = cpu_register_io_memory(pci_apb_ioread,
278                                           pci_apb_iowrite, s);
279     sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
280     /* mem_config  */
281     pci_mem_config = cpu_register_io_memory(pci_apb_config_read,
282                                             pci_apb_config_write, s);
283     sysbus_init_mmio(dev, 0x10ULL, pci_mem_config);
284     /* mem_data */
285     pci_mem_data = cpu_register_io_memory(pci_apb_read,
286                                           pci_apb_write, &s->host_state);
287     sysbus_init_mmio(dev, 0x10000000ULL, pci_mem_data);
288     return 0;
289 }
290
291 static int pbm_pci_host_init(PCIDevice *d)
292 {
293     pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
294     pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
295     d->config[0x04] = 0x06; // command = bus master, pci mem
296     d->config[0x05] = 0x00;
297     d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
298     d->config[0x07] = 0x03; // status = medium devsel
299     d->config[0x08] = 0x00; // revision
300     d->config[0x09] = 0x00; // programming i/f
301     pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
302     d->config[0x0D] = 0x10; // latency_timer
303     d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
304     return 0;
305 }
306
307 static PCIDeviceInfo pbm_pci_host_info = {
308     .qdev.name = "pbm",
309     .qdev.size = sizeof(PCIDevice),
310     .init      = pbm_pci_host_init,
311 };
312
313 static void pbm_register_devices(void)
314 {
315     sysbus_register_dev("pbm", sizeof(APBState), pci_pbm_init_device);
316     pci_qdev_register(&pbm_pci_host_info);
317 }
318
319 device_init(pbm_register_devices)