npcm_clk.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220
  1. /*
  2. * Nuvoton NPCM7xx/8xx Clock Control Registers.
  3. *
  4. * Copyright 2020 Google LLC
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * for more details.
  15. */
  16. #include "qemu/osdep.h"
  17. #include "hw/misc/npcm_clk.h"
  18. #include "hw/timer/npcm7xx_timer.h"
  19. #include "hw/qdev-clock.h"
  20. #include "migration/vmstate.h"
  21. #include "qemu/error-report.h"
  22. #include "qemu/log.h"
  23. #include "qemu/module.h"
  24. #include "qemu/timer.h"
  25. #include "qemu/units.h"
  26. #include "trace.h"
  27. #include "system/watchdog.h"
  28. /*
  29. * The reference clock hz, and the SECCNT and CNTR25M registers in this module,
  30. * is always 25 MHz.
  31. */
  32. #define NPCM7XX_CLOCK_REF_HZ (25000000)
  33. /* Register Field Definitions */
  34. #define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex-A9 Cores */
  35. #define PLLCON_LOKI BIT(31)
  36. #define PLLCON_LOKS BIT(30)
  37. #define PLLCON_PWDEN BIT(12)
  38. #define PLLCON_FBDV(con) extract32((con), 16, 12)
  39. #define PLLCON_OTDV2(con) extract32((con), 13, 3)
  40. #define PLLCON_OTDV1(con) extract32((con), 8, 3)
  41. #define PLLCON_INDV(con) extract32((con), 0, 6)
  42. enum NPCM7xxCLKRegisters {
  43. NPCM7XX_CLK_CLKEN1,
  44. NPCM7XX_CLK_CLKSEL,
  45. NPCM7XX_CLK_CLKDIV1,
  46. NPCM7XX_CLK_PLLCON0,
  47. NPCM7XX_CLK_PLLCON1,
  48. NPCM7XX_CLK_SWRSTR,
  49. NPCM7XX_CLK_IPSRST1 = 0x20 / sizeof(uint32_t),
  50. NPCM7XX_CLK_IPSRST2,
  51. NPCM7XX_CLK_CLKEN2,
  52. NPCM7XX_CLK_CLKDIV2,
  53. NPCM7XX_CLK_CLKEN3,
  54. NPCM7XX_CLK_IPSRST3,
  55. NPCM7XX_CLK_WD0RCR,
  56. NPCM7XX_CLK_WD1RCR,
  57. NPCM7XX_CLK_WD2RCR,
  58. NPCM7XX_CLK_SWRSTC1,
  59. NPCM7XX_CLK_SWRSTC2,
  60. NPCM7XX_CLK_SWRSTC3,
  61. NPCM7XX_CLK_SWRSTC4,
  62. NPCM7XX_CLK_PLLCON2,
  63. NPCM7XX_CLK_CLKDIV3,
  64. NPCM7XX_CLK_CORSTC,
  65. NPCM7XX_CLK_PLLCONG,
  66. NPCM7XX_CLK_AHBCKFI,
  67. NPCM7XX_CLK_SECCNT,
  68. NPCM7XX_CLK_CNTR25M,
  69. };
  70. enum NPCM8xxCLKRegisters {
  71. NPCM8XX_CLK_CLKEN1,
  72. NPCM8XX_CLK_CLKSEL,
  73. NPCM8XX_CLK_CLKDIV1,
  74. NPCM8XX_CLK_PLLCON0,
  75. NPCM8XX_CLK_PLLCON1,
  76. NPCM8XX_CLK_SWRSTR,
  77. NPCM8XX_CLK_IPSRST1 = 0x20 / sizeof(uint32_t),
  78. NPCM8XX_CLK_IPSRST2,
  79. NPCM8XX_CLK_CLKEN2,
  80. NPCM8XX_CLK_CLKDIV2,
  81. NPCM8XX_CLK_CLKEN3,
  82. NPCM8XX_CLK_IPSRST3,
  83. NPCM8XX_CLK_WD0RCR,
  84. NPCM8XX_CLK_WD1RCR,
  85. NPCM8XX_CLK_WD2RCR,
  86. NPCM8XX_CLK_SWRSTC1,
  87. NPCM8XX_CLK_SWRSTC2,
  88. NPCM8XX_CLK_SWRSTC3,
  89. NPCM8XX_CLK_TIPRSTC,
  90. NPCM8XX_CLK_PLLCON2,
  91. NPCM8XX_CLK_CLKDIV3,
  92. NPCM8XX_CLK_CORSTC,
  93. NPCM8XX_CLK_PLLCONG,
  94. NPCM8XX_CLK_AHBCKFI,
  95. NPCM8XX_CLK_SECCNT,
  96. NPCM8XX_CLK_CNTR25M,
  97. /* Registers unique to NPCM8XX SoC */
  98. NPCM8XX_CLK_CLKEN4,
  99. NPCM8XX_CLK_IPSRST4,
  100. NPCM8XX_CLK_BUSTO,
  101. NPCM8XX_CLK_CLKDIV4,
  102. NPCM8XX_CLK_WD0RCRB,
  103. NPCM8XX_CLK_WD1RCRB,
  104. NPCM8XX_CLK_WD2RCRB,
  105. NPCM8XX_CLK_SWRSTC1B,
  106. NPCM8XX_CLK_SWRSTC2B,
  107. NPCM8XX_CLK_SWRSTC3B,
  108. NPCM8XX_CLK_TIPRSTCB,
  109. NPCM8XX_CLK_CORSTCB,
  110. NPCM8XX_CLK_IPSRSTDIS1,
  111. NPCM8XX_CLK_IPSRSTDIS2,
  112. NPCM8XX_CLK_IPSRSTDIS3,
  113. NPCM8XX_CLK_IPSRSTDIS4,
  114. NPCM8XX_CLK_CLKENDIS1,
  115. NPCM8XX_CLK_CLKENDIS2,
  116. NPCM8XX_CLK_CLKENDIS3,
  117. NPCM8XX_CLK_CLKENDIS4,
  118. NPCM8XX_CLK_THRTL_CNT,
  119. };
  120. /*
  121. * These reset values were taken from version 0.91 of the NPCM750R data sheet.
  122. *
  123. * All are loaded on power-up reset. CLKENx and SWRSTR should also be loaded on
  124. * core domain reset, but this reset type is not yet supported by QEMU.
  125. */
  126. static const uint32_t npcm7xx_cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
  127. [NPCM7XX_CLK_CLKEN1] = 0xffffffff,
  128. [NPCM7XX_CLK_CLKSEL] = 0x004aaaaa,
  129. [NPCM7XX_CLK_CLKDIV1] = 0x5413f855,
  130. [NPCM7XX_CLK_PLLCON0] = 0x00222101 | PLLCON_LOKI,
  131. [NPCM7XX_CLK_PLLCON1] = 0x00202101 | PLLCON_LOKI,
  132. [NPCM7XX_CLK_IPSRST1] = 0x00001000,
  133. [NPCM7XX_CLK_IPSRST2] = 0x80000000,
  134. [NPCM7XX_CLK_CLKEN2] = 0xffffffff,
  135. [NPCM7XX_CLK_CLKDIV2] = 0xaa4f8f9f,
  136. [NPCM7XX_CLK_CLKEN3] = 0xffffffff,
  137. [NPCM7XX_CLK_IPSRST3] = 0x03000000,
  138. [NPCM7XX_CLK_WD0RCR] = 0xffffffff,
  139. [NPCM7XX_CLK_WD1RCR] = 0xffffffff,
  140. [NPCM7XX_CLK_WD2RCR] = 0xffffffff,
  141. [NPCM7XX_CLK_SWRSTC1] = 0x00000003,
  142. [NPCM7XX_CLK_PLLCON2] = 0x00c02105 | PLLCON_LOKI,
  143. [NPCM7XX_CLK_CORSTC] = 0x04000003,
  144. [NPCM7XX_CLK_PLLCONG] = 0x01228606 | PLLCON_LOKI,
  145. [NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
  146. };
  147. /*
  148. * These reset values were taken from version 0.92 of the NPCM8xx data sheet.
  149. */
  150. static const uint32_t npcm8xx_cold_reset_values[NPCM8XX_CLK_NR_REGS] = {
  151. [NPCM8XX_CLK_CLKEN1] = 0xffffffff,
  152. [NPCM8XX_CLK_CLKSEL] = 0x154aaaaa,
  153. [NPCM8XX_CLK_CLKDIV1] = 0x5413f855,
  154. [NPCM8XX_CLK_PLLCON0] = 0x00222101 | PLLCON_LOKI,
  155. [NPCM8XX_CLK_PLLCON1] = 0x00202101 | PLLCON_LOKI,
  156. [NPCM8XX_CLK_IPSRST1] = 0x00001000,
  157. [NPCM8XX_CLK_IPSRST2] = 0x80000000,
  158. [NPCM8XX_CLK_CLKEN2] = 0xffffffff,
  159. [NPCM8XX_CLK_CLKDIV2] = 0xaa4f8f9f,
  160. [NPCM8XX_CLK_CLKEN3] = 0xffffffff,
  161. [NPCM8XX_CLK_IPSRST3] = 0x03000000,
  162. [NPCM8XX_CLK_WD0RCR] = 0xffffffff,
  163. [NPCM8XX_CLK_WD1RCR] = 0xffffffff,
  164. [NPCM8XX_CLK_WD2RCR] = 0xffffffff,
  165. [NPCM8XX_CLK_SWRSTC1] = 0x00000003,
  166. [NPCM8XX_CLK_SWRSTC2] = 0x00000001,
  167. [NPCM8XX_CLK_SWRSTC3] = 0x00000001,
  168. [NPCM8XX_CLK_TIPRSTC] = 0x00000001,
  169. [NPCM8XX_CLK_PLLCON2] = 0x00c02105 | PLLCON_LOKI,
  170. [NPCM8XX_CLK_CLKDIV3] = 0x00009100,
  171. [NPCM8XX_CLK_CORSTC] = 0x04000003,
  172. [NPCM8XX_CLK_PLLCONG] = 0x01228606 | PLLCON_LOKI,
  173. [NPCM8XX_CLK_AHBCKFI] = 0x000000c8,
  174. [NPCM8XX_CLK_CLKEN4] = 0xffffffff,
  175. [NPCM8XX_CLK_CLKDIV4] = 0x70009000,
  176. [NPCM8XX_CLK_IPSRST4] = 0x02000000,
  177. [NPCM8XX_CLK_WD0RCRB] = 0xfffffe71,
  178. [NPCM8XX_CLK_WD1RCRB] = 0xfffffe71,
  179. [NPCM8XX_CLK_WD2RCRB] = 0xfffffe71,
  180. [NPCM8XX_CLK_SWRSTC1B] = 0xfffffe71,
  181. [NPCM8XX_CLK_SWRSTC2B] = 0xfffffe71,
  182. [NPCM8XX_CLK_SWRSTC3B] = 0xfffffe71,
  183. [NPCM8XX_CLK_TIPRSTCB] = 0xfffffe71,
  184. [NPCM8XX_CLK_CORSTCB] = 0xfffffe71,
  185. };
  186. /* The number of watchdogs that can trigger a reset. */
  187. #define NPCM7XX_NR_WATCHDOGS (3)
  188. /* Clock converter functions */
  189. #define TYPE_NPCM7XX_CLOCK_PLL "npcm7xx-clock-pll"
  190. #define NPCM7XX_CLOCK_PLL(obj) OBJECT_CHECK(NPCM7xxClockPLLState, \
  191. (obj), TYPE_NPCM7XX_CLOCK_PLL)
  192. #define TYPE_NPCM7XX_CLOCK_SEL "npcm7xx-clock-sel"
  193. #define NPCM7XX_CLOCK_SEL(obj) OBJECT_CHECK(NPCM7xxClockSELState, \
  194. (obj), TYPE_NPCM7XX_CLOCK_SEL)
  195. #define TYPE_NPCM7XX_CLOCK_DIVIDER "npcm7xx-clock-divider"
  196. #define NPCM7XX_CLOCK_DIVIDER(obj) OBJECT_CHECK(NPCM7xxClockDividerState, \
  197. (obj), TYPE_NPCM7XX_CLOCK_DIVIDER)
  198. static void npcm7xx_clk_update_pll(void *opaque)
  199. {
  200. NPCM7xxClockPLLState *s = opaque;
  201. uint32_t con = s->clk->regs[s->reg];
  202. uint64_t freq;
  203. /* The PLL is grounded if it is not locked yet. */
  204. if (con & PLLCON_LOKI) {
  205. freq = clock_get_hz(s->clock_in);
  206. freq *= PLLCON_FBDV(con);
  207. freq /= PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con);
  208. } else {
  209. freq = 0;
  210. }
  211. clock_update_hz(s->clock_out, freq);
  212. }
  213. static void npcm7xx_clk_update_sel(void *opaque)
  214. {
  215. NPCM7xxClockSELState *s = opaque;
  216. uint32_t index = extract32(s->clk->regs[NPCM7XX_CLK_CLKSEL], s->offset,
  217. s->len);
  218. if (index >= s->input_size) {
  219. qemu_log_mask(LOG_GUEST_ERROR,
  220. "%s: SEL index: %u out of range\n",
  221. __func__, index);
  222. index = 0;
  223. }
  224. clock_update_hz(s->clock_out, clock_get_hz(s->clock_in[index]));
  225. }
  226. static void npcm7xx_clk_update_divider(void *opaque)
  227. {
  228. NPCM7xxClockDividerState *s = opaque;
  229. uint32_t freq;
  230. freq = s->divide(s);
  231. clock_update_hz(s->clock_out, freq);
  232. }
  233. static uint32_t divide_by_constant(NPCM7xxClockDividerState *s)
  234. {
  235. return clock_get_hz(s->clock_in) / s->divisor;
  236. }
  237. static uint32_t divide_by_reg_divisor(NPCM7xxClockDividerState *s)
  238. {
  239. return clock_get_hz(s->clock_in) /
  240. (extract32(s->clk->regs[s->reg], s->offset, s->len) + 1);
  241. }
  242. static uint32_t divide_by_reg_divisor_times_2(NPCM7xxClockDividerState *s)
  243. {
  244. return divide_by_reg_divisor(s) / 2;
  245. }
  246. static uint32_t shift_by_reg_divisor(NPCM7xxClockDividerState *s)
  247. {
  248. return clock_get_hz(s->clock_in) >>
  249. extract32(s->clk->regs[s->reg], s->offset, s->len);
  250. }
  251. static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
  252. {
  253. switch (reg) {
  254. case NPCM7XX_CLK_PLLCON0:
  255. return NPCM7XX_CLOCK_PLL0;
  256. case NPCM7XX_CLK_PLLCON1:
  257. return NPCM7XX_CLOCK_PLL1;
  258. case NPCM7XX_CLK_PLLCON2:
  259. return NPCM7XX_CLOCK_PLL2;
  260. case NPCM7XX_CLK_PLLCONG:
  261. return NPCM7XX_CLOCK_PLLG;
  262. default:
  263. g_assert_not_reached();
  264. }
  265. }
  266. static void npcm7xx_clk_update_all_plls(NPCMCLKState *clk)
  267. {
  268. int i;
  269. for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
  270. npcm7xx_clk_update_pll(&clk->plls[i]);
  271. }
  272. }
  273. static void npcm7xx_clk_update_all_sels(NPCMCLKState *clk)
  274. {
  275. int i;
  276. for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
  277. npcm7xx_clk_update_sel(&clk->sels[i]);
  278. }
  279. }
  280. static void npcm7xx_clk_update_all_dividers(NPCMCLKState *clk)
  281. {
  282. int i;
  283. for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
  284. npcm7xx_clk_update_divider(&clk->dividers[i]);
  285. }
  286. }
  287. static void npcm7xx_clk_update_all_clocks(NPCMCLKState *clk)
  288. {
  289. clock_update_hz(clk->clkref, NPCM7XX_CLOCK_REF_HZ);
  290. npcm7xx_clk_update_all_plls(clk);
  291. npcm7xx_clk_update_all_sels(clk);
  292. npcm7xx_clk_update_all_dividers(clk);
  293. }
  294. /* Types of clock sources. */
  295. typedef enum ClockSrcType {
  296. CLKSRC_REF,
  297. CLKSRC_PLL,
  298. CLKSRC_SEL,
  299. CLKSRC_DIV,
  300. } ClockSrcType;
  301. typedef struct PLLInitInfo {
  302. const char *name;
  303. ClockSrcType src_type;
  304. int src_index;
  305. int reg;
  306. const char *public_name;
  307. } PLLInitInfo;
  308. typedef struct SELInitInfo {
  309. const char *name;
  310. uint8_t input_size;
  311. ClockSrcType src_type[NPCM7XX_CLK_SEL_MAX_INPUT];
  312. int src_index[NPCM7XX_CLK_SEL_MAX_INPUT];
  313. int offset;
  314. int len;
  315. const char *public_name;
  316. } SELInitInfo;
  317. typedef struct DividerInitInfo {
  318. const char *name;
  319. ClockSrcType src_type;
  320. int src_index;
  321. uint32_t (*divide)(NPCM7xxClockDividerState *s);
  322. int reg; /* not used when type == CONSTANT */
  323. int offset; /* not used when type == CONSTANT */
  324. int len; /* not used when type == CONSTANT */
  325. int divisor; /* used only when type == CONSTANT */
  326. const char *public_name;
  327. } DividerInitInfo;
  328. static const PLLInitInfo pll_init_info_list[] = {
  329. [NPCM7XX_CLOCK_PLL0] = {
  330. .name = "pll0",
  331. .src_type = CLKSRC_REF,
  332. .reg = NPCM7XX_CLK_PLLCON0,
  333. },
  334. [NPCM7XX_CLOCK_PLL1] = {
  335. .name = "pll1",
  336. .src_type = CLKSRC_REF,
  337. .reg = NPCM7XX_CLK_PLLCON1,
  338. },
  339. [NPCM7XX_CLOCK_PLL2] = {
  340. .name = "pll2",
  341. .src_type = CLKSRC_REF,
  342. .reg = NPCM7XX_CLK_PLLCON2,
  343. },
  344. [NPCM7XX_CLOCK_PLLG] = {
  345. .name = "pllg",
  346. .src_type = CLKSRC_REF,
  347. .reg = NPCM7XX_CLK_PLLCONG,
  348. },
  349. };
  350. static const SELInitInfo sel_init_info_list[] = {
  351. [NPCM7XX_CLOCK_PIXCKSEL] = {
  352. .name = "pixcksel",
  353. .input_size = 2,
  354. .src_type = {CLKSRC_PLL, CLKSRC_REF},
  355. .src_index = {NPCM7XX_CLOCK_PLLG, 0},
  356. .offset = 5,
  357. .len = 1,
  358. .public_name = "pixel-clock",
  359. },
  360. [NPCM7XX_CLOCK_MCCKSEL] = {
  361. .name = "mccksel",
  362. .input_size = 4,
  363. .src_type = {CLKSRC_DIV, CLKSRC_REF, CLKSRC_REF,
  364. /*MCBPCK, shouldn't be used in normal operation*/
  365. CLKSRC_REF},
  366. .src_index = {NPCM7XX_CLOCK_PLL1D2, 0, 0, 0},
  367. .offset = 12,
  368. .len = 2,
  369. .public_name = "mc-phy-clock",
  370. },
  371. [NPCM7XX_CLOCK_CPUCKSEL] = {
  372. .name = "cpucksel",
  373. .input_size = 4,
  374. .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
  375. /*SYSBPCK, shouldn't be used in normal operation*/
  376. CLKSRC_REF},
  377. .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0, 0},
  378. .offset = 0,
  379. .len = 2,
  380. .public_name = "system-clock",
  381. },
  382. [NPCM7XX_CLOCK_CLKOUTSEL] = {
  383. .name = "clkoutsel",
  384. .input_size = 5,
  385. .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
  386. CLKSRC_PLL, CLKSRC_DIV},
  387. .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
  388. NPCM7XX_CLOCK_PLLG, NPCM7XX_CLOCK_PLL2D2},
  389. .offset = 18,
  390. .len = 3,
  391. .public_name = "tock",
  392. },
  393. [NPCM7XX_CLOCK_UARTCKSEL] = {
  394. .name = "uartcksel",
  395. .input_size = 4,
  396. .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
  397. .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
  398. NPCM7XX_CLOCK_PLL2D2},
  399. .offset = 8,
  400. .len = 2,
  401. },
  402. [NPCM7XX_CLOCK_TIMCKSEL] = {
  403. .name = "timcksel",
  404. .input_size = 4,
  405. .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
  406. .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
  407. NPCM7XX_CLOCK_PLL2D2},
  408. .offset = 14,
  409. .len = 2,
  410. },
  411. [NPCM7XX_CLOCK_SDCKSEL] = {
  412. .name = "sdcksel",
  413. .input_size = 4,
  414. .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
  415. .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
  416. NPCM7XX_CLOCK_PLL2D2},
  417. .offset = 6,
  418. .len = 2,
  419. },
  420. [NPCM7XX_CLOCK_GFXMSEL] = {
  421. .name = "gfxmksel",
  422. .input_size = 2,
  423. .src_type = {CLKSRC_REF, CLKSRC_PLL},
  424. .src_index = {0, NPCM7XX_CLOCK_PLL2},
  425. .offset = 21,
  426. .len = 1,
  427. },
  428. [NPCM7XX_CLOCK_SUCKSEL] = {
  429. .name = "sucksel",
  430. .input_size = 4,
  431. .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
  432. .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
  433. NPCM7XX_CLOCK_PLL2D2},
  434. .offset = 10,
  435. .len = 2,
  436. },
  437. };
  438. static const DividerInitInfo divider_init_info_list[] = {
  439. [NPCM7XX_CLOCK_PLL1D2] = {
  440. .name = "pll1d2",
  441. .src_type = CLKSRC_PLL,
  442. .src_index = NPCM7XX_CLOCK_PLL1,
  443. .divide = divide_by_constant,
  444. .divisor = 2,
  445. },
  446. [NPCM7XX_CLOCK_PLL2D2] = {
  447. .name = "pll2d2",
  448. .src_type = CLKSRC_PLL,
  449. .src_index = NPCM7XX_CLOCK_PLL2,
  450. .divide = divide_by_constant,
  451. .divisor = 2,
  452. },
  453. [NPCM7XX_CLOCK_MC_DIVIDER] = {
  454. .name = "mc-divider",
  455. .src_type = CLKSRC_SEL,
  456. .src_index = NPCM7XX_CLOCK_MCCKSEL,
  457. .divide = divide_by_constant,
  458. .divisor = 2,
  459. .public_name = "mc-clock"
  460. },
  461. [NPCM7XX_CLOCK_AXI_DIVIDER] = {
  462. .name = "axi-divider",
  463. .src_type = CLKSRC_SEL,
  464. .src_index = NPCM7XX_CLOCK_CPUCKSEL,
  465. .divide = shift_by_reg_divisor,
  466. .reg = NPCM7XX_CLK_CLKDIV1,
  467. .offset = 0,
  468. .len = 1,
  469. .public_name = "clk2"
  470. },
  471. [NPCM7XX_CLOCK_AHB_DIVIDER] = {
  472. .name = "ahb-divider",
  473. .src_type = CLKSRC_DIV,
  474. .src_index = NPCM7XX_CLOCK_AXI_DIVIDER,
  475. .divide = divide_by_reg_divisor,
  476. .reg = NPCM7XX_CLK_CLKDIV1,
  477. .offset = 26,
  478. .len = 2,
  479. .public_name = "clk4"
  480. },
  481. [NPCM7XX_CLOCK_AHB3_DIVIDER] = {
  482. .name = "ahb3-divider",
  483. .src_type = CLKSRC_DIV,
  484. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  485. .divide = divide_by_reg_divisor,
  486. .reg = NPCM7XX_CLK_CLKDIV1,
  487. .offset = 6,
  488. .len = 5,
  489. .public_name = "ahb3-spi3-clock"
  490. },
  491. [NPCM7XX_CLOCK_SPI0_DIVIDER] = {
  492. .name = "spi0-divider",
  493. .src_type = CLKSRC_DIV,
  494. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  495. .divide = divide_by_reg_divisor,
  496. .reg = NPCM7XX_CLK_CLKDIV3,
  497. .offset = 6,
  498. .len = 5,
  499. .public_name = "spi0-clock",
  500. },
  501. [NPCM7XX_CLOCK_SPIX_DIVIDER] = {
  502. .name = "spix-divider",
  503. .src_type = CLKSRC_DIV,
  504. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  505. .divide = divide_by_reg_divisor,
  506. .reg = NPCM7XX_CLK_CLKDIV3,
  507. .offset = 1,
  508. .len = 5,
  509. .public_name = "spix-clock",
  510. },
  511. [NPCM7XX_CLOCK_APB1_DIVIDER] = {
  512. .name = "apb1-divider",
  513. .src_type = CLKSRC_DIV,
  514. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  515. .divide = shift_by_reg_divisor,
  516. .reg = NPCM7XX_CLK_CLKDIV2,
  517. .offset = 24,
  518. .len = 2,
  519. .public_name = "apb1-clock",
  520. },
  521. [NPCM7XX_CLOCK_APB2_DIVIDER] = {
  522. .name = "apb2-divider",
  523. .src_type = CLKSRC_DIV,
  524. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  525. .divide = shift_by_reg_divisor,
  526. .reg = NPCM7XX_CLK_CLKDIV2,
  527. .offset = 26,
  528. .len = 2,
  529. .public_name = "apb2-clock",
  530. },
  531. [NPCM7XX_CLOCK_APB3_DIVIDER] = {
  532. .name = "apb3-divider",
  533. .src_type = CLKSRC_DIV,
  534. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  535. .divide = shift_by_reg_divisor,
  536. .reg = NPCM7XX_CLK_CLKDIV2,
  537. .offset = 28,
  538. .len = 2,
  539. .public_name = "apb3-clock",
  540. },
  541. [NPCM7XX_CLOCK_APB4_DIVIDER] = {
  542. .name = "apb4-divider",
  543. .src_type = CLKSRC_DIV,
  544. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  545. .divide = shift_by_reg_divisor,
  546. .reg = NPCM7XX_CLK_CLKDIV2,
  547. .offset = 30,
  548. .len = 2,
  549. .public_name = "apb4-clock",
  550. },
  551. [NPCM7XX_CLOCK_APB5_DIVIDER] = {
  552. .name = "apb5-divider",
  553. .src_type = CLKSRC_DIV,
  554. .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
  555. .divide = shift_by_reg_divisor,
  556. .reg = NPCM7XX_CLK_CLKDIV2,
  557. .offset = 22,
  558. .len = 2,
  559. .public_name = "apb5-clock",
  560. },
  561. [NPCM7XX_CLOCK_CLKOUT_DIVIDER] = {
  562. .name = "clkout-divider",
  563. .src_type = CLKSRC_SEL,
  564. .src_index = NPCM7XX_CLOCK_CLKOUTSEL,
  565. .divide = divide_by_reg_divisor,
  566. .reg = NPCM7XX_CLK_CLKDIV2,
  567. .offset = 16,
  568. .len = 5,
  569. .public_name = "clkout",
  570. },
  571. [NPCM7XX_CLOCK_UART_DIVIDER] = {
  572. .name = "uart-divider",
  573. .src_type = CLKSRC_SEL,
  574. .src_index = NPCM7XX_CLOCK_UARTCKSEL,
  575. .divide = divide_by_reg_divisor,
  576. .reg = NPCM7XX_CLK_CLKDIV1,
  577. .offset = 16,
  578. .len = 5,
  579. .public_name = "uart-clock",
  580. },
  581. [NPCM7XX_CLOCK_TIMER_DIVIDER] = {
  582. .name = "timer-divider",
  583. .src_type = CLKSRC_SEL,
  584. .src_index = NPCM7XX_CLOCK_TIMCKSEL,
  585. .divide = divide_by_reg_divisor,
  586. .reg = NPCM7XX_CLK_CLKDIV1,
  587. .offset = 21,
  588. .len = 5,
  589. .public_name = "timer-clock",
  590. },
  591. [NPCM7XX_CLOCK_ADC_DIVIDER] = {
  592. .name = "adc-divider",
  593. .src_type = CLKSRC_DIV,
  594. .src_index = NPCM7XX_CLOCK_TIMER_DIVIDER,
  595. .divide = shift_by_reg_divisor,
  596. .reg = NPCM7XX_CLK_CLKDIV1,
  597. .offset = 28,
  598. .len = 3,
  599. .public_name = "adc-clock",
  600. },
  601. [NPCM7XX_CLOCK_MMC_DIVIDER] = {
  602. .name = "mmc-divider",
  603. .src_type = CLKSRC_SEL,
  604. .src_index = NPCM7XX_CLOCK_SDCKSEL,
  605. .divide = divide_by_reg_divisor,
  606. .reg = NPCM7XX_CLK_CLKDIV1,
  607. .offset = 11,
  608. .len = 5,
  609. .public_name = "mmc-clock",
  610. },
  611. [NPCM7XX_CLOCK_SDHC_DIVIDER] = {
  612. .name = "sdhc-divider",
  613. .src_type = CLKSRC_SEL,
  614. .src_index = NPCM7XX_CLOCK_SDCKSEL,
  615. .divide = divide_by_reg_divisor_times_2,
  616. .reg = NPCM7XX_CLK_CLKDIV2,
  617. .offset = 0,
  618. .len = 4,
  619. .public_name = "sdhc-clock",
  620. },
  621. [NPCM7XX_CLOCK_GFXM_DIVIDER] = {
  622. .name = "gfxm-divider",
  623. .src_type = CLKSRC_SEL,
  624. .src_index = NPCM7XX_CLOCK_GFXMSEL,
  625. .divide = divide_by_constant,
  626. .divisor = 3,
  627. .public_name = "gfxm-clock",
  628. },
  629. [NPCM7XX_CLOCK_UTMI_DIVIDER] = {
  630. .name = "utmi-divider",
  631. .src_type = CLKSRC_SEL,
  632. .src_index = NPCM7XX_CLOCK_SUCKSEL,
  633. .divide = divide_by_reg_divisor,
  634. .reg = NPCM7XX_CLK_CLKDIV2,
  635. .offset = 8,
  636. .len = 5,
  637. .public_name = "utmi-clock",
  638. },
  639. };
  640. static void npcm7xx_clk_update_pll_cb(void *opaque, ClockEvent event)
  641. {
  642. npcm7xx_clk_update_pll(opaque);
  643. }
  644. static void npcm7xx_clk_pll_init(Object *obj)
  645. {
  646. NPCM7xxClockPLLState *pll = NPCM7XX_CLOCK_PLL(obj);
  647. pll->clock_in = qdev_init_clock_in(DEVICE(pll), "clock-in",
  648. npcm7xx_clk_update_pll_cb, pll,
  649. ClockUpdate);
  650. pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
  651. }
  652. static void npcm7xx_clk_update_sel_cb(void *opaque, ClockEvent event)
  653. {
  654. npcm7xx_clk_update_sel(opaque);
  655. }
  656. static void npcm7xx_clk_sel_init(Object *obj)
  657. {
  658. int i;
  659. NPCM7xxClockSELState *sel = NPCM7XX_CLOCK_SEL(obj);
  660. for (i = 0; i < NPCM7XX_CLK_SEL_MAX_INPUT; ++i) {
  661. g_autofree char *s = g_strdup_printf("clock-in[%d]", i);
  662. sel->clock_in[i] = qdev_init_clock_in(DEVICE(sel), s,
  663. npcm7xx_clk_update_sel_cb, sel, ClockUpdate);
  664. }
  665. sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
  666. }
  667. static void npcm7xx_clk_update_divider_cb(void *opaque, ClockEvent event)
  668. {
  669. npcm7xx_clk_update_divider(opaque);
  670. }
  671. static void npcm7xx_clk_divider_init(Object *obj)
  672. {
  673. NPCM7xxClockDividerState *div = NPCM7XX_CLOCK_DIVIDER(obj);
  674. div->clock_in = qdev_init_clock_in(DEVICE(div), "clock-in",
  675. npcm7xx_clk_update_divider_cb,
  676. div, ClockUpdate);
  677. div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
  678. }
  679. static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
  680. NPCMCLKState *clk, const PLLInitInfo *init_info)
  681. {
  682. pll->name = init_info->name;
  683. pll->clk = clk;
  684. pll->reg = init_info->reg;
  685. if (init_info->public_name != NULL) {
  686. qdev_alias_clock(DEVICE(pll), "clock-out", DEVICE(clk),
  687. init_info->public_name);
  688. }
  689. }
  690. static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
  691. NPCMCLKState *clk, const SELInitInfo *init_info)
  692. {
  693. int input_size = init_info->input_size;
  694. sel->name = init_info->name;
  695. sel->clk = clk;
  696. sel->input_size = init_info->input_size;
  697. g_assert(input_size <= NPCM7XX_CLK_SEL_MAX_INPUT);
  698. sel->offset = init_info->offset;
  699. sel->len = init_info->len;
  700. if (init_info->public_name != NULL) {
  701. qdev_alias_clock(DEVICE(sel), "clock-out", DEVICE(clk),
  702. init_info->public_name);
  703. }
  704. }
  705. static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
  706. NPCMCLKState *clk, const DividerInitInfo *init_info)
  707. {
  708. div->name = init_info->name;
  709. div->clk = clk;
  710. div->divide = init_info->divide;
  711. if (div->divide == divide_by_constant) {
  712. div->divisor = init_info->divisor;
  713. } else {
  714. div->reg = init_info->reg;
  715. div->offset = init_info->offset;
  716. div->len = init_info->len;
  717. }
  718. if (init_info->public_name != NULL) {
  719. qdev_alias_clock(DEVICE(div), "clock-out", DEVICE(clk),
  720. init_info->public_name);
  721. }
  722. }
  723. static Clock *npcm7xx_get_clock(NPCMCLKState *clk, ClockSrcType type,
  724. int index)
  725. {
  726. switch (type) {
  727. case CLKSRC_REF:
  728. return clk->clkref;
  729. case CLKSRC_PLL:
  730. return clk->plls[index].clock_out;
  731. case CLKSRC_SEL:
  732. return clk->sels[index].clock_out;
  733. case CLKSRC_DIV:
  734. return clk->dividers[index].clock_out;
  735. default:
  736. g_assert_not_reached();
  737. }
  738. }
  739. static void npcm7xx_connect_clocks(NPCMCLKState *clk)
  740. {
  741. int i, j;
  742. Clock *src;
  743. for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
  744. src = npcm7xx_get_clock(clk, pll_init_info_list[i].src_type,
  745. pll_init_info_list[i].src_index);
  746. clock_set_source(clk->plls[i].clock_in, src);
  747. }
  748. for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
  749. for (j = 0; j < sel_init_info_list[i].input_size; ++j) {
  750. src = npcm7xx_get_clock(clk, sel_init_info_list[i].src_type[j],
  751. sel_init_info_list[i].src_index[j]);
  752. clock_set_source(clk->sels[i].clock_in[j], src);
  753. }
  754. }
  755. for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
  756. src = npcm7xx_get_clock(clk, divider_init_info_list[i].src_type,
  757. divider_init_info_list[i].src_index);
  758. clock_set_source(clk->dividers[i].clock_in, src);
  759. }
  760. }
  761. static uint64_t npcm_clk_read(void *opaque, hwaddr offset, unsigned size)
  762. {
  763. uint32_t reg = offset / sizeof(uint32_t);
  764. NPCMCLKState *s = opaque;
  765. NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
  766. int64_t now_ns;
  767. uint32_t value = 0;
  768. if (reg >= c->nr_regs) {
  769. qemu_log_mask(LOG_GUEST_ERROR,
  770. "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
  771. __func__, offset);
  772. return 0;
  773. }
  774. switch (reg) {
  775. case NPCM7XX_CLK_SWRSTR:
  776. qemu_log_mask(LOG_GUEST_ERROR,
  777. "%s: register @ 0x%04" HWADDR_PRIx " is write-only\n",
  778. __func__, offset);
  779. break;
  780. case NPCM7XX_CLK_SECCNT:
  781. now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  782. value = (now_ns - s->ref_ns) / NANOSECONDS_PER_SECOND;
  783. break;
  784. case NPCM7XX_CLK_CNTR25M:
  785. now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  786. /*
  787. * This register counts 25 MHz cycles, updating every 640 ns. It rolls
  788. * over to zero every second.
  789. *
  790. * The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
  791. */
  792. value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_CLOCK_REF_HZ;
  793. break;
  794. default:
  795. value = s->regs[reg];
  796. break;
  797. };
  798. trace_npcm_clk_read(offset, value);
  799. return value;
  800. }
  801. static void npcm_clk_write(void *opaque, hwaddr offset,
  802. uint64_t v, unsigned size)
  803. {
  804. uint32_t reg = offset / sizeof(uint32_t);
  805. NPCMCLKState *s = opaque;
  806. NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
  807. uint32_t value = v;
  808. trace_npcm_clk_write(offset, value);
  809. if (reg >= c->nr_regs) {
  810. qemu_log_mask(LOG_GUEST_ERROR,
  811. "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
  812. __func__, offset);
  813. return;
  814. }
  815. switch (reg) {
  816. case NPCM7XX_CLK_SWRSTR:
  817. qemu_log_mask(LOG_UNIMP, "%s: SW reset not implemented: 0x%02x\n",
  818. __func__, value);
  819. value = 0;
  820. break;
  821. case NPCM7XX_CLK_PLLCON0:
  822. case NPCM7XX_CLK_PLLCON1:
  823. case NPCM7XX_CLK_PLLCON2:
  824. case NPCM7XX_CLK_PLLCONG:
  825. if (value & PLLCON_PWDEN) {
  826. /* Power down -- clear lock and indicate loss of lock */
  827. value &= ~PLLCON_LOKI;
  828. value |= PLLCON_LOKS;
  829. } else {
  830. /* Normal mode -- assume always locked */
  831. value |= PLLCON_LOKI;
  832. /* Keep LOKS unchanged unless cleared by writing 1 */
  833. if (value & PLLCON_LOKS) {
  834. value &= ~PLLCON_LOKS;
  835. } else {
  836. value |= (value & PLLCON_LOKS);
  837. }
  838. }
  839. /* Only update PLL when it is locked. */
  840. if (value & PLLCON_LOKI) {
  841. npcm7xx_clk_update_pll(&s->plls[find_pll_by_reg(reg)]);
  842. }
  843. break;
  844. case NPCM7XX_CLK_CLKSEL:
  845. npcm7xx_clk_update_all_sels(s);
  846. break;
  847. case NPCM7XX_CLK_CLKDIV1:
  848. case NPCM7XX_CLK_CLKDIV2:
  849. case NPCM7XX_CLK_CLKDIV3:
  850. npcm7xx_clk_update_all_dividers(s);
  851. break;
  852. case NPCM7XX_CLK_CNTR25M:
  853. qemu_log_mask(LOG_GUEST_ERROR,
  854. "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
  855. __func__, offset);
  856. return;
  857. }
  858. s->regs[reg] = value;
  859. }
  860. /* Perform reset action triggered by a watchdog */
  861. static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
  862. int level)
  863. {
  864. NPCMCLKState *clk = NPCM_CLK(opaque);
  865. uint32_t rcr;
  866. g_assert(n >= 0 && n <= NPCM7XX_NR_WATCHDOGS);
  867. rcr = clk->regs[NPCM7XX_CLK_WD0RCR + n];
  868. if (rcr & NPCM7XX_CLK_WDRCR_CA9C) {
  869. watchdog_perform_action();
  870. } else {
  871. qemu_log_mask(LOG_UNIMP,
  872. "%s: only CPU reset is implemented. (requested 0x%" PRIx32")\n",
  873. __func__, rcr);
  874. }
  875. }
  876. static const struct MemoryRegionOps npcm_clk_ops = {
  877. .read = npcm_clk_read,
  878. .write = npcm_clk_write,
  879. .endianness = DEVICE_LITTLE_ENDIAN,
  880. .valid = {
  881. .min_access_size = 4,
  882. .max_access_size = 4,
  883. .unaligned = false,
  884. },
  885. };
  886. static void npcm_clk_enter_reset(Object *obj, ResetType type)
  887. {
  888. NPCMCLKState *s = NPCM_CLK(obj);
  889. NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
  890. size_t sizeof_regs = c->nr_regs * sizeof(uint32_t);
  891. g_assert(sizeof(s->regs) >= sizeof_regs);
  892. memcpy(s->regs, c->cold_reset_values, sizeof_regs);
  893. s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  894. npcm7xx_clk_update_all_clocks(s);
  895. /*
  896. * A small number of registers need to be reset on a core domain reset,
  897. * but no such reset type exists yet.
  898. */
  899. }
  900. static void npcm7xx_clk_init_clock_hierarchy(NPCMCLKState *s)
  901. {
  902. int i;
  903. s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL, 0);
  904. /* First pass: init all converter modules */
  905. QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) != NPCM7XX_CLOCK_NR_PLLS);
  906. QEMU_BUILD_BUG_ON(ARRAY_SIZE(sel_init_info_list) != NPCM7XX_CLOCK_NR_SELS);
  907. QEMU_BUILD_BUG_ON(ARRAY_SIZE(divider_init_info_list)
  908. != NPCM7XX_CLOCK_NR_DIVIDERS);
  909. for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
  910. object_initialize_child(OBJECT(s), pll_init_info_list[i].name,
  911. &s->plls[i], TYPE_NPCM7XX_CLOCK_PLL);
  912. npcm7xx_init_clock_pll(&s->plls[i], s,
  913. &pll_init_info_list[i]);
  914. }
  915. for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
  916. object_initialize_child(OBJECT(s), sel_init_info_list[i].name,
  917. &s->sels[i], TYPE_NPCM7XX_CLOCK_SEL);
  918. npcm7xx_init_clock_sel(&s->sels[i], s,
  919. &sel_init_info_list[i]);
  920. }
  921. for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
  922. object_initialize_child(OBJECT(s), divider_init_info_list[i].name,
  923. &s->dividers[i], TYPE_NPCM7XX_CLOCK_DIVIDER);
  924. npcm7xx_init_clock_divider(&s->dividers[i], s,
  925. &divider_init_info_list[i]);
  926. }
  927. /* Second pass: connect converter modules */
  928. npcm7xx_connect_clocks(s);
  929. clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
  930. }
  931. static void npcm_clk_init(Object *obj)
  932. {
  933. NPCMCLKState *s = NPCM_CLK(obj);
  934. memory_region_init_io(&s->iomem, obj, &npcm_clk_ops, s,
  935. TYPE_NPCM_CLK, 4 * KiB);
  936. sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
  937. }
  938. static int npcm_clk_post_load(void *opaque, int version_id)
  939. {
  940. if (version_id >= 1) {
  941. NPCMCLKState *clk = opaque;
  942. npcm7xx_clk_update_all_clocks(clk);
  943. }
  944. return 0;
  945. }
  946. static void npcm_clk_realize(DeviceState *dev, Error **errp)
  947. {
  948. int i;
  949. NPCMCLKState *s = NPCM_CLK(dev);
  950. qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
  951. NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
  952. npcm7xx_clk_init_clock_hierarchy(s);
  953. /* Realize child devices */
  954. for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
  955. if (!qdev_realize(DEVICE(&s->plls[i]), NULL, errp)) {
  956. return;
  957. }
  958. }
  959. for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
  960. if (!qdev_realize(DEVICE(&s->sels[i]), NULL, errp)) {
  961. return;
  962. }
  963. }
  964. for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
  965. if (!qdev_realize(DEVICE(&s->dividers[i]), NULL, errp)) {
  966. return;
  967. }
  968. }
  969. }
  970. static const VMStateDescription vmstate_npcm7xx_clk_pll = {
  971. .name = "npcm7xx-clock-pll",
  972. .version_id = 0,
  973. .minimum_version_id = 0,
  974. .fields = (const VMStateField[]) {
  975. VMSTATE_CLOCK(clock_in, NPCM7xxClockPLLState),
  976. VMSTATE_END_OF_LIST(),
  977. },
  978. };
  979. static const VMStateDescription vmstate_npcm7xx_clk_sel = {
  980. .name = "npcm7xx-clock-sel",
  981. .version_id = 0,
  982. .minimum_version_id = 0,
  983. .fields = (const VMStateField[]) {
  984. VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(clock_in, NPCM7xxClockSELState,
  985. NPCM7XX_CLK_SEL_MAX_INPUT, 0, vmstate_clock, Clock),
  986. VMSTATE_END_OF_LIST(),
  987. },
  988. };
  989. static const VMStateDescription vmstate_npcm7xx_clk_divider = {
  990. .name = "npcm7xx-clock-divider",
  991. .version_id = 0,
  992. .minimum_version_id = 0,
  993. .fields = (const VMStateField[]) {
  994. VMSTATE_CLOCK(clock_in, NPCM7xxClockDividerState),
  995. VMSTATE_END_OF_LIST(),
  996. },
  997. };
  998. static const VMStateDescription vmstate_npcm_clk = {
  999. .name = "npcm-clk",
  1000. .version_id = 3,
  1001. .minimum_version_id = 3,
  1002. .post_load = npcm_clk_post_load,
  1003. .fields = (const VMStateField[]) {
  1004. VMSTATE_UINT32_ARRAY(regs, NPCMCLKState, NPCM_CLK_MAX_NR_REGS),
  1005. VMSTATE_INT64(ref_ns, NPCMCLKState),
  1006. VMSTATE_CLOCK(clkref, NPCMCLKState),
  1007. VMSTATE_END_OF_LIST(),
  1008. },
  1009. };
  1010. static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data)
  1011. {
  1012. DeviceClass *dc = DEVICE_CLASS(klass);
  1013. dc->desc = "NPCM7xx Clock PLL Module";
  1014. dc->vmsd = &vmstate_npcm7xx_clk_pll;
  1015. /* Reason: Part of NPCMCLKState component */
  1016. dc->user_creatable = false;
  1017. }
  1018. static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data)
  1019. {
  1020. DeviceClass *dc = DEVICE_CLASS(klass);
  1021. dc->desc = "NPCM7xx Clock SEL Module";
  1022. dc->vmsd = &vmstate_npcm7xx_clk_sel;
  1023. /* Reason: Part of NPCMCLKState component */
  1024. dc->user_creatable = false;
  1025. }
  1026. static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data)
  1027. {
  1028. DeviceClass *dc = DEVICE_CLASS(klass);
  1029. dc->desc = "NPCM7xx Clock Divider Module";
  1030. dc->vmsd = &vmstate_npcm7xx_clk_divider;
  1031. /* Reason: Part of NPCMCLKState component */
  1032. dc->user_creatable = false;
  1033. }
  1034. static void npcm_clk_class_init(ObjectClass *klass, void *data)
  1035. {
  1036. ResettableClass *rc = RESETTABLE_CLASS(klass);
  1037. DeviceClass *dc = DEVICE_CLASS(klass);
  1038. dc->vmsd = &vmstate_npcm_clk;
  1039. dc->realize = npcm_clk_realize;
  1040. rc->phases.enter = npcm_clk_enter_reset;
  1041. }
  1042. static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
  1043. {
  1044. NPCMCLKClass *c = NPCM_CLK_CLASS(klass);
  1045. DeviceClass *dc = DEVICE_CLASS(klass);
  1046. dc->desc = "NPCM7xx Clock Control Registers";
  1047. c->nr_regs = NPCM7XX_CLK_NR_REGS;
  1048. c->cold_reset_values = npcm7xx_cold_reset_values;
  1049. }
  1050. static void npcm8xx_clk_class_init(ObjectClass *klass, void *data)
  1051. {
  1052. NPCMCLKClass *c = NPCM_CLK_CLASS(klass);
  1053. DeviceClass *dc = DEVICE_CLASS(klass);
  1054. dc->desc = "NPCM8xx Clock Control Registers";
  1055. c->nr_regs = NPCM8XX_CLK_NR_REGS;
  1056. c->cold_reset_values = npcm8xx_cold_reset_values;
  1057. }
  1058. static const TypeInfo npcm7xx_clk_pll_info = {
  1059. .name = TYPE_NPCM7XX_CLOCK_PLL,
  1060. .parent = TYPE_DEVICE,
  1061. .instance_size = sizeof(NPCM7xxClockPLLState),
  1062. .instance_init = npcm7xx_clk_pll_init,
  1063. .class_init = npcm7xx_clk_pll_class_init,
  1064. };
  1065. static const TypeInfo npcm7xx_clk_sel_info = {
  1066. .name = TYPE_NPCM7XX_CLOCK_SEL,
  1067. .parent = TYPE_DEVICE,
  1068. .instance_size = sizeof(NPCM7xxClockSELState),
  1069. .instance_init = npcm7xx_clk_sel_init,
  1070. .class_init = npcm7xx_clk_sel_class_init,
  1071. };
  1072. static const TypeInfo npcm7xx_clk_divider_info = {
  1073. .name = TYPE_NPCM7XX_CLOCK_DIVIDER,
  1074. .parent = TYPE_DEVICE,
  1075. .instance_size = sizeof(NPCM7xxClockDividerState),
  1076. .instance_init = npcm7xx_clk_divider_init,
  1077. .class_init = npcm7xx_clk_divider_class_init,
  1078. };
  1079. static const TypeInfo npcm_clk_info = {
  1080. .name = TYPE_NPCM_CLK,
  1081. .parent = TYPE_SYS_BUS_DEVICE,
  1082. .instance_size = sizeof(NPCMCLKState),
  1083. .instance_init = npcm_clk_init,
  1084. .class_size = sizeof(NPCMCLKClass),
  1085. .class_init = npcm_clk_class_init,
  1086. .abstract = true,
  1087. };
  1088. static const TypeInfo npcm7xx_clk_info = {
  1089. .name = TYPE_NPCM7XX_CLK,
  1090. .parent = TYPE_NPCM_CLK,
  1091. .class_init = npcm7xx_clk_class_init,
  1092. };
  1093. static const TypeInfo npcm8xx_clk_info = {
  1094. .name = TYPE_NPCM8XX_CLK,
  1095. .parent = TYPE_NPCM_CLK,
  1096. .class_init = npcm8xx_clk_class_init,
  1097. };
  1098. static void npcm7xx_clk_register_type(void)
  1099. {
  1100. type_register_static(&npcm7xx_clk_pll_info);
  1101. type_register_static(&npcm7xx_clk_sel_info);
  1102. type_register_static(&npcm7xx_clk_divider_info);
  1103. type_register_static(&npcm_clk_info);
  1104. type_register_static(&npcm7xx_clk_info);
  1105. type_register_static(&npcm8xx_clk_info);
  1106. }
  1107. type_init(npcm7xx_clk_register_type);