xref: /openbmc/qemu/hw/misc/imx25_ccm.c (revision 59c2ddedcbe70a9ead3378b4946edc66b8757cb6)
1  /*
2   * IMX25 Clock Control Module
3   *
4   * Copyright (C) 2012 NICTA
5   * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
6   *
7   * This work is licensed under the terms of the GNU GPL, version 2 or later.
8   * See the COPYING file in the top-level directory.
9   *
10   * To get the timer frequencies right, we need to emulate at least part of
11   * the CCM.
12   */
13  
14  #include "qemu/osdep.h"
15  #include "hw/misc/imx25_ccm.h"
16  #include "migration/vmstate.h"
17  #include "qemu/log.h"
18  #include "qemu/module.h"
19  
20  #ifndef DEBUG_IMX25_CCM
21  #define DEBUG_IMX25_CCM 0
22  #endif
23  
24  #define DPRINTF(fmt, args...) \
25      do { \
26          if (DEBUG_IMX25_CCM) { \
27              fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \
28                                               __func__, ##args); \
29          } \
30      } while (0)
31  
32  static const char *imx25_ccm_reg_name(uint32_t reg)
33  {
34      static char unknown[20];
35  
36      switch (reg) {
37      case IMX25_CCM_MPCTL_REG:
38          return "mpctl";
39      case IMX25_CCM_UPCTL_REG:
40          return "upctl";
41      case IMX25_CCM_CCTL_REG:
42          return "cctl";
43      case IMX25_CCM_CGCR0_REG:
44          return "cgcr0";
45      case IMX25_CCM_CGCR1_REG:
46          return "cgcr1";
47      case IMX25_CCM_CGCR2_REG:
48          return "cgcr2";
49      case IMX25_CCM_PCDR0_REG:
50          return "pcdr0";
51      case IMX25_CCM_PCDR1_REG:
52          return "pcdr1";
53      case IMX25_CCM_PCDR2_REG:
54          return "pcdr2";
55      case IMX25_CCM_PCDR3_REG:
56          return "pcdr3";
57      case IMX25_CCM_RCSR_REG:
58          return "rcsr";
59      case IMX25_CCM_CRDR_REG:
60          return "crdr";
61      case IMX25_CCM_DCVR0_REG:
62          return "dcvr0";
63      case IMX25_CCM_DCVR1_REG:
64          return "dcvr1";
65      case IMX25_CCM_DCVR2_REG:
66          return "dcvr2";
67      case IMX25_CCM_DCVR3_REG:
68          return "dcvr3";
69      case IMX25_CCM_LTR0_REG:
70          return "ltr0";
71      case IMX25_CCM_LTR1_REG:
72          return "ltr1";
73      case IMX25_CCM_LTR2_REG:
74          return "ltr2";
75      case IMX25_CCM_LTR3_REG:
76          return "ltr3";
77      case IMX25_CCM_LTBR0_REG:
78          return "ltbr0";
79      case IMX25_CCM_LTBR1_REG:
80          return "ltbr1";
81      case IMX25_CCM_PMCR0_REG:
82          return "pmcr0";
83      case IMX25_CCM_PMCR1_REG:
84          return "pmcr1";
85      case IMX25_CCM_PMCR2_REG:
86          return "pmcr2";
87      case IMX25_CCM_MCR_REG:
88          return "mcr";
89      case IMX25_CCM_LPIMR0_REG:
90          return "lpimr0";
91      case IMX25_CCM_LPIMR1_REG:
92          return "lpimr1";
93      default:
94          sprintf(unknown, "[%u ?]", reg);
95          return unknown;
96      }
97  }
98  #define CKIH_FREQ 24000000 /* 24MHz crystal input */
99  
100  static const VMStateDescription vmstate_imx25_ccm = {
101      .name = TYPE_IMX25_CCM,
102      .version_id = 1,
103      .minimum_version_id = 1,
104      .fields = (const VMStateField[]) {
105          VMSTATE_UINT32_ARRAY(reg, IMX25CCMState, IMX25_CCM_MAX_REG),
106          VMSTATE_END_OF_LIST()
107      },
108  };
109  
110  static uint32_t imx25_ccm_get_mpll_clk(IMXCCMState *dev)
111  {
112      uint32_t freq;
113      IMX25CCMState *s = IMX25_CCM(dev);
114  
115      if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], MPLL_BYPASS)) {
116          freq = CKIH_FREQ;
117      } else {
118          freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_MPCTL_REG], CKIH_FREQ);
119      }
120  
121      DPRINTF("freq = %u\n", freq);
122  
123      return freq;
124  }
125  
126  static uint32_t imx25_ccm_get_mcu_clk(IMXCCMState *dev)
127  {
128      uint32_t freq;
129      IMX25CCMState *s = IMX25_CCM(dev);
130  
131      freq = imx25_ccm_get_mpll_clk(dev);
132  
133      if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_SRC)) {
134          freq = (freq * 3 / 4);
135      }
136  
137      freq = freq / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_CLK_DIV));
138  
139      DPRINTF("freq = %u\n", freq);
140  
141      return freq;
142  }
143  
144  static uint32_t imx25_ccm_get_ahb_clk(IMXCCMState *dev)
145  {
146      uint32_t freq;
147      IMX25CCMState *s = IMX25_CCM(dev);
148  
149      freq = imx25_ccm_get_mcu_clk(dev)
150             / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], AHB_CLK_DIV));
151  
152      DPRINTF("freq = %u\n", freq);
153  
154      return freq;
155  }
156  
157  static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev)
158  {
159      uint32_t freq;
160  
161      freq = imx25_ccm_get_ahb_clk(dev) / 2;
162  
163      DPRINTF("freq = %u\n", freq);
164  
165      return freq;
166  }
167  
168  static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
169  {
170      uint32_t freq = 0;
171      DPRINTF("Clock = %d)\n", clock);
172  
173      switch (clock) {
174      case CLK_NONE:
175          break;
176      case CLK_IPG:
177      case CLK_IPG_HIGH:
178          freq = imx25_ccm_get_ipg_clk(dev);
179          break;
180      case CLK_32k:
181          freq = CKIL_FREQ;
182          break;
183      default:
184          qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
185                        TYPE_IMX25_CCM, __func__, clock);
186          break;
187      }
188  
189      DPRINTF("Clock = %d) = %u\n", clock, freq);
190  
191      return freq;
192  }
193  
194  static void imx25_ccm_reset(DeviceState *dev)
195  {
196      IMX25CCMState *s = IMX25_CCM(dev);
197  
198      DPRINTF("\n");
199  
200      memset(s->reg, 0, IMX25_CCM_MAX_REG * sizeof(uint32_t));
201      s->reg[IMX25_CCM_MPCTL_REG] = 0x800b2c01;
202      s->reg[IMX25_CCM_UPCTL_REG] = 0x84042800;
203      /*
204       * The value below gives:
205       * CPU = 133 MHz, AHB = 66,5 MHz, IPG = 33 MHz.
206       */
207      s->reg[IMX25_CCM_CCTL_REG]  = 0xd0030000;
208      s->reg[IMX25_CCM_CGCR0_REG] = 0x028A0100;
209      s->reg[IMX25_CCM_CGCR1_REG] = 0x04008100;
210      s->reg[IMX25_CCM_CGCR2_REG] = 0x00000438;
211      s->reg[IMX25_CCM_PCDR0_REG] = 0x01010101;
212      s->reg[IMX25_CCM_PCDR1_REG] = 0x01010101;
213      s->reg[IMX25_CCM_PCDR2_REG] = 0x01010101;
214      s->reg[IMX25_CCM_PCDR3_REG] = 0x01010101;
215      s->reg[IMX25_CCM_PMCR0_REG] = 0x00A00000;
216      s->reg[IMX25_CCM_PMCR1_REG] = 0x0000A030;
217      s->reg[IMX25_CCM_PMCR2_REG] = 0x0000A030;
218      s->reg[IMX25_CCM_MCR_REG]   = 0x43000000;
219  
220      /*
221       * default boot will change the reset values to allow:
222       * CPU = 399 MHz, AHB = 133 MHz, IPG = 66,5 MHz.
223       * For some reason, this doesn't work. With the value below, linux
224       * detects a 88 MHz IPG CLK instead of 66,5 MHz.
225      s->reg[IMX25_CCM_CCTL_REG]  = 0x20032000;
226       */
227  }
228  
229  static uint64_t imx25_ccm_read(void *opaque, hwaddr offset, unsigned size)
230  {
231      uint32_t value = 0;
232      IMX25CCMState *s = (IMX25CCMState *)opaque;
233  
234      if (offset < 0x70) {
235          value = s->reg[offset >> 2];
236      } else {
237          qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
238                        HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
239      }
240  
241      DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
242              value);
243  
244      return value;
245  }
246  
247  static void imx25_ccm_write(void *opaque, hwaddr offset, uint64_t value,
248                              unsigned size)
249  {
250      IMX25CCMState *s = (IMX25CCMState *)opaque;
251  
252      DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
253              (uint32_t)value);
254  
255      if (offset < 0x70) {
256          /*
257           * We will do a better implementation later. In particular some bits
258           * cannot be written to.
259           */
260          s->reg[offset >> 2] = value;
261      } else {
262          qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
263                        HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
264      }
265  }
266  
267  static const struct MemoryRegionOps imx25_ccm_ops = {
268      .read = imx25_ccm_read,
269      .write = imx25_ccm_write,
270      .endianness = DEVICE_NATIVE_ENDIAN,
271      .valid = {
272          /*
273           * Our device would not work correctly if the guest was doing
274           * unaligned access. This might not be a limitation on the real
275           * device but in practice there is no reason for a guest to access
276           * this device unaligned.
277           */
278          .min_access_size = 4,
279          .max_access_size = 4,
280          .unaligned = false,
281      },
282  };
283  
284  static void imx25_ccm_init(Object *obj)
285  {
286      DeviceState *dev = DEVICE(obj);
287      SysBusDevice *sd = SYS_BUS_DEVICE(obj);
288      IMX25CCMState *s = IMX25_CCM(obj);
289  
290      memory_region_init_io(&s->iomem, OBJECT(dev), &imx25_ccm_ops, s,
291                            TYPE_IMX25_CCM, 0x1000);
292      sysbus_init_mmio(sd, &s->iomem);
293  }
294  
295  static void imx25_ccm_class_init(ObjectClass *klass, void *data)
296  {
297      DeviceClass *dc = DEVICE_CLASS(klass);
298      IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
299  
300      dc->reset = imx25_ccm_reset;
301      dc->vmsd = &vmstate_imx25_ccm;
302      dc->desc = "i.MX25 Clock Control Module";
303  
304      ccm->get_clock_frequency = imx25_ccm_get_clock_frequency;
305  }
306  
307  static const TypeInfo imx25_ccm_info = {
308      .name          = TYPE_IMX25_CCM,
309      .parent        = TYPE_IMX_CCM,
310      .instance_size = sizeof(IMX25CCMState),
311      .instance_init = imx25_ccm_init,
312      .class_init    = imx25_ccm_class_init,
313  };
314  
315  static void imx25_ccm_register_types(void)
316  {
317      type_register_static(&imx25_ccm_info);
318  }
319  
320  type_init(imx25_ccm_register_types)
321