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_HDCP:
356 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
357 break;
358 case IMX8MP_HDMIBLK_PD_HRV:
359 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
360 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
361 break;
362 default:
363 break;
364 }
365 }
366
imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl * bc,struct imx8mp_blk_ctrl_domain * domain)367 static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
368 struct imx8mp_blk_ctrl_domain *domain)
369 {
370 switch (domain->id) {
371 case IMX8MP_HDMIBLK_PD_IRQSTEER:
372 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
373 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
374 break;
375 case IMX8MP_HDMIBLK_PD_LCDIF:
376 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
377 BIT(4) | BIT(5) | BIT(6));
378 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
379 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
380 BIT(16) | BIT(17) | BIT(18) |
381 BIT(19) | BIT(20));
382 break;
383 case IMX8MP_HDMIBLK_PD_PAI:
384 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
385 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
386 break;
387 case IMX8MP_HDMIBLK_PD_PVI:
388 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
389 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
390 break;
391 case IMX8MP_HDMIBLK_PD_TRNG:
392 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
393 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
394 break;
395 case IMX8MP_HDMIBLK_PD_HDMI_TX:
396 regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
397 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
398 BIT(7) | BIT(10) | BIT(11));
399 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
400 BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
401 BIT(18) | BIT(19) | BIT(20) | BIT(21));
402 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
403 BIT(2) | BIT(4) | BIT(5));
404 break;
405 case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
406 regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
407 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
408 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
409 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
410 break;
411 case IMX8MP_HDMIBLK_PD_HDCP:
412 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
413 break;
414 case IMX8MP_HDMIBLK_PD_HRV:
415 regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
416 regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
417 break;
418 default:
419 break;
420 }
421 }
422
imx8mp_hdmi_power_notifier(struct notifier_block * nb,unsigned long action,void * data)423 static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
424 unsigned long action, void *data)
425 {
426 struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
427 power_nb);
428
429 if (action != GENPD_NOTIFY_ON)
430 return NOTIFY_OK;
431
432 /*
433 * Contrary to other blk-ctrls the reset and clock don't clear when the
434 * power domain is powered down. To ensure the proper reset pulsing,
435 * first clear them all to asserted state, then enable the bus clocks
436 * and then release the ADB reset.
437 */
438 regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0);
439 regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
440 regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
441 regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
442 BIT(0) | BIT(1) | BIT(10));
443 regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
444
445 /*
446 * On power up we have no software backchannel to the GPC to
447 * wait for the ADB handshake to happen, so we just delay for a
448 * bit. On power down the GPC driver waits for the handshake.
449 */
450 udelay(5);
451
452 return NOTIFY_OK;
453 }
454
455 static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
456 [IMX8MP_HDMIBLK_PD_IRQSTEER] = {
457 .name = "hdmiblk-irqsteer",
458 .clk_names = (const char *[]){ "apb" },
459 .num_clks = 1,
460 .gpc_name = "irqsteer",
461 },
462 [IMX8MP_HDMIBLK_PD_LCDIF] = {
463 .name = "hdmiblk-lcdif",
464 .clk_names = (const char *[]){ "axi", "apb", "fdcc" },
465 .num_clks = 3,
466 .gpc_name = "lcdif",
467 .path_names = (const char *[]){"lcdif-hdmi"},
468 .num_paths = 1,
469 },
470 [IMX8MP_HDMIBLK_PD_PAI] = {
471 .name = "hdmiblk-pai",
472 .clk_names = (const char *[]){ "apb" },
473 .num_clks = 1,
474 .gpc_name = "pai",
475 },
476 [IMX8MP_HDMIBLK_PD_PVI] = {
477 .name = "hdmiblk-pvi",
478 .clk_names = (const char *[]){ "apb" },
479 .num_clks = 1,
480 .gpc_name = "pvi",
481 },
482 [IMX8MP_HDMIBLK_PD_TRNG] = {
483 .name = "hdmiblk-trng",
484 .clk_names = (const char *[]){ "apb" },
485 .num_clks = 1,
486 .gpc_name = "trng",
487 },
488 [IMX8MP_HDMIBLK_PD_HDMI_TX] = {
489 .name = "hdmiblk-hdmi-tx",
490 .clk_names = (const char *[]){ "apb", "ref_266m", "fdcc" },
491 .num_clks = 3,
492 .gpc_name = "hdmi-tx",
493 },
494 [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
495 .name = "hdmiblk-hdmi-tx-phy",
496 .clk_names = (const char *[]){ "apb", "ref_24m" },
497 .num_clks = 2,
498 .gpc_name = "hdmi-tx-phy",
499 },
500 [IMX8MP_HDMIBLK_PD_HRV] = {
501 .name = "hdmiblk-hrv",
502 .clk_names = (const char *[]){ "axi", "apb" },
503 .num_clks = 2,
504 .gpc_name = "hrv",
505 .path_names = (const char *[]){"hrv"},
506 .num_paths = 1,
507 },
508 [IMX8MP_HDMIBLK_PD_HDCP] = {
509 .name = "hdmiblk-hdcp",
510 .clk_names = (const char *[]){ "axi", "apb" },
511 .num_clks = 2,
512 .gpc_name = "hdcp",
513 .path_names = (const char *[]){"hdcp"},
514 .num_paths = 1,
515 },
516 };
517
518 static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
519 .max_reg = 0x23c,
520 .power_on = imx8mp_hdmi_blk_ctrl_power_on,
521 .power_off = imx8mp_hdmi_blk_ctrl_power_off,
522 .power_notifier_fn = imx8mp_hdmi_power_notifier,
523 .domains = imx8mp_hdmi_domain_data,
524 .num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data),
525 };
526
imx8mp_blk_ctrl_power_on(struct generic_pm_domain * genpd)527 static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
528 {
529 struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
530 const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
531 struct imx8mp_blk_ctrl *bc = domain->bc;
532 int ret;
533
534 /* make sure bus domain is awake */
535 ret = pm_runtime_resume_and_get(bc->bus_power_dev);
536 if (ret < 0) {
537 dev_err(bc->dev, "failed to power up bus domain\n");
538 return ret;
539 }
540
541 /* enable upstream clocks */
542 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
543 if (ret) {
544 dev_err(bc->dev, "failed to enable clocks\n");
545 goto bus_put;
546 }
547
548 /* domain specific blk-ctrl manipulation */
549 bc->power_on(bc, domain);
550
551 /* power up upstream GPC domain */
552 ret = pm_runtime_resume_and_get(domain->power_dev);
553 if (ret < 0) {
554 dev_err(bc->dev, "failed to power up peripheral domain\n");
555 goto clk_disable;
556 }
557
558 ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
559 if (ret)
560 dev_err(bc->dev, "failed to set icc bw\n");
561
562 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
563
564 return 0;
565
566 clk_disable:
567 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
568 bus_put:
569 pm_runtime_put(bc->bus_power_dev);
570
571 return ret;
572 }
573
imx8mp_blk_ctrl_power_off(struct generic_pm_domain * genpd)574 static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
575 {
576 struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
577 const struct imx8mp_blk_ctrl_domain_data *data = domain->data;
578 struct imx8mp_blk_ctrl *bc = domain->bc;
579 int ret;
580
581 ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
582 if (ret) {
583 dev_err(bc->dev, "failed to enable clocks\n");
584 return ret;
585 }
586
587 /* domain specific blk-ctrl manipulation */
588 bc->power_off(bc, domain);
589
590 clk_bulk_disable_unprepare(data->num_clks, domain->clks);
591
592 /* power down upstream GPC domain */
593 pm_runtime_put(domain->power_dev);
594
595 /* allow bus domain to suspend */
596 pm_runtime_put(bc->bus_power_dev);
597
598 return 0;
599 }
600
imx8mp_blk_ctrl_gpc_notifier(struct notifier_block * nb,unsigned long action,void * data)601 static int imx8mp_blk_ctrl_gpc_notifier(struct notifier_block *nb,
602 unsigned long action, void *data)
603 {
604 struct imx8mp_blk_ctrl_domain *domain =
605 container_of(nb, struct imx8mp_blk_ctrl_domain, power_nb);
606
607 if (action == GENPD_NOTIFY_PRE_OFF) {
608 if (domain->genpd.status == GENPD_STATE_ON)
609 return NOTIFY_BAD;
610 }
611
612 return NOTIFY_OK;
613 }
614
615 static struct lock_class_key blk_ctrl_genpd_lock_class;
616
imx8mp_blk_ctrl_probe(struct platform_device * pdev)617 static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
618 {
619 const struct imx8mp_blk_ctrl_data *bc_data;
620 struct device *dev = &pdev->dev;
621 struct imx8mp_blk_ctrl *bc;
622 void __iomem *base;
623 int num_domains, i, ret;
624
625 struct regmap_config regmap_config = {
626 .reg_bits = 32,
627 .val_bits = 32,
628 .reg_stride = 4,
629 };
630
631 bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
632 if (!bc)
633 return -ENOMEM;
634
635 bc->dev = dev;
636
637 bc_data = of_device_get_match_data(dev);
638 num_domains = bc_data->num_domains;
639
640 base = devm_platform_ioremap_resource(pdev, 0);
641 if (IS_ERR(base))
642 return PTR_ERR(base);
643
644 regmap_config.max_register = bc_data->max_reg;
645 bc->regmap = devm_regmap_init_mmio(dev, base, ®map_config);
646 if (IS_ERR(bc->regmap))
647 return dev_err_probe(dev, PTR_ERR(bc->regmap),
648 "failed to init regmap\n");
649
650 bc->domains = devm_kcalloc(dev, num_domains,
651 sizeof(struct imx8mp_blk_ctrl_domain),
652 GFP_KERNEL);
653 if (!bc->domains)
654 return -ENOMEM;
655
656 bc->onecell_data.num_domains = num_domains;
657 bc->onecell_data.domains =
658 devm_kcalloc(dev, num_domains,
659 sizeof(struct generic_pm_domain *), GFP_KERNEL);
660 if (!bc->onecell_data.domains)
661 return -ENOMEM;
662
663 bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus");
664 if (IS_ERR(bc->bus_power_dev))
665 return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
666 "failed to attach bus power domain\n");
667
668 bc->power_off = bc_data->power_off;
669 bc->power_on = bc_data->power_on;
670
671 for (i = 0; i < num_domains; i++) {
672 const struct imx8mp_blk_ctrl_domain_data *data = &bc_data->domains[i];
673 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
674 int j;
675
676 domain->data = data;
677 domain->num_paths = data->num_paths;
678
679 for (j = 0; j < data->num_clks; j++)
680 domain->clks[j].id = data->clk_names[j];
681
682 for (j = 0; j < data->num_paths; j++) {
683 domain->paths[j].name = data->path_names[j];
684 /* Fake value for now, just let ICC could configure NoC mode/priority */
685 domain->paths[j].avg_bw = 1;
686 domain->paths[j].peak_bw = 1;
687 }
688
689 ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
690 if (ret) {
691 if (ret != -EPROBE_DEFER) {
692 dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
693 domain->num_paths = 0;
694 } else {
695 dev_err_probe(dev, ret, "failed to get noc entries\n");
696 goto cleanup_pds;
697 }
698 }
699
700 ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
701 if (ret) {
702 dev_err_probe(dev, ret, "failed to get clock\n");
703 goto cleanup_pds;
704 }
705
706 domain->power_dev =
707 dev_pm_domain_attach_by_name(dev, data->gpc_name);
708 if (IS_ERR_OR_NULL(domain->power_dev)) {
709 if (!domain->power_dev)
710 ret = -ENODEV;
711 else
712 ret = PTR_ERR(domain->power_dev);
713 dev_err_probe(dev, ret,
714 "failed to attach power domain %s\n",
715 data->gpc_name);
716 goto cleanup_pds;
717 }
718
719 domain->power_nb.notifier_call = imx8mp_blk_ctrl_gpc_notifier;
720 ret = dev_pm_genpd_add_notifier(domain->power_dev, &domain->power_nb);
721 if (ret) {
722 dev_err_probe(dev, ret, "failed to add power notifier\n");
723 dev_pm_domain_detach(domain->power_dev, true);
724 goto cleanup_pds;
725 }
726
727 domain->genpd.name = data->name;
728 domain->genpd.power_on = imx8mp_blk_ctrl_power_on;
729 domain->genpd.power_off = imx8mp_blk_ctrl_power_off;
730 domain->genpd.flags = data->flags;
731 domain->bc = bc;
732 domain->id = i;
733
734 ret = pm_genpd_init(&domain->genpd, NULL, true);
735 if (ret) {
736 dev_err_probe(dev, ret, "failed to init power domain\n");
737 dev_pm_genpd_remove_notifier(domain->power_dev);
738 dev_pm_domain_detach(domain->power_dev, true);
739 goto cleanup_pds;
740 }
741
742 /*
743 * We use runtime PM to trigger power on/off of the upstream GPC
744 * domain, as a strict hierarchical parent/child power domain
745 * setup doesn't allow us to meet the sequencing requirements.
746 * This means we have nested locking of genpd locks, without the
747 * nesting being visible at the genpd level, so we need a
748 * separate lock class to make lockdep aware of the fact that
749 * this are separate domain locks that can be nested without a
750 * self-deadlock.
751 */
752 lockdep_set_class(&domain->genpd.mlock,
753 &blk_ctrl_genpd_lock_class);
754
755 bc->onecell_data.domains[i] = &domain->genpd;
756 }
757
758 ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
759 if (ret) {
760 dev_err_probe(dev, ret, "failed to add power domain provider\n");
761 goto cleanup_pds;
762 }
763
764 bc->power_nb.notifier_call = bc_data->power_notifier_fn;
765 ret = dev_pm_genpd_add_notifier(bc->bus_power_dev, &bc->power_nb);
766 if (ret) {
767 dev_err_probe(dev, ret, "failed to add power notifier\n");
768 goto cleanup_provider;
769 }
770
771 if (bc_data->probe) {
772 ret = bc_data->probe(bc);
773 if (ret)
774 goto cleanup_provider;
775 }
776
777 dev_set_drvdata(dev, bc);
778
779 return 0;
780
781 cleanup_provider:
782 of_genpd_del_provider(dev->of_node);
783 cleanup_pds:
784 for (i--; i >= 0; i--) {
785 pm_genpd_remove(&bc->domains[i].genpd);
786 dev_pm_genpd_remove_notifier(bc->domains[i].power_dev);
787 dev_pm_domain_detach(bc->domains[i].power_dev, true);
788 }
789
790 dev_pm_domain_detach(bc->bus_power_dev, true);
791
792 return ret;
793 }
794
imx8mp_blk_ctrl_remove(struct platform_device * pdev)795 static void imx8mp_blk_ctrl_remove(struct platform_device *pdev)
796 {
797 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
798 int i;
799
800 of_genpd_del_provider(pdev->dev.of_node);
801
802 for (i = 0; i < bc->onecell_data.num_domains; i++) {
803 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
804
805 pm_genpd_remove(&domain->genpd);
806 dev_pm_genpd_remove_notifier(domain->power_dev);
807 dev_pm_domain_detach(domain->power_dev, true);
808 }
809
810 dev_pm_genpd_remove_notifier(bc->bus_power_dev);
811
812 dev_pm_domain_detach(bc->bus_power_dev, true);
813 }
814
815 #ifdef CONFIG_PM_SLEEP
imx8mp_blk_ctrl_suspend(struct device * dev)816 static int imx8mp_blk_ctrl_suspend(struct device *dev)
817 {
818 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
819 int ret, i;
820
821 /*
822 * This may look strange, but is done so the generic PM_SLEEP code
823 * can power down our domains and more importantly power them up again
824 * after resume, without tripping over our usage of runtime PM to
825 * control the upstream GPC domains. Things happen in the right order
826 * in the system suspend/resume paths due to the device parent/child
827 * hierarchy.
828 */
829 ret = pm_runtime_get_sync(bc->bus_power_dev);
830 if (ret < 0) {
831 pm_runtime_put_noidle(bc->bus_power_dev);
832 return ret;
833 }
834
835 for (i = 0; i < bc->onecell_data.num_domains; i++) {
836 struct imx8mp_blk_ctrl_domain *domain = &bc->domains[i];
837
838 ret = pm_runtime_get_sync(domain->power_dev);
839 if (ret < 0) {
840 pm_runtime_put_noidle(domain->power_dev);
841 goto out_fail;
842 }
843 }
844
845 return 0;
846
847 out_fail:
848 for (i--; i >= 0; i--)
849 pm_runtime_put(bc->domains[i].power_dev);
850
851 pm_runtime_put(bc->bus_power_dev);
852
853 return ret;
854 }
855
imx8mp_blk_ctrl_resume(struct device * dev)856 static int imx8mp_blk_ctrl_resume(struct device *dev)
857 {
858 struct imx8mp_blk_ctrl *bc = dev_get_drvdata(dev);
859 int i;
860
861 for (i = 0; i < bc->onecell_data.num_domains; i++)
862 pm_runtime_put(bc->domains[i].power_dev);
863
864 pm_runtime_put(bc->bus_power_dev);
865
866 return 0;
867 }
868 #endif
869
870 static const struct dev_pm_ops imx8mp_blk_ctrl_pm_ops = {
871 SET_SYSTEM_SLEEP_PM_OPS(imx8mp_blk_ctrl_suspend,
872 imx8mp_blk_ctrl_resume)
873 };
874
875 static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
876 {
877 .compatible = "fsl,imx8mp-hsio-blk-ctrl",
878 .data = &imx8mp_hsio_blk_ctl_dev_data,
879 }, {
880 .compatible = "fsl,imx8mp-hdmi-blk-ctrl",
881 .data = &imx8mp_hdmi_blk_ctl_dev_data,
882 }, {
883 /* Sentinel */
884 }
885 };
886 MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match);
887
888 static struct platform_driver imx8mp_blk_ctrl_driver = {
889 .probe = imx8mp_blk_ctrl_probe,
890 .remove = imx8mp_blk_ctrl_remove,
891 .driver = {
892 .name = "imx8mp-blk-ctrl",
893 .pm = &imx8mp_blk_ctrl_pm_ops,
894 .of_match_table = imx8mp_blk_ctrl_of_match,
895 .suppress_bind_attrs = true,
896 },
897 };
898 module_platform_driver(imx8mp_blk_ctrl_driver);
899 MODULE_LICENSE("GPL");
900