sam9x7.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * SAM9X7 PMC code.
  4. *
  5. * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries
  6. *
  7. * Author: Varshini Rajendran <varshini.rajendran@microchip.com>
  8. *
  9. */
  10. #include <linux/clk.h>
  11. #include <linux/clk-provider.h>
  12. #include <linux/mfd/syscon.h>
  13. #include <linux/slab.h>
  14. #include <dt-bindings/clock/at91.h>
  15. #include "pmc.h"
  16. static DEFINE_SPINLOCK(pmc_pll_lock);
  17. static DEFINE_SPINLOCK(mck_lock);
  18. /**
  19. * enum pll_ids - PLL clocks identifiers
  20. * @PLL_ID_PLLA: PLLA identifier
  21. * @PLL_ID_UPLL: UPLL identifier
  22. * @PLL_ID_AUDIO: Audio PLL identifier
  23. * @PLL_ID_LVDS: LVDS PLL identifier
  24. * @PLL_ID_PLLA_DIV2: PLLA DIV2 identifier
  25. * @PLL_ID_MAX: Max PLL Identifier
  26. */
  27. enum pll_ids {
  28. PLL_ID_PLLA,
  29. PLL_ID_UPLL,
  30. PLL_ID_AUDIO,
  31. PLL_ID_LVDS,
  32. PLL_ID_PLLA_DIV2,
  33. PLL_ID_MAX,
  34. };
  35. /**
  36. * enum pll_type - PLL type identifiers
  37. * @PLL_TYPE_FRAC: fractional PLL identifier
  38. * @PLL_TYPE_DIV: divider PLL identifier
  39. */
  40. enum pll_type {
  41. PLL_TYPE_FRAC,
  42. PLL_TYPE_DIV,
  43. };
  44. static const struct clk_master_characteristics mck_characteristics = {
  45. .output = { .min = 32000000, .max = 266666667 },
  46. .divisors = { 1, 2, 4, 3, 5},
  47. .have_div3_pres = 1,
  48. };
  49. static const struct clk_master_layout sam9x7_master_layout = {
  50. .mask = 0x373,
  51. .pres_shift = 4,
  52. .offset = 0x28,
  53. };
  54. /* Fractional PLL core output range. */
  55. static const struct clk_range plla_core_outputs[] = {
  56. { .min = 375000000, .max = 1600000000 },
  57. };
  58. static const struct clk_range upll_core_outputs[] = {
  59. { .min = 600000000, .max = 1200000000 },
  60. };
  61. static const struct clk_range lvdspll_core_outputs[] = {
  62. { .min = 400000000, .max = 800000000 },
  63. };
  64. static const struct clk_range audiopll_core_outputs[] = {
  65. { .min = 400000000, .max = 800000000 },
  66. };
  67. static const struct clk_range plladiv2_core_outputs[] = {
  68. { .min = 375000000, .max = 1600000000 },
  69. };
  70. /* Fractional PLL output range. */
  71. static const struct clk_range plla_outputs[] = {
  72. { .min = 732421, .max = 800000000 },
  73. };
  74. static const struct clk_range upll_outputs[] = {
  75. { .min = 300000000, .max = 600000000 },
  76. };
  77. static const struct clk_range lvdspll_outputs[] = {
  78. { .min = 10000000, .max = 800000000 },
  79. };
  80. static const struct clk_range audiopll_outputs[] = {
  81. { .min = 10000000, .max = 800000000 },
  82. };
  83. static const struct clk_range plladiv2_outputs[] = {
  84. { .min = 366210, .max = 400000000 },
  85. };
  86. /* PLL characteristics. */
  87. static const struct clk_pll_characteristics plla_characteristics = {
  88. .input = { .min = 20000000, .max = 50000000 },
  89. .num_output = ARRAY_SIZE(plla_outputs),
  90. .output = plla_outputs,
  91. .core_output = plla_core_outputs,
  92. };
  93. static const struct clk_pll_characteristics upll_characteristics = {
  94. .input = { .min = 20000000, .max = 50000000 },
  95. .num_output = ARRAY_SIZE(upll_outputs),
  96. .output = upll_outputs,
  97. .core_output = upll_core_outputs,
  98. .upll = true,
  99. };
  100. static const struct clk_pll_characteristics lvdspll_characteristics = {
  101. .input = { .min = 20000000, .max = 50000000 },
  102. .num_output = ARRAY_SIZE(lvdspll_outputs),
  103. .output = lvdspll_outputs,
  104. .core_output = lvdspll_core_outputs,
  105. };
  106. static const struct clk_pll_characteristics audiopll_characteristics = {
  107. .input = { .min = 20000000, .max = 50000000 },
  108. .num_output = ARRAY_SIZE(audiopll_outputs),
  109. .output = audiopll_outputs,
  110. .core_output = audiopll_core_outputs,
  111. };
  112. static const struct clk_pll_characteristics plladiv2_characteristics = {
  113. .input = { .min = 20000000, .max = 50000000 },
  114. .num_output = ARRAY_SIZE(plladiv2_outputs),
  115. .output = plladiv2_outputs,
  116. .core_output = plladiv2_core_outputs,
  117. };
  118. /* Layout for fractional PLL ID PLLA. */
  119. static const struct clk_pll_layout plla_frac_layout = {
  120. .mul_mask = GENMASK(31, 24),
  121. .frac_mask = GENMASK(21, 0),
  122. .mul_shift = 24,
  123. .frac_shift = 0,
  124. .div2 = 1,
  125. };
  126. /* Layout for fractional PLLs. */
  127. static const struct clk_pll_layout pll_frac_layout = {
  128. .mul_mask = GENMASK(31, 24),
  129. .frac_mask = GENMASK(21, 0),
  130. .mul_shift = 24,
  131. .frac_shift = 0,
  132. };
  133. /* Layout for DIV PLLs. */
  134. static const struct clk_pll_layout pll_divpmc_layout = {
  135. .div_mask = GENMASK(7, 0),
  136. .endiv_mask = BIT(29),
  137. .div_shift = 0,
  138. .endiv_shift = 29,
  139. };
  140. /* Layout for DIV PLL ID PLLADIV2. */
  141. static const struct clk_pll_layout plladiv2_divpmc_layout = {
  142. .div_mask = GENMASK(7, 0),
  143. .endiv_mask = BIT(29),
  144. .div_shift = 0,
  145. .endiv_shift = 29,
  146. .div2 = 1,
  147. };
  148. /* Layout for DIVIO dividers. */
  149. static const struct clk_pll_layout pll_divio_layout = {
  150. .div_mask = GENMASK(19, 12),
  151. .endiv_mask = BIT(30),
  152. .div_shift = 12,
  153. .endiv_shift = 30,
  154. };
  155. /*
  156. * PLL clocks description
  157. * @n: clock name
  158. * @p: clock parent
  159. * @l: clock layout
  160. * @t: clock type
  161. * @c: pll characteristics
  162. * @f: clock flags
  163. * @eid: export index in sam9x7->chws[] array
  164. */
  165. static const struct {
  166. const char *n;
  167. const char *p;
  168. const struct clk_pll_layout *l;
  169. u8 t;
  170. const struct clk_pll_characteristics *c;
  171. unsigned long f;
  172. u8 eid;
  173. } sam9x7_plls[][3] = {
  174. [PLL_ID_PLLA] = {
  175. {
  176. .n = "plla_fracck",
  177. .p = "mainck",
  178. .l = &plla_frac_layout,
  179. .t = PLL_TYPE_FRAC,
  180. /*
  181. * This feeds plla_divpmcck which feeds CPU. It should
  182. * not be disabled.
  183. */
  184. .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
  185. .c = &plla_characteristics,
  186. },
  187. {
  188. .n = "plla_divpmcck",
  189. .p = "plla_fracck",
  190. .l = &pll_divpmc_layout,
  191. .t = PLL_TYPE_DIV,
  192. /* This feeds CPU. It should not be disabled */
  193. .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
  194. .eid = PMC_PLLACK,
  195. .c = &plla_characteristics,
  196. },
  197. },
  198. [PLL_ID_UPLL] = {
  199. {
  200. .n = "upll_fracck",
  201. .p = "main_osc",
  202. .l = &pll_frac_layout,
  203. .t = PLL_TYPE_FRAC,
  204. .f = CLK_SET_RATE_GATE,
  205. .c = &upll_characteristics,
  206. },
  207. {
  208. .n = "upll_divpmcck",
  209. .p = "upll_fracck",
  210. .l = &pll_divpmc_layout,
  211. .t = PLL_TYPE_DIV,
  212. .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
  213. CLK_SET_RATE_PARENT,
  214. .eid = PMC_UTMI,
  215. .c = &upll_characteristics,
  216. },
  217. },
  218. [PLL_ID_AUDIO] = {
  219. {
  220. .n = "audiopll_fracck",
  221. .p = "main_osc",
  222. .l = &pll_frac_layout,
  223. .f = CLK_SET_RATE_GATE,
  224. .c = &audiopll_characteristics,
  225. .t = PLL_TYPE_FRAC,
  226. },
  227. {
  228. .n = "audiopll_divpmcck",
  229. .p = "audiopll_fracck",
  230. .l = &pll_divpmc_layout,
  231. .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
  232. CLK_SET_RATE_PARENT,
  233. .c = &audiopll_characteristics,
  234. .eid = PMC_AUDIOPMCPLL,
  235. .t = PLL_TYPE_DIV,
  236. },
  237. {
  238. .n = "audiopll_diviock",
  239. .p = "audiopll_fracck",
  240. .l = &pll_divio_layout,
  241. .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
  242. CLK_SET_RATE_PARENT,
  243. .c = &audiopll_characteristics,
  244. .eid = PMC_AUDIOIOPLL,
  245. .t = PLL_TYPE_DIV,
  246. },
  247. },
  248. [PLL_ID_LVDS] = {
  249. {
  250. .n = "lvdspll_fracck",
  251. .p = "main_osc",
  252. .l = &pll_frac_layout,
  253. .f = CLK_SET_RATE_GATE,
  254. .c = &lvdspll_characteristics,
  255. .t = PLL_TYPE_FRAC,
  256. },
  257. {
  258. .n = "lvdspll_divpmcck",
  259. .p = "lvdspll_fracck",
  260. .l = &pll_divpmc_layout,
  261. .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
  262. CLK_SET_RATE_PARENT,
  263. .c = &lvdspll_characteristics,
  264. .eid = PMC_LVDSPLL,
  265. .t = PLL_TYPE_DIV,
  266. },
  267. },
  268. [PLL_ID_PLLA_DIV2] = {
  269. {
  270. .n = "plla_div2pmcck",
  271. .p = "plla_fracck",
  272. .l = &plladiv2_divpmc_layout,
  273. /*
  274. * This may feed critical parts of the system like timers.
  275. * It should not be disabled.
  276. */
  277. .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
  278. .c = &plladiv2_characteristics,
  279. .eid = PMC_PLLADIV2,
  280. .t = PLL_TYPE_DIV,
  281. },
  282. },
  283. };
  284. static const struct clk_programmable_layout sam9x7_programmable_layout = {
  285. .pres_mask = 0xff,
  286. .pres_shift = 8,
  287. .css_mask = 0x1f,
  288. .have_slck_mck = 0,
  289. .is_pres_direct = 1,
  290. };
  291. static const struct clk_pcr_layout sam9x7_pcr_layout = {
  292. .offset = 0x88,
  293. .cmd = BIT(31),
  294. .gckcss_mask = GENMASK(12, 8),
  295. .pid_mask = GENMASK(6, 0),
  296. };
  297. static const struct {
  298. char *n;
  299. char *p;
  300. u8 id;
  301. unsigned long flags;
  302. } sam9x7_systemck[] = {
  303. /*
  304. * ddrck feeds DDR controller and is enabled by bootloader thus we need
  305. * to keep it enabled in case there is no Linux consumer for it.
  306. */
  307. { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
  308. { .n = "uhpck", .p = "usbck", .id = 6 },
  309. { .n = "pck0", .p = "prog0", .id = 8 },
  310. { .n = "pck1", .p = "prog1", .id = 9 },
  311. };
  312. /*
  313. * Peripheral clocks description
  314. * @n: clock name
  315. * @f: clock flags
  316. * @id: peripheral id
  317. */
  318. static const struct {
  319. char *n;
  320. unsigned long f;
  321. u8 id;
  322. } sam9x7_periphck[] = {
  323. { .n = "pioA_clk", .id = 2, },
  324. { .n = "pioB_clk", .id = 3, },
  325. { .n = "pioC_clk", .id = 4, },
  326. { .n = "flex0_clk", .id = 5, },
  327. { .n = "flex1_clk", .id = 6, },
  328. { .n = "flex2_clk", .id = 7, },
  329. { .n = "flex3_clk", .id = 8, },
  330. { .n = "flex6_clk", .id = 9, },
  331. { .n = "flex7_clk", .id = 10, },
  332. { .n = "flex8_clk", .id = 11, },
  333. { .n = "sdmmc0_clk", .id = 12, },
  334. { .n = "flex4_clk", .id = 13, },
  335. { .n = "flex5_clk", .id = 14, },
  336. { .n = "flex9_clk", .id = 15, },
  337. { .n = "flex10_clk", .id = 16, },
  338. { .n = "tcb0_clk", .id = 17, },
  339. { .n = "pwm_clk", .id = 18, },
  340. { .n = "adc_clk", .id = 19, },
  341. { .n = "dma0_clk", .id = 20, },
  342. { .n = "uhphs_clk", .id = 22, },
  343. { .n = "udphs_clk", .id = 23, },
  344. { .n = "macb0_clk", .id = 24, },
  345. { .n = "lcd_clk", .id = 25, },
  346. { .n = "sdmmc1_clk", .id = 26, },
  347. { .n = "ssc_clk", .id = 28, },
  348. { .n = "can0_clk", .id = 29, },
  349. { .n = "can1_clk", .id = 30, },
  350. { .n = "flex11_clk", .id = 32, },
  351. { .n = "flex12_clk", .id = 33, },
  352. { .n = "i2s_clk", .id = 34, },
  353. { .n = "qspi_clk", .id = 35, },
  354. { .n = "gfx2d_clk", .id = 36, },
  355. { .n = "pit64b0_clk", .id = 37, },
  356. { .n = "trng_clk", .id = 38, },
  357. { .n = "aes_clk", .id = 39, },
  358. { .n = "tdes_clk", .id = 40, },
  359. { .n = "sha_clk", .id = 41, },
  360. { .n = "classd_clk", .id = 42, },
  361. { .n = "isi_clk", .id = 43, },
  362. { .n = "pioD_clk", .id = 44, },
  363. { .n = "tcb1_clk", .id = 45, },
  364. { .n = "dbgu_clk", .id = 47, },
  365. /*
  366. * mpddr_clk feeds DDR controller and is enabled by bootloader thus we
  367. * need to keep it enabled in case there is no Linux consumer for it.
  368. */
  369. { .n = "mpddr_clk", .id = 49, .f = CLK_IS_CRITICAL },
  370. { .n = "csi2dc_clk", .id = 52, },
  371. { .n = "csi4l_clk", .id = 53, },
  372. { .n = "dsi4l_clk", .id = 54, },
  373. { .n = "lvdsc_clk", .id = 56, },
  374. { .n = "pit64b1_clk", .id = 58, },
  375. { .n = "puf_clk", .id = 59, },
  376. { .n = "gmactsu_clk", .id = 67, },
  377. };
  378. /*
  379. * Generic clock description
  380. * @n: clock name
  381. * @pp: PLL parents
  382. * @pp_mux_table: PLL parents mux table
  383. * @r: clock output range
  384. * @pp_chg_id: id in parent array of changeable PLL parent
  385. * @pp_count: PLL parents count
  386. * @id: clock id
  387. */
  388. static const struct {
  389. const char *n;
  390. const char *pp[8];
  391. const char pp_mux_table[8];
  392. struct clk_range r;
  393. int pp_chg_id;
  394. u8 pp_count;
  395. u8 id;
  396. } sam9x7_gck[] = {
  397. {
  398. .n = "flex0_gclk",
  399. .id = 5,
  400. .pp = { "plla_div2pmcck", },
  401. .pp_mux_table = { 8, },
  402. .pp_count = 1,
  403. .pp_chg_id = INT_MIN,
  404. },
  405. {
  406. .n = "flex1_gclk",
  407. .id = 6,
  408. .pp = { "plla_div2pmcck", },
  409. .pp_mux_table = { 8, },
  410. .pp_count = 1,
  411. .pp_chg_id = INT_MIN,
  412. },
  413. {
  414. .n = "flex2_gclk",
  415. .id = 7,
  416. .pp = { "plla_div2pmcck", },
  417. .pp_mux_table = { 8, },
  418. .pp_count = 1,
  419. .pp_chg_id = INT_MIN,
  420. },
  421. {
  422. .n = "flex3_gclk",
  423. .id = 8,
  424. .pp = { "plla_div2pmcck", },
  425. .pp_mux_table = { 8, },
  426. .pp_count = 1,
  427. .pp_chg_id = INT_MIN,
  428. },
  429. {
  430. .n = "flex6_gclk",
  431. .id = 9,
  432. .pp = { "plla_div2pmcck", },
  433. .pp_mux_table = { 8, },
  434. .pp_count = 1,
  435. .pp_chg_id = INT_MIN,
  436. },
  437. {
  438. .n = "flex7_gclk",
  439. .id = 10,
  440. .pp = { "plla_div2pmcck", },
  441. .pp_mux_table = { 8, },
  442. .pp_count = 1,
  443. .pp_chg_id = INT_MIN,
  444. },
  445. {
  446. .n = "flex8_gclk",
  447. .id = 11,
  448. .pp = { "plla_div2pmcck", },
  449. .pp_mux_table = { 8, },
  450. .pp_count = 1,
  451. .pp_chg_id = INT_MIN,
  452. },
  453. {
  454. .n = "sdmmc0_gclk",
  455. .id = 12,
  456. .r = { .max = 105000000 },
  457. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  458. .pp_mux_table = { 6, 8, },
  459. .pp_count = 2,
  460. .pp_chg_id = INT_MIN,
  461. },
  462. {
  463. .n = "flex4_gclk",
  464. .id = 13,
  465. .pp = { "plla_div2pmcck", },
  466. .pp_mux_table = { 8, },
  467. .pp_count = 1,
  468. .pp_chg_id = INT_MIN,
  469. },
  470. {
  471. .n = "flex5_gclk",
  472. .id = 14,
  473. .pp = { "plla_div2pmcck", },
  474. .pp_mux_table = { 8, },
  475. .pp_count = 1,
  476. .pp_chg_id = INT_MIN,
  477. },
  478. {
  479. .n = "flex9_gclk",
  480. .id = 15,
  481. .pp = { "plla_div2pmcck", },
  482. .pp_mux_table = { 8, },
  483. .pp_count = 1,
  484. .pp_chg_id = INT_MIN,
  485. },
  486. {
  487. .n = "flex10_gclk",
  488. .id = 16,
  489. .pp = { "plla_div2pmcck", },
  490. .pp_mux_table = { 8, },
  491. .pp_count = 1,
  492. .pp_chg_id = INT_MIN,
  493. },
  494. {
  495. .n = "tcb0_gclk",
  496. .id = 17,
  497. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  498. .pp_mux_table = { 6, 8, },
  499. .pp_count = 2,
  500. .pp_chg_id = INT_MIN,
  501. },
  502. {
  503. .n = "adc_gclk",
  504. .id = 19,
  505. .pp = { "upll_divpmcck", "plla_div2pmcck", },
  506. .pp_mux_table = { 5, 8, },
  507. .pp_count = 2,
  508. .pp_chg_id = INT_MIN,
  509. },
  510. {
  511. .n = "lcd_gclk",
  512. .id = 25,
  513. .r = { .max = 75000000 },
  514. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  515. .pp_mux_table = { 6, 8, },
  516. .pp_count = 2,
  517. .pp_chg_id = INT_MIN,
  518. },
  519. {
  520. .n = "sdmmc1_gclk",
  521. .id = 26,
  522. .r = { .max = 105000000 },
  523. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  524. .pp_mux_table = { 6, 8, },
  525. .pp_count = 2,
  526. .pp_chg_id = INT_MIN,
  527. },
  528. {
  529. .n = "mcan0_gclk",
  530. .id = 29,
  531. .r = { .max = 80000000 },
  532. .pp = { "upll_divpmcck", "plla_div2pmcck", },
  533. .pp_mux_table = { 5, 8, },
  534. .pp_count = 2,
  535. .pp_chg_id = INT_MIN,
  536. },
  537. {
  538. .n = "mcan1_gclk",
  539. .id = 30,
  540. .r = { .max = 80000000 },
  541. .pp = { "upll_divpmcck", "plla_div2pmcck", },
  542. .pp_mux_table = { 5, 8, },
  543. .pp_count = 2,
  544. .pp_chg_id = INT_MIN,
  545. },
  546. {
  547. .n = "flex11_gclk",
  548. .id = 32,
  549. .pp = { "plla_div2pmcck", },
  550. .pp_mux_table = { 8, },
  551. .pp_count = 1,
  552. .pp_chg_id = INT_MIN,
  553. },
  554. {
  555. .n = "flex12_gclk",
  556. .id = 33,
  557. .pp = { "plla_div2pmcck", },
  558. .pp_mux_table = { 8, },
  559. .pp_count = 1,
  560. .pp_chg_id = INT_MIN,
  561. },
  562. {
  563. .n = "i2s_gclk",
  564. .id = 34,
  565. .r = { .max = 100000000 },
  566. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  567. .pp_mux_table = { 6, 8, },
  568. .pp_count = 2,
  569. .pp_chg_id = INT_MIN,
  570. },
  571. {
  572. .n = "qspi_gclk",
  573. .id = 35,
  574. .r = { .max = 200000000 },
  575. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  576. .pp_mux_table = { 6, 8, },
  577. .pp_count = 2,
  578. .pp_chg_id = INT_MIN,
  579. },
  580. {
  581. .n = "pit64b0_gclk",
  582. .id = 37,
  583. .pp = { "plla_div2pmcck", },
  584. .pp_mux_table = { 8, },
  585. .pp_count = 1,
  586. .pp_chg_id = INT_MIN,
  587. },
  588. {
  589. .n = "classd_gclk",
  590. .id = 42,
  591. .r = { .max = 100000000 },
  592. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  593. .pp_mux_table = { 6, 8, },
  594. .pp_count = 2,
  595. .pp_chg_id = INT_MIN,
  596. },
  597. {
  598. .n = "tcb1_gclk",
  599. .id = 45,
  600. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  601. .pp_mux_table = { 6, 8, },
  602. .pp_count = 2,
  603. .pp_chg_id = INT_MIN,
  604. },
  605. {
  606. .n = "dbgu_gclk",
  607. .id = 47,
  608. .pp = { "plla_div2pmcck", },
  609. .pp_mux_table = { 8, },
  610. .pp_count = 1,
  611. .pp_chg_id = INT_MIN,
  612. },
  613. {
  614. .n = "mipiphy_gclk",
  615. .id = 55,
  616. .r = { .max = 27000000 },
  617. .pp = { "plla_div2pmcck", },
  618. .pp_mux_table = { 8, },
  619. .pp_count = 1,
  620. .pp_chg_id = INT_MIN,
  621. },
  622. {
  623. .n = "pit64b1_gclk",
  624. .id = 58,
  625. .pp = { "plla_div2pmcck", },
  626. .pp_mux_table = { 8, },
  627. .pp_count = 1,
  628. .pp_chg_id = INT_MIN,
  629. },
  630. {
  631. .n = "gmac_gclk",
  632. .id = 67,
  633. .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
  634. .pp_mux_table = { 6, 8, },
  635. .pp_count = 2,
  636. .pp_chg_id = INT_MIN,
  637. },
  638. };
  639. static void __init sam9x7_pmc_setup(struct device_node *np)
  640. {
  641. struct clk_range range = CLK_RANGE(0, 0);
  642. const char *td_slck_name, *md_slck_name, *mainxtal_name;
  643. struct pmc_data *sam9x7_pmc;
  644. const char *parent_names[9];
  645. void **clk_mux_buffer = NULL;
  646. int clk_mux_buffer_size = 0;
  647. struct clk_hw *main_osc_hw;
  648. struct regmap *regmap;
  649. struct clk_hw *hw;
  650. int i, j;
  651. i = of_property_match_string(np, "clock-names", "td_slck");
  652. if (i < 0)
  653. return;
  654. td_slck_name = of_clk_get_parent_name(np, i);
  655. i = of_property_match_string(np, "clock-names", "md_slck");
  656. if (i < 0)
  657. return;
  658. md_slck_name = of_clk_get_parent_name(np, i);
  659. i = of_property_match_string(np, "clock-names", "main_xtal");
  660. if (i < 0)
  661. return;
  662. mainxtal_name = of_clk_get_parent_name(np, i);
  663. regmap = device_node_to_regmap(np);
  664. if (IS_ERR(regmap))
  665. return;
  666. sam9x7_pmc = pmc_data_allocate(PMC_LVDSPLL + 1,
  667. nck(sam9x7_systemck),
  668. nck(sam9x7_periphck),
  669. nck(sam9x7_gck), 8);
  670. if (!sam9x7_pmc)
  671. return;
  672. clk_mux_buffer = kmalloc(sizeof(void *) *
  673. (ARRAY_SIZE(sam9x7_gck)),
  674. GFP_KERNEL);
  675. if (!clk_mux_buffer)
  676. goto err_free;
  677. hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
  678. 50000000);
  679. if (IS_ERR(hw))
  680. goto err_free;
  681. hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, NULL, 0);
  682. if (IS_ERR(hw))
  683. goto err_free;
  684. main_osc_hw = hw;
  685. parent_names[0] = "main_rc_osc";
  686. parent_names[1] = "main_osc";
  687. hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, NULL, 2);
  688. if (IS_ERR(hw))
  689. goto err_free;
  690. sam9x7_pmc->chws[PMC_MAIN] = hw;
  691. for (i = 0; i < PLL_ID_MAX; i++) {
  692. for (j = 0; j < 3; j++) {
  693. struct clk_hw *parent_hw;
  694. if (!sam9x7_plls[i][j].n)
  695. continue;
  696. switch (sam9x7_plls[i][j].t) {
  697. case PLL_TYPE_FRAC:
  698. if (!strcmp(sam9x7_plls[i][j].p, "mainck"))
  699. parent_hw = sam9x7_pmc->chws[PMC_MAIN];
  700. else if (!strcmp(sam9x7_plls[i][j].p, "main_osc"))
  701. parent_hw = main_osc_hw;
  702. else
  703. parent_hw = __clk_get_hw(of_clk_get_by_name
  704. (np, sam9x7_plls[i][j].p));
  705. hw = sam9x60_clk_register_frac_pll(regmap,
  706. &pmc_pll_lock,
  707. sam9x7_plls[i][j].n,
  708. sam9x7_plls[i][j].p,
  709. parent_hw, i,
  710. sam9x7_plls[i][j].c,
  711. sam9x7_plls[i][j].l,
  712. sam9x7_plls[i][j].f);
  713. break;
  714. case PLL_TYPE_DIV:
  715. hw = sam9x60_clk_register_div_pll(regmap,
  716. &pmc_pll_lock,
  717. sam9x7_plls[i][j].n,
  718. sam9x7_plls[i][j].p, NULL, i,
  719. sam9x7_plls[i][j].c,
  720. sam9x7_plls[i][j].l,
  721. sam9x7_plls[i][j].f, 0);
  722. break;
  723. default:
  724. continue;
  725. }
  726. if (IS_ERR(hw))
  727. goto err_free;
  728. if (sam9x7_plls[i][j].eid)
  729. sam9x7_pmc->chws[sam9x7_plls[i][j].eid] = hw;
  730. }
  731. }
  732. parent_names[0] = md_slck_name;
  733. parent_names[1] = "mainck";
  734. parent_names[2] = "plla_divpmcck";
  735. parent_names[3] = "upll_divpmcck";
  736. hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
  737. parent_names, NULL, &sam9x7_master_layout,
  738. &mck_characteristics, &mck_lock);
  739. if (IS_ERR(hw))
  740. goto err_free;
  741. hw = at91_clk_register_master_div(regmap, "masterck_div",
  742. "masterck_pres", NULL, &sam9x7_master_layout,
  743. &mck_characteristics, &mck_lock,
  744. CLK_SET_RATE_GATE, 0);
  745. if (IS_ERR(hw))
  746. goto err_free;
  747. sam9x7_pmc->chws[PMC_MCK] = hw;
  748. parent_names[0] = "plla_divpmcck";
  749. parent_names[1] = "upll_divpmcck";
  750. parent_names[2] = "main_osc";
  751. hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
  752. if (IS_ERR(hw))
  753. goto err_free;
  754. parent_names[0] = md_slck_name;
  755. parent_names[1] = td_slck_name;
  756. parent_names[2] = "mainck";
  757. parent_names[3] = "masterck_div";
  758. parent_names[4] = "plla_divpmcck";
  759. parent_names[5] = "upll_divpmcck";
  760. parent_names[6] = "audiopll_divpmcck";
  761. for (i = 0; i < 2; i++) {
  762. char name[6];
  763. snprintf(name, sizeof(name), "prog%d", i);
  764. hw = at91_clk_register_programmable(regmap, name,
  765. parent_names, NULL, 7, i,
  766. &sam9x7_programmable_layout,
  767. NULL);
  768. if (IS_ERR(hw))
  769. goto err_free;
  770. sam9x7_pmc->pchws[i] = hw;
  771. }
  772. for (i = 0; i < ARRAY_SIZE(sam9x7_systemck); i++) {
  773. hw = at91_clk_register_system(regmap, sam9x7_systemck[i].n,
  774. sam9x7_systemck[i].p, NULL,
  775. sam9x7_systemck[i].id,
  776. sam9x7_systemck[i].flags);
  777. if (IS_ERR(hw))
  778. goto err_free;
  779. sam9x7_pmc->shws[sam9x7_systemck[i].id] = hw;
  780. }
  781. for (i = 0; i < ARRAY_SIZE(sam9x7_periphck); i++) {
  782. hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
  783. &sam9x7_pcr_layout,
  784. sam9x7_periphck[i].n,
  785. "masterck_div", NULL,
  786. sam9x7_periphck[i].id,
  787. &range, INT_MIN,
  788. sam9x7_periphck[i].f);
  789. if (IS_ERR(hw))
  790. goto err_free;
  791. sam9x7_pmc->phws[sam9x7_periphck[i].id] = hw;
  792. }
  793. parent_names[0] = md_slck_name;
  794. parent_names[1] = td_slck_name;
  795. parent_names[2] = "mainck";
  796. parent_names[3] = "masterck_div";
  797. for (i = 0; i < ARRAY_SIZE(sam9x7_gck); i++) {
  798. u8 num_parents = 4 + sam9x7_gck[i].pp_count;
  799. u32 *mux_table;
  800. mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
  801. GFP_KERNEL);
  802. if (!mux_table)
  803. goto err_free;
  804. PMC_INIT_TABLE(mux_table, 4);
  805. PMC_FILL_TABLE(&mux_table[4], sam9x7_gck[i].pp_mux_table,
  806. sam9x7_gck[i].pp_count);
  807. PMC_FILL_TABLE(&parent_names[4], sam9x7_gck[i].pp,
  808. sam9x7_gck[i].pp_count);
  809. hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
  810. &sam9x7_pcr_layout,
  811. sam9x7_gck[i].n,
  812. parent_names, NULL, mux_table,
  813. num_parents,
  814. sam9x7_gck[i].id,
  815. &sam9x7_gck[i].r,
  816. sam9x7_gck[i].pp_chg_id);
  817. if (IS_ERR(hw))
  818. goto err_free;
  819. sam9x7_pmc->ghws[sam9x7_gck[i].id] = hw;
  820. clk_mux_buffer[clk_mux_buffer_size++] = mux_table;
  821. }
  822. of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x7_pmc);
  823. kfree(clk_mux_buffer);
  824. return;
  825. err_free:
  826. if (clk_mux_buffer) {
  827. for (i = 0; i < clk_mux_buffer_size; i++)
  828. kfree(clk_mux_buffer[i]);
  829. kfree(clk_mux_buffer);
  830. }
  831. kfree(sam9x7_pmc);
  832. }
  833. /* Some clks are used for a clocksource */
  834. CLK_OF_DECLARE(sam9x7_pmc, "microchip,sam9x7-pmc", sam9x7_pmc_setup);