1ebc1fbb4SSubbaraya Sundeep /* 2ebc1fbb4SSubbaraya Sundeep * SmartFusion2 SoC emulation. 3ebc1fbb4SSubbaraya Sundeep * 405b7374aSSubbaraya Sundeep * Copyright (c) 2017-2020 Subbaraya Sundeep <sundeep.lkml@gmail.com> 5ebc1fbb4SSubbaraya Sundeep * 6ebc1fbb4SSubbaraya Sundeep * Permission is hereby granted, free of charge, to any person obtaining a copy 7ebc1fbb4SSubbaraya Sundeep * of this software and associated documentation files (the "Software"), to deal 8ebc1fbb4SSubbaraya Sundeep * in the Software without restriction, including without limitation the rights 9ebc1fbb4SSubbaraya Sundeep * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10ebc1fbb4SSubbaraya Sundeep * copies of the Software, and to permit persons to whom the Software is 11ebc1fbb4SSubbaraya Sundeep * furnished to do so, subject to the following conditions: 12ebc1fbb4SSubbaraya Sundeep * 13ebc1fbb4SSubbaraya Sundeep * The above copyright notice and this permission notice shall be included in 14ebc1fbb4SSubbaraya Sundeep * all copies or substantial portions of the Software. 15ebc1fbb4SSubbaraya Sundeep * 16ebc1fbb4SSubbaraya Sundeep * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17ebc1fbb4SSubbaraya Sundeep * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18ebc1fbb4SSubbaraya Sundeep * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19ebc1fbb4SSubbaraya Sundeep * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20ebc1fbb4SSubbaraya Sundeep * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21ebc1fbb4SSubbaraya Sundeep * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22ebc1fbb4SSubbaraya Sundeep * THE SOFTWARE. 23ebc1fbb4SSubbaraya Sundeep */ 24ebc1fbb4SSubbaraya Sundeep 25ebc1fbb4SSubbaraya Sundeep #include "qemu/osdep.h" 26fc6b3cf9SPhilippe Mathieu-Daudé #include "qemu/units.h" 27ebc1fbb4SSubbaraya Sundeep #include "qapi/error.h" 28ebc1fbb4SSubbaraya Sundeep #include "exec/address-spaces.h" 29ebc1fbb4SSubbaraya Sundeep #include "hw/char/serial.h" 30ebc1fbb4SSubbaraya Sundeep #include "hw/arm/msf2-soc.h" 31ebc1fbb4SSubbaraya Sundeep #include "hw/misc/unimp.h" 329bfaf375SPeter Maydell #include "hw/qdev-clock.h" 3346517dd4SMarkus Armbruster #include "sysemu/sysemu.h" 34ebc1fbb4SSubbaraya Sundeep 35ebc1fbb4SSubbaraya Sundeep #define MSF2_TIMER_BASE 0x40004000 36ebc1fbb4SSubbaraya Sundeep #define MSF2_SYSREG_BASE 0x40038000 3705b7374aSSubbaraya Sundeep #define MSF2_EMAC_BASE 0x40041000 38ebc1fbb4SSubbaraya Sundeep 39ebc1fbb4SSubbaraya Sundeep #define ENVM_BASE_ADDRESS 0x60000000 40ebc1fbb4SSubbaraya Sundeep 41ebc1fbb4SSubbaraya Sundeep #define SRAM_BASE_ADDRESS 0x20000000 42ebc1fbb4SSubbaraya Sundeep 4305b7374aSSubbaraya Sundeep #define MSF2_EMAC_IRQ 12 4405b7374aSSubbaraya Sundeep 45d23b6caaSPhilippe Mathieu-Daudé #define MSF2_ENVM_MAX_SIZE (512 * KiB) 46ebc1fbb4SSubbaraya Sundeep 47ebc1fbb4SSubbaraya Sundeep /* 48ebc1fbb4SSubbaraya Sundeep * eSRAM max size is 80k without SECDED(Single error correction and 49ebc1fbb4SSubbaraya Sundeep * dual error detection) feature and 64k with SECDED. 50ebc1fbb4SSubbaraya Sundeep * We do not support SECDED now. 51ebc1fbb4SSubbaraya Sundeep */ 52d23b6caaSPhilippe Mathieu-Daudé #define MSF2_ESRAM_MAX_SIZE (80 * KiB) 53ebc1fbb4SSubbaraya Sundeep 54ebc1fbb4SSubbaraya Sundeep static const uint32_t spi_addr[MSF2_NUM_SPIS] = { 0x40001000 , 0x40011000 }; 55ebc1fbb4SSubbaraya Sundeep static const uint32_t uart_addr[MSF2_NUM_UARTS] = { 0x40000000 , 0x40010000 }; 56ebc1fbb4SSubbaraya Sundeep 57ebc1fbb4SSubbaraya Sundeep static const int spi_irq[MSF2_NUM_SPIS] = { 2, 3 }; 58ebc1fbb4SSubbaraya Sundeep static const int uart_irq[MSF2_NUM_UARTS] = { 10, 11 }; 59ebc1fbb4SSubbaraya Sundeep static const int timer_irq[MSF2_NUM_TIMERS] = { 14, 15 }; 60ebc1fbb4SSubbaraya Sundeep 61ebc1fbb4SSubbaraya Sundeep static void m2sxxx_soc_initfn(Object *obj) 62ebc1fbb4SSubbaraya Sundeep { 63ebc1fbb4SSubbaraya Sundeep MSF2State *s = MSF2_SOC(obj); 64ebc1fbb4SSubbaraya Sundeep int i; 65ebc1fbb4SSubbaraya Sundeep 66db873cc5SMarkus Armbruster object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M); 67ebc1fbb4SSubbaraya Sundeep 68db873cc5SMarkus Armbruster object_initialize_child(obj, "sysreg", &s->sysreg, TYPE_MSF2_SYSREG); 69ebc1fbb4SSubbaraya Sundeep 70db873cc5SMarkus Armbruster object_initialize_child(obj, "timer", &s->timer, TYPE_MSS_TIMER); 71ebc1fbb4SSubbaraya Sundeep 72ebc1fbb4SSubbaraya Sundeep for (i = 0; i < MSF2_NUM_SPIS; i++) { 73db873cc5SMarkus Armbruster object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_MSS_SPI); 74ebc1fbb4SSubbaraya Sundeep } 7505b7374aSSubbaraya Sundeep 76db873cc5SMarkus Armbruster object_initialize_child(obj, "emac", &s->emac, TYPE_MSS_EMAC); 779bfaf375SPeter Maydell 789bfaf375SPeter Maydell s->m3clk = qdev_init_clock_in(DEVICE(obj), "m3clk", NULL, NULL, 0); 79*3b76e185SPeter Maydell s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk", NULL, NULL, 0); 80ebc1fbb4SSubbaraya Sundeep } 81ebc1fbb4SSubbaraya Sundeep 82ebc1fbb4SSubbaraya Sundeep static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp) 83ebc1fbb4SSubbaraya Sundeep { 84ebc1fbb4SSubbaraya Sundeep MSF2State *s = MSF2_SOC(dev_soc); 85ebc1fbb4SSubbaraya Sundeep DeviceState *dev, *armv7m; 86ebc1fbb4SSubbaraya Sundeep SysBusDevice *busdev; 87ebc1fbb4SSubbaraya Sundeep int i; 88ebc1fbb4SSubbaraya Sundeep 89ebc1fbb4SSubbaraya Sundeep MemoryRegion *system_memory = get_system_memory(); 90ebc1fbb4SSubbaraya Sundeep 919bfaf375SPeter Maydell if (!clock_has_source(s->m3clk)) { 929bfaf375SPeter Maydell error_setg(errp, "m3clk must be wired up by the board code"); 939bfaf375SPeter Maydell return; 949bfaf375SPeter Maydell } 959bfaf375SPeter Maydell 96*3b76e185SPeter Maydell /* 97*3b76e185SPeter Maydell * We use s->refclk internally and only define it with qdev_init_clock_in() 98*3b76e185SPeter Maydell * so it is correctly parented and not leaked on an init/deinit; it is not 99*3b76e185SPeter Maydell * intended as an externally exposed clock. 100*3b76e185SPeter Maydell */ 101*3b76e185SPeter Maydell if (clock_has_source(s->refclk)) { 102*3b76e185SPeter Maydell error_setg(errp, "refclk must not be wired up by the board code"); 103*3b76e185SPeter Maydell return; 104*3b76e185SPeter Maydell } 105*3b76e185SPeter Maydell 106*3b76e185SPeter Maydell /* 107*3b76e185SPeter Maydell * TODO: ideally we should model the SoC SYSTICK_CR register at 0xe0042038, 108*3b76e185SPeter Maydell * which allows the guest to program the divisor between the m3clk and 109*3b76e185SPeter Maydell * the systick refclk to either /4, /8, /16 or /32, as well as setting 110*3b76e185SPeter Maydell * the value the guest can read in the STCALIB register. Currently we 111*3b76e185SPeter Maydell * implement the divisor as a fixed /32, which matches the reset value 112*3b76e185SPeter Maydell * of SYSTICK_CR. 113*3b76e185SPeter Maydell */ 114*3b76e185SPeter Maydell clock_set_mul_div(s->refclk, 32, 1); 115*3b76e185SPeter Maydell clock_set_source(s->refclk, s->m3clk); 116*3b76e185SPeter Maydell 117a4b1e9d3SPeter Maydell memory_region_init_rom(&s->nvm, OBJECT(dev_soc), "MSF2.eNVM", s->envm_size, 118ebc1fbb4SSubbaraya Sundeep &error_fatal); 119ebc1fbb4SSubbaraya Sundeep /* 120ebc1fbb4SSubbaraya Sundeep * On power-on, the eNVM region 0x60000000 is automatically 121ebc1fbb4SSubbaraya Sundeep * remapped to the Cortex-M3 processor executable region 122ebc1fbb4SSubbaraya Sundeep * start address (0x0). We do not support remapping other eNVM, 123ebc1fbb4SSubbaraya Sundeep * eSRAM and DDR regions by guest(via Sysreg) currently. 124ebc1fbb4SSubbaraya Sundeep */ 125a4b1e9d3SPeter Maydell memory_region_init_alias(&s->nvm_alias, OBJECT(dev_soc), "MSF2.eNVM", 126a4b1e9d3SPeter Maydell &s->nvm, 0, s->envm_size); 127ebc1fbb4SSubbaraya Sundeep 128a4b1e9d3SPeter Maydell memory_region_add_subregion(system_memory, ENVM_BASE_ADDRESS, &s->nvm); 129a4b1e9d3SPeter Maydell memory_region_add_subregion(system_memory, 0, &s->nvm_alias); 130ebc1fbb4SSubbaraya Sundeep 131a4b1e9d3SPeter Maydell memory_region_init_ram(&s->sram, NULL, "MSF2.eSRAM", s->esram_size, 132ebc1fbb4SSubbaraya Sundeep &error_fatal); 133a4b1e9d3SPeter Maydell memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram); 134ebc1fbb4SSubbaraya Sundeep 135ebc1fbb4SSubbaraya Sundeep armv7m = DEVICE(&s->armv7m); 136ebc1fbb4SSubbaraya Sundeep qdev_prop_set_uint32(armv7m, "num-irq", 81); 137ebc1fbb4SSubbaraya Sundeep qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type); 138a1c5a062SStefan Hajnoczi qdev_prop_set_bit(armv7m, "enable-bitband", true); 1399bfaf375SPeter Maydell qdev_connect_clock_in(armv7m, "cpuclk", s->m3clk); 140*3b76e185SPeter Maydell qdev_connect_clock_in(armv7m, "refclk", s->refclk); 1415325cc34SMarkus Armbruster object_property_set_link(OBJECT(&s->armv7m), "memory", 1425325cc34SMarkus Armbruster OBJECT(get_system_memory()), &error_abort); 143668f62ecSMarkus Armbruster if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) { 144ebc1fbb4SSubbaraya Sundeep return; 145ebc1fbb4SSubbaraya Sundeep } 146ebc1fbb4SSubbaraya Sundeep 1479bfaf375SPeter Maydell system_clock_scale = clock_ticks_to_ns(s->m3clk, 1); 148ebc1fbb4SSubbaraya Sundeep 149ebc1fbb4SSubbaraya Sundeep for (i = 0; i < MSF2_NUM_UARTS; i++) { 1509bca0edbSPeter Maydell if (serial_hd(i)) { 151ebc1fbb4SSubbaraya Sundeep serial_mm_init(get_system_memory(), uart_addr[i], 2, 152ebc1fbb4SSubbaraya Sundeep qdev_get_gpio_in(armv7m, uart_irq[i]), 1539bca0edbSPeter Maydell 115200, serial_hd(i), DEVICE_NATIVE_ENDIAN); 154ebc1fbb4SSubbaraya Sundeep } 155ebc1fbb4SSubbaraya Sundeep } 156ebc1fbb4SSubbaraya Sundeep 157ebc1fbb4SSubbaraya Sundeep dev = DEVICE(&s->timer); 1589bfaf375SPeter Maydell /* 1599bfaf375SPeter Maydell * APB0 clock is the timer input clock. 1609bfaf375SPeter Maydell * TODO: ideally the MSF2 timer device should use a Clock rather than a 1619bfaf375SPeter Maydell * clock-frequency integer property. 1629bfaf375SPeter Maydell */ 1639bfaf375SPeter Maydell qdev_prop_set_uint32(dev, "clock-frequency", 1649bfaf375SPeter Maydell clock_get_hz(s->m3clk) / s->apb0div); 165668f62ecSMarkus Armbruster if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), errp)) { 166ebc1fbb4SSubbaraya Sundeep return; 167ebc1fbb4SSubbaraya Sundeep } 168ebc1fbb4SSubbaraya Sundeep busdev = SYS_BUS_DEVICE(dev); 169ebc1fbb4SSubbaraya Sundeep sysbus_mmio_map(busdev, 0, MSF2_TIMER_BASE); 170ebc1fbb4SSubbaraya Sundeep sysbus_connect_irq(busdev, 0, 171ebc1fbb4SSubbaraya Sundeep qdev_get_gpio_in(armv7m, timer_irq[0])); 172ebc1fbb4SSubbaraya Sundeep sysbus_connect_irq(busdev, 1, 173ebc1fbb4SSubbaraya Sundeep qdev_get_gpio_in(armv7m, timer_irq[1])); 174ebc1fbb4SSubbaraya Sundeep 175ebc1fbb4SSubbaraya Sundeep dev = DEVICE(&s->sysreg); 176ebc1fbb4SSubbaraya Sundeep qdev_prop_set_uint32(dev, "apb0divisor", s->apb0div); 177ebc1fbb4SSubbaraya Sundeep qdev_prop_set_uint32(dev, "apb1divisor", s->apb1div); 178668f62ecSMarkus Armbruster if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp)) { 179ebc1fbb4SSubbaraya Sundeep return; 180ebc1fbb4SSubbaraya Sundeep } 181ebc1fbb4SSubbaraya Sundeep busdev = SYS_BUS_DEVICE(dev); 182ebc1fbb4SSubbaraya Sundeep sysbus_mmio_map(busdev, 0, MSF2_SYSREG_BASE); 183ebc1fbb4SSubbaraya Sundeep 184ebc1fbb4SSubbaraya Sundeep for (i = 0; i < MSF2_NUM_SPIS; i++) { 185ebc1fbb4SSubbaraya Sundeep gchar *bus_name; 186ebc1fbb4SSubbaraya Sundeep 187668f62ecSMarkus Armbruster if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { 188ebc1fbb4SSubbaraya Sundeep return; 189ebc1fbb4SSubbaraya Sundeep } 190ebc1fbb4SSubbaraya Sundeep 191ebc1fbb4SSubbaraya Sundeep sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]); 192ebc1fbb4SSubbaraya Sundeep sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, 193ebc1fbb4SSubbaraya Sundeep qdev_get_gpio_in(armv7m, spi_irq[i])); 194ebc1fbb4SSubbaraya Sundeep 195ebc1fbb4SSubbaraya Sundeep /* Alias controller SPI bus to the SoC itself */ 196ebc1fbb4SSubbaraya Sundeep bus_name = g_strdup_printf("spi%d", i); 197ebc1fbb4SSubbaraya Sundeep object_property_add_alias(OBJECT(s), bus_name, 198d2623129SMarkus Armbruster OBJECT(&s->spi[i]), "spi"); 199ebc1fbb4SSubbaraya Sundeep g_free(bus_name); 200ebc1fbb4SSubbaraya Sundeep } 201ebc1fbb4SSubbaraya Sundeep 2022b065020SMarkus Armbruster /* FIXME use qdev NIC properties instead of nd_table[] */ 2032b065020SMarkus Armbruster if (nd_table[0].used) { 2042b065020SMarkus Armbruster qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC); 2052b065020SMarkus Armbruster qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]); 2062b065020SMarkus Armbruster } 20705b7374aSSubbaraya Sundeep dev = DEVICE(&s->emac); 2085325cc34SMarkus Armbruster object_property_set_link(OBJECT(&s->emac), "ahb-bus", 2095325cc34SMarkus Armbruster OBJECT(get_system_memory()), &error_abort); 210668f62ecSMarkus Armbruster if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), errp)) { 21105b7374aSSubbaraya Sundeep return; 21205b7374aSSubbaraya Sundeep } 21305b7374aSSubbaraya Sundeep busdev = SYS_BUS_DEVICE(dev); 21405b7374aSSubbaraya Sundeep sysbus_mmio_map(busdev, 0, MSF2_EMAC_BASE); 21505b7374aSSubbaraya Sundeep sysbus_connect_irq(busdev, 0, 21605b7374aSSubbaraya Sundeep qdev_get_gpio_in(armv7m, MSF2_EMAC_IRQ)); 21705b7374aSSubbaraya Sundeep 218ebc1fbb4SSubbaraya Sundeep /* Below devices are not modelled yet. */ 219ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("i2c_0", 0x40002000, 0x1000); 220ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("dma", 0x40003000, 0x1000); 221ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("watchdog", 0x40005000, 0x1000); 222ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("i2c_1", 0x40012000, 0x1000); 223ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("gpio", 0x40013000, 0x1000); 224ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("hs-dma", 0x40014000, 0x1000); 225ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("can", 0x40015000, 0x1000); 226ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("rtc", 0x40017000, 0x1000); 227ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("apb_config", 0x40020000, 0x10000); 228ebc1fbb4SSubbaraya Sundeep create_unimplemented_device("usb", 0x40043000, 0x1000); 229ebc1fbb4SSubbaraya Sundeep } 230ebc1fbb4SSubbaraya Sundeep 231ebc1fbb4SSubbaraya Sundeep static Property m2sxxx_soc_properties[] = { 232ebc1fbb4SSubbaraya Sundeep /* 233ebc1fbb4SSubbaraya Sundeep * part name specifies the type of SmartFusion2 device variant(this 234ebc1fbb4SSubbaraya Sundeep * property is for information purpose only. 235ebc1fbb4SSubbaraya Sundeep */ 236ebc1fbb4SSubbaraya Sundeep DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type), 237ebc1fbb4SSubbaraya Sundeep DEFINE_PROP_STRING("part-name", MSF2State, part_name), 238ebc1fbb4SSubbaraya Sundeep DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE), 239ebc1fbb4SSubbaraya Sundeep DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size, 240ebc1fbb4SSubbaraya Sundeep MSF2_ESRAM_MAX_SIZE), 241ebc1fbb4SSubbaraya Sundeep /* default divisors in Libero GUI */ 242ebc1fbb4SSubbaraya Sundeep DEFINE_PROP_UINT8("apb0div", MSF2State, apb0div, 2), 243ebc1fbb4SSubbaraya Sundeep DEFINE_PROP_UINT8("apb1div", MSF2State, apb1div, 2), 244ebc1fbb4SSubbaraya Sundeep DEFINE_PROP_END_OF_LIST(), 245ebc1fbb4SSubbaraya Sundeep }; 246ebc1fbb4SSubbaraya Sundeep 247ebc1fbb4SSubbaraya Sundeep static void m2sxxx_soc_class_init(ObjectClass *klass, void *data) 248ebc1fbb4SSubbaraya Sundeep { 249ebc1fbb4SSubbaraya Sundeep DeviceClass *dc = DEVICE_CLASS(klass); 250ebc1fbb4SSubbaraya Sundeep 251ebc1fbb4SSubbaraya Sundeep dc->realize = m2sxxx_soc_realize; 2524f67d30bSMarc-André Lureau device_class_set_props(dc, m2sxxx_soc_properties); 253ebc1fbb4SSubbaraya Sundeep } 254ebc1fbb4SSubbaraya Sundeep 255ebc1fbb4SSubbaraya Sundeep static const TypeInfo m2sxxx_soc_info = { 256ebc1fbb4SSubbaraya Sundeep .name = TYPE_MSF2_SOC, 257ebc1fbb4SSubbaraya Sundeep .parent = TYPE_SYS_BUS_DEVICE, 258ebc1fbb4SSubbaraya Sundeep .instance_size = sizeof(MSF2State), 259ebc1fbb4SSubbaraya Sundeep .instance_init = m2sxxx_soc_initfn, 260ebc1fbb4SSubbaraya Sundeep .class_init = m2sxxx_soc_class_init, 261ebc1fbb4SSubbaraya Sundeep }; 262ebc1fbb4SSubbaraya Sundeep 263ebc1fbb4SSubbaraya Sundeep static void m2sxxx_soc_types(void) 264ebc1fbb4SSubbaraya Sundeep { 265ebc1fbb4SSubbaraya Sundeep type_register_static(&m2sxxx_soc_info); 266ebc1fbb4SSubbaraya Sundeep } 267ebc1fbb4SSubbaraya Sundeep 268ebc1fbb4SSubbaraya Sundeep type_init(m2sxxx_soc_types) 269