imx25_ccm.c 8.8 KB

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