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