xref: /openbmc/qemu/hw/arm/msf2-soc.c (revision 2113aed6)
1  /*
2   * SmartFusion2 SoC emulation.
3   *
4   * Copyright (c) 2017-2020 Subbaraya Sundeep <sundeep.lkml@gmail.com>
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  #include "qemu/osdep.h"
26  #include "qemu/units.h"
27  #include "qapi/error.h"
28  #include "exec/address-spaces.h"
29  #include "hw/char/serial.h"
30  #include "hw/arm/msf2-soc.h"
31  #include "hw/misc/unimp.h"
32  #include "hw/qdev-clock.h"
33  #include "sysemu/sysemu.h"
34  
35  #define MSF2_TIMER_BASE       0x40004000
36  #define MSF2_SYSREG_BASE      0x40038000
37  #define MSF2_EMAC_BASE        0x40041000
38  
39  #define ENVM_BASE_ADDRESS     0x60000000
40  
41  #define SRAM_BASE_ADDRESS     0x20000000
42  
43  #define MSF2_EMAC_IRQ         12
44  
45  #define MSF2_ENVM_MAX_SIZE    (512 * KiB)
46  
47  /*
48   * eSRAM max size is 80k without SECDED(Single error correction and
49   * dual error detection) feature and 64k with SECDED.
50   * We do not support SECDED now.
51   */
52  #define MSF2_ESRAM_MAX_SIZE       (80 * KiB)
53  
54  static const uint32_t spi_addr[MSF2_NUM_SPIS] = { 0x40001000 , 0x40011000 };
55  static const uint32_t uart_addr[MSF2_NUM_UARTS] = { 0x40000000 , 0x40010000 };
56  
57  static const int spi_irq[MSF2_NUM_SPIS] = { 2, 3 };
58  static const int uart_irq[MSF2_NUM_UARTS] = { 10, 11 };
59  static const int timer_irq[MSF2_NUM_TIMERS] = { 14, 15 };
60  
61  static void m2sxxx_soc_initfn(Object *obj)
62  {
63      MSF2State *s = MSF2_SOC(obj);
64      int i;
65  
66      object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
67  
68      object_initialize_child(obj, "sysreg", &s->sysreg, TYPE_MSF2_SYSREG);
69  
70      object_initialize_child(obj, "timer", &s->timer, TYPE_MSS_TIMER);
71  
72      for (i = 0; i < MSF2_NUM_SPIS; i++) {
73          object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_MSS_SPI);
74      }
75  
76      object_initialize_child(obj, "emac", &s->emac, TYPE_MSS_EMAC);
77  
78      s->m3clk = qdev_init_clock_in(DEVICE(obj), "m3clk", NULL, NULL, 0);
79      s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk", NULL, NULL, 0);
80  }
81  
82  static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
83  {
84      MSF2State *s = MSF2_SOC(dev_soc);
85      DeviceState *dev, *armv7m;
86      SysBusDevice *busdev;
87      int i;
88  
89      MemoryRegion *system_memory = get_system_memory();
90  
91      if (!clock_has_source(s->m3clk)) {
92          error_setg(errp, "m3clk must be wired up by the board code");
93          return;
94      }
95  
96      /*
97       * We use s->refclk internally and only define it with qdev_init_clock_in()
98       * so it is correctly parented and not leaked on an init/deinit; it is not
99       * intended as an externally exposed clock.
100       */
101      if (clock_has_source(s->refclk)) {
102          error_setg(errp, "refclk must not be wired up by the board code");
103          return;
104      }
105  
106      /*
107       * TODO: ideally we should model the SoC SYSTICK_CR register at 0xe0042038,
108       * which allows the guest to program the divisor between the m3clk and
109       * the systick refclk to either /4, /8, /16 or /32, as well as setting
110       * the value the guest can read in the STCALIB register. Currently we
111       * implement the divisor as a fixed /32, which matches the reset value
112       * of SYSTICK_CR.
113       */
114      clock_set_mul_div(s->refclk, 32, 1);
115      clock_set_source(s->refclk, s->m3clk);
116  
117      memory_region_init_rom(&s->nvm, OBJECT(dev_soc), "MSF2.eNVM", s->envm_size,
118                             &error_fatal);
119      /*
120       * On power-on, the eNVM region 0x60000000 is automatically
121       * remapped to the Cortex-M3 processor executable region
122       * start address (0x0). We do not support remapping other eNVM,
123       * eSRAM and DDR regions by guest(via Sysreg) currently.
124       */
125      memory_region_init_alias(&s->nvm_alias, OBJECT(dev_soc), "MSF2.eNVM",
126                               &s->nvm, 0, s->envm_size);
127  
128      memory_region_add_subregion(system_memory, ENVM_BASE_ADDRESS, &s->nvm);
129      memory_region_add_subregion(system_memory, 0, &s->nvm_alias);
130  
131      memory_region_init_ram(&s->sram, NULL, "MSF2.eSRAM", s->esram_size,
132                             &error_fatal);
133      memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
134  
135      armv7m = DEVICE(&s->armv7m);
136      qdev_prop_set_uint32(armv7m, "num-irq", 81);
137      qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
138      qdev_prop_set_bit(armv7m, "enable-bitband", true);
139      qdev_connect_clock_in(armv7m, "cpuclk", s->m3clk);
140      qdev_connect_clock_in(armv7m, "refclk", s->refclk);
141      object_property_set_link(OBJECT(&s->armv7m), "memory",
142                               OBJECT(get_system_memory()), &error_abort);
143      if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
144          return;
145      }
146  
147      for (i = 0; i < MSF2_NUM_UARTS; i++) {
148          if (serial_hd(i)) {
149              serial_mm_init(get_system_memory(), uart_addr[i], 2,
150                             qdev_get_gpio_in(armv7m, uart_irq[i]),
151                             115200, serial_hd(i), DEVICE_NATIVE_ENDIAN);
152          }
153      }
154  
155      dev = DEVICE(&s->timer);
156      /*
157       * APB0 clock is the timer input clock.
158       * TODO: ideally the MSF2 timer device should use a Clock rather than a
159       * clock-frequency integer property.
160       */
161      qdev_prop_set_uint32(dev, "clock-frequency",
162                           clock_get_hz(s->m3clk) / s->apb0div);
163      if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), errp)) {
164          return;
165      }
166      busdev = SYS_BUS_DEVICE(dev);
167      sysbus_mmio_map(busdev, 0, MSF2_TIMER_BASE);
168      sysbus_connect_irq(busdev, 0,
169                             qdev_get_gpio_in(armv7m, timer_irq[0]));
170      sysbus_connect_irq(busdev, 1,
171                             qdev_get_gpio_in(armv7m, timer_irq[1]));
172  
173      dev = DEVICE(&s->sysreg);
174      qdev_prop_set_uint32(dev, "apb0divisor", s->apb0div);
175      qdev_prop_set_uint32(dev, "apb1divisor", s->apb1div);
176      if (!sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp)) {
177          return;
178      }
179      busdev = SYS_BUS_DEVICE(dev);
180      sysbus_mmio_map(busdev, 0, MSF2_SYSREG_BASE);
181  
182      for (i = 0; i < MSF2_NUM_SPIS; i++) {
183          gchar *bus_name;
184  
185          if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
186              return;
187          }
188  
189          sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]);
190          sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
191                             qdev_get_gpio_in(armv7m, spi_irq[i]));
192  
193          /* Alias controller SPI bus to the SoC itself */
194          bus_name = g_strdup_printf("spi%d", i);
195          object_property_add_alias(OBJECT(s), bus_name,
196                                    OBJECT(&s->spi[i]), "spi");
197          g_free(bus_name);
198      }
199  
200      /* FIXME use qdev NIC properties instead of nd_table[] */
201      if (nd_table[0].used) {
202          qemu_check_nic_model(&nd_table[0], TYPE_MSS_EMAC);
203          qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
204      }
205      dev = DEVICE(&s->emac);
206      object_property_set_link(OBJECT(&s->emac), "ahb-bus",
207                               OBJECT(get_system_memory()), &error_abort);
208      if (!sysbus_realize(SYS_BUS_DEVICE(&s->emac), errp)) {
209          return;
210      }
211      busdev = SYS_BUS_DEVICE(dev);
212      sysbus_mmio_map(busdev, 0, MSF2_EMAC_BASE);
213      sysbus_connect_irq(busdev, 0,
214                         qdev_get_gpio_in(armv7m, MSF2_EMAC_IRQ));
215  
216      /* Below devices are not modelled yet. */
217      create_unimplemented_device("i2c_0", 0x40002000, 0x1000);
218      create_unimplemented_device("dma", 0x40003000, 0x1000);
219      create_unimplemented_device("watchdog", 0x40005000, 0x1000);
220      create_unimplemented_device("i2c_1", 0x40012000, 0x1000);
221      create_unimplemented_device("gpio", 0x40013000, 0x1000);
222      create_unimplemented_device("hs-dma", 0x40014000, 0x1000);
223      create_unimplemented_device("can", 0x40015000, 0x1000);
224      create_unimplemented_device("rtc", 0x40017000, 0x1000);
225      create_unimplemented_device("apb_config", 0x40020000, 0x10000);
226      create_unimplemented_device("usb", 0x40043000, 0x1000);
227  }
228  
229  static Property m2sxxx_soc_properties[] = {
230      /*
231       * part name specifies the type of SmartFusion2 device variant(this
232       * property is for information purpose only.
233       */
234      DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type),
235      DEFINE_PROP_STRING("part-name", MSF2State, part_name),
236      DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE),
237      DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size,
238                          MSF2_ESRAM_MAX_SIZE),
239      /* default divisors in Libero GUI */
240      DEFINE_PROP_UINT8("apb0div", MSF2State, apb0div, 2),
241      DEFINE_PROP_UINT8("apb1div", MSF2State, apb1div, 2),
242      DEFINE_PROP_END_OF_LIST(),
243  };
244  
245  static void m2sxxx_soc_class_init(ObjectClass *klass, void *data)
246  {
247      DeviceClass *dc = DEVICE_CLASS(klass);
248  
249      dc->realize = m2sxxx_soc_realize;
250      device_class_set_props(dc, m2sxxx_soc_properties);
251  }
252  
253  static const TypeInfo m2sxxx_soc_info = {
254      .name          = TYPE_MSF2_SOC,
255      .parent        = TYPE_SYS_BUS_DEVICE,
256      .instance_size = sizeof(MSF2State),
257      .instance_init = m2sxxx_soc_initfn,
258      .class_init    = m2sxxx_soc_class_init,
259  };
260  
261  static void m2sxxx_soc_types(void)
262  {
263      type_register_static(&m2sxxx_soc_info);
264  }
265  
266  type_init(m2sxxx_soc_types)
267