]>
Commit | Line | Data |
---|---|---|
43e3346e | 1 | /* |
ff90606f | 2 | * ASPEED SoC family |
43e3346e AJ |
3 | * |
4 | * Andrew Jeffery <[email protected]> | |
5 | * Jeremy Kerr <[email protected]> | |
6 | * | |
7 | * Copyright 2016 IBM Corp. | |
8 | * | |
9 | * This code is licensed under the GPL version 2 or later. See | |
10 | * the COPYING file in the top-level directory. | |
11 | */ | |
12 | ||
13 | #include "qemu/osdep.h" | |
da34e65c | 14 | #include "qapi/error.h" |
4771d756 PB |
15 | #include "qemu-common.h" |
16 | #include "cpu.h" | |
43e3346e | 17 | #include "exec/address-spaces.h" |
00442402 | 18 | #include "hw/arm/aspeed_soc.h" |
43e3346e | 19 | #include "hw/char/serial.h" |
03dd024f | 20 | #include "qemu/log.h" |
16020011 | 21 | #include "hw/i2c/aspeed_i2c.h" |
43e3346e | 22 | |
ff90606f CLG |
23 | #define ASPEED_SOC_UART_5_BASE 0x00184000 |
24 | #define ASPEED_SOC_IOMEM_SIZE 0x00200000 | |
25 | #define ASPEED_SOC_IOMEM_BASE 0x1E600000 | |
26 | #define ASPEED_SOC_FMC_BASE 0x1E620000 | |
27 | #define ASPEED_SOC_SPI_BASE 0x1E630000 | |
6dc52326 | 28 | #define ASPEED_SOC_SPI2_BASE 0x1E631000 |
ff90606f CLG |
29 | #define ASPEED_SOC_VIC_BASE 0x1E6C0000 |
30 | #define ASPEED_SOC_SDMC_BASE 0x1E6E0000 | |
31 | #define ASPEED_SOC_SCU_BASE 0x1E6E2000 | |
32 | #define ASPEED_SOC_TIMER_BASE 0x1E782000 | |
33 | #define ASPEED_SOC_I2C_BASE 0x1E78A000 | |
34 | ||
43e3346e AJ |
35 | static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; |
36 | static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; | |
37 | ||
b033271f | 38 | #define AST2400_SDRAM_BASE 0x40000000 |
365aff1e | 39 | #define AST2500_SDRAM_BASE 0x80000000 |
b033271f | 40 | |
dbcabeeb | 41 | static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE }; |
6dc52326 | 42 | static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" }; |
dbcabeeb | 43 | |
6dc52326 CLG |
44 | static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE, |
45 | ASPEED_SOC_SPI2_BASE}; | |
46 | static const char *aspeed_soc_ast2500_typenames[] = { | |
47 | "aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" }; | |
dbcabeeb | 48 | |
b033271f | 49 | static const AspeedSoCInfo aspeed_socs[] = { |
dbcabeeb | 50 | { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, |
6dc52326 CLG |
51 | 1, aspeed_soc_ast2400_spi_bases, |
52 | "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, | |
dbcabeeb | 53 | { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, |
6dc52326 CLG |
54 | 1, aspeed_soc_ast2400_spi_bases, |
55 | "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, | |
dbcabeeb | 56 | { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE, |
6dc52326 CLG |
57 | 2, aspeed_soc_ast2500_spi_bases, |
58 | "aspeed.smc.ast2500-fmc", aspeed_soc_ast2500_typenames }, | |
b033271f CLG |
59 | }; |
60 | ||
43e3346e AJ |
61 | /* |
62 | * IO handlers: simply catch any reads/writes to IO addresses that aren't | |
63 | * handled by a device mapping. | |
64 | */ | |
65 | ||
ff90606f | 66 | static uint64_t aspeed_soc_io_read(void *p, hwaddr offset, unsigned size) |
43e3346e AJ |
67 | { |
68 | qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", | |
69 | __func__, offset, size); | |
70 | return 0; | |
71 | } | |
72 | ||
ff90606f | 73 | static void aspeed_soc_io_write(void *opaque, hwaddr offset, uint64_t value, |
43e3346e AJ |
74 | unsigned size) |
75 | { | |
76 | qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n", | |
77 | __func__, offset, value, size); | |
78 | } | |
79 | ||
ff90606f CLG |
80 | static const MemoryRegionOps aspeed_soc_io_ops = { |
81 | .read = aspeed_soc_io_read, | |
82 | .write = aspeed_soc_io_write, | |
43e3346e AJ |
83 | .endianness = DEVICE_LITTLE_ENDIAN, |
84 | }; | |
85 | ||
ff90606f | 86 | static void aspeed_soc_init(Object *obj) |
43e3346e | 87 | { |
ff90606f | 88 | AspeedSoCState *s = ASPEED_SOC(obj); |
b033271f | 89 | AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); |
dbcabeeb | 90 | int i; |
43e3346e | 91 | |
b033271f | 92 | s->cpu = cpu_arm_init(sc->info->cpu_model); |
43e3346e AJ |
93 | |
94 | object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); | |
95 | object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); | |
96 | qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default()); | |
97 | ||
98 | object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); | |
99 | object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); | |
100 | qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); | |
16020011 CLG |
101 | |
102 | object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); | |
103 | object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL); | |
104 | qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default()); | |
334973bb AJ |
105 | |
106 | object_initialize(&s->scu, sizeof(s->scu), TYPE_ASPEED_SCU); | |
107 | object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL); | |
108 | qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default()); | |
109 | qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", | |
b033271f | 110 | sc->info->silicon_rev); |
334973bb AJ |
111 | object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), |
112 | "hw-strap1", &error_abort); | |
113 | object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), | |
114 | "hw-strap2", &error_abort); | |
7c1c69bc | 115 | |
6dc52326 | 116 | object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename); |
0e5803df CLG |
117 | object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); |
118 | qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); | |
7c1c69bc | 119 | |
dbcabeeb | 120 | for (i = 0; i < sc->info->spis_num; i++) { |
6dc52326 CLG |
121 | object_initialize(&s->spi[i], sizeof(s->spi[i]), |
122 | sc->info->spi_typename[i]); | |
dbcabeeb CLG |
123 | object_property_add_child(obj, "spi", OBJECT(&s->spi[i]), NULL); |
124 | qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); | |
125 | } | |
c2da8a8b CLG |
126 | |
127 | object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC); | |
128 | object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL); | |
129 | qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default()); | |
130 | qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev", | |
b033271f | 131 | sc->info->silicon_rev); |
c6c7cfb0 CLG |
132 | object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), |
133 | "ram-size", &error_abort); | |
43e3346e AJ |
134 | } |
135 | ||
ff90606f | 136 | static void aspeed_soc_realize(DeviceState *dev, Error **errp) |
43e3346e AJ |
137 | { |
138 | int i; | |
ff90606f | 139 | AspeedSoCState *s = ASPEED_SOC(dev); |
dbcabeeb | 140 | AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); |
7c1c69bc | 141 | Error *err = NULL, *local_err = NULL; |
43e3346e AJ |
142 | |
143 | /* IO space */ | |
ff90606f CLG |
144 | memory_region_init_io(&s->iomem, NULL, &aspeed_soc_io_ops, NULL, |
145 | "aspeed_soc.io", ASPEED_SOC_IOMEM_SIZE); | |
146 | memory_region_add_subregion_overlap(get_system_memory(), | |
147 | ASPEED_SOC_IOMEM_BASE, &s->iomem, -1); | |
43e3346e AJ |
148 | |
149 | /* VIC */ | |
150 | object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); | |
151 | if (err) { | |
152 | error_propagate(errp, err); | |
153 | return; | |
154 | } | |
ff90606f | 155 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE); |
43e3346e AJ |
156 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, |
157 | qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); | |
158 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, | |
159 | qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); | |
160 | ||
161 | /* Timer */ | |
162 | object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); | |
163 | if (err) { | |
164 | error_propagate(errp, err); | |
165 | return; | |
166 | } | |
ff90606f | 167 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE); |
43e3346e AJ |
168 | for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) { |
169 | qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]); | |
170 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); | |
171 | } | |
172 | ||
334973bb AJ |
173 | /* SCU */ |
174 | object_property_set_bool(OBJECT(&s->scu), true, "realized", &err); | |
175 | if (err) { | |
176 | error_propagate(errp, err); | |
177 | return; | |
178 | } | |
ff90606f | 179 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE); |
334973bb | 180 | |
43e3346e AJ |
181 | /* UART - attach an 8250 to the IO space as our UART5 */ |
182 | if (serial_hds[0]) { | |
183 | qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); | |
ff90606f | 184 | serial_mm_init(&s->iomem, ASPEED_SOC_UART_5_BASE, 2, |
43e3346e AJ |
185 | uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); |
186 | } | |
16020011 CLG |
187 | |
188 | /* I2C */ | |
189 | object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err); | |
190 | if (err) { | |
191 | error_propagate(errp, err); | |
192 | return; | |
193 | } | |
ff90606f | 194 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE); |
16020011 CLG |
195 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, |
196 | qdev_get_gpio_in(DEVICE(&s->vic), 12)); | |
7c1c69bc | 197 | |
0e5803df CLG |
198 | /* FMC */ |
199 | object_property_set_int(OBJECT(&s->fmc), 1, "num-cs", &err); | |
200 | object_property_set_bool(OBJECT(&s->fmc), true, "realized", &local_err); | |
7c1c69bc CLG |
201 | error_propagate(&err, local_err); |
202 | if (err) { | |
203 | error_propagate(errp, err); | |
204 | return; | |
205 | } | |
0e5803df | 206 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE); |
dcb83444 CLG |
207 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, |
208 | s->fmc.ctrl->flash_window_base); | |
0e5803df | 209 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, |
7c1c69bc CLG |
210 | qdev_get_gpio_in(DEVICE(&s->vic), 19)); |
211 | ||
212 | /* SPI */ | |
dbcabeeb CLG |
213 | for (i = 0; i < sc->info->spis_num; i++) { |
214 | object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err); | |
215 | object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", | |
216 | &local_err); | |
217 | error_propagate(&err, local_err); | |
218 | if (err) { | |
219 | error_propagate(errp, err); | |
220 | return; | |
221 | } | |
222 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->info->spi_bases[i]); | |
223 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1, | |
224 | s->spi[i].ctrl->flash_window_base); | |
7c1c69bc | 225 | } |
c2da8a8b CLG |
226 | |
227 | /* SDMC - SDRAM Memory Controller */ | |
228 | object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); | |
229 | if (err) { | |
230 | error_propagate(errp, err); | |
231 | return; | |
232 | } | |
ff90606f | 233 | sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE); |
43e3346e AJ |
234 | } |
235 | ||
ff90606f | 236 | static void aspeed_soc_class_init(ObjectClass *oc, void *data) |
43e3346e AJ |
237 | { |
238 | DeviceClass *dc = DEVICE_CLASS(oc); | |
b033271f | 239 | AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc); |
43e3346e | 240 | |
b033271f | 241 | sc->info = (AspeedSoCInfo *) data; |
ff90606f | 242 | dc->realize = aspeed_soc_realize; |
43e3346e AJ |
243 | |
244 | /* | |
245 | * Reason: creates an ARM CPU, thus use after free(), see | |
246 | * arm_cpu_class_init() | |
247 | */ | |
248 | dc->cannot_destroy_with_object_finalize_yet = true; | |
249 | } | |
250 | ||
ff90606f | 251 | static const TypeInfo aspeed_soc_type_info = { |
b033271f CLG |
252 | .name = TYPE_ASPEED_SOC, |
253 | .parent = TYPE_DEVICE, | |
254 | .instance_init = aspeed_soc_init, | |
255 | .instance_size = sizeof(AspeedSoCState), | |
256 | .class_size = sizeof(AspeedSoCClass), | |
257 | .abstract = true, | |
43e3346e AJ |
258 | }; |
259 | ||
ff90606f | 260 | static void aspeed_soc_register_types(void) |
43e3346e | 261 | { |
b033271f CLG |
262 | int i; |
263 | ||
ff90606f | 264 | type_register_static(&aspeed_soc_type_info); |
b033271f CLG |
265 | for (i = 0; i < ARRAY_SIZE(aspeed_socs); ++i) { |
266 | TypeInfo ti = { | |
267 | .name = aspeed_socs[i].name, | |
268 | .parent = TYPE_ASPEED_SOC, | |
269 | .class_init = aspeed_soc_class_init, | |
270 | .class_data = (void *) &aspeed_socs[i], | |
271 | }; | |
272 | type_register(&ti); | |
273 | } | |
43e3346e AJ |
274 | } |
275 | ||
ff90606f | 276 | type_init(aspeed_soc_register_types) |