1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
7 #include <linux/mfd/syscon.h>
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/phy/phy.h>
11 #include <linux/regmap.h>
12 #include <linux/regulator/consumer.h>
14 #include <drm/bridge/dw_hdmi.h>
15 #include <drm/drm_edid.h>
16 #include <drm/drm_of.h>
17 #include <drm/drm_probe_helper.h>
18 #include <drm/drm_simple_kms_helper.h>
20 #include "rockchip_drm_drv.h"
22 #define RK3228_GRF_SOC_CON2 0x0408
23 #define RK3228_HDMI_SDAIN_MSK BIT(14)
24 #define RK3228_HDMI_SCLIN_MSK BIT(13)
25 #define RK3228_GRF_SOC_CON6 0x0418
26 #define RK3228_HDMI_HPD_VSEL BIT(6)
27 #define RK3228_HDMI_SDA_VSEL BIT(5)
28 #define RK3228_HDMI_SCL_VSEL BIT(4)
30 #define RK3288_GRF_SOC_CON6 0x025C
31 #define RK3288_HDMI_LCDC_SEL BIT(4)
32 #define RK3328_GRF_SOC_CON2 0x0408
34 #define RK3328_HDMI_SDAIN_MSK BIT(11)
35 #define RK3328_HDMI_SCLIN_MSK BIT(10)
36 #define RK3328_HDMI_HPD_IOE BIT(2)
37 #define RK3328_GRF_SOC_CON3 0x040c
38 /* need to be unset if hdmi or i2c should control voltage */
39 #define RK3328_HDMI_SDA5V_GRF BIT(15)
40 #define RK3328_HDMI_SCL5V_GRF BIT(14)
41 #define RK3328_HDMI_HPD5V_GRF BIT(13)
42 #define RK3328_HDMI_CEC5V_GRF BIT(12)
43 #define RK3328_GRF_SOC_CON4 0x0410
44 #define RK3328_HDMI_HPD_SARADC BIT(13)
45 #define RK3328_HDMI_CEC_5V BIT(11)
46 #define RK3328_HDMI_SDA_5V BIT(10)
47 #define RK3328_HDMI_SCL_5V BIT(9)
48 #define RK3328_HDMI_HPD_5V BIT(8)
50 #define RK3399_GRF_SOC_CON20 0x6250
51 #define RK3399_HDMI_LCDC_SEL BIT(6)
53 #define RK3568_GRF_VO_CON1 0x0364
54 #define RK3568_HDMI_SDAIN_MSK BIT(15)
55 #define RK3568_HDMI_SCLIN_MSK BIT(14)
57 #define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
60 * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips
61 * @lcdsel_grf_reg: grf register offset of lcdc select
62 * @lcdsel_big: reg value of selecting vop big for HDMI
63 * @lcdsel_lit: reg value of selecting vop little for HDMI
64 * @max_tmds_clock: maximum TMDS clock rate supported
66 struct rockchip_hdmi_chip_data
{
73 struct rockchip_hdmi
{
75 struct regmap
*regmap
;
76 struct rockchip_encoder encoder
;
77 const struct rockchip_hdmi_chip_data
*chip_data
;
78 const struct dw_hdmi_plat_data
*plat_data
;
79 struct clk
*hdmiphy_clk
;
86 static struct rockchip_hdmi
*to_rockchip_hdmi(struct drm_encoder
*encoder
)
88 struct rockchip_encoder
*rkencoder
= to_rockchip_encoder(encoder
);
90 return container_of(rkencoder
, struct rockchip_hdmi
, encoder
);
93 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg
[] = {
181 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr
[] = {
182 /* pixelclk bpp8 bpp10 bpp12 */
184 600000000, { 0x0000, 0x0000, 0x0000 },
186 ~0UL, { 0x0000, 0x0000, 0x0000 },
190 static const struct dw_hdmi_phy_config rockchip_phy_config
[] = {
191 /*pixelclk symbol term vlev*/
192 { 74250000, 0x8009, 0x0004, 0x0272},
193 { 165000000, 0x802b, 0x0004, 0x0209},
194 { 297000000, 0x8039, 0x0005, 0x028d},
195 { 594000000, 0x8039, 0x0000, 0x019d},
196 { ~0UL, 0x0000, 0x0000, 0x0000}
199 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi
*hdmi
)
201 struct device_node
*np
= hdmi
->dev
->of_node
;
204 hdmi
->regmap
= syscon_regmap_lookup_by_phandle(np
, "rockchip,grf");
205 if (IS_ERR(hdmi
->regmap
)) {
206 drm_err(hdmi
, "Unable to get rockchip,grf\n");
207 return PTR_ERR(hdmi
->regmap
);
210 hdmi
->ref_clk
= devm_clk_get_optional_enabled(hdmi
->dev
, "ref");
212 hdmi
->ref_clk
= devm_clk_get_optional_enabled(hdmi
->dev
, "vpll");
214 if (IS_ERR(hdmi
->ref_clk
)) {
215 ret
= PTR_ERR(hdmi
->ref_clk
);
216 if (ret
!= -EPROBE_DEFER
)
217 drm_err(hdmi
, "failed to get reference clock\n");
221 hdmi
->grf_clk
= devm_clk_get_optional(hdmi
->dev
, "grf");
222 if (IS_ERR(hdmi
->grf_clk
)) {
223 ret
= PTR_ERR(hdmi
->grf_clk
);
224 if (ret
!= -EPROBE_DEFER
)
225 drm_err(hdmi
, "failed to get grf clock\n");
229 ret
= devm_regulator_get_enable(hdmi
->dev
, "avdd-0v9");
233 ret
= devm_regulator_get_enable(hdmi
->dev
, "avdd-1v8");
238 static enum drm_mode_status
239 dw_hdmi_rockchip_mode_valid(struct dw_hdmi
*dw_hdmi
, void *data
,
240 const struct drm_display_info
*info
,
241 const struct drm_display_mode
*mode
)
243 struct rockchip_hdmi
*hdmi
= data
;
244 int pclk
= mode
->clock
* 1000;
246 if (hdmi
->chip_data
->max_tmds_clock
&&
247 mode
->clock
> hdmi
->chip_data
->max_tmds_clock
)
248 return MODE_CLOCK_HIGH
;
251 int rpclk
= clk_round_rate(hdmi
->ref_clk
, pclk
);
253 if (rpclk
< 0 || abs(rpclk
- pclk
) > pclk
/ 1000)
257 if (hdmi
->hdmiphy_clk
) {
258 int rpclk
= clk_round_rate(hdmi
->hdmiphy_clk
, pclk
);
260 if (rpclk
< 0 || abs(rpclk
- pclk
) > pclk
/ 1000)
267 static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder
*encoder
)
272 dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder
*encoder
,
273 const struct drm_display_mode
*mode
,
274 struct drm_display_mode
*adj_mode
)
279 static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder
*encoder
,
280 struct drm_display_mode
*mode
,
281 struct drm_display_mode
*adj_mode
)
283 struct rockchip_hdmi
*hdmi
= to_rockchip_hdmi(encoder
);
285 clk_set_rate(hdmi
->ref_clk
, adj_mode
->clock
* 1000);
288 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder
*encoder
)
290 struct rockchip_hdmi
*hdmi
= to_rockchip_hdmi(encoder
);
294 if (hdmi
->chip_data
->lcdsel_grf_reg
< 0)
297 ret
= drm_of_encoder_active_endpoint_id(hdmi
->dev
->of_node
, encoder
);
299 val
= hdmi
->chip_data
->lcdsel_lit
;
301 val
= hdmi
->chip_data
->lcdsel_big
;
303 ret
= clk_prepare_enable(hdmi
->grf_clk
);
305 drm_err(hdmi
, "failed to enable grfclk %d\n", ret
);
309 ret
= regmap_write(hdmi
->regmap
, hdmi
->chip_data
->lcdsel_grf_reg
, val
);
311 drm_err(hdmi
, "Could not write to GRF: %d\n", ret
);
313 clk_disable_unprepare(hdmi
->grf_clk
);
314 drm_dbg(hdmi
, "vop %s output to hdmi\n", ret
? "LIT" : "BIG");
318 dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder
*encoder
,
319 struct drm_crtc_state
*crtc_state
,
320 struct drm_connector_state
*conn_state
)
322 struct rockchip_crtc_state
*s
= to_rockchip_crtc_state(crtc_state
);
324 s
->output_mode
= ROCKCHIP_OUT_MODE_AAAA
;
325 s
->output_type
= DRM_MODE_CONNECTOR_HDMIA
;
330 static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs
= {
331 .mode_fixup
= dw_hdmi_rockchip_encoder_mode_fixup
,
332 .mode_set
= dw_hdmi_rockchip_encoder_mode_set
,
333 .enable
= dw_hdmi_rockchip_encoder_enable
,
334 .disable
= dw_hdmi_rockchip_encoder_disable
,
335 .atomic_check
= dw_hdmi_rockchip_encoder_atomic_check
,
338 static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi
*dw_hdmi
, void *data
,
339 const struct drm_display_info
*display
,
340 const struct drm_display_mode
*mode
)
342 struct rockchip_hdmi
*hdmi
= (struct rockchip_hdmi
*)data
;
344 dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi
, display
);
346 return phy_power_on(hdmi
->phy
);
349 static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi
*dw_hdmi
, void *data
)
351 struct rockchip_hdmi
*hdmi
= (struct rockchip_hdmi
*)data
;
353 phy_power_off(hdmi
->phy
);
356 static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi
*dw_hdmi
, void *data
)
358 struct rockchip_hdmi
*hdmi
= (struct rockchip_hdmi
*)data
;
360 dw_hdmi_phy_setup_hpd(dw_hdmi
, data
);
362 regmap_write(hdmi
->regmap
,
364 HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL
| RK3228_HDMI_SDA_VSEL
|
365 RK3228_HDMI_SCL_VSEL
,
366 RK3228_HDMI_HPD_VSEL
| RK3228_HDMI_SDA_VSEL
|
367 RK3228_HDMI_SCL_VSEL
));
369 regmap_write(hdmi
->regmap
,
371 HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK
| RK3228_HDMI_SCLIN_MSK
,
372 RK3228_HDMI_SDAIN_MSK
| RK3228_HDMI_SCLIN_MSK
));
375 static enum drm_connector_status
376 dw_hdmi_rk3328_read_hpd(struct dw_hdmi
*dw_hdmi
, void *data
)
378 struct rockchip_hdmi
*hdmi
= (struct rockchip_hdmi
*)data
;
379 enum drm_connector_status status
;
381 status
= dw_hdmi_phy_read_hpd(dw_hdmi
, data
);
383 if (status
== connector_status_connected
)
384 regmap_write(hdmi
->regmap
,
386 HIWORD_UPDATE(RK3328_HDMI_SDA_5V
| RK3328_HDMI_SCL_5V
,
387 RK3328_HDMI_SDA_5V
| RK3328_HDMI_SCL_5V
));
389 regmap_write(hdmi
->regmap
,
391 HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V
|
392 RK3328_HDMI_SCL_5V
));
396 static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi
*dw_hdmi
, void *data
)
398 struct rockchip_hdmi
*hdmi
= (struct rockchip_hdmi
*)data
;
400 dw_hdmi_phy_setup_hpd(dw_hdmi
, data
);
402 /* Enable and map pins to 3V grf-controlled io-voltage */
403 regmap_write(hdmi
->regmap
,
405 HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC
| RK3328_HDMI_CEC_5V
|
406 RK3328_HDMI_SDA_5V
| RK3328_HDMI_SCL_5V
|
407 RK3328_HDMI_HPD_5V
));
408 regmap_write(hdmi
->regmap
,
410 HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF
| RK3328_HDMI_SCL5V_GRF
|
411 RK3328_HDMI_HPD5V_GRF
|
412 RK3328_HDMI_CEC5V_GRF
));
413 regmap_write(hdmi
->regmap
,
415 HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK
| RK3328_HDMI_SCLIN_MSK
,
416 RK3328_HDMI_SDAIN_MSK
| RK3328_HDMI_SCLIN_MSK
|
417 RK3328_HDMI_HPD_IOE
));
419 dw_hdmi_rk3328_read_hpd(dw_hdmi
, data
);
422 static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops
= {
423 .init
= dw_hdmi_rockchip_genphy_init
,
424 .disable
= dw_hdmi_rockchip_genphy_disable
,
425 .read_hpd
= dw_hdmi_phy_read_hpd
,
426 .update_hpd
= dw_hdmi_phy_update_hpd
,
427 .setup_hpd
= dw_hdmi_rk3228_setup_hpd
,
430 static struct rockchip_hdmi_chip_data rk3228_chip_data
= {
431 .lcdsel_grf_reg
= -1,
432 .max_tmds_clock
= 594000,
435 static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data
= {
436 .mode_valid
= dw_hdmi_rockchip_mode_valid
,
437 .phy_data
= &rk3228_chip_data
,
438 .phy_ops
= &rk3228_hdmi_phy_ops
,
439 .phy_name
= "inno_dw_hdmi_phy2",
440 .phy_force_vendor
= true,
443 static struct rockchip_hdmi_chip_data rk3288_chip_data
= {
444 .lcdsel_grf_reg
= RK3288_GRF_SOC_CON6
,
445 .lcdsel_big
= HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL
),
446 .lcdsel_lit
= HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL
, RK3288_HDMI_LCDC_SEL
),
447 .max_tmds_clock
= 340000,
450 static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data
= {
451 .mode_valid
= dw_hdmi_rockchip_mode_valid
,
452 .mpll_cfg
= rockchip_mpll_cfg
,
453 .cur_ctr
= rockchip_cur_ctr
,
454 .phy_config
= rockchip_phy_config
,
455 .phy_data
= &rk3288_chip_data
,
458 static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops
= {
459 .init
= dw_hdmi_rockchip_genphy_init
,
460 .disable
= dw_hdmi_rockchip_genphy_disable
,
461 .read_hpd
= dw_hdmi_rk3328_read_hpd
,
462 .update_hpd
= dw_hdmi_phy_update_hpd
,
463 .setup_hpd
= dw_hdmi_rk3328_setup_hpd
,
466 static struct rockchip_hdmi_chip_data rk3328_chip_data
= {
467 .lcdsel_grf_reg
= -1,
468 .max_tmds_clock
= 594000,
471 static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data
= {
472 .mode_valid
= dw_hdmi_rockchip_mode_valid
,
473 .phy_data
= &rk3328_chip_data
,
474 .phy_ops
= &rk3328_hdmi_phy_ops
,
475 .phy_name
= "inno_dw_hdmi_phy2",
476 .phy_force_vendor
= true,
477 .use_drm_infoframe
= true,
480 static struct rockchip_hdmi_chip_data rk3399_chip_data
= {
481 .lcdsel_grf_reg
= RK3399_GRF_SOC_CON20
,
482 .lcdsel_big
= HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL
),
483 .lcdsel_lit
= HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL
, RK3399_HDMI_LCDC_SEL
),
484 .max_tmds_clock
= 594000,
487 static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data
= {
488 .mode_valid
= dw_hdmi_rockchip_mode_valid
,
489 .mpll_cfg
= rockchip_mpll_cfg
,
490 .cur_ctr
= rockchip_cur_ctr
,
491 .phy_config
= rockchip_phy_config
,
492 .phy_data
= &rk3399_chip_data
,
493 .use_drm_infoframe
= true,
496 static struct rockchip_hdmi_chip_data rk3568_chip_data
= {
497 .lcdsel_grf_reg
= -1,
498 .max_tmds_clock
= 594000,
501 static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data
= {
502 .mode_valid
= dw_hdmi_rockchip_mode_valid
,
503 .mpll_cfg
= rockchip_mpll_cfg
,
504 .cur_ctr
= rockchip_cur_ctr
,
505 .phy_config
= rockchip_phy_config
,
506 .phy_data
= &rk3568_chip_data
,
507 .use_drm_infoframe
= true,
510 static const struct of_device_id dw_hdmi_rockchip_dt_ids
[] = {
511 { .compatible
= "rockchip,rk3228-dw-hdmi",
512 .data
= &rk3228_hdmi_drv_data
514 { .compatible
= "rockchip,rk3288-dw-hdmi",
515 .data
= &rk3288_hdmi_drv_data
517 { .compatible
= "rockchip,rk3328-dw-hdmi",
518 .data
= &rk3328_hdmi_drv_data
520 { .compatible
= "rockchip,rk3399-dw-hdmi",
521 .data
= &rk3399_hdmi_drv_data
523 { .compatible
= "rockchip,rk3568-dw-hdmi",
524 .data
= &rk3568_hdmi_drv_data
528 MODULE_DEVICE_TABLE(of
, dw_hdmi_rockchip_dt_ids
);
530 static int dw_hdmi_rockchip_bind(struct device
*dev
, struct device
*master
,
533 struct platform_device
*pdev
= to_platform_device(dev
);
534 struct dw_hdmi_plat_data
*plat_data
;
535 const struct of_device_id
*match
;
536 struct drm_device
*drm
= data
;
537 struct drm_encoder
*encoder
;
538 struct rockchip_hdmi
*hdmi
;
541 if (!pdev
->dev
.of_node
)
544 hdmi
= devm_kzalloc(&pdev
->dev
, sizeof(*hdmi
), GFP_KERNEL
);
548 match
= of_match_node(dw_hdmi_rockchip_dt_ids
, pdev
->dev
.of_node
);
549 plat_data
= devm_kmemdup(&pdev
->dev
, match
->data
,
550 sizeof(*plat_data
), GFP_KERNEL
);
554 hdmi
->dev
= &pdev
->dev
;
555 hdmi
->plat_data
= plat_data
;
556 hdmi
->chip_data
= plat_data
->phy_data
;
557 plat_data
->phy_data
= hdmi
;
558 plat_data
->priv_data
= hdmi
;
559 encoder
= &hdmi
->encoder
.encoder
;
561 encoder
->possible_crtcs
= drm_of_find_possible_crtcs(drm
, dev
->of_node
);
562 rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi
->encoder
,
566 * If we failed to find the CRTC(s) which this encoder is
567 * supposed to be connected to, it's because the CRTC has
568 * not been registered yet. Defer probing, and hope that
569 * the required CRTC is added later.
571 if (encoder
->possible_crtcs
== 0)
572 return -EPROBE_DEFER
;
574 ret
= rockchip_hdmi_parse_dt(hdmi
);
576 if (ret
!= -EPROBE_DEFER
)
577 drm_err(hdmi
, "Unable to parse OF data\n");
581 hdmi
->phy
= devm_phy_optional_get(dev
, "hdmi");
582 if (IS_ERR(hdmi
->phy
)) {
583 ret
= PTR_ERR(hdmi
->phy
);
584 if (ret
!= -EPROBE_DEFER
)
585 drm_err(hdmi
, "failed to get phy\n");
590 struct of_phandle_args clkspec
;
592 clkspec
.np
= hdmi
->phy
->dev
.of_node
;
593 hdmi
->hdmiphy_clk
= of_clk_get_from_provider(&clkspec
);
594 if (IS_ERR(hdmi
->hdmiphy_clk
))
595 hdmi
->hdmiphy_clk
= NULL
;
598 if (hdmi
->chip_data
== &rk3568_chip_data
) {
599 regmap_write(hdmi
->regmap
, RK3568_GRF_VO_CON1
,
600 HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK
|
601 RK3568_HDMI_SCLIN_MSK
,
602 RK3568_HDMI_SDAIN_MSK
|
603 RK3568_HDMI_SCLIN_MSK
));
606 drm_encoder_helper_add(encoder
, &dw_hdmi_rockchip_encoder_helper_funcs
);
607 drm_simple_encoder_init(drm
, encoder
, DRM_MODE_ENCODER_TMDS
);
609 platform_set_drvdata(pdev
, hdmi
);
611 hdmi
->hdmi
= dw_hdmi_bind(pdev
, encoder
, plat_data
);
614 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
615 * which would have called the encoder cleanup. Do it manually.
617 if (IS_ERR(hdmi
->hdmi
)) {
618 ret
= PTR_ERR(hdmi
->hdmi
);
625 drm_encoder_cleanup(encoder
);
630 static void dw_hdmi_rockchip_unbind(struct device
*dev
, struct device
*master
,
633 struct rockchip_hdmi
*hdmi
= dev_get_drvdata(dev
);
635 dw_hdmi_unbind(hdmi
->hdmi
);
636 drm_encoder_cleanup(&hdmi
->encoder
.encoder
);
639 static const struct component_ops dw_hdmi_rockchip_ops
= {
640 .bind
= dw_hdmi_rockchip_bind
,
641 .unbind
= dw_hdmi_rockchip_unbind
,
644 static int dw_hdmi_rockchip_probe(struct platform_device
*pdev
)
646 return component_add(&pdev
->dev
, &dw_hdmi_rockchip_ops
);
649 static void dw_hdmi_rockchip_remove(struct platform_device
*pdev
)
651 component_del(&pdev
->dev
, &dw_hdmi_rockchip_ops
);
654 static int __maybe_unused
dw_hdmi_rockchip_resume(struct device
*dev
)
656 struct rockchip_hdmi
*hdmi
= dev_get_drvdata(dev
);
658 dw_hdmi_resume(hdmi
->hdmi
);
663 static const struct dev_pm_ops dw_hdmi_rockchip_pm
= {
664 SET_SYSTEM_SLEEP_PM_OPS(NULL
, dw_hdmi_rockchip_resume
)
667 struct platform_driver dw_hdmi_rockchip_pltfm_driver
= {
668 .probe
= dw_hdmi_rockchip_probe
,
669 .remove
= dw_hdmi_rockchip_remove
,
671 .name
= "dwhdmi-rockchip",
672 .pm
= &dw_hdmi_rockchip_pm
,
673 .of_match_table
= dw_hdmi_rockchip_dt_ids
,