Skip to content

Commit e344202

Browse files
lynxeye-devShawn Guo
authored andcommitted
soc: imx: add i.MX8MP HDMI blk-ctrl
This adds driver support for the HDMI blk-ctrl found on the i.MX8MP SoC. Signed-off-by: Lucas Stach <[email protected]> Signed-off-by: Shawn Guo <[email protected]>
1 parent 07614fe commit e344202

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed

drivers/soc/imx/imx8mp-blk-ctrl.c

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,196 @@ static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
174174
.num_domains = ARRAY_SIZE(imx8mp_hsio_domain_data),
175175
};
176176

177+
#define HDMI_RTX_RESET_CTL0 0x20
178+
#define HDMI_RTX_CLK_CTL0 0x40
179+
#define HDMI_RTX_CLK_CTL1 0x50
180+
#define HDMI_RTX_CLK_CTL2 0x60
181+
#define HDMI_RTX_CLK_CTL3 0x70
182+
#define HDMI_RTX_CLK_CTL4 0x80
183+
#define HDMI_TX_CONTROL0 0x200
184+
185+
static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
186+
struct imx8mp_blk_ctrl_domain *domain)
187+
{
188+
switch (domain->id) {
189+
case IMX8MP_HDMIBLK_PD_IRQSTEER:
190+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
191+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
192+
break;
193+
case IMX8MP_HDMIBLK_PD_LCDIF:
194+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
195+
BIT(7) | BIT(16) | BIT(17) | BIT(18) |
196+
BIT(19) | BIT(20));
197+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
198+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
199+
BIT(4) | BIT(5) | BIT(6));
200+
break;
201+
case IMX8MP_HDMIBLK_PD_PAI:
202+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
203+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
204+
break;
205+
case IMX8MP_HDMIBLK_PD_PVI:
206+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
207+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
208+
break;
209+
case IMX8MP_HDMIBLK_PD_TRNG:
210+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
211+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
212+
break;
213+
case IMX8MP_HDMIBLK_PD_HDMI_TX:
214+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
215+
BIT(2) | BIT(4) | BIT(5));
216+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
217+
BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
218+
BIT(18) | BIT(19) | BIT(20) | BIT(21));
219+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
220+
BIT(7) | BIT(10) | BIT(11));
221+
regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
222+
break;
223+
case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
224+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
225+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
226+
regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
227+
break;
228+
default:
229+
break;
230+
}
231+
}
232+
233+
static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
234+
struct imx8mp_blk_ctrl_domain *domain)
235+
{
236+
switch (domain->id) {
237+
case IMX8MP_HDMIBLK_PD_IRQSTEER:
238+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(9));
239+
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(16));
240+
break;
241+
case IMX8MP_HDMIBLK_PD_LCDIF:
242+
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
243+
BIT(4) | BIT(5) | BIT(6));
244+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
245+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
246+
BIT(7) | BIT(16) | BIT(17) | BIT(18) |
247+
BIT(19) | BIT(20));
248+
break;
249+
case IMX8MP_HDMIBLK_PD_PAI:
250+
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(18));
251+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
252+
break;
253+
case IMX8MP_HDMIBLK_PD_PVI:
254+
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(22));
255+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(28));
256+
break;
257+
case IMX8MP_HDMIBLK_PD_TRNG:
258+
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(20));
259+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(27) | BIT(30));
260+
break;
261+
case IMX8MP_HDMIBLK_PD_HDMI_TX:
262+
regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
263+
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
264+
BIT(7) | BIT(10) | BIT(11));
265+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1,
266+
BIT(12) | BIT(13) | BIT(14) | BIT(15) | BIT(16) |
267+
BIT(18) | BIT(19) | BIT(20) | BIT(21));
268+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
269+
BIT(2) | BIT(4) | BIT(5));
270+
break;
271+
case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
272+
regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
273+
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
274+
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
275+
break;
276+
default:
277+
break;
278+
}
279+
}
280+
281+
static int imx8mp_hdmi_power_notifier(struct notifier_block *nb,
282+
unsigned long action, void *data)
283+
{
284+
struct imx8mp_blk_ctrl *bc = container_of(nb, struct imx8mp_blk_ctrl,
285+
power_nb);
286+
287+
if (action != GENPD_NOTIFY_ON)
288+
return NOTIFY_OK;
289+
290+
/*
291+
* Contrary to other blk-ctrls the reset and clock don't clear when the
292+
* power domain is powered down. To ensure the proper reset pulsing,
293+
* first clear them all to asserted state, then enable the bus clocks
294+
* and then release the ADB reset.
295+
*/
296+
regmap_write(bc->regmap, HDMI_RTX_RESET_CTL0, 0x0);
297+
regmap_write(bc->regmap, HDMI_RTX_CLK_CTL0, 0x0);
298+
regmap_write(bc->regmap, HDMI_RTX_CLK_CTL1, 0x0);
299+
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
300+
BIT(0) | BIT(1) | BIT(10));
301+
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(0));
302+
303+
/*
304+
* On power up we have no software backchannel to the GPC to
305+
* wait for the ADB handshake to happen, so we just delay for a
306+
* bit. On power down the GPC driver waits for the handshake.
307+
*/
308+
udelay(5);
309+
310+
return NOTIFY_OK;
311+
}
312+
313+
static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
314+
[IMX8MP_HDMIBLK_PD_IRQSTEER] = {
315+
.name = "hdmiblk-irqsteer",
316+
.clk_names = (const char *[]){ "apb" },
317+
.num_clks = 1,
318+
.gpc_name = "irqsteer",
319+
},
320+
[IMX8MP_HDMIBLK_PD_LCDIF] = {
321+
.name = "hdmiblk-lcdif",
322+
.clk_names = (const char *[]){ "axi", "apb" },
323+
.num_clks = 2,
324+
.gpc_name = "lcdif",
325+
},
326+
[IMX8MP_HDMIBLK_PD_PAI] = {
327+
.name = "hdmiblk-pai",
328+
.clk_names = (const char *[]){ "apb" },
329+
.num_clks = 1,
330+
.gpc_name = "pai",
331+
},
332+
[IMX8MP_HDMIBLK_PD_PVI] = {
333+
.name = "hdmiblk-pvi",
334+
.clk_names = (const char *[]){ "apb" },
335+
.num_clks = 1,
336+
.gpc_name = "pvi",
337+
},
338+
[IMX8MP_HDMIBLK_PD_TRNG] = {
339+
.name = "hdmiblk-trng",
340+
.clk_names = (const char *[]){ "apb" },
341+
.num_clks = 1,
342+
.gpc_name = "trng",
343+
},
344+
[IMX8MP_HDMIBLK_PD_HDMI_TX] = {
345+
.name = "hdmiblk-hdmi-tx",
346+
.clk_names = (const char *[]){ "apb", "ref_266m" },
347+
.num_clks = 2,
348+
.gpc_name = "hdmi-tx",
349+
},
350+
[IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = {
351+
.name = "hdmiblk-hdmi-tx-phy",
352+
.clk_names = (const char *[]){ "apb", "ref_24m" },
353+
.num_clks = 2,
354+
.gpc_name = "hdmi-tx-phy",
355+
},
356+
};
357+
358+
static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
359+
.max_reg = 0x23c,
360+
.power_on = imx8mp_hdmi_blk_ctrl_power_on,
361+
.power_off = imx8mp_hdmi_blk_ctrl_power_off,
362+
.power_notifier_fn = imx8mp_hdmi_power_notifier,
363+
.domains = imx8mp_hdmi_domain_data,
364+
.num_domains = ARRAY_SIZE(imx8mp_hdmi_domain_data),
365+
};
366+
177367
static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
178368
{
179369
struct imx8mp_blk_ctrl_domain *domain = to_imx8mp_blk_ctrl_domain(genpd);
@@ -485,6 +675,9 @@ static const struct of_device_id imx8mp_blk_ctrl_of_match[] = {
485675
{
486676
.compatible = "fsl,imx8mp-hsio-blk-ctrl",
487677
.data = &imx8mp_hsio_blk_ctl_dev_data,
678+
}, {
679+
.compatible = "fsl,imx8mp-hdmi-blk-ctrl",
680+
.data = &imx8mp_hdmi_blk_ctl_dev_data,
488681
}, {
489682
/* Sentinel */
490683
}

0 commit comments

Comments
 (0)