]>
Commit | Line | Data |
---|---|---|
04a7c7b1 IV |
1 | /* |
2 | * STM32L4x5 SoC family | |
3 | * | |
5b5b014b IV |
4 | * Copyright (c) 2023-2024 Arnaud Minier <arnaud.minier@telecom-paris.fr> |
5 | * Copyright (c) 2023-2024 Inès Varhol <ines.varhol@telecom-paris.fr> | |
04a7c7b1 IV |
6 | * |
7 | * SPDX-License-Identifier: GPL-2.0-or-later | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
10 | * See the COPYING file in the top-level directory. | |
11 | * | |
12 | * This work is heavily inspired by the stm32f405_soc by Alistair Francis. | |
13 | * Original code is licensed under the MIT License: | |
14 | * | |
15 | * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> | |
16 | */ | |
17 | ||
18 | /* | |
19 | * The reference used is the STMicroElectronics RM0351 Reference manual | |
20 | * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs. | |
21 | * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html | |
22 | */ | |
23 | ||
24 | #include "qemu/osdep.h" | |
25 | #include "qemu/units.h" | |
26 | #include "qapi/error.h" | |
27 | #include "exec/address-spaces.h" | |
28 | #include "sysemu/sysemu.h" | |
5928ed26 | 29 | #include "hw/or-irq.h" |
04a7c7b1 | 30 | #include "hw/arm/stm32l4x5_soc.h" |
92741432 | 31 | #include "hw/char/stm32l4x5_usart.h" |
1c38129d | 32 | #include "hw/gpio/stm32l4x5_gpio.h" |
04a7c7b1 IV |
33 | #include "hw/qdev-clock.h" |
34 | #include "hw/misc/unimp.h" | |
35 | ||
36 | #define FLASH_BASE_ADDRESS 0x08000000 | |
37 | #define SRAM1_BASE_ADDRESS 0x20000000 | |
38 | #define SRAM1_SIZE (96 * KiB) | |
39 | #define SRAM2_BASE_ADDRESS 0x10000000 | |
40 | #define SRAM2_SIZE (32 * KiB) | |
41 | ||
52671f69 | 42 | #define EXTI_ADDR 0x40010400 |
7dfe2312 | 43 | #define SYSCFG_ADDR 0x40010000 |
52671f69 IV |
44 | |
45 | #define NUM_EXTI_IRQ 40 | |
46 | /* Match exti line connections with their CPU IRQ number */ | |
47 | /* See Vector Table (Reference Manual p.396) */ | |
5928ed26 IV |
48 | /* |
49 | * Some IRQs are connected to the same CPU IRQ (denoted by -1) | |
50 | * and require an intermediary OR gate to function correctly. | |
51 | */ | |
52671f69 IV |
52 | static const int exti_irq[NUM_EXTI_IRQ] = { |
53 | 6, /* GPIO[0] */ | |
54 | 7, /* GPIO[1] */ | |
55 | 8, /* GPIO[2] */ | |
56 | 9, /* GPIO[3] */ | |
57 | 10, /* GPIO[4] */ | |
5928ed26 IV |
58 | -1, -1, -1, -1, -1, /* GPIO[5..9] OR gate 23 */ |
59 | -1, -1, -1, -1, -1, -1, /* GPIO[10..15] OR gate 40 */ | |
60 | -1, /* PVD OR gate 1 */ | |
52671f69 IV |
61 | 67, /* OTG_FS_WKUP, Direct */ |
62 | 41, /* RTC_ALARM */ | |
63 | 2, /* RTC_TAMP_STAMP2/CSS_LSE */ | |
64 | 3, /* RTC wakeup timer */ | |
5928ed26 | 65 | -1, -1, /* COMP[1..2] OR gate 63 */ |
52671f69 IV |
66 | 31, /* I2C1 wakeup, Direct */ |
67 | 33, /* I2C2 wakeup, Direct */ | |
68 | 72, /* I2C3 wakeup, Direct */ | |
69 | 37, /* USART1 wakeup, Direct */ | |
70 | 38, /* USART2 wakeup, Direct */ | |
71 | 39, /* USART3 wakeup, Direct */ | |
72 | 52, /* UART4 wakeup, Direct */ | |
73 | 53, /* UART4 wakeup, Direct */ | |
74 | 70, /* LPUART1 wakeup, Direct */ | |
75 | 65, /* LPTIM1, Direct */ | |
76 | 66, /* LPTIM2, Direct */ | |
77 | 76, /* SWPMI1 wakeup, Direct */ | |
5928ed26 | 78 | -1, -1, -1, -1, /* PVM[1..4] OR gate 1 */ |
52671f69 IV |
79 | 78 /* LCD wakeup, Direct */ |
80 | }; | |
d6b55a0f AM |
81 | #define RCC_BASE_ADDRESS 0x40021000 |
82 | #define RCC_IRQ 5 | |
52671f69 | 83 | |
5928ed26 IV |
84 | static const int exti_or_gates_out[NUM_EXTI_OR_GATES] = { |
85 | 23, 40, 63, 1, | |
86 | }; | |
87 | ||
88 | static const int exti_or_gates_num_lines_in[NUM_EXTI_OR_GATES] = { | |
89 | 5, 6, 2, 5, | |
90 | }; | |
91 | ||
92 | /* 3 OR gates with consecutive inputs */ | |
93 | #define NUM_EXTI_SIMPLE_OR_GATES 3 | |
94 | static const int exti_or_gates_first_line_in[NUM_EXTI_SIMPLE_OR_GATES] = { | |
95 | 5, 10, 21, | |
96 | }; | |
97 | ||
98 | /* 1 OR gate with non-consecutive inputs */ | |
99 | #define EXTI_OR_GATE1_NUM_LINES_IN 5 | |
100 | static const int exti_or_gate1_lines_in[EXTI_OR_GATE1_NUM_LINES_IN] = { | |
101 | 16, 35, 36, 37, 38, | |
102 | }; | |
103 | ||
1c38129d IV |
104 | static const struct { |
105 | uint32_t addr; | |
106 | uint32_t moder_reset; | |
107 | uint32_t ospeedr_reset; | |
108 | uint32_t pupdr_reset; | |
109 | } stm32l4x5_gpio_cfg[NUM_GPIOS] = { | |
110 | { 0x48000000, 0xABFFFFFF, 0x0C000000, 0x64000000 }, | |
111 | { 0x48000400, 0xFFFFFEBF, 0x00000000, 0x00000100 }, | |
112 | { 0x48000800, 0xFFFFFFFF, 0x00000000, 0x00000000 }, | |
113 | { 0x48000C00, 0xFFFFFFFF, 0x00000000, 0x00000000 }, | |
114 | { 0x48001000, 0xFFFFFFFF, 0x00000000, 0x00000000 }, | |
115 | { 0x48001400, 0xFFFFFFFF, 0x00000000, 0x00000000 }, | |
116 | { 0x48001800, 0xFFFFFFFF, 0x00000000, 0x00000000 }, | |
117 | { 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 }, | |
118 | }; | |
119 | ||
92741432 AM |
120 | static const hwaddr usart_addr[] = { |
121 | 0x40013800, /* "USART1", 0x400 */ | |
122 | 0x40004400, /* "USART2", 0x400 */ | |
123 | 0x40004800, /* "USART3", 0x400 */ | |
124 | }; | |
125 | static const hwaddr uart_addr[] = { | |
126 | 0x40004C00, /* "UART4" , 0x400 */ | |
127 | 0x40005000 /* "UART5" , 0x400 */ | |
128 | }; | |
129 | ||
130 | #define LPUART_BASE_ADDRESS 0x40008000 | |
131 | ||
132 | static const int usart_irq[] = { 37, 38, 39 }; | |
133 | static const int uart_irq[] = { 52, 53 }; | |
134 | #define LPUART_IRQ 70 | |
135 | ||
04a7c7b1 IV |
136 | static void stm32l4x5_soc_initfn(Object *obj) |
137 | { | |
138 | Stm32l4x5SocState *s = STM32L4X5_SOC(obj); | |
139 | ||
52671f69 | 140 | object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI); |
5928ed26 IV |
141 | for (unsigned i = 0; i < NUM_EXTI_OR_GATES; i++) { |
142 | object_initialize_child(obj, "exti_or_gates[*]", &s->exti_or_gates[i], | |
143 | TYPE_OR_IRQ); | |
144 | } | |
7dfe2312 | 145 | object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG); |
d6b55a0f | 146 | object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32L4X5_RCC); |
1c38129d IV |
147 | |
148 | for (unsigned i = 0; i < NUM_GPIOS; i++) { | |
149 | g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i); | |
150 | object_initialize_child(obj, name, &s->gpio[i], TYPE_STM32L4X5_GPIO); | |
151 | } | |
92741432 AM |
152 | |
153 | for (int i = 0; i < STM_NUM_USARTS; i++) { | |
154 | object_initialize_child(obj, "usart[*]", &s->usart[i], | |
155 | TYPE_STM32L4X5_USART); | |
156 | } | |
157 | ||
158 | for (int i = 0; i < STM_NUM_UARTS; i++) { | |
159 | object_initialize_child(obj, "uart[*]", &s->uart[i], | |
160 | TYPE_STM32L4X5_UART); | |
161 | } | |
162 | object_initialize_child(obj, "lpuart1", &s->lpuart, | |
163 | TYPE_STM32L4X5_LPUART); | |
04a7c7b1 IV |
164 | } |
165 | ||
166 | static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) | |
167 | { | |
168 | ERRP_GUARD(); | |
169 | Stm32l4x5SocState *s = STM32L4X5_SOC(dev_soc); | |
170 | const Stm32l4x5SocClass *sc = STM32L4X5_SOC_GET_CLASS(dev_soc); | |
171 | MemoryRegion *system_memory = get_system_memory(); | |
1c38129d | 172 | DeviceState *armv7m, *dev; |
52671f69 | 173 | SysBusDevice *busdev; |
1c38129d | 174 | uint32_t pin_index; |
04a7c7b1 | 175 | |
04a7c7b1 IV |
176 | if (!memory_region_init_rom(&s->flash, OBJECT(dev_soc), "flash", |
177 | sc->flash_size, errp)) { | |
178 | return; | |
179 | } | |
180 | memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc), | |
181 | "flash_boot_alias", &s->flash, 0, | |
182 | sc->flash_size); | |
183 | ||
184 | memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash); | |
185 | memory_region_add_subregion(system_memory, 0, &s->flash_alias); | |
186 | ||
187 | if (!memory_region_init_ram(&s->sram1, OBJECT(dev_soc), "SRAM1", SRAM1_SIZE, | |
188 | errp)) { | |
189 | return; | |
190 | } | |
191 | memory_region_add_subregion(system_memory, SRAM1_BASE_ADDRESS, &s->sram1); | |
192 | ||
193 | if (!memory_region_init_ram(&s->sram2, OBJECT(dev_soc), "SRAM2", SRAM2_SIZE, | |
194 | errp)) { | |
195 | return; | |
196 | } | |
197 | memory_region_add_subregion(system_memory, SRAM2_BASE_ADDRESS, &s->sram2); | |
198 | ||
199 | object_initialize_child(OBJECT(dev_soc), "armv7m", &s->armv7m, TYPE_ARMV7M); | |
200 | armv7m = DEVICE(&s->armv7m); | |
201 | qdev_prop_set_uint32(armv7m, "num-irq", 96); | |
4a04655c | 202 | qdev_prop_set_uint32(armv7m, "num-prio-bits", 4); |
04a7c7b1 IV |
203 | qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4")); |
204 | qdev_prop_set_bit(armv7m, "enable-bitband", true); | |
60849fe4 AM |
205 | qdev_connect_clock_in(armv7m, "cpuclk", |
206 | qdev_get_clock_out(DEVICE(&(s->rcc)), "cortex-fclk-out")); | |
207 | qdev_connect_clock_in(armv7m, "refclk", | |
208 | qdev_get_clock_out(DEVICE(&(s->rcc)), "cortex-refclk-out")); | |
04a7c7b1 IV |
209 | object_property_set_link(OBJECT(&s->armv7m), "memory", |
210 | OBJECT(system_memory), &error_abort); | |
211 | if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { | |
212 | return; | |
213 | } | |
214 | ||
1c38129d IV |
215 | /* GPIOs */ |
216 | for (unsigned i = 0; i < NUM_GPIOS; i++) { | |
217 | g_autofree char *name = g_strdup_printf("%c", 'A' + i); | |
218 | dev = DEVICE(&s->gpio[i]); | |
219 | qdev_prop_set_string(dev, "name", name); | |
220 | qdev_prop_set_uint32(dev, "mode-reset", | |
221 | stm32l4x5_gpio_cfg[i].moder_reset); | |
222 | qdev_prop_set_uint32(dev, "ospeed-reset", | |
223 | stm32l4x5_gpio_cfg[i].ospeedr_reset); | |
224 | qdev_prop_set_uint32(dev, "pupd-reset", | |
225 | stm32l4x5_gpio_cfg[i].pupdr_reset); | |
226 | busdev = SYS_BUS_DEVICE(&s->gpio[i]); | |
227 | g_free(name); | |
228 | name = g_strdup_printf("gpio%c-out", 'a' + i); | |
229 | qdev_connect_clock_in(DEVICE(&s->gpio[i]), "clk", | |
230 | qdev_get_clock_out(DEVICE(&(s->rcc)), name)); | |
231 | if (!sysbus_realize(busdev, errp)) { | |
232 | return; | |
233 | } | |
234 | sysbus_mmio_map(busdev, 0, stm32l4x5_gpio_cfg[i].addr); | |
235 | } | |
236 | ||
7dfe2312 IV |
237 | /* System configuration controller */ |
238 | busdev = SYS_BUS_DEVICE(&s->syscfg); | |
239 | if (!sysbus_realize(busdev, errp)) { | |
240 | return; | |
241 | } | |
242 | sysbus_mmio_map(busdev, 0, SYSCFG_ADDR); | |
1c38129d IV |
243 | |
244 | for (unsigned i = 0; i < NUM_GPIOS; i++) { | |
245 | for (unsigned j = 0; j < GPIO_NUM_PINS; j++) { | |
246 | pin_index = GPIO_NUM_PINS * i + j; | |
247 | qdev_connect_gpio_out(DEVICE(&s->gpio[i]), j, | |
248 | qdev_get_gpio_in(DEVICE(&s->syscfg), | |
249 | pin_index)); | |
250 | } | |
251 | } | |
7dfe2312 | 252 | |
5b5b014b IV |
253 | qdev_pass_gpios(DEVICE(&s->syscfg), dev_soc, NULL); |
254 | ||
7dfe2312 | 255 | /* EXTI device */ |
52671f69 IV |
256 | busdev = SYS_BUS_DEVICE(&s->exti); |
257 | if (!sysbus_realize(busdev, errp)) { | |
258 | return; | |
259 | } | |
260 | sysbus_mmio_map(busdev, 0, EXTI_ADDR); | |
5928ed26 IV |
261 | |
262 | /* IRQs with fan-in that require an OR gate */ | |
263 | for (unsigned i = 0; i < NUM_EXTI_OR_GATES; i++) { | |
264 | if (!object_property_set_int(OBJECT(&s->exti_or_gates[i]), "num-lines", | |
265 | exti_or_gates_num_lines_in[i], errp)) { | |
266 | return; | |
267 | } | |
268 | if (!qdev_realize(DEVICE(&s->exti_or_gates[i]), NULL, errp)) { | |
269 | return; | |
270 | } | |
271 | ||
272 | qdev_connect_gpio_out(DEVICE(&s->exti_or_gates[i]), 0, | |
273 | qdev_get_gpio_in(armv7m, exti_or_gates_out[i])); | |
274 | ||
275 | if (i < NUM_EXTI_SIMPLE_OR_GATES) { | |
276 | /* consecutive inputs for OR gates 23, 40, 63 */ | |
277 | for (unsigned j = 0; j < exti_or_gates_num_lines_in[i]; j++) { | |
278 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->exti), | |
279 | exti_or_gates_first_line_in[i] + j, | |
280 | qdev_get_gpio_in(DEVICE(&s->exti_or_gates[i]), j)); | |
281 | } | |
282 | } else { | |
283 | /* non-consecutive inputs for OR gate 1 */ | |
284 | for (unsigned j = 0; j < EXTI_OR_GATE1_NUM_LINES_IN; j++) { | |
285 | sysbus_connect_irq(SYS_BUS_DEVICE(&s->exti), | |
286 | exti_or_gate1_lines_in[j], | |
287 | qdev_get_gpio_in(DEVICE(&s->exti_or_gates[i]), j)); | |
288 | } | |
289 | } | |
290 | } | |
291 | ||
292 | /* IRQs that don't require fan-in */ | |
52671f69 | 293 | for (unsigned i = 0; i < NUM_EXTI_IRQ; i++) { |
5928ed26 IV |
294 | if (exti_irq[i] != -1) { |
295 | sysbus_connect_irq(busdev, i, | |
296 | qdev_get_gpio_in(armv7m, exti_irq[i])); | |
297 | } | |
52671f69 IV |
298 | } |
299 | ||
1c38129d | 300 | for (unsigned i = 0; i < GPIO_NUM_PINS; i++) { |
7dfe2312 IV |
301 | qdev_connect_gpio_out(DEVICE(&s->syscfg), i, |
302 | qdev_get_gpio_in(DEVICE(&s->exti), i)); | |
303 | } | |
304 | ||
d6b55a0f AM |
305 | /* RCC device */ |
306 | busdev = SYS_BUS_DEVICE(&s->rcc); | |
307 | if (!sysbus_realize(busdev, errp)) { | |
308 | return; | |
309 | } | |
310 | sysbus_mmio_map(busdev, 0, RCC_BASE_ADDRESS); | |
311 | sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, RCC_IRQ)); | |
312 | ||
92741432 AM |
313 | /* USART devices */ |
314 | for (int i = 0; i < STM_NUM_USARTS; i++) { | |
315 | g_autofree char *name = g_strdup_printf("usart%d-out", i + 1); | |
316 | dev = DEVICE(&(s->usart[i])); | |
317 | qdev_prop_set_chr(dev, "chardev", serial_hd(i)); | |
318 | qdev_connect_clock_in(dev, "clk", | |
319 | qdev_get_clock_out(DEVICE(&(s->rcc)), name)); | |
320 | busdev = SYS_BUS_DEVICE(dev); | |
321 | if (!sysbus_realize(busdev, errp)) { | |
322 | return; | |
323 | } | |
324 | sysbus_mmio_map(busdev, 0, usart_addr[i]); | |
325 | sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i])); | |
326 | } | |
327 | ||
328 | /* | |
329 | * TODO: Connect the USARTs, UARTs and LPUART to the EXTI once the EXTI | |
330 | * can handle other gpio-in than the gpios. (e.g. Direct Lines for the | |
331 | * usarts) | |
332 | */ | |
333 | ||
334 | /* UART devices */ | |
335 | for (int i = 0; i < STM_NUM_UARTS; i++) { | |
336 | g_autofree char *name = g_strdup_printf("uart%d-out", STM_NUM_USARTS + i + 1); | |
337 | dev = DEVICE(&(s->uart[i])); | |
338 | qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + i)); | |
339 | qdev_connect_clock_in(dev, "clk", | |
340 | qdev_get_clock_out(DEVICE(&(s->rcc)), name)); | |
341 | busdev = SYS_BUS_DEVICE(dev); | |
342 | if (!sysbus_realize(busdev, errp)) { | |
343 | return; | |
344 | } | |
345 | sysbus_mmio_map(busdev, 0, uart_addr[i]); | |
346 | sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, uart_irq[i])); | |
347 | } | |
348 | ||
349 | /* LPUART device*/ | |
350 | dev = DEVICE(&(s->lpuart)); | |
351 | qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + STM_NUM_UARTS)); | |
352 | qdev_connect_clock_in(dev, "clk", | |
353 | qdev_get_clock_out(DEVICE(&(s->rcc)), "lpuart1-out")); | |
354 | busdev = SYS_BUS_DEVICE(dev); | |
355 | if (!sysbus_realize(busdev, errp)) { | |
356 | return; | |
357 | } | |
358 | sysbus_mmio_map(busdev, 0, LPUART_BASE_ADDRESS); | |
359 | sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, LPUART_IRQ)); | |
360 | ||
04a7c7b1 IV |
361 | /* APB1 BUS */ |
362 | create_unimplemented_device("TIM2", 0x40000000, 0x400); | |
363 | create_unimplemented_device("TIM3", 0x40000400, 0x400); | |
364 | create_unimplemented_device("TIM4", 0x40000800, 0x400); | |
365 | create_unimplemented_device("TIM5", 0x40000C00, 0x400); | |
366 | create_unimplemented_device("TIM6", 0x40001000, 0x400); | |
367 | create_unimplemented_device("TIM7", 0x40001400, 0x400); | |
368 | /* RESERVED: 0x40001800, 0x1000 */ | |
369 | create_unimplemented_device("RTC", 0x40002800, 0x400); | |
370 | create_unimplemented_device("WWDG", 0x40002C00, 0x400); | |
371 | create_unimplemented_device("IWDG", 0x40003000, 0x400); | |
372 | /* RESERVED: 0x40001800, 0x400 */ | |
373 | create_unimplemented_device("SPI2", 0x40003800, 0x400); | |
374 | create_unimplemented_device("SPI3", 0x40003C00, 0x400); | |
375 | /* RESERVED: 0x40004000, 0x400 */ | |
04a7c7b1 IV |
376 | create_unimplemented_device("I2C1", 0x40005400, 0x400); |
377 | create_unimplemented_device("I2C2", 0x40005800, 0x400); | |
378 | create_unimplemented_device("I2C3", 0x40005C00, 0x400); | |
379 | /* RESERVED: 0x40006000, 0x400 */ | |
380 | create_unimplemented_device("CAN1", 0x40006400, 0x400); | |
381 | /* RESERVED: 0x40006800, 0x400 */ | |
382 | create_unimplemented_device("PWR", 0x40007000, 0x400); | |
383 | create_unimplemented_device("DAC1", 0x40007400, 0x400); | |
384 | create_unimplemented_device("OPAMP", 0x40007800, 0x400); | |
385 | create_unimplemented_device("LPTIM1", 0x40007C00, 0x400); | |
04a7c7b1 IV |
386 | /* RESERVED: 0x40008400, 0x400 */ |
387 | create_unimplemented_device("SWPMI1", 0x40008800, 0x400); | |
388 | /* RESERVED: 0x40008C00, 0x800 */ | |
389 | create_unimplemented_device("LPTIM2", 0x40009400, 0x400); | |
390 | /* RESERVED: 0x40009800, 0x6800 */ | |
391 | ||
392 | /* APB2 BUS */ | |
04a7c7b1 IV |
393 | create_unimplemented_device("VREFBUF", 0x40010030, 0x1D0); |
394 | create_unimplemented_device("COMP", 0x40010200, 0x200); | |
04a7c7b1 IV |
395 | /* RESERVED: 0x40010800, 0x1400 */ |
396 | create_unimplemented_device("FIREWALL", 0x40011C00, 0x400); | |
397 | /* RESERVED: 0x40012000, 0x800 */ | |
398 | create_unimplemented_device("SDMMC1", 0x40012800, 0x400); | |
399 | create_unimplemented_device("TIM1", 0x40012C00, 0x400); | |
400 | create_unimplemented_device("SPI1", 0x40013000, 0x400); | |
401 | create_unimplemented_device("TIM8", 0x40013400, 0x400); | |
04a7c7b1 IV |
402 | /* RESERVED: 0x40013C00, 0x400 */ |
403 | create_unimplemented_device("TIM15", 0x40014000, 0x400); | |
404 | create_unimplemented_device("TIM16", 0x40014400, 0x400); | |
405 | create_unimplemented_device("TIM17", 0x40014800, 0x400); | |
406 | /* RESERVED: 0x40014C00, 0x800 */ | |
407 | create_unimplemented_device("SAI1", 0x40015400, 0x400); | |
408 | create_unimplemented_device("SAI2", 0x40015800, 0x400); | |
409 | /* RESERVED: 0x40015C00, 0x400 */ | |
410 | create_unimplemented_device("DFSDM1", 0x40016000, 0x400); | |
411 | /* RESERVED: 0x40016400, 0x9C00 */ | |
412 | ||
413 | /* AHB1 BUS */ | |
414 | create_unimplemented_device("DMA1", 0x40020000, 0x400); | |
415 | create_unimplemented_device("DMA2", 0x40020400, 0x400); | |
416 | /* RESERVED: 0x40020800, 0x800 */ | |
04a7c7b1 IV |
417 | /* RESERVED: 0x40021400, 0xC00 */ |
418 | create_unimplemented_device("FLASH", 0x40022000, 0x400); | |
419 | /* RESERVED: 0x40022400, 0xC00 */ | |
420 | create_unimplemented_device("CRC", 0x40023000, 0x400); | |
421 | /* RESERVED: 0x40023400, 0x400 */ | |
422 | create_unimplemented_device("TSC", 0x40024000, 0x400); | |
423 | ||
424 | /* RESERVED: 0x40024400, 0x7FDBC00 */ | |
425 | ||
426 | /* AHB2 BUS */ | |
04a7c7b1 IV |
427 | /* RESERVED: 0x48002000, 0x7FDBC00 */ |
428 | create_unimplemented_device("OTG_FS", 0x50000000, 0x40000); | |
429 | create_unimplemented_device("ADC", 0x50040000, 0x400); | |
430 | /* RESERVED: 0x50040400, 0x20400 */ | |
431 | create_unimplemented_device("RNG", 0x50060800, 0x400); | |
432 | ||
433 | /* AHB3 BUS */ | |
434 | create_unimplemented_device("FMC", 0xA0000000, 0x1000); | |
435 | create_unimplemented_device("QUADSPI", 0xA0001000, 0x400); | |
436 | } | |
437 | ||
438 | static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data) | |
439 | { | |
440 | ||
441 | DeviceClass *dc = DEVICE_CLASS(klass); | |
442 | ||
443 | dc->realize = stm32l4x5_soc_realize; | |
444 | /* Reason: Mapped at fixed location on the system bus */ | |
445 | dc->user_creatable = false; | |
446 | /* No vmstate or reset required: device has no internal state */ | |
447 | } | |
448 | ||
449 | static void stm32l4x5xc_soc_class_init(ObjectClass *oc, void *data) | |
450 | { | |
451 | Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); | |
452 | ||
453 | ssc->flash_size = 256 * KiB; | |
454 | } | |
455 | ||
456 | static void stm32l4x5xe_soc_class_init(ObjectClass *oc, void *data) | |
457 | { | |
458 | Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); | |
459 | ||
460 | ssc->flash_size = 512 * KiB; | |
461 | } | |
462 | ||
463 | static void stm32l4x5xg_soc_class_init(ObjectClass *oc, void *data) | |
464 | { | |
465 | Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); | |
466 | ||
467 | ssc->flash_size = 1 * MiB; | |
468 | } | |
469 | ||
470 | static const TypeInfo stm32l4x5_soc_types[] = { | |
471 | { | |
472 | .name = TYPE_STM32L4X5XC_SOC, | |
473 | .parent = TYPE_STM32L4X5_SOC, | |
474 | .class_init = stm32l4x5xc_soc_class_init, | |
475 | }, { | |
476 | .name = TYPE_STM32L4X5XE_SOC, | |
477 | .parent = TYPE_STM32L4X5_SOC, | |
478 | .class_init = stm32l4x5xe_soc_class_init, | |
479 | }, { | |
480 | .name = TYPE_STM32L4X5XG_SOC, | |
481 | .parent = TYPE_STM32L4X5_SOC, | |
482 | .class_init = stm32l4x5xg_soc_class_init, | |
483 | }, { | |
484 | .name = TYPE_STM32L4X5_SOC, | |
485 | .parent = TYPE_SYS_BUS_DEVICE, | |
486 | .instance_size = sizeof(Stm32l4x5SocState), | |
487 | .instance_init = stm32l4x5_soc_initfn, | |
488 | .class_size = sizeof(Stm32l4x5SocClass), | |
489 | .class_init = stm32l4x5_soc_class_init, | |
490 | .abstract = true, | |
491 | } | |
492 | }; | |
493 | ||
494 | DEFINE_TYPES(stm32l4x5_soc_types) |