imx8mp-blk-ctrl.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de>
  4. */
  5. #include <linux/bitfield.h>
  6. #include <linux/clk.h>
  7. #include <linux/clk-provider.h>
  8. #include <linux/device.h>
  9. #include <linux/interconnect.h>
  10. #include <linux/module.h>
  11. #include <linux/of.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/pm_domain.h>
  14. #include <linux/pm_runtime.h>
  15. #include <linux/regmap.h>
  16. #include <dt-bindings/power/imx8mp-power.h>
  17. #define GPR_REG0 0x0
  18. #define PCIE_CLOCK_MODULE_EN BIT(0)
  19. #define USB_CLOCK_MODULE_EN BIT(1)
  20. #define PCIE_PHY_APB_RST BIT(4)
  21. #define PCIE_PHY_INIT_RST BIT(5)
  22. #define GPR_REG1 0x4
  23. #define PLL_LOCK BIT(13)
  24. #define GPR_REG2 0x8
  25. #define P_PLL_MASK GENMASK(5, 0)
  26. #define M_PLL_MASK GENMASK(15, 6)
  27. #define S_PLL_MASK GENMASK(18, 16)
  28. #define GPR_REG3 0xc
  29. #define PLL_CKE BIT(17)
  30. #define PLL_RST BIT(31)
  31. struct imx8mp_blk_ctrl_domain;
  32. struct imx8mp_blk_ctrl {
  33. struct device *dev;
  34. struct notifier_block power_nb;
  35. struct device *bus_power_dev;
  36. struct regmap *regmap;
  37. struct imx8mp_blk_ctrl_domain *domains;
  38. struct genpd_onecell_data onecell_data;
  39. void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
  40. void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
  41. };
  42. struct imx8mp_blk_ctrl_domain_data {
  43. const char *name;
  44. const char * const *clk_names;
  45. int num_clks;
  46. const char * const *path_names;
  47. int num_paths;
  48. const char *gpc_name;
  49. const unsigned int flags;
  50. };
  51. #define DOMAIN_MAX_CLKS 3
  52. #define DOMAIN_MAX_PATHS 3
  53. struct imx8mp_blk_ctrl_domain {
  54. struct generic_pm_domain genpd;
  55. const struct imx8mp_blk_ctrl_domain_data *data;
  56. struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
  57. struct icc_bulk_data paths[DOMAIN_MAX_PATHS];
  58. struct device *power_dev;
  59. struct imx8mp_blk_ctrl *bc;
  60. struct notifier_block power_nb;
  61. int num_paths;
  62. int id;
  63. };
  64. struct imx8mp_blk_ctrl_data {
  65. int max_reg;
  66. int (*probe) (struct imx8mp_blk_ctrl *bc);
  67. notifier_fn_t power_notifier_fn;
  68. void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
  69. void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
  70. const struct imx8mp_blk_ctrl_domain_data *domains;
  71. int num_domains;
  72. };
  73. static inline struct imx8mp_blk_ctrl_domain *
  74. to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd)
  75. {
  76. return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd);
  77. }
  78. struct clk_hsio_pll {
  79. struct clk_hw hw;
  80. struct regmap *regmap;
  81. };
  82. static inline struct clk_hsio_pll *to_clk_hsio_pll(struct clk_hw *hw)
  83. {
  84. return container_of(hw, struct clk_hsio_pll, hw);
  85. }
  86. static int clk_hsio_pll_prepare(struct clk_hw *hw)
  87. {
  88. struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
  89. u32 val;
  90. /* set the PLL configuration */
  91. regmap_update_bits(clk->regmap, GPR_REG2,
  92. P_PLL_MASK | M_PLL_MASK | S_PLL_MASK,
  93. FIELD_PREP(P_PLL_MASK, 12) |
  94. FIELD_PREP(M_PLL_MASK, 800) |
  95. FIELD_PREP(S_PLL_MASK, 4));
  96. /* de-assert PLL reset */
  97. regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST, PLL_RST);
  98. /* enable PLL */
  99. regmap_update_bits(clk->regmap, GPR_REG3, PLL_CKE, PLL_CKE);
  100. return regmap_read_poll_timeout(clk->regmap, GPR_REG1, val,
  101. val & PLL_LOCK, 10, 100);
  102. }
  103. static void clk_hsio_pll_unprepare(struct clk_hw *hw)
  104. {
  105. struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
  106. regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST | PLL_CKE, 0);
  107. }
  108. static int clk_hsio_pll_is_prepared(struct clk_hw *hw)
  109. {
  110. struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
  111. return regmap_test_bits(clk->regmap, GPR_REG1, PLL_LOCK);
  112. }
  113. static unsigned long clk_hsio_pll_recalc_rate(struct clk_hw *hw,
  114. unsigned long parent_rate)
  115. {
  116. return 100000000;
  117. }
  118. static const struct clk_ops clk_hsio_pll_ops = {
  119. .prepare = clk_hsio_pll_prepare,
  120. .unprepare = clk_hsio_pll_unprepare,
  121. .is_prepared = clk_hsio_pll_is_prepared,
  122. .recalc_rate = clk_hsio_pll_recalc_rate,
  123. };
  124. static int imx8mp_hsio_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc)
  125. {
  126. struct clk_hsio_pll *clk_hsio_pll;
  127. struct clk_hw *hw;
  128. struct clk_init_data init = {};
  129. int ret;
  130. clk_hsio_pll = devm_kzalloc(bc->dev, sizeof(*clk_hsio_pll), GFP_KERNEL);
  131. if (!clk_hsio_pll)
  132. return -ENOMEM;
  133. init.name = "hsio_pll";
  134. init.ops = &clk_hsio_pll_ops;
  135. init.parent_names = (const char *[]){"osc_24m"};
  136. init.num_parents = 1;
  137. clk_hsio_pll->regmap = bc->regmap;
  138. clk_hsio_pll->hw.init = &init;
  139. hw = &clk_hsio_pll->hw;
  140. ret = devm_clk_hw_register(bc->bus_power_dev, hw);
  141. if (ret)
  142. return ret;
  143. return devm_of_clk_add_hw_provider(bc->dev, of_clk_hw_simple_get, hw);
  144. }
  145. static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
  146. struct imx8mp_blk_ctrl_domain *domain)
  147. {
  148. switch (domain->id) {
  149. case IMX8MP_HSIOBLK_PD_USB:
  150. regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
  151. break;
  152. case IMX8MP_HSIOBLK_PD_PCIE:
  153. regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
  154. break;
  155. case IMX8MP_HSIOBLK_PD_PCIE_PHY:
  156. regmap_set_bits(bc->regmap, GPR_REG0,
  157. PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
  158. break;
  159. default:
  160. break;
  161. }
  162. }
  163. static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
  164. struct imx8mp_blk_ctrl_domain *domain)
  165. {
  166. switch (domain->id) {
  167. case IMX8MP_HSIOBLK_PD_USB:
  168. regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
  169. break;
  170. case IMX8MP_HSIOBLK_PD_PCIE:
  171. regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
  172. break;
  173. case IMX8MP_HSIOBLK_PD_PCIE_PHY:
  174. regmap_clear_bits(bc->regmap, GPR_REG0,
  175. PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
  176. break;
  177. default:
  178. break;
  179. }
  180. }
  181. static int imx8mp_hsio_power_notifier(struct notifier_block *nb,
  182. unsigned long action, void *data)
  183. {
  184. struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
  185. power_nb);
  186. struct clk_bulk_data *usb_clk = bc->domains[IMX8MP_HSIOBLK_PD_USB].clks;
  187. int num_clks = bc->domains[IMX8MP_HSIOBLK_PD_USB].data->num_clks;
  188. int ret;
  189. switch (action) {
  190. case GENPD_NOTIFY_ON:
  191. /*
  192. * enable USB clock for a moment for the power-on ADB handshake
  193. * to proceed
  194. */
  195. ret = clk_bulk_prepare_enable(num_clks, usb_clk);
  196. if (ret)
  197. return NOTIFY_BAD;
  198. regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
  199. udelay(5);
  200. regmap_clear_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
  201. clk_bulk_disable_unprepare(num_clks, usb_clk);
  202. break;
  203. case GENPD_NOTIFY_PRE_OFF:
  204. /* enable USB clock for the power-down ADB handshake to work */
  205. ret = clk_bulk_prepare_enable(num_clks, usb_clk);
  206. if (ret)
  207. return NOTIFY_BAD;
  208. regmap_set_bits(bc->regmap, GPR_REG0, USB_CLOCK_MODULE_EN);
  209. break;
  210. case GENPD_NOTIFY_OFF:
  211. clk_bulk_disable_unprepare(num_clks, usb_clk);
  212. break;
  213. default:
  214. break;
  215. }
  216. return NOTIFY_OK;
  217. }
  218. static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
  219. [IMX8MP_HSIOBLK_PD_USB] = {
  220. .name = "hsioblk-usb",
  221. .clk_names = (const char *[]){ "usb" },
  222. .num_clks = 1,
  223. .gpc_name = "usb",
  224. .path_names = (const char *[]){"usb1", "usb2"},
  225. .num_paths = 2,
  226. },
  227. [IMX8MP_HSIOBLK_PD_USB_PHY1] = {
  228. .name = "hsioblk-usb-phy1",
  229. .gpc_name = "usb-phy1",
  230. .flags = GENPD_FLAG_ACTIVE_WAKEUP,
  231. },
  232. [IMX8MP_HSIOBLK_PD_USB_PHY2] = {
  233. .name = "hsioblk-usb-phy2",
  234. .gpc_name = "usb-phy2",
  235. .flags = GENPD_FLAG_ACTIVE_WAKEUP,
  236. },
  237. [IMX8MP_HSIOBLK_PD_PCIE] = {
  238. .name = "hsioblk-pcie",
  239. .clk_names = (const char *[]){ "pcie" },
  240. .num_clks = 1,
  241. .gpc_name = "pcie",
  242. .path_names = (const char *[]){"noc-pcie", "pcie"},
  243. .num_paths = 2,
  244. },
  245. [IMX8MP_HSIOBLK_PD_PCIE_PHY] = {
  246. .name = "hsioblk-pcie-phy",
  247. .gpc_name = "pcie-phy",
  248. },
  249. };
  250. static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
  251. .max_reg = 0x24,
  252. .probe = imx8mp_hsio_blk_ctrl_probe,
  253. .power_on = imx8mp_hsio_blk_ctrl_power_on,
  254. .power_off = imx8mp_hsio_blk_ctrl_power_off,
  255. .power_notifier_fn = imx8mp_hsio_power_notifier,
  256. .domains = imx8mp_hsio_domain_data,
  257. .num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data),
  258. };
  259. #define HDMI_RTX_RESET_CTL0 0x20
  260. #define HDMI_RTX_CLK_CTL0 0x40
  261. #define HDMI_RTX_CLK_CTL1 0x50
  262. #define HDMI_RTX_CLK_CTL2 0x60
  263. #define HDMI_RTX_CLK_CTL3 0x70
  264. #define HDMI_RTX_CLK_CTL4 0x80
  265. #define HDMI_TX_CONTROL0 0x200
  266. #define HDMI_LCDIF_NOC_HURRY_MASK GENMASK(14, 12)
  267. static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
  268. struct imx8mp_blk_ctrl_domain *domain)
  269. {
  270. switch (domain->id) {
  271. case IMX8MP_HDMIBLK_PD_IRQSTEER:
  272. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
  273. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
  274. break;
  275. case IMX8MP_HDMIBLK_PD_LCDIF:
  276. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
  277. BIT(16) | BIT(17) | BIT(18) |
  278. BIT(19) | BIT(20));
  279. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
  280. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
  281. BIT(4) | BIT(5) | BIT(6));
  282. regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0,
  283. FIELD_PREP(HDMI_LCDIF_NOC_HURRY_MASK, 7));
  284. break;
  285. case IMX8MP_HDMIBLK_PD_PAI:
  286. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
  287. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
  288. break;
  289. case IMX8MP_HDMIBLK_PD_PVI:
  290. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
  291. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
  292. break;
  293. case IMX8MP_HDMIBLK_PD_TRNG:
  294. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
  295. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
  296. break;
  297. case IMX8MP_HDMIBLK_PD_HDMI_TX:
  298. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
  299. BIT(2) | BIT(4) | BIT(5));
  300. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
  301. BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
  302. BIT(18) | BIT(19) | BIT(20) | BIT(21));
  303. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
  304. BIT(7) | BIT(10) | BIT(11));
  305. regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
  306. break;
  307. case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
  308. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
  309. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
  310. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
  311. regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
  312. break;
  313. case IMX8MP_HDMIBLK_PD_HRV:
  314. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
  315. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
  316. break;
  317. default:
  318. break;
  319. }
  320. }
  321. static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
  322. struct imx8mp_blk_ctrl_domain *domain)
  323. {
  324. switch (domain->id) {
  325. case IMX8MP_HDMIBLK_PD_IRQSTEER:
  326. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
  327. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
  328. break;
  329. case IMX8MP_HDMIBLK_PD_LCDIF:
  330. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
  331. BIT(4) | BIT(5) | BIT(6));
  332. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
  333. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
  334. BIT(16) | BIT(17) | BIT(18) |
  335. BIT(19) | BIT(20));
  336. break;
  337. case IMX8MP_HDMIBLK_PD_PAI:
  338. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
  339. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
  340. break;
  341. case IMX8MP_HDMIBLK_PD_PVI:
  342. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
  343. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
  344. break;
  345. case IMX8MP_HDMIBLK_PD_TRNG:
  346. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
  347. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
  348. break;
  349. case IMX8MP_HDMIBLK_PD_HDMI_TX:
  350. regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
  351. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
  352. BIT(7) | BIT(10) | BIT(11));
  353. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
  354. BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
  355. BIT(18) | BIT(19) | BIT(20) | BIT(21));
  356. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
  357. BIT(2) | BIT(4) | BIT(5));
  358. break;
  359. case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
  360. regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
  361. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
  362. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
  363. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
  364. break;
  365. case IMX8MP_HDMIBLK_PD_HRV:
  366. regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
  367. regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
  368. break;
  369. default:
  370. break;
  371. }
  372. }
  373. static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
  374. unsigned long action, void *data)
  375. {
  376. struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
  377. power_nb);
  378. if (action != GENPD_NOTIFY_ON)
  379. return NOTIFY_OK;
  380. /*
  381. * Contrary to other blk-ctrls the reset and clock don't clear when the
  382. * power domain is powered down. To ensure the proper reset pulsing,
  383. * first clear them all to asserted state, then enable the bus clocks
  384. * and then release the ADB reset.
  385. */
  386. regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0);
  387. regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
  388. regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
  389. regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
  390. BIT(0) | BIT(1) | BIT(10) | BIT(11));
  391. regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
  392. /*
  393. * On power up we have no software backchannel to the GPC to
  394. * wait for the ADB handshake to happen, so we just delay for a
  395. * bit. On power down the GPC driver waits for the handshake.
  396. */
  397. udelay(5);
  398. return NOTIFY_OK;
  399. }
  400. static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
  401. [IMX8MP_HDMIBLK_PD_IRQSTEER] = {
  402. .name = "hdmiblk-irqsteer",
  403. .clk_names = (const char *[]){ "apb" },
  404. .num_clks = 1,
  405. .gpc_name = "irqsteer",
  406. },
  407. [IMX8MP_HDMIBLK_PD_LCDIF] = {
  408. .name = "hdmiblk-lcdif",
  409. .clk_names = (const char *[]){ "axi", "apb", "fdcc" },
  410. .num_clks = 3,
  411. .gpc_name = "lcdif",
  412. .path_names = (const char *[]){"lcdif-hdmi"},
  413. .num_paths = 1,
  414. },
  415. [IMX8MP_HDMIBLK_PD_PAI] = {
  416. .name = "hdmiblk-pai",
  417. .clk_names = (const char *[]){ "apb" },
  418. .num_clks = 1,
  419. .gpc_name = "pai",
  420. },
  421. [IMX8MP_HDMIBLK_PD_PVI] = {
  422. .name = "hdmiblk-pvi",
  423. .clk_names = (const char *[]){ "apb" },
  424. .num_clks = 1,
  425. .gpc_name = "pvi",
  426. },
  427. [IMX8MP_HDMIBLK_PD_TRNG] = {
  428. .name = "hdmiblk-trng",
  429. .clk_names = (const char *[]){ "apb" },
  430. .num_clks = 1,
  431. .gpc_name = "trng",
  432. },
  433. [IMX8MP_HDMIBLK_PD_HDMI_TX] = {
  434. .name = "hdmiblk-hdmi-tx",
  435. .clk_names = (const char *[]){ "apb", "ref_266m", "fdcc" },
  436. .num_clks = 3,
  437. .gpc_name = "hdmi-tx",
  438. },
  439. [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
  440. .name = "hdmiblk-hdmi-tx-phy",
  441. .clk_names = (const char *[]){ "apb", "ref_24m" },
  442. .num_clks = 2,
  443. .gpc_name = "hdmi-tx-phy",
  444. },
  445. [IMX8MP_HDMIBLK_PD_HRV] = {
  446. .name = "hdmiblk-hrv",
  447. .clk_names = (const char *[]){ "axi", "apb" },
  448. .num_clks = 2,
  449. .gpc_name = "hrv",
  450. .path_names = (const char *[]){"hrv"},
  451. .num_paths = 1,
  452. },
  453. [IMX8MP_HDMIBLK_PD_HDCP] = {
  454. .name = "hdmiblk-hdcp",
  455. .clk_names = (const char *[]){ "axi", "apb" },
  456. .num_clks = 2,
  457. .gpc_name = "hdcp",
  458. .path_names = (const char *[]){"hdcp"},
  459. .num_paths = 1,
  460. },
  461. };
  462. static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
  463. .max_reg = 0x23c,
  464. .power_on = imx8mp_hdmi_blk_ctrl_power_on,
  465. .power_off = imx8mp_hdmi_blk_ctrl_power_off,
  466. .power_notifier_fn = imx8mp_hdmi_power_notifier,
  467. .domains = imx8mp_hdmi_domain_data,
  468. .num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data),
  469. };
  470. static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
  471. {
  472. struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
  473. const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
  474. struct imx8mp_blk_ctrl *bc = domain->bc;
  475. int ret;
  476. /* make sure bus domain is awake */
  477. ret = pm_runtime_resume_and_get(bc->bus_power_dev);
  478. if (ret < 0) {
  479. dev_err(bc->dev, "failed to power up bus domain\n");
  480. return ret;
  481. }
  482. /* enable upstream clocks */
  483. ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
  484. if (ret) {
  485. dev_err(bc->dev, "failed to enable clocks\n");
  486. goto bus_put;
  487. }
  488. /* domain specific blk-ctrl manipulation */
  489. bc->power_on(bc, domain);
  490. /* power up upstream GPC domain */
  491. ret = pm_runtime_resume_and_get(domain->power_dev);
  492. if (ret < 0) {
  493. dev_err(bc->dev, "failed to power up peripheral domain\n");
  494. goto clk_disable;
  495. }
  496. ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
  497. if (ret)
  498. dev_err(bc->dev, "failed to set icc bw\n");
  499. clk_bulk_disable_unprepare(data->num_clks, domain->clks);
  500. return 0;
  501. clk_disable:
  502. clk_bulk_disable_unprepare(data->num_clks, domain->clks);
  503. bus_put:
  504. pm_runtime_put(bc->bus_power_dev);
  505. return ret;
  506. }
  507. static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
  508. {
  509. struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
  510. const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
  511. struct imx8mp_blk_ctrl *bc = domain->bc;
  512. int ret;
  513. ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
  514. if (ret) {
  515. dev_err(bc->dev, "failed to enable clocks\n");
  516. return ret;
  517. }
  518. /* domain specific blk-ctrl manipulation */
  519. bc->power_off(bc, domain);
  520. clk_bulk_disable_unprepare(data->num_clks, domain->clks);
  521. /* power down upstream GPC domain */
  522. pm_runtime_put(domain->power_dev);
  523. /* allow bus domain to suspend */
  524. pm_runtime_put(bc->bus_power_dev);
  525. return 0;
  526. }
  527. static int imx8mp_blk_ctrl_gpc_notifier(struct notifier_block *nb,
  528. unsigned long action, void *data)
  529. {
  530. struct imx8mp_blk_ctrl_domain *domain =
  531. container_of(nb, struct imx8mp_blk_ctrl_domain, power_nb);
  532. if (action == GENPD_NOTIFY_PRE_OFF) {
  533. if (domain->genpd.status == GENPD_STATE_ON)
  534. return NOTIFY_BAD;
  535. }
  536. return NOTIFY_OK;
  537. }
  538. static struct lock_class_key blk_ctrl_genpd_lock_class;
  539. static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
  540. {
  541. const struct imx8mp_blk_ctrl_data *bc_data;
  542. struct device *dev = &pdev->dev;
  543. struct imx8mp_blk_ctrl *bc;
  544. void __iomem *base;
  545. int num_domains, i, ret;
  546. struct regmap_config regmap_config = {
  547. .reg_bits = 32,
  548. .val_bits = 32,
  549. .reg_stride = 4,
  550. };
  551. bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
  552. if (!bc)
  553. return -ENOMEM;
  554. bc->dev = dev;
  555. bc_data = of_device_get_match_data(dev);
  556. num_domains = bc_data->num_domains;
  557. base = devm_platform_ioremap_resource(pdev, 0);
  558. if (IS_ERR(base))
  559. return PTR_ERR(base);
  560. regmap_config.max_register = bc_data->max_reg;
  561. bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
  562. if (IS_ERR(bc->regmap))
  563. return dev_err_probe(dev, PTR_ERR(bc->regmap),
  564. "failed to init regmap\n");
  565. bc->domains = devm_kcalloc(dev, num_domains,
  566. sizeof(struct imx8mp_blk_ctrl_domain),
  567. GFP_KERNEL);
  568. if (!bc->domains)
  569. return -ENOMEM;
  570. bc->onecell_data.num_domains = num_domains;
  571. bc->onecell_data.domains =
  572. devm_kcalloc(dev, num_domains,
  573. sizeof(struct generic_pm_domain *), GFP_KERNEL);
  574. if (!bc->onecell_data.domains)
  575. return -ENOMEM;
  576. bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus");
  577. if (IS_ERR(bc->bus_power_dev))
  578. return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
  579. "failed to attach bus power domain\n");
  580. bc->power_off = bc_data->power_off;
  581. bc->power_on = bc_data->power_on;
  582. for (i = 0; i < num_domains; i++) {
  583. const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i];
  584. struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
  585. int j;
  586. domain->data = data;
  587. domain->num_paths = data->num_paths;
  588. for (j = 0; j < data->num_clks; j++)
  589. domain->clks[j].id = data->clk_names[j];
  590. for (j = 0; j < data->num_paths; j++) {
  591. domain->paths[j].name = data->path_names[j];
  592. /* Fake value for now, just let ICC could configure NoC mode/priority */
  593. domain->paths[j].avg_bw = 1;
  594. domain->paths[j].peak_bw = 1;
  595. }
  596. ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
  597. if (ret) {
  598. if (ret != -EPROBE_DEFER) {
  599. dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
  600. domain->num_paths = 0;
  601. } else {
  602. dev_err_probe(dev, ret, "failed to get noc entries\n");
  603. goto cleanup_pds;
  604. }
  605. }
  606. ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
  607. if (ret) {
  608. dev_err_probe(dev, ret, "failed to get clock\n");
  609. goto cleanup_pds;
  610. }
  611. domain->power_dev =
  612. dev_pm_domain_attach_by_name(dev, data->gpc_name);
  613. if (IS_ERR_OR_NULL(domain->power_dev)) {
  614. if (!domain->power_dev)
  615. ret = -ENODEV;
  616. else
  617. ret = PTR_ERR(domain->power_dev);
  618. dev_err_probe(dev, ret,
  619. "failed to attach power domain %s\n",
  620. data->gpc_name);
  621. goto cleanup_pds;
  622. }
  623. domain->power_nb.notifier_call = imx8mp_blk_ctrl_gpc_notifier;
  624. ret = dev_pm_genpd_add_notifier(domain->power_dev, &domain->power_nb);
  625. if (ret) {
  626. dev_err_probe(dev, ret, "failed to add power notifier\n");
  627. dev_pm_domain_detach(domain->power_dev, true);
  628. goto cleanup_pds;
  629. }
  630. domain->genpd.name = data->name;
  631. domain->genpd.power_on = imx8mp_blk_ctrl_power_on;
  632. domain->genpd.power_off = imx8mp_blk_ctrl_power_off;
  633. domain->genpd.flags = data->flags;
  634. domain->bc = bc;
  635. domain->id = i;
  636. ret = pm_genpd_init(&domain->genpd, NULL, true);
  637. if (ret) {
  638. dev_err_probe(dev, ret, "failed to init power domain\n");
  639. dev_pm_genpd_remove_notifier(domain->power_dev);
  640. dev_pm_domain_detach(domain->power_dev, true);
  641. goto cleanup_pds;
  642. }
  643. /*
  644. * We use runtime PM to trigger power on/off of the upstream GPC
  645. * domain, as a strict hierarchical parent/child power domain
  646. * setup doesn't allow us to meet the sequencing requirements.
  647. * This means we have nested locking of genpd locks, without the
  648. * nesting being visible at the genpd level, so we need a
  649. * separate lock class to make lockdep aware of the fact that
  650. * this are separate domain locks that can be nested without a
  651. * self-deadlock.
  652. */
  653. lockdep_set_class(&domain->genpd.mlock,
  654. &blk_ctrl_genpd_lock_class);
  655. bc->onecell_data.domains[i] = &domain->genpd;
  656. }
  657. ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
  658. if (ret) {
  659. dev_err_probe(dev, ret, "failed to add power domain provider\n");
  660. goto cleanup_pds;
  661. }
  662. bc->power_nb.notifier_call = bc_data->power_notifier_fn;
  663. ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
  664. if (ret) {
  665. dev_err_probe(dev, ret, "failed to add power notifier\n");
  666. goto cleanup_provider;
  667. }
  668. if (bc_data->probe) {
  669. ret = bc_data->probe(bc);
  670. if (ret)
  671. goto cleanup_provider;
  672. }
  673. dev_set_drvdata(dev, bc);
  674. return 0;
  675. cleanup_provider:
  676. of_genpd_del_provider(dev->of_node);
  677. cleanup_pds:
  678. for (i--; i >= 0; i--) {
  679. pm_genpd_remove(&bc->domains[i].genpd);
  680. dev_pm_genpd_remove_notifier(bc->domains[i].power_dev);
  681. dev_pm_domain_detach(bc->domains[i].power_dev, true);
  682. }
  683. dev_pm_domain_detach(bc->bus_power_dev, true);
  684. return ret;
  685. }
  686. static void imx8mp_blk_ctrl_remove(struct platform_device *pdev)
  687. {
  688. struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
  689. int i;
  690. of_genpd_del_provider(pdev->dev.of_node);
  691. for (i = 0; i < bc->onecell_data.num_domains; i++) {
  692. struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
  693. pm_genpd_remove(&domain->genpd);
  694. dev_pm_genpd_remove_notifier(domain->power_dev);
  695. dev_pm_domain_detach(domain->power_dev, true);
  696. }
  697. dev_pm_genpd_remove_notifier(bc->bus_power_dev);
  698. dev_pm_domain_detach(bc->bus_power_dev, true);
  699. }
  700. #ifdef CONFIG_PM_SLEEP
  701. static int imx8mp_blk_ctrl_suspend(struct device *dev)
  702. {
  703. struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
  704. int ret, i;
  705. /*
  706. * This may look strange, but is done so the generic PM_SLEEP code
  707. * can power down our domains and more importantly power them up again
  708. * after resume, without tripping over our usage of runtime PM to
  709. * control the upstream GPC domains. Things happen in the right order
  710. * in the system suspend/resume paths due to the device parent/child
  711. * hierarchy.
  712. */
  713. ret = pm_runtime_get_sync(bc->bus_power_dev);
  714. if (ret < 0) {
  715. pm_runtime_put_noidle(bc->bus_power_dev);
  716. return ret;
  717. }
  718. for (i = 0; i < bc->onecell_data.num_domains; i++) {
  719. struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
  720. ret = pm_runtime_get_sync(domain->power_dev);
  721. if (ret < 0) {
  722. pm_runtime_put_noidle(domain->power_dev);
  723. goto out_fail;
  724. }
  725. }
  726. return 0;
  727. out_fail:
  728. for (i--; i >= 0; i--)
  729. pm_runtime_put(bc->domains[i].power_dev);
  730. pm_runtime_put(bc->bus_power_dev);
  731. return ret;
  732. }
  733. static int imx8mp_blk_ctrl_resume(struct device *dev)
  734. {
  735. struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
  736. int i;
  737. for (i = 0; i < bc->onecell_data.num_domains; i++)
  738. pm_runtime_put(bc->domains[i].power_dev);
  739. pm_runtime_put(bc->bus_power_dev);
  740. return 0;
  741. }
  742. #endif
  743. static const struct dev_pm_ops imx8mp_blk_ctrl_pm_ops = {
  744. SET_SYSTEM_SLEEP_PM_OPS(imx8mp_blk_ctrl_suspend,
  745. imx8mp_blk_ctrl_resume)
  746. };
  747. static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
  748. {
  749. .compatible = "fsl,imx8mp-hsio-blk-ctrl",
  750. .data = &imx8mp_hsio_blk_ctl_dev_data,
  751. }, {
  752. .compatible = "fsl,imx8mp-hdmi-blk-ctrl",
  753. .data = &imx8mp_hdmi_blk_ctl_dev_data,
  754. }, {
  755. /* Sentinel */
  756. }
  757. };
  758. MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match);
  759. static struct platform_driver imx8mp_blk_ctrl_driver = {
  760. .probe = imx8mp_blk_ctrl_probe,
  761. .remove = imx8mp_blk_ctrl_remove,
  762. .driver = {
  763. .name = "imx8mp-blk-ctrl",
  764. .pm = &imx8mp_blk_ctrl_pm_ops,
  765. .of_match_table = imx8mp_blk_ctrl_of_match,
  766. .suppress_bind_attrs = true,
  767. },
  768. };
  769. module_platform_driver(imx8mp_blk_ctrl_driver);
  770. MODULE_LICENSE("GPL");