@@ -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+
177367static 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