From 429136e062dada1192260d2274d3173693c5b442 Mon Sep 17 00:00:00 2001 From: Paolo Sabatino Date: Sat, 17 Jul 2021 13:51:18 +0000 Subject: [PATCH] rk322x: rework patch for kernel 5.12 --- .../rk322x-5.12/01-linux-1001-drm-wip.patch | 4676 +++++++++++++++++ 1 file changed, 4676 insertions(+) create mode 100644 patch/kernel/archive/rk322x-5.12/01-linux-1001-drm-wip.patch diff --git a/patch/kernel/archive/rk322x-5.12/01-linux-1001-drm-wip.patch b/patch/kernel/archive/rk322x-5.12/01-linux-1001-drm-wip.patch new file mode 100644 index 0000000000..d19f5d1cc4 --- /dev/null +++ b/patch/kernel/archive/rk322x-5.12/01-linux-1001-drm-wip.patch @@ -0,0 +1,4676 @@ +From 0af28d066edbb4297d5140ff4c93db7b0bc0b182 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 3 May 2020 16:51:31 +0000 +Subject: [PATCH] drm/rockchip: vop: filter modes outside 0.5% pixel clock + tolerance + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 33 +++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index c80f7d9fd13f..6cbdb4672a4b 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1142,6 +1142,38 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) + spin_unlock_irqrestore(&vop->irq_lock, flags); + } + ++/* ++ * The VESA DMT standard specifies a 0.5% pixel clock frequency tolerance. ++ * The CVT spec reuses that tolerance in its examples. ++ */ ++#define CLOCK_TOLERANCE_PER_MILLE 5 ++ ++static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, ++ const struct drm_display_mode *mode) ++{ ++ struct vop *vop = to_vop(crtc); ++ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); ++ long rounded_rate; ++ long lowest, highest; ++ ++ if (s->output_type != DRM_MODE_CONNECTOR_HDMIA) ++ return MODE_OK; ++ ++ rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999); ++ if (rounded_rate < 0) ++ return MODE_NOCLOCK; ++ ++ lowest = mode->clock * (1000 - CLOCK_TOLERANCE_PER_MILLE); ++ if (rounded_rate < lowest) ++ return MODE_CLOCK_LOW; ++ ++ highest = mode->clock * (1000 + CLOCK_TOLERANCE_PER_MILLE); ++ if (rounded_rate > highest) ++ return MODE_CLOCK_HIGH; ++ ++ return MODE_OK; ++} ++ + static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +@@ -1512,6 +1544,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, + } + + static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { ++ .mode_valid = vop_crtc_mode_valid, + .mode_fixup = vop_crtc_mode_fixup, + .atomic_check = vop_crtc_atomic_check, + .atomic_begin = vop_crtc_atomic_begin, + +From 35e601dd9730b541bde93ec5cd5320b2c14a84fa Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 11:46:16 +0000 +Subject: [PATCH] WIP: drm/rockchip: vop: max_output + +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 ++++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 7 +++++++ + 3 files changed, 18 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 6cbdb4672a4b..106b38ea12df 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1152,6 +1152,7 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) + { + struct vop *vop = to_vop(crtc); ++ const struct vop_rect *max_output = &vop->data->max_output; + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); + long rounded_rate; + long lowest, highest; +@@ -1171,6 +1172,10 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + if (rounded_rate > highest) + return MODE_CLOCK_HIGH; + ++ if (max_output->width && max_output->height) ++ return drm_mode_validate_size(mode, max_output->width, ++ max_output->height); ++ + return MODE_OK; + } + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 4a2099cb582e..1516231bbf93 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -185,6 +185,11 @@ struct vop_win_data { + enum drm_plane_type type; + }; + ++struct vop_rect { ++ int width; ++ int height; ++}; ++ + struct vop_data { + uint32_t version; + const struct vop_intr *intr; +@@ -197,6 +202,7 @@ struct vop_data { + const struct vop_win_data *win; + unsigned int win_size; + unsigned int lut_size; ++ struct vop_rect max_output; + + #define VOP_FEATURE_OUTPUT_RGB10 BIT(0) + #define VOP_FEATURE_INTERNAL_RGB BIT(1) +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 80053d91a301..57c36e9207c1 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -682,6 +682,7 @@ static const struct vop_intr rk3288_vop_intr = { + static const struct vop_data rk3288_vop = { + .version = VOP_VERSION(3, 1), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 3840, 2160 }, + .intr = &rk3288_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -782,6 +783,7 @@ static const struct vop_misc rk3368_misc = { + + static const struct vop_data rk3368_vop = { + .version = VOP_VERSION(3, 2), ++ .max_output = { 4096, 2160 }, + .intr = &rk3368_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -803,6 +805,7 @@ static const struct vop_intr rk3366_vop_intr = { + + static const struct vop_data rk3366_vop = { + .version = VOP_VERSION(3, 4), ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -909,6 +912,7 @@ static const struct vop_afbc rk3399_vop_afbc = { + static const struct vop_data rk3399_vop_big = { + .version = VOP_VERSION(3, 5), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -935,6 +939,7 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = { + + static const struct vop_data rk3399_vop_lit = { + .version = VOP_VERSION(3, 6), ++ .max_output = { 2560, 1600 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -955,6 +960,7 @@ static const struct vop_win_data rk3228_vop_win_data[] = { + static const struct vop_data rk3228_vop = { + .version = VOP_VERSION(3, 7), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3366_vop_intr, + .common = &rk3288_common, + .modeset = &rk3288_modeset, +@@ -1026,6 +1032,7 @@ static const struct vop_win_data rk3328_vop_win_data[] = { + static const struct vop_data rk3328_vop = { + .version = VOP_VERSION(3, 8), + .feature = VOP_FEATURE_OUTPUT_RGB10, ++ .max_output = { 4096, 2160 }, + .intr = &rk3328_vop_intr, + .common = &rk3328_common, + .modeset = &rk3328_modeset, + +From 61b85ebc7d075446c5f8a57607eb1fc87b16e2a8 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:49 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: allow high tmds bit rates + +Prepare support for High TMDS Bit Rates used by HDMI2.0 display modes. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 23de359a1dec..cdf953850873 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -317,6 +317,8 @@ static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, + { + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; + ++ dw_hdmi_set_high_tmds_clock_ratio(dw_hdmi, display); ++ + return phy_power_on(hdmi->phy); + } + + +From a1675f5032286c3f2e939a7392361fc15099c0b7 Mon Sep 17 00:00:00 2001 +From: Yakir Yang +Date: Mon, 11 Jul 2016 19:05:39 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: adjust cklvl & txlvl for RF/EMI + +Dut to the high HDMI signal voltage driver, Mickey have meet +a serious RF/EMI problem, so we decided to reduce HDMI signal +voltage to a proper value. + +The default params for phy is cklvl = 20 & txlvl = 13 (RF/EMI failed) + ck: lvl = 13, term=100, vlo = 2.71, vhi=3.14, vswing = 0.43 + tx: lvl = 20, term=100, vlo = 2.81, vhi=3.16, vswing = 0.35 + +1. We decided to reduce voltage value to lower, but VSwing still +keep high, RF/EMI have been improved but still failed. + ck: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + tx: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + +2. We try to keep voltage value and vswing both lower, then RF/EMI +test all passed ;) + ck: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 + tx: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 +When we back to run HDMI different test and single-end test, we see +different test passed, but signle-end test failed. The oscilloscope +show that simgle-end clock's VL value is 1.78v (which remind LowLimit +should not lower then 2.6v). + +3. That's to say there are some different between PHY document and +measure value. And according to experiment 2 results, we need to +higher clock voltage and lower data voltage, then we can keep RF/EMI +satisfied and single-end & differen test passed. + ck: lvl = 9, term=100, vlo = 2.65, vhi=3.12, vswing = 0.47 + tx: lvl = 16, term=100, vlo = 2.75, vhi=3.15, vswing = 0.39 + +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cdf953850873..4652c0e0dcd6 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -181,7 +181,7 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + /*pixelclk symbol term vlev*/ + { 74250000, 0x8009, 0x0004, 0x0272}, +- { 148500000, 0x802b, 0x0004, 0x028d}, ++ { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; + +From 15a5f1ae8e0f570e81affb35b9b4aa4c0f485614 Mon Sep 17 00:00:00 2001 +From: Nickey Yang +Date: Mon, 13 Feb 2017 15:40:29 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: add phy_config for 594Mhz pixel clock + +Add phy_config for 594Mhz pixel clock used for 4K@60hz + +Signed-off-by: Nickey Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 4652c0e0dcd6..10c3dc521cbd 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -183,6 +183,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + { 74250000, 0x8009, 0x0004, 0x0272}, + { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, ++ { 594000000, 0x8039, 0x0000, 0x019d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; + + +From 43ac4790ecf27cf8db51e68298c541224af046a6 Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Mon, 11 Jul 2016 19:05:36 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: Set cur_ctr to 0 always + +Jitter was improved by lowering the MPLL bandwidth to account for high +frequency noise in the rk3288 PLL. In each case MPLL bandwidth was +lowered only enough to get us a comfortable margin. We believe that +lowering the bandwidth like this is safe given sufficient testing. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++-------------- + 1 file changed, 2 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 10c3dc521cbd..cc7675638e4f 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -160,20 +160,8 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { +- 40000000, { 0x0018, 0x0018, 0x0018 }, +- }, { +- 65000000, { 0x0028, 0x0028, 0x0028 }, +- }, { +- 66000000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 74250000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 83500000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 146250000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 148500000, { 0x0000, 0x0038, 0x0038 }, +- }, { ++ 600000000, { 0x0000, 0x0000, 0x0000 }, ++ }, { + ~0UL, { 0x0000, 0x0000, 0x0000}, + } + }; + +From 7604ef86c3d010fbfa61cf030b055b3860a53682 Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Mon, 11 Jul 2016 19:05:42 +0800 +Subject: [PATCH] drm/rockchip: dw_hdmi: Use auto-generated tables + +The previous tables for mpll_cfg and curr_ctrl were created using the +20-pages of example settings provided by the PHY vendor. Those +example settings weren't particularly dense, so there were places +where we were guessing what the settings would be for 10-bit and +12-bit (not that we use those anyway). It was also always a lot of +extra work every time we wanted to add a new clock rate since we had +to cross-reference several tables. + +In I've gone through the work to figure +out how to generate this table automatically. Let's now use the +automatically generated table and then we'll never need to look at it +again. + +We only support 8-bit mode right now and only support a small number +of clock rates and and I've verified that the only 8-bit rate that was +affected was 148.5. That mode appears to have been wrong in the old +table. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 130 +++++++++++--------- + 1 file changed, 69 insertions(+), 61 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cc7675638e4f..c4c158106ca4 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -79,80 +79,88 @@ struct rockchip_hdmi { + + static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + { +- 27000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ 30666000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40f3, 0x0000 }, + }, +- }, { +- 36000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ }, { ++ 36800000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 40000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ }, { ++ 46000000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 54000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ }, { ++ 61333000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, +- }, { +- 65000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ }, { ++ 73600000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x4061, 0x0002 }, + }, +- }, { +- 66000000, { +- { 0x013e, 0x0003}, +- { 0x217e, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 92000000, { ++ { 0x0072, 0x0001 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, ++ }, ++ }, { ++ 122666000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, + }, +- }, { +- 74250000, { +- { 0x0072, 0x0001}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 147200000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 83500000, { +- { 0x0072, 0x0001}, ++ }, { ++ 184000000, { ++ { 0x0051, 0x0002 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 108000000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 226666000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, +- }, { +- 106500000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 272000000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { +- 146250000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ }, { ++ 340000000, { ++ { 0x0040, 0x0003 }, ++ { 0x3b4c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { +- 148500000, { +- { 0x0051, 0x0003}, +- { 0x214c, 0x0003}, +- { 0x4064, 0x0003} ++ }, { ++ 600000000, { ++ { 0x1a40, 0x0003 }, ++ { 0x3b4c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, +- }, { ++ }, { + ~0UL, { +- { 0x00a0, 0x000a }, +- { 0x2001, 0x000f }, +- { 0x4002, 0x000f }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, + }, + } + }; + +From 119aca9dc20be1639fe8146237d2821695a2bc6b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:52 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: limit tmds to 340mhz + +RK3228/RK3328 does not provide a stable hdmi signal at TMDS rates +above 371.25MHz (340MHz pixel clock). + +Limit the pixel clock rate to 340MHz to provide a stable signal. +Also limit the pixel clock to the display reported max tmds clock. + +This also enables use of pixel clocks up to 340MHz on RK3288/RK3399. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index c4c158106ca4..b62d8f4fc9a8 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -221,19 +221,11 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) + { +- const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; +- int pclk = mode->clock * 1000; +- bool valid = false; +- int i; +- +- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { +- if (pclk == mpll_cfg[i].mpixelclock) { +- valid = true; +- break; +- } +- } ++ if (mode->clock > 340000 || ++ (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) ++ return MODE_CLOCK_HIGH; + +- return (valid) ? MODE_OK : MODE_BAD; ++ return MODE_OK; + } + + static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) + +From 9f31d6e1e2951eeaa979e1f9eb4b04cb64a4daf8 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 3 May 2020 22:36:23 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: limit resolution to 3840x2160 + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index b62d8f4fc9a8..6f7641fbe6cc 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -225,7 +225,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) + return MODE_CLOCK_HIGH; + +- return MODE_OK; ++ return drm_mode_validate_size(mode, 3840, 2160); + } + + static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) + +From bea1222407f1eb9d6af776d98eae5bd0f3544134 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:52 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: remove unused plat_data on + rk3228/rk3328 + +mpll_cfg/cur_ctr/phy_config is not used when phy_force_vendor is true, +lets remove them. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 6f7641fbe6cc..cc20a83fa9b8 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -396,9 +396,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { + + static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, +- .mpll_cfg = rockchip_mpll_cfg, +- .cur_ctr = rockchip_cur_ctr, +- .phy_config = rockchip_phy_config, + .phy_data = &rk3228_chip_data, + .phy_ops = &rk3228_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", +@@ -433,9 +430,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { + + static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, +- .mpll_cfg = rockchip_mpll_cfg, +- .cur_ctr = rockchip_cur_ctr, +- .phy_config = rockchip_phy_config, + .phy_data = &rk3328_chip_data, + .phy_ops = &rk3328_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", + +From 0bd355e25df8c93481ea6995bec7f452da97d5bf Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 8 Jan 2020 21:07:50 +0000 +Subject: [PATCH] clk: rockchip: set parent rate for DCLK_VOP clock on rk3228 + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3228.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c +index 2ac006e99c03..1f9176a5cc07 100644 +--- a/drivers/clk/rockchip/clk-rk3228.c ++++ b/drivers/clk/rockchip/clk-rk3228.c +@@ -393,7 +393,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = { + RK2928_CLKSEL_CON(29), 0, 3, DFLAGS), + DIV(0, "sclk_vop_pre", "sclk_vop_src", 0, + RK2928_CLKSEL_CON(27), 8, 8, DFLAGS), +- MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, 0, ++ MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK2928_CLKSEL_CON(27), 1, 1, MFLAGS), + + FACTOR(0, "xin12m", "xin24m", 0, 1, 2), + +From 957c41ed6b5a182b12880b6f16f6e17d034bf483 Mon Sep 17 00:00:00 2001 +From: Nickey Yang +Date: Mon, 17 Jul 2017 16:35:34 +0800 +Subject: [PATCH] HACK: clk: rockchip: rk3288: dedicate npll for vopb and hdmi + use + +MINIARM: set npll be used for hdmi only + +Signed-off-by: Nickey Yang +Signed-off-by: Jonas Karlman +--- + arch/arm/boot/dts/rk3288.dtsi | 2 ++ + drivers/clk/rockchip/clk-rk3288.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 68d5a58cfe88..a376dea3bb1b 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1046,6 +1046,8 @@ vopb: vop@ff930000 { + resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>; + reset-names = "axi", "ahb", "dclk"; + iommus = <&vopb_mmu>; ++ assigned-clocks = <&cru DCLK_VOP0>; ++ assigned-clock-parents = <&cru PLL_NPLL>; + status = "disabled"; + + vopb_out: port { +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 15c8f1dcba9a..460b19d65ef3 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -234,7 +234,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), + RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), +- RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), ++ RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates), + }; + + static struct clk_div_table div_hclk_cpu_t[] = { +@@ -444,7 +444,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { + RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3288_CLKGATE_CON(3), 4, GFLAGS), + +- COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, 0, ++ COMPOSITE(DCLK_VOP0, "dclk_vop0", mux_pll_src_cpll_gpll_npll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + RK3288_CLKSEL_CON(27), 0, 2, MFLAGS, 8, 8, DFLAGS, + RK3288_CLKGATE_CON(3), 1, GFLAGS), + COMPOSITE(DCLK_VOP1, "dclk_vop1", mux_pll_src_cpll_gpll_npll_p, 0, + +From 0f7295f13d592ba60dee79a0cc23302ed2febffa Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 4 Aug 2018 14:51:14 +0200 +Subject: [PATCH] HACK: clk: rockchip: rk3288: use npll table to to improve + HDMI compatibility + +Based on https://github.com/TinkerBoard/debian_kernel/commit/3d90870530b8a2901681f7b7fa598ee7381e49f3 + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3288.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index 460b19d65ef3..b973c6b0315b 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -124,6 +124,27 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = { + { /* sentinel */ }, + }; + ++static struct rockchip_pll_rate_table rk3288_npll_rates[] = { ++ RK3066_PLL_RATE_NB(594000000, 1, 99, 4, 32), ++ RK3066_PLL_RATE_NB(585000000, 6, 585, 4, 32), ++ RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32), ++ RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32), ++ RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32), ++ RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32), ++ RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16), ++ RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32), ++ RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32), ++ RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32), ++ RK3066_PLL_RATE(148352000, 13, 1125, 14), ++ RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32), ++ RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32), ++ RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32), ++ RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32), ++ RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32), ++ RK3066_PLL_RATE(74176000, 26, 1125, 14), ++ { /* sentinel */ }, ++}; ++ + #define RK3288_DIV_ACLK_CORE_M0_MASK 0xf + #define RK3288_DIV_ACLK_CORE_M0_SHIFT 0 + #define RK3288_DIV_ACLK_CORE_MP_MASK 0xf +@@ -234,7 +255,7 @@ static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), + RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), +- RK3288_MODE_CON, 14, 9, 0, rk3288_pll_rates), ++ RK3288_MODE_CON, 14, 9, 0, rk3288_npll_rates), + }; + + static struct clk_div_table div_hclk_cpu_t[] = { + +From e9d9694635e5cd9a84779e045c670239fc255606 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 28 Oct 2018 21:43:01 +0100 +Subject: [PATCH] HACK: clk: rockchip: rk3288: add more npll clocks + +Fixes 2560x1440@60Hz, 1600x1200@60Hz, 1920x1200@60Hz, 1680x1050@60Hz and 1440x900@60Hz modes on my monitor + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3288.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c +index b973c6b0315b..9192b89c2550 100644 +--- a/drivers/clk/rockchip/clk-rk3288.c ++++ b/drivers/clk/rockchip/clk-rk3288.c +@@ -130,18 +130,34 @@ static struct rockchip_pll_rate_table rk3288_npll_rates[] = { + RK3066_PLL_RATE_NB(432000000, 3, 216, 4, 32), + RK3066_PLL_RATE_NB(426000000, 3, 213, 4, 32), + RK3066_PLL_RATE_NB(400000000, 1, 100, 6, 32), ++ RK3066_PLL_RATE(348500000, 8, 697, 6), + RK3066_PLL_RATE_NB(342000000, 3, 171, 4, 32), + RK3066_PLL_RATE_NB(297000000, 2, 198, 8, 16), + RK3066_PLL_RATE_NB(270000000, 1, 135, 12, 32), + RK3066_PLL_RATE_NB(260000000, 1, 130, 12, 32), ++ RK3066_PLL_RATE(241500000, 2, 161, 8), ++ RK3066_PLL_RATE(162000000, 1, 81, 12), ++ RK3066_PLL_RATE(154000000, 6, 539, 14), + RK3066_PLL_RATE_NB(148500000, 1, 99, 16, 32), + RK3066_PLL_RATE(148352000, 13, 1125, 14), + RK3066_PLL_RATE_NB(146250000, 6, 585, 16, 32), ++ RK3066_PLL_RATE(121750000, 6, 487, 16), ++ RK3066_PLL_RATE(119000000, 3, 238, 16), + RK3066_PLL_RATE_NB(108000000, 1, 54, 12, 32), + RK3066_PLL_RATE_NB(106500000, 4, 213, 12, 32), ++ RK3066_PLL_RATE(101000000, 3, 202, 16), ++ RK3066_PLL_RATE(88750000, 6, 355, 16), + RK3066_PLL_RATE_NB(85500000, 4, 171, 12, 32), ++ RK3066_PLL_RATE(83500000, 3, 167, 16), ++ RK3066_PLL_RATE(79500000, 1, 53, 16), + RK3066_PLL_RATE_NB(74250000, 4, 198, 16, 32), + RK3066_PLL_RATE(74176000, 26, 1125, 14), ++ RK3066_PLL_RATE(72000000, 1, 48, 16), ++ RK3066_PLL_RATE(71000000, 3, 142, 16), ++ RK3066_PLL_RATE(68250000, 2, 91, 16), ++ RK3066_PLL_RATE(65000000, 3, 130, 16), ++ RK3066_PLL_RATE(40000000, 3, 80, 16), ++ RK3066_PLL_RATE(33750000, 2, 45, 16), + { /* sentinel */ }, + }; + + +From 2e18be0e366e9afcfe7dcdb69c3c90cce472bfa0 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 25 May 2020 20:36:45 +0000 +Subject: [PATCH] HACK: clk: rockchip: rk3399: dedicate vpll for vopb and hdmi + use + +Signed-off-by: Jonas Karlman +--- + drivers/clk/rockchip/clk-rk3399.c | 32 +++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c +index 3682d5675cf7..0934145c09ad 100644 +--- a/drivers/clk/rockchip/clk-rk3399.c ++++ b/drivers/clk/rockchip/clk-rk3399.c +@@ -111,6 +111,25 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { + { /* sentinel */ }, + }; + ++static struct rockchip_pll_rate_table rk3399_vpll_rates[] = { ++ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ ++ RK3036_PLL_RATE( 594000000, 1, 123, 5, 1, 0, 12582912), /* vco = 2970000000 */ ++ RK3036_PLL_RATE( 593406592, 1, 123, 5, 1, 0, 10508804), /* vco = 2967032965 */ ++ RK3036_PLL_RATE( 297000000, 1, 123, 5, 2, 0, 12582912), /* vco = 2970000000 */ ++ RK3036_PLL_RATE( 296703296, 1, 123, 5, 2, 0, 10508807), /* vco = 2967032970 */ ++ RK3036_PLL_RATE( 148500000, 1, 129, 7, 3, 0, 15728640), /* vco = 3118500000 */ ++ RK3036_PLL_RATE( 148351648, 1, 123, 5, 4, 0, 10508800), /* vco = 2967032960 */ ++ RK3036_PLL_RATE( 106500000, 1, 124, 7, 4, 0, 4194304), /* vco = 2982000000 */ ++ RK3036_PLL_RATE( 74250000, 1, 129, 7, 6, 0, 15728640), /* vco = 3118500000 */ ++ RK3036_PLL_RATE( 74175824, 1, 129, 7, 6, 0, 13550823), /* vco = 3115384608 */ ++ RK3036_PLL_RATE( 65000000, 1, 113, 7, 6, 0, 12582912), /* vco = 2730000000 */ ++ RK3036_PLL_RATE( 59340659, 1, 121, 7, 7, 0, 2581098), /* vco = 2907692291 */ ++ RK3036_PLL_RATE( 54000000, 1, 110, 7, 7, 0, 4194304), /* vco = 2646000000 */ ++ RK3036_PLL_RATE( 27000000, 1, 55, 7, 7, 0, 2097152), /* vco = 1323000000 */ ++ RK3036_PLL_RATE( 26973026, 1, 55, 7, 7, 0, 1173232), /* vco = 1321678323 */ ++ { /* sentinel */ }, ++}; ++ + /* CRU parents */ + PNAME(mux_pll_p) = { "xin24m", "xin32k" }; + +@@ -129,7 +148,7 @@ PNAME(mux_ddrclk_p) = { "clk_ddrc_lpll_src", + PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", + "gpll_aclk_cci_src", + "npll_aclk_cci_src", +- "vpll_aclk_cci_src" }; ++ "prevent:vpll" }; + PNAME(mux_cci_trace_p) = { "cpll_cci_trace", + "gpll_cci_trace" }; + PNAME(mux_cs_p) = { "cpll_cs", "gpll_cs", +@@ -156,9 +175,10 @@ PNAME(mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p) = { "cpll", "gpll", "npll", + "ppll", "upll", "xin24m" }; + + PNAME(mux_pll_src_vpll_cpll_gpll_p) = { "vpll", "cpll", "gpll" }; +-PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "vpll", "cpll", "gpll", ++ ++PNAME(mux_pll_src_vpll_cpll_gpll_npll_p) = { "prevent:vpll", "cpll", "gpll", + "npll" }; +-PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "vpll", "cpll", "gpll", ++PNAME(mux_pll_src_vpll_cpll_gpll_24m_p) = { "prevent:vpll", "cpll", "gpll", + "xin24m" }; + + PNAME(mux_dclk_vop0_p) = { "dclk_vop0_div", +@@ -235,7 +255,7 @@ static struct rockchip_pll_clock rk3399_pll_clks[] __initdata = { + [npll] = PLL(pll_rk3399, PLL_NPLL, "npll", mux_pll_p, 0, RK3399_PLL_CON(40), + RK3399_PLL_CON(43), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), + [vpll] = PLL(pll_rk3399, PLL_VPLL, "vpll", mux_pll_p, 0, RK3399_PLL_CON(48), +- RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_pll_rates), ++ RK3399_PLL_CON(51), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rk3399_vpll_rates), + }; + + static struct rockchip_pll_clock rk3399_pmu_pll_clks[] __initdata = { +@@ -285,7 +305,7 @@ static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata = + RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata = +- MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT, ++ MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(49), 11, 1, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata = +@@ -1166,7 +1186,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { + GATE(HCLK_VOP0_NOC, "hclk_vop0_noc", "hclk_vop0_pre", CLK_IGNORE_UNUSED, + RK3399_CLKGATE_CON(28), 0, GFLAGS), + +- COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, 0, ++ COMPOSITE(DCLK_VOP0_DIV, "dclk_vop0_div", mux_pll_src_vpll_cpll_gpll_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(49), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3399_CLKGATE_CON(10), 12, GFLAGS), + + +From b2d23eae37a78a425144a21eb8bfbedc03edc754 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 19 Jul 2020 16:35:11 +0000 +Subject: [PATCH] HACK: dts: rockchip: do not use vopl for hdmi + +--- + arch/arm/boot/dts/rk3288.dtsi | 9 --------- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 9 --------- + 2 files changed, 18 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index a376dea3bb1b..9757976d6e8a 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1104,11 +1104,6 @@ vopl_out: port { + #address-cells = <1>; + #size-cells = <0>; + +- vopl_out_hdmi: endpoint@0 { +- reg = <0>; +- remote-endpoint = <&hdmi_in_vopl>; +- }; +- + vopl_out_edp: endpoint@1 { + reg = <1>; + remote-endpoint = <&edp_in_vopl>; +@@ -1249,10 +1244,6 @@ hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; +- hdmi_in_vopl: endpoint@1 { +- reg = <1>; +- remote-endpoint = <&vopl_out_hdmi>; +- }; + }; + }; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index f5dee5f447bb..3e44bf8eac5c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -1640,11 +1640,6 @@ vopl_out_edp: endpoint@1 { + remote-endpoint = <&edp_in_vopl>; + }; + +- vopl_out_hdmi: endpoint@2 { +- reg = <2>; +- remote-endpoint = <&hdmi_in_vopl>; +- }; +- + vopl_out_mipi1: endpoint@3 { + reg = <3>; + remote-endpoint = <&mipi1_in_vopl>; +@@ -1816,10 +1811,6 @@ hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; +- hdmi_in_vopl: endpoint@1 { +- reg = <1>; +- remote-endpoint = <&vopl_out_hdmi>; +- }; + }; + }; + }; + +From c94f4e569387f6874b2c96a3db684751529fb6b6 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 12:33:01 +0000 +Subject: [PATCH] Revert "fixup! WIP: drm/rockchip: vop: max_output" + +This reverts commit c69612ca6820500cd1a0a3e4f8eb8c6f7b971cda. +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 106b38ea12df..138f449924f8 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1184,8 +1184,19 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode) + { + struct vop *vop = to_vop(crtc); ++ const struct vop_rect *max_output = &vop->data->max_output; + unsigned long rate; + ++ if (max_output->width && max_output->height) { ++ enum drm_mode_status status; ++ ++ status = drm_mode_validate_size(adjusted_mode, ++ max_output->width, ++ max_output->height); ++ if (status != MODE_OK) ++ return false; ++ } ++ + /* + * Clock craziness. + * + +From 8af324175e002a9ee48be8618dce51ffc348a409 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 15 Jul 2020 15:24:47 +0000 +Subject: [PATCH] drm/rockchip: vop: fix crtc duplicate state + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 138f449924f8..0a25de483515 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1578,7 +1578,11 @@ static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc) + { + struct rockchip_crtc_state *rockchip_state; + +- rockchip_state = kzalloc(sizeof(*rockchip_state), GFP_KERNEL); ++ if (WARN_ON(!crtc->state)) ++ return NULL; ++ ++ rockchip_state = kmemdup(to_rockchip_crtc_state(crtc->state), ++ sizeof(*rockchip_state), GFP_KERNEL); + if (!rockchip_state) + return NULL; + + +From cf2f0b3497dd7094b96d0f61d71e07927aae3e0c Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 15:15:50 +0000 +Subject: [PATCH] WIP: drm/rockchip: vop: filter interlaced modes + +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 0a25de483515..5ab1412173a7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1160,6 +1160,9 @@ static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, + if (s->output_type != DRM_MODE_CONNECTOR_HDMIA) + return MODE_OK; + ++ if (mode->flags & DRM_MODE_FLAG_INTERLACE) ++ return MODE_NO_INTERLACE; ++ + rounded_rate = clk_round_rate(vop->dclk, mode->clock * 1000 + 999); + if (rounded_rate < 0) + return MODE_NOCLOCK; + +From 1400714403b22c227d281c8fc5a3c07cc6312740 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:42 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: add bridge and switch to + drm_bridge_funcs + +Switch the dw-hdmi driver to drm_bridge_funcs by implementing +a new local bridge, connecting it to the dw-hdmi bridge. + +Also enable bridge format negotiation by implementing +atomic_get_input_bus_fmts and support for 8-bit RGB 4:4:4. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 138 ++++++++++++++------ + 1 file changed, 95 insertions(+), 43 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index cc20a83fa9b8..745fd1c13cef 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -68,6 +68,7 @@ struct rockchip_hdmi { + struct device *dev; + struct regmap *regmap; + struct drm_encoder encoder; ++ struct drm_bridge bridge; + const struct rockchip_hdmi_chip_data *chip_data; + struct clk *vpll_clk; + struct clk *grf_clk; +@@ -228,30 +229,20 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + return drm_mode_validate_size(mode, 3840, 2160); + } + +-static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) ++static void ++dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) + { +-} ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); + +-static bool +-dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, +- const struct drm_display_mode *mode, +- struct drm_display_mode *adj_mode) +-{ +- return true; ++ clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); + } + +-static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, +- struct drm_display_mode *mode, +- struct drm_display_mode *adj_mode) ++static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) + { +- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); +- +- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); +-} +- +-static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) +-{ +- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_encoder *encoder = bridge->encoder; + u32 val; + int ret; + +@@ -279,10 +270,21 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) + ret ? "LIT" : "BIG"); + } + ++static bool is_rgb(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int +-dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, +- struct drm_crtc_state *crtc_state, +- struct drm_connector_state *conn_state) ++dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) + { + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + +@@ -292,12 +294,38 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, + return 0; + } + +-static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { +- .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, +- .mode_set = dw_hdmi_rockchip_encoder_mode_set, +- .enable = dw_hdmi_rockchip_encoder_enable, +- .disable = dw_hdmi_rockchip_encoder_disable, +- .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, ++static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state, ++ u32 output_fmt, ++ unsigned int *num_input_fmts) ++{ ++ u32 *input_fmt; ++ ++ *num_input_fmts = 0; ++ ++ if (!is_rgb(output_fmt)) ++ return NULL; ++ ++ input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); ++ if (!input_fmt) ++ return NULL; ++ ++ *num_input_fmts = 1; ++ *input_fmt = output_fmt; ++ ++ return input_fmt; ++} ++ ++static const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = { ++ .mode_set = dw_hdmi_rockchip_bridge_mode_set, ++ .enable = dw_hdmi_rockchip_bridge_enable, ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_get_input_bus_fmts = dw_hdmi_rockchip_get_input_bus_fmts, ++ .atomic_check = dw_hdmi_rockchip_bridge_atomic_check, ++ .atomic_reset = drm_atomic_helper_bridge_reset, + }; + + static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, +@@ -476,6 +504,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + struct dw_hdmi_plat_data *plat_data; + const struct of_device_id *match; + struct drm_device *drm = data; ++ struct drm_bridge *next_bridge; + struct drm_encoder *encoder; + struct rockchip_hdmi *hdmi; + int ret; +@@ -516,8 +545,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + + ret = clk_prepare_enable(hdmi->vpll_clk); + if (ret) { +- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n", +- ret); ++ DRM_DEV_ERROR(hdmi->dev, "Failed to enable vpll: %d\n", ret); + return ret; + } + +@@ -525,27 +553,51 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->phy)) { + ret = PTR_ERR(hdmi->phy); + if (ret != -EPROBE_DEFER) +- DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); +- return ret; ++ DRM_DEV_ERROR(hdmi->dev, "Failed to get phy: %d\n", ret); ++ goto err_disable_clk; + } + +- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); +- drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); ++ ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); ++ if (ret) { ++ DRM_DEV_ERROR(hdmi->dev, "Failed to init encoder: %d\n", ret); ++ goto err_disable_clk; ++ } + +- platform_set_drvdata(pdev, hdmi); ++ hdmi->bridge.funcs = &dw_hdmi_rockchip_bridge_funcs; ++ drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0); + +- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); ++ platform_set_drvdata(pdev, hdmi); + +- /* +- * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), +- * which would have called the encoder cleanup. Do it manually. +- */ ++ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi->hdmi)) { + ret = PTR_ERR(hdmi->hdmi); +- drm_encoder_cleanup(encoder); +- clk_disable_unprepare(hdmi->vpll_clk); ++ if (ret != -EPROBE_DEFER) ++ DRM_DEV_ERROR(hdmi->dev, "Failed to init dw-hdmi bridge: %d\n", ret); ++ goto err_encoder_cleanup; ++ } ++ ++ next_bridge = of_drm_find_bridge(pdev->dev.of_node); ++ if (!next_bridge) { ++ ret = -EPROBE_DEFER; ++ goto err_dw_hdmi_remove; ++ } ++ ++ ret = drm_bridge_attach(encoder, next_bridge, &hdmi->bridge, 0); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ DRM_DEV_ERROR(hdmi->dev, "Failed to attach dw-hdmi bridge: %d\n", ret); ++ goto err_dw_hdmi_remove; + } + ++ return 0; ++ ++err_dw_hdmi_remove: ++ dw_hdmi_remove(hdmi->hdmi); ++err_encoder_cleanup: ++ drm_encoder_cleanup(encoder); ++err_disable_clk: ++ clk_disable_unprepare(hdmi->vpll_clk); ++ + return ret; + } + +@@ -554,7 +606,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, + { + struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); + +- dw_hdmi_unbind(hdmi->hdmi); ++ dw_hdmi_remove(hdmi->hdmi); + clk_disable_unprepare(hdmi->vpll_clk); + } + + +From ea791312a81f11f719a019e30c7736e7ab314739 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 18:00:44 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: add mtmdsclock parameter to phy + configure ops + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 10 ++++++---- + drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c | 3 ++- + include/drm/bridge/dw_hdmi.h | 3 ++- + 3 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 0c79a9ba48bb..50199329ad6f 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -137,7 +137,8 @@ struct dw_hdmi_phy_data { + bool has_svsret; + int (*configure)(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *pdata, +- unsigned long mpixelclock); ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock); + }; + + struct dw_hdmi { +@@ -1441,7 +1442,8 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi) + */ + static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *pdata, +- unsigned long mpixelclock) ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock) + { + const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; + const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; +@@ -1516,9 +1518,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, + + /* Write to the PHY as configured by the platform */ + if (pdata->configure_phy) +- ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock); ++ ret = pdata->configure_phy(hdmi, pdata->priv_data, mpixelclock, mtmdsclock); + else +- ret = phy->configure(hdmi, pdata, mpixelclock); ++ ret = phy->configure(hdmi, pdata, mpixelclock, mtmdsclock); + if (ret) { + dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n", + mpixelclock); +diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +index 7b8ec8310699..539d86131fd4 100644 +--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c ++++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c +@@ -53,7 +53,8 @@ rcar_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + } + + static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi, void *data, +- unsigned long mpixelclock) ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock) + { + const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params; + +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index ea34ca146b82..4f61ede6486d 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -152,7 +152,8 @@ struct dw_hdmi_plat_data { + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; + int (*configure_phy)(struct dw_hdmi *hdmi, void *data, +- unsigned long mpixelclock); ++ unsigned long mpixelclock, ++ unsigned long mtmdsclock); + }; + + struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, + +From 0ea5bddefeeecd75d9dbee409ad8a8fddff6d378 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 21:34:48 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: support configuring phy for deep color + +Q: Should we rename dw_hdmi_curr_ctrl and dw_hdmi_phy_config mpixelclock to mtmdsclock ? + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 50199329ad6f..2581789178c7 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1448,6 +1448,7 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; + const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; + const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; ++ int depth; + + /* TOFIX Will need 420 specific PHY configuration tables */ + +@@ -1457,11 +1458,11 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + break; + + for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) +- if (mpixelclock <= curr_ctrl->mpixelclock) ++ if (mtmdsclock <= curr_ctrl->mpixelclock) + break; + + for (; phy_config->mpixelclock != ~0UL; phy_config++) +- if (mpixelclock <= phy_config->mpixelclock) ++ if (mtmdsclock <= phy_config->mpixelclock) + break; + + if (mpll_config->mpixelclock == ~0UL || +@@ -1469,11 +1470,17 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + phy_config->mpixelclock == ~0UL) + return -EINVAL; + +- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, ++ depth = hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format); ++ if (depth > 8 && mpixelclock != mtmdsclock) ++ depth = fls(depth - 8) - 1; ++ else ++ depth = 0; ++ ++ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].cpce, + HDMI_3D_TX_PHY_CPCE_CTRL); +- dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, ++ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[depth].gmp, + HDMI_3D_TX_PHY_GMPCTRL); +- dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], ++ dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[depth], + HDMI_3D_TX_PHY_CURRCTRL); + + dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL); + +From 153e20ab5fd968cb5aff1e0cd7191d1ca1a6744e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 20 Jul 2020 22:25:15 +0000 +Subject: [PATCH] drm/bridge: dw-hdmi: add mpll_cfg_420 for ycbcr420 mode + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 +++- + include/drm/bridge/dw_hdmi.h | 1 + + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 2581789178c7..6d319b95b992 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1450,7 +1450,9 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, + const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; + int depth; + +- /* TOFIX Will need 420 specific PHY configuration tables */ ++ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) && ++ pdata->mpll_cfg_420) ++ mpll_config = pdata->mpll_cfg_420; + + /* PLL/MPLL Cfg - always match on final entry */ + for (; mpll_config->mpixelclock != ~0UL; mpll_config++) +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 4f61ede6486d..0ebe01835d2a 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -149,6 +149,7 @@ struct dw_hdmi_plat_data { + + /* Synopsys PHY support */ + const struct dw_hdmi_mpll_config *mpll_cfg; ++ const struct dw_hdmi_mpll_config *mpll_cfg_420; + const struct dw_hdmi_curr_ctrl *cur_ctr; + const struct dw_hdmi_phy_config *phy_config; + int (*configure_phy)(struct dw_hdmi *hdmi, void *data, + +From 21174838c2d39a88ea46dbf64ced1ac133f32e7c Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 15 Jul 2020 09:49:21 +0000 +Subject: [PATCH] drm/rockchip: dw-hdmi: mode_valid: allow 420 clock rate + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 745fd1c13cef..9784111ea746 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -222,8 +222,15 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) + { +- if (mode->clock > 340000 || +- (info->max_tmds_clock && mode->clock > info->max_tmds_clock)) ++ struct dw_hdmi_plat_data *pdata = (struct dw_hdmi_plat_data *)data; ++ int clock = mode->clock; ++ ++ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) ++ clock /= 2; ++ ++ if (clock > 340000 || ++ (info->max_tmds_clock && clock > info->max_tmds_clock)) + return MODE_CLOCK_HIGH; + + return drm_mode_validate_size(mode, 3840, 2160); +@@ -524,6 +531,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, + + hdmi->dev = &pdev->dev; + hdmi->chip_data = plat_data->phy_data; ++ plat_data->priv_data = plat_data; + plat_data->phy_data = hdmi; + encoder = &hdmi->encoder; + + +From fbf69694a8f832cfa942f16a4bd8a630aa8f0f3f Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/bridge: dw-hdmi: limit mode and bus format to + max_tmds_clock + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 120 ++++++++++++++-------- + 1 file changed, 76 insertions(+), 44 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6d319b95b992..c2425d7fc465 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1859,6 +1859,21 @@ static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi, + HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN); + } + ++static unsigned int ++hdmi_get_tmdsclock(unsigned int bus_format, unsigned int pixelclock) ++{ ++ int color_depth = hdmi_bus_fmt_color_depth(bus_format); ++ unsigned int tmdsclock = pixelclock; ++ ++ if (!hdmi_bus_fmt_is_yuv422(bus_format) && color_depth > 8) ++ tmdsclock = (u64)pixelclock * color_depth / 8; ++ ++ if (hdmi_bus_fmt_is_yuv420(bus_format)) ++ tmdsclock /= 2; ++ ++ return tmdsclock; ++} ++ + static void hdmi_av_composer(struct dw_hdmi *hdmi, + const struct drm_display_info *display, + const struct drm_display_mode *mode) +@@ -1870,29 +1885,11 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, + unsigned int vdisplay, hdisplay; + + vmode->mpixelclock = mode->clock * 1000; ++ vmode->mtmdsclock = ++ hdmi_get_tmdsclock(hdmi->hdmi_data.enc_out_bus_format, ++ vmode->mpixelclock); + + dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); +- +- vmode->mtmdsclock = vmode->mpixelclock; +- +- if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) { +- switch (hdmi_bus_fmt_color_depth( +- hdmi->hdmi_data.enc_out_bus_format)) { +- case 16: +- vmode->mtmdsclock = vmode->mpixelclock * 2; +- break; +- case 12: +- vmode->mtmdsclock = vmode->mpixelclock * 3 / 2; +- break; +- case 10: +- vmode->mtmdsclock = vmode->mpixelclock * 5 / 4; +- break; +- } +- } +- +- if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) +- vmode->mtmdsclock /= 2; +- + dev_dbg(hdmi->dev, "final tmdsclock = %d\n", vmode->mtmdsclock); + + /* Set up HDMI_FC_INVIDCONF */ +@@ -2544,8 +2541,21 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) + * - MEDIA_BUS_FMT_RGB888_1X24, + */ + +-/* Can return a maximum of 11 possible output formats for a mode/connector */ +-#define MAX_OUTPUT_SEL_FORMATS 11 ++/* Can return a maximum of 15 possible output formats for a mode/connector */ ++#define MAX_OUTPUT_SEL_FORMATS 15 ++ ++static bool is_tmds_allowed(struct drm_display_info *info, ++ struct drm_display_mode *mode, ++ u32 bus_format) ++{ ++ unsigned long tmdsclock = hdmi_get_tmdsclock(bus_format, mode->clock); ++ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000; ++ ++ if (max_tmds_clock >= tmdsclock) ++ return true; ++ ++ return false; ++} + + static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, +@@ -2557,8 +2567,6 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_display_info *info = &conn->display_info; + struct drm_display_mode *mode = &crtc_state->mode; + u8 max_bpc = conn_state->max_requested_bpc; +- bool is_hdmi2_sink = info->hdmi.scdc.supported || +- (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); + u32 *output_fmts; + unsigned int i = 0; + +@@ -2581,29 +2589,33 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + * If the current mode enforces 4:2:0, force the output but format + * to 4:2:0 and do not add the YUV422/444/RGB formats + */ +- if (conn->ycbcr_420_allowed && +- (drm_mode_is_420_only(info, mode) || +- (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) { ++ if (conn->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) { + + /* Order bus formats from 16bit to 8bit if supported */ + if (max_bpc >= 16 && info->bpc == 16 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY16_0_5X48)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48; + + if (max_bpc >= 12 && info->bpc >= 12 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY12_0_5X36)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36; + + if (max_bpc >= 10 && info->bpc >= 10 && +- (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)) ++ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY10_0_5X30)) + output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30; + + /* Default 8bit fallback */ +- output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYYVYY8_0_5X24)) ++ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24; + + *num_output_fmts = i; + +- return output_fmts; ++ if (drm_mode_is_420_only(info, mode)) ++ return output_fmts; + } + + /* +@@ -2612,40 +2624,51 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + */ + + if (max_bpc >= 16 && info->bpc == 16) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV16_1X48)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB161616_1X48)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; + } + + if (max_bpc >= 12 && info->bpc >= 12) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY12_1X24)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV12_1X36)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB121212_1X36)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; + } + + if (max_bpc >= 10 && info->bpc >= 10) { +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY10_1X20)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV10_1X30)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; + +- output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB101010_1X30)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; + } + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB422) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_UYVY8_1X16)) + output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; + +- if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ if ((info->color_formats & DRM_COLOR_FORMAT_YCRCB444) && ++ is_tmds_allowed(info, mode, MEDIA_BUS_FMT_YUV8_1X24)) + output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; + + /* Default 8bit RGB fallback */ +- output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ if (is_tmds_allowed(info, mode, MEDIA_BUS_FMT_RGB888_1X24)) ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; + + *num_output_fmts = i; + +@@ -2825,11 +2848,20 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + struct dw_hdmi *hdmi = bridge->driver_private; + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; + enum drm_mode_status mode_status = MODE_OK; ++ int max_tmds_clock = info->max_tmds_clock ? info->max_tmds_clock : 340000; ++ int clock = mode->clock; + + /* We don't support double-clocked modes */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + ++ if (pdata->ycbcr_420_allowed && drm_mode_is_420(info, mode) && ++ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420)) ++ clock /= 2; ++ ++ if (clock > max_tmds_clock) ++ return MODE_CLOCK_HIGH; ++ + if (pdata->mode_valid) + mode_status = pdata->mode_valid(hdmi, pdata->priv_data, info, + mode); + +From 6e9f31fe455b92a19f12c4bae9c9f4b00efde58e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:42 +0000 +Subject: [PATCH] WIP: drm/rockchip: dw_hdmi: add 10-bit rgb bus format + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 + + 2 files changed, 43 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index 9784111ea746..ddff1582b271 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -77,6 +77,7 @@ struct rockchip_hdmi { + }; + + #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) ++#define to_crtc_state(x) container_of(x, struct drm_crtc_state, x) + + static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + { +@@ -242,6 +243,11 @@ dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *adjusted_mode) + { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_crtc_state *crtc_state = to_crtc_state(adjusted_mode); ++ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); ++ ++ if (hdmi->phy) ++ phy_set_bus_width(hdmi->phy, s->bus_width); + + clk_set_rate(hdmi->vpll_clk, adjusted_mode->clock * 1000); + } +@@ -280,6 +286,7 @@ static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge) + static bool is_rgb(u32 format) + { + switch (format) { ++ case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_RGB888_1X24: + return true; + default: +@@ -287,6 +294,16 @@ static bool is_rgb(u32 format) + } + } + ++static bool is_10bit(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static int + dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, +@@ -294,9 +311,24 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_connector_state *conn_state) + { + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); ++ struct drm_atomic_state *state = bridge_state->base.state; ++ struct drm_crtc_state *old_crtc_state; ++ struct rockchip_crtc_state *old_state; ++ u32 format = bridge_state->output_bus_cfg.format; + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; ++ s->output_bpc = 10; ++ s->bus_format = format; ++ s->bus_width = is_10bit(format) ? 10 : 8; ++ ++ old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); ++ if (old_crtc_state && !crtc_state->mode_changed) { ++ old_state = to_rockchip_crtc_state(old_crtc_state); ++ if (s->bus_format != old_state->bus_format || ++ s->bus_width != old_state->bus_width) ++ crtc_state->mode_changed = true; ++ } + + return 0; + } +@@ -308,10 +340,19 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + u32 output_fmt, + unsigned int *num_input_fmts) + { ++ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); ++ struct drm_encoder *encoder = bridge->encoder; + u32 *input_fmt; ++ bool has_10bit = true; + + *num_input_fmts = 0; + ++ if (drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder)) ++ has_10bit = false; ++ ++ if (!has_10bit && is_10bit(output_fmt)) ++ return NULL; ++ + if (!is_rgb(output_fmt)) + return NULL; + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +index e33c2dcd0d4b..03944e08b6c7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +@@ -31,6 +31,8 @@ struct rockchip_crtc_state { + int output_bpc; + int output_flags; + bool enable_afbc; ++ u32 bus_format; ++ int bus_width; + }; + #define to_rockchip_crtc_state(s) \ + container_of(s, struct rockchip_crtc_state, base) + +From 83871fb221f71065f78cff3c8019f8684481a155 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 8 Dec 2019 23:42:44 +0000 +Subject: [PATCH] WIP: drm: dw-hdmi: add content type connector property + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index c2425d7fc465..f86b8fa40ab6 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1646,6 +1646,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + const struct drm_connector *connector, + const struct drm_display_mode *mode) + { ++ const struct drm_connector_state *conn_state = connector->state; + struct hdmi_avi_infoframe frame; + u8 val; + +@@ -1703,6 +1704,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + } + ++ drm_hdmi_avi_infoframe_content_type(&frame, conn_state); ++ + /* + * The Designware IP uses a different byte format from standard + * AVI info frames, though generally the bits are in the correct +@@ -2431,7 +2434,8 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, + if (!crtc) + return 0; + +- if (!hdr_metadata_equal(old_state, new_state)) { ++ if (!hdr_metadata_equal(old_state, new_state) || ++ old_state->content_type != new_state->content_type) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); +@@ -2499,6 +2503,8 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi) + + drm_connector_attach_max_bpc_property(connector, 8, 16); + ++ drm_connector_attach_content_type_property(connector); ++ + if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) + drm_object_attach_property(&connector->base, + connector->dev->mode_config.hdr_output_metadata_property, 0); + +From 553cc49748b8f0d074735f18cd45f050fca567e7 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/rockchip: add yuv444 support + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 30 ++++++++++++++++++++- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 ++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 6 +++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 14 ++++++++++ + 4 files changed, 78 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index ddff1582b271..eea8e1491204 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -62,6 +62,7 @@ struct rockchip_hdmi_chip_data { + int lcdsel_grf_reg; + u32 lcdsel_big; + u32 lcdsel_lit; ++ bool ycbcr_444_allowed; + }; + + struct rockchip_hdmi { +@@ -294,10 +295,22 @@ static bool is_rgb(u32 format) + } + } + ++static bool is_yuv444(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static bool is_10bit(u32 format) + { + switch (format) { + case MEDIA_BUS_FMT_RGB101010_1X30: ++ case MEDIA_BUS_FMT_YUV10_1X30: + return true; + default: + return false; +@@ -314,12 +327,22 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_atomic_state *state = bridge_state->base.state; + struct drm_crtc_state *old_crtc_state; + struct rockchip_crtc_state *old_state; ++ struct drm_bridge *next_bridge; ++ struct drm_bridge_state *next_bridge_state; + u32 format = bridge_state->output_bus_cfg.format; + + s->output_mode = ROCKCHIP_OUT_MODE_AAAA; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; + s->output_bpc = 10; + s->bus_format = format; ++ ++ next_bridge = drm_bridge_get_next_bridge(bridge); ++ if (next_bridge) { ++ next_bridge_state = drm_atomic_get_new_bridge_state(state, ++ next_bridge); ++ format = next_bridge_state->output_bus_cfg.format; ++ } ++ + s->bus_width = is_10bit(format) ? 10 : 8; + + old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); +@@ -353,7 +376,10 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + if (!has_10bit && is_10bit(output_fmt)) + return NULL; + +- if (!is_rgb(output_fmt)) ++ if (is_yuv444(output_fmt)) { ++ if (!hdmi->chip_data->ycbcr_444_allowed) ++ return NULL; ++ } else if (!is_rgb(output_fmt)) + return NULL; + + input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL); +@@ -502,6 +528,7 @@ static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = { + + static struct rockchip_hdmi_chip_data rk3328_chip_data = { + .lcdsel_grf_reg = -1, ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { +@@ -517,6 +544,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { + .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, + .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), + .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL), ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 5ab1412173a7..a17bd4e90ba7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -310,6 +310,17 @@ static int vop_convert_afbc_format(uint32_t format) + return -EINVAL; + } + ++static bool is_yuv_output(uint32_t bus_format) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, + uint32_t dst, bool is_horizontal, + int vsu_mode, int *vskiplines) +@@ -1329,6 +1340,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + u16 vact_end = vact_st + vdisplay; + uint32_t pin_pol, val; + int dither_bpc = s->output_bpc ? s->output_bpc : 10; ++ bool yuv_output = is_yuv_output(s->bus_format); + int ret; + + if (old_state && old_state->self_refresh_active) { +@@ -1402,6 +1414,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + ++ VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); ++ + if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) + VOP_REG_SET(vop, common, pre_dither_down, 1); + else +@@ -1417,6 +1431,21 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + + VOP_REG_SET(vop, common, out_mode, s->output_mode); + ++ VOP_REG_SET(vop, common, overlay_mode, yuv_output); ++ VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); ++ ++ /* ++ * Background color is 10bit depth if vop version >= 3.5 ++ */ ++ if (!yuv_output) ++ val = 0; ++ else if (VOP_MAJOR(vop_data->version) == 3 && ++ VOP_MINOR(vop_data->version) >= 5) ++ val = 0x20010200; ++ else ++ val = 0x801080; ++ VOP_REG_SET(vop, common, dsp_background, val); ++ + VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len); + val = hact_st << 16; + val |= hact_end; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 1516231bbf93..b820ad3fa091 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -92,10 +92,16 @@ struct vop_common { + struct vop_reg mmu_en; + struct vop_reg out_mode; + struct vop_reg standby; ++ ++ struct vop_reg overlay_mode; ++ struct vop_reg dsp_data_swap; ++ struct vop_reg dsp_out_yuv; ++ struct vop_reg dsp_background; + }; + + struct vop_misc { + struct vop_reg global_regdone_en; ++ struct vop_reg win_channel[4]; + }; + + struct vop_intr { +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 57c36e9207c1..800b9341dd42 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -644,6 +644,11 @@ static const struct vop_common rk3288_common = { + .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), ++ ++ .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), ++ .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), ++ .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), ++ .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), + }; + + /* +@@ -996,6 +1001,10 @@ static const struct vop_output rk3328_output = { + + static const struct vop_misc rk3328_misc = { + .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11), ++ ++ .win_channel[0] = VOP_REG(RK3328_WIN0_CTRL2, 0xff, 0), ++ .win_channel[1] = VOP_REG(RK3328_WIN1_CTRL2, 0xff, 0), ++ .win_channel[2] = VOP_REG(RK3328_WIN2_CTRL2, 0xff, 0), + }; + + static const struct vop_common rk3328_common = { +@@ -1008,6 +1017,11 @@ static const struct vop_common rk3328_common = { + .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18), + .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), ++ ++ .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), ++ .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), ++ .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), ++ .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + }; + + static const struct vop_intr rk3328_vop_intr = { + +From 6127108151898a2c69fb50749d7e647ac35cf8aa Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 20 Dec 2019 08:12:43 +0000 +Subject: [PATCH] WIP: drm/rockchip: add yuv420 support + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 23 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 18 +++++++++++++++- + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 10 +++++---- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 ++ + 4 files changed, 48 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index eea8e1491204..c25ebe31b98d 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -306,9 +306,21 @@ static bool is_yuv444(u32 format) + } + } + ++static bool is_yuv420(u32 format) ++{ ++ switch (format) { ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: ++ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static bool is_10bit(u32 format) + { + switch (format) { ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_RGB101010_1X30: + case MEDIA_BUS_FMT_YUV10_1X30: + return true; +@@ -345,6 +357,11 @@ dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge, + + s->bus_width = is_10bit(format) ? 10 : 8; + ++ if (is_yuv420(format)) { ++ s->output_mode = ROCKCHIP_OUT_MODE_YUV420; ++ s->bus_width /= 2; ++ } ++ + old_crtc_state = drm_atomic_get_old_crtc_state(state, conn_state->crtc); + if (old_crtc_state && !crtc_state->mode_changed) { + old_state = to_rockchip_crtc_state(old_crtc_state); +@@ -365,6 +382,7 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + { + struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge); + struct drm_encoder *encoder = bridge->encoder; ++ struct drm_connector *connector = conn_state->connector; + u32 *input_fmt; + bool has_10bit = true; + +@@ -379,6 +397,9 @@ static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge, + if (is_yuv444(output_fmt)) { + if (!hdmi->chip_data->ycbcr_444_allowed) + return NULL; ++ } else if (is_yuv420(output_fmt)) { ++ if (!connector->ycbcr_420_allowed) ++ return NULL; + } else if (!is_rgb(output_fmt)) + return NULL; + +@@ -538,6 +559,7 @@ static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { + .phy_name = "inno_dw_hdmi_phy2", + .phy_force_vendor = true, + .use_drm_infoframe = true, ++ .ycbcr_420_allowed = true, + }; + + static struct rockchip_hdmi_chip_data rk3399_chip_data = { +@@ -554,6 +576,7 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { + .phy_config = rockchip_phy_config, + .phy_data = &rk3399_chip_data, + .use_drm_infoframe = true, ++ .ycbcr_420_allowed = true, + }; + + static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index a17bd4e90ba7..5ea8031eb0f7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -311,6 +311,19 @@ static int vop_convert_afbc_format(uint32_t format) + } + + static bool is_yuv_output(uint32_t bus_format) ++{ ++ switch (bus_format) { ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_UYYVYY8_0_5X24: ++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static bool has_uv_swapped(uint32_t bus_format) + { + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: +@@ -1414,7 +1427,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) + s->output_mode = ROCKCHIP_OUT_MODE_P888; + +- VOP_REG_SET(vop, common, dsp_data_swap, yuv_output ? 2 : 0); ++ VOP_REG_SET(vop, common, dsp_data_swap, has_uv_swapped(s->bus_format) ? 2 : 0); + + if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) + VOP_REG_SET(vop, common, pre_dither_down, 1); +@@ -1431,6 +1444,9 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + + VOP_REG_SET(vop, common, out_mode, s->output_mode); + ++ VOP_REG_SET(vop, common, dclk_ddr, ++ s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0); ++ + VOP_REG_SET(vop, common, overlay_mode, yuv_output); + VOP_REG_SET(vop, common, dsp_out_yuv, yuv_output); + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index b820ad3fa091..8e6e999e5163 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -94,6 +94,7 @@ struct vop_common { + struct vop_reg standby; + + struct vop_reg overlay_mode; ++ struct vop_reg dclk_ddr; + struct vop_reg dsp_data_swap; + struct vop_reg dsp_out_yuv; + struct vop_reg dsp_background; +@@ -257,11 +258,12 @@ struct vop_data { + /* + * display output interface supported by rockchip lcdc + */ +-#define ROCKCHIP_OUT_MODE_P888 0 +-#define ROCKCHIP_OUT_MODE_P666 1 +-#define ROCKCHIP_OUT_MODE_P565 2 ++#define ROCKCHIP_OUT_MODE_P888 0 ++#define ROCKCHIP_OUT_MODE_P666 1 ++#define ROCKCHIP_OUT_MODE_P565 2 ++#define ROCKCHIP_OUT_MODE_YUV420 14 + /* for use special outface */ +-#define ROCKCHIP_OUT_MODE_AAAA 15 ++#define ROCKCHIP_OUT_MODE_AAAA 15 + + /* output flags */ + #define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0) +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 800b9341dd42..dd4546f9f410 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -646,6 +646,7 @@ static const struct vop_common rk3288_common = { + .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0), + + .overlay_mode = VOP_REG(RK3288_SYS_CTRL, 0x1, 16), ++ .dclk_ddr = VOP_REG(RK3288_DSP_CTRL0, 0x1, 8), + .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12), + .dsp_out_yuv = VOP_REG(RK3288_POST_SCL_CTRL, 0x1, 2), + .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0), +@@ -1019,6 +1020,7 @@ static const struct vop_common rk3328_common = { + .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0), + + .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16), ++ .dclk_ddr = VOP_REG(RK3328_DSP_CTRL0, 0x1, 8), + .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12), + .dsp_out_yuv = VOP_REG(RK3328_POST_SCL_CTRL, 0x1, 2), + .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0), + +From c70da56116a103e5f6bd154b7819217410a9c4f7 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 7 Jun 2020 20:25:25 +0000 +Subject: [PATCH] drm: drm_fourcc: add NV20 and NV30 YUV formats + +DRM_FORMAT_NV20 and DRM_FORMAT_NV30 formats is the 2x1 and non-subsampled +variant of NV15, a 10-bit 2-plane YUV format that has no padding between +components. Instead, luminance and chrominance samples are grouped into 4s +so that each group is packed into an integer number of bytes: + +YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes + +The '20' and '30' suffix refers to the optimum effective bits per pixel +which is achieved when the total number of luminance samples is a multiple +of 4. + +V2: Added NV30 format + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/drm_fourcc.c | 8 ++++++++ + include/uapi/drm/drm_fourcc.h | 2 ++ + 2 files changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c +index 722c7ebe4e88..2daf8a304b53 100644 +--- a/drivers/gpu/drm/drm_fourcc.c ++++ b/drivers/gpu/drm/drm_fourcc.c +@@ -278,6 +278,14 @@ const struct drm_format_info *__drm_format_info(u32 format) + .num_planes = 2, .char_per_block = { 5, 5, 0 }, + .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, + .vsub = 2, .is_yuv = true }, ++ { .format = DRM_FORMAT_NV20, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, ++ .vsub = 1, .is_yuv = true }, ++ { .format = DRM_FORMAT_NV30, .depth = 0, ++ .num_planes = 2, .char_per_block = { 5, 5, 0 }, ++ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 1, ++ .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_Q410, .depth = 0, + .num_planes = 3, .char_per_block = { 2, 2, 2 }, + .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0, +diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h +index 82f327801267..d8e6159213dc 100644 +--- a/include/uapi/drm/drm_fourcc.h ++++ b/include/uapi/drm/drm_fourcc.h +@@ -242,6 +242,8 @@ extern "C" { + * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian + */ + #define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */ + + /* + * 2 plane YCbCr MSB aligned + +From b41c8312d8bcd440bc42a799dd09b4acd9d4eca2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 7 Jun 2020 20:25:26 +0000 +Subject: [PATCH] drm: rockchip: add NV15, NV20 and NV30 support + +Add support for displaying 10-bit 4:2:0 and 4:2:2 formats produced by the +Rockchip Video Decoder on RK322X, RK3288, RK3328, RK3368 and RK3399. +Also add support for 10-bit 4:4:4 format while at it. + +V2: Added NV30 support + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 +++++++++++++++++-- + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 + + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 32 +++++++++++++++++---- + 3 files changed, 54 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 5ea8031eb0f7..413534cf1a93 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -261,6 +261,18 @@ static bool has_rb_swapped(uint32_t format) + } + } + ++static bool is_fmt_10(uint32_t format) ++{ ++ switch (format) { ++ case DRM_FORMAT_NV15: ++ case DRM_FORMAT_NV20: ++ case DRM_FORMAT_NV30: ++ return true; ++ default: ++ return false; ++ } ++} ++ + static enum vop_data_format vop_convert_format(uint32_t format) + { + switch (format) { +@@ -276,10 +288,13 @@ static enum vop_data_format vop_convert_format(uint32_t format) + case DRM_FORMAT_BGR565: + return VOP_FMT_RGB565; + case DRM_FORMAT_NV12: ++ case DRM_FORMAT_NV15: + return VOP_FMT_YUV420SP; + case DRM_FORMAT_NV16: ++ case DRM_FORMAT_NV20: + return VOP_FMT_YUV422SP; + case DRM_FORMAT_NV24: ++ case DRM_FORMAT_NV30: + return VOP_FMT_YUV444SP; + default: + DRM_ERROR("unsupported format[%08x]\n", format); +@@ -946,7 +961,12 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start; + dsp_st = dsp_sty << 16 | (dsp_stx & 0xffff); + +- offset = (src->x1 >> 16) * fb->format->cpp[0]; ++ if (fb->format->block_w[0]) ++ offset = (src->x1 >> 16) * fb->format->char_per_block[0] / ++ fb->format->block_w[0]; ++ else ++ offset = (src->x1 >> 16) * fb->format->cpp[0]; ++ + offset += (src->y1 >> 16) * fb->pitches[0]; + dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; + +@@ -972,6 +992,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + } + + VOP_WIN_SET(vop, win, format, format); ++ VOP_WIN_SET(vop, win, fmt_10, is_fmt_10(fb->format->format)); + VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); + VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); + VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); +@@ -988,7 +1009,11 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + uv_obj = fb->obj[1]; + rk_uv_obj = to_rockchip_obj(uv_obj); + +- offset = (src->x1 >> 16) * bpp / hsub; ++ if (fb->format->block_w[1]) ++ offset = (src->x1 >> 16) * bpp / ++ fb->format->block_w[1] / hsub; ++ else ++ offset = (src->x1 >> 16) * bpp / hsub; + offset += (src->y1 >> 16) * fb->pitches[1] / vsub; + + dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +index 8e6e999e5163..9f50e0e00127 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +@@ -161,6 +161,7 @@ struct vop_win_phy { + struct vop_reg enable; + struct vop_reg gate; + struct vop_reg format; ++ struct vop_reg fmt_10; + struct vop_reg rb_swap; + struct vop_reg act_info; + struct vop_reg dsp_info; +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index dd4546f9f410..7d5191421ddf 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -50,6 +50,23 @@ static const uint32_t formats_win_full[] = { + DRM_FORMAT_NV24, + }; + ++static const uint32_t formats_win_full_10[] = { ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ABGR8888, ++ DRM_FORMAT_RGB888, ++ DRM_FORMAT_BGR888, ++ DRM_FORMAT_RGB565, ++ DRM_FORMAT_BGR565, ++ DRM_FORMAT_NV12, ++ DRM_FORMAT_NV16, ++ DRM_FORMAT_NV24, ++ DRM_FORMAT_NV15, ++ DRM_FORMAT_NV20, ++ DRM_FORMAT_NV30, ++}; ++ + static const uint64_t format_modifiers_win_full[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +@@ -579,11 +596,12 @@ static const struct vop_scl_regs rk3288_win_full_scl = { + + static const struct vop_win_phy rk3288_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), +@@ -720,11 +738,12 @@ static const struct vop_intr rk3368_vop_intr = { + + static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12), + .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22), +@@ -871,11 +890,12 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = { + + static const struct vop_win_phy rk3399_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full, +- .nformats = ARRAY_SIZE(formats_win_full), ++ .data_formats = formats_win_full_10, ++ .nformats = ARRAY_SIZE(formats_win_full_10), + .format_modifiers = format_modifiers_win_full_afbc, + .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), ++ .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), + .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), + +From 478dd53361097d99541d777ce0f7fec7a79b7fa8 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 21:11:08 +0200 +Subject: [PATCH] !fixup drm/rockchip: rk3368's vop does not support 10-bit + formats + +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 7d5191421ddf..20c3e6248ec7 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -738,8 +738,8 @@ static const struct vop_intr rk3368_vop_intr = { + + static const struct vop_win_phy rk3368_win01_data = { + .scl = &rk3288_win_full_scl, +- .data_formats = formats_win_full_10, +- .nformats = ARRAY_SIZE(formats_win_full_10), ++ .data_formats = formats_win_full, ++ .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1), + +From 1f05ca5dfe7bd1553d32be9f450614b545be0912 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 23:20:34 +0200 +Subject: [PATCH] drm/rockchip: enable ycbcr_420_allowed and ycbcr_444_allowed + for RK3228 + +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +index c25ebe31b98d..5562326e4bce 100644 +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -515,6 +515,7 @@ static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { + + static struct rockchip_hdmi_chip_data rk3228_chip_data = { + .lcdsel_grf_reg = -1, ++ .ycbcr_444_allowed = true, + }; + + static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { +@@ -523,6 +524,7 @@ static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { + .phy_ops = &rk3228_hdmi_phy_ops, + .phy_name = "inno_dw_hdmi_phy2", + .phy_force_vendor = true, ++ .ycbcr_420_allowed = true, + }; + + static struct rockchip_hdmi_chip_data rk3288_chip_data = { + +From 4273e39fec795fe18f83414655d30b0b9c5420d9 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:28 +0200 +Subject: [PATCH] drm: rockchip: add scaling for RK3036 win1 + +Add the registers needed to make scaling work on RK3036's win1. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 20c3e6248ec7..93a00b6ac295 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -94,15 +94,20 @@ static const uint64_t format_modifiers_win_lite[] = { + DRM_FORMAT_MOD_INVALID, + }; + +-static const struct vop_scl_regs rk3036_win_scl = { ++static const struct vop_scl_regs rk3036_win0_scl = { + .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16), + }; + ++static const struct vop_scl_regs rk3036_win1_scl = { ++ .scale_yrgb_x = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 0x0), ++ .scale_yrgb_y = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 16), ++}; ++ + static const struct vop_win_phy rk3036_win0_data = { +- .scl = &rk3036_win_scl, ++ .scl = &rk3036_win0_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, +@@ -119,6 +124,7 @@ static const struct vop_win_phy rk3036_win0_data = { + }; + + static const struct vop_win_phy rk3036_win1_data = { ++ .scl = &rk3036_win1_scl, + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + +From a05d484d84e54a59c7846d2b409dda1e7355e3de Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:29 +0200 +Subject: [PATCH] drm: rockchip: add missing registers for RK3188 + +Add dither_up, dsp_lut_en and data_blank registers to enable their +respective functionality for RK3188's VOP. +While at that also fix .dsp_blank register which is (only) set though +BIT24 (same as RK3066) + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 93a00b6ac295..f8a898c5bb62 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -528,7 +528,10 @@ static const struct vop_common rk3188_common = { + .dither_down_sel = VOP_REG(RK3188_DSP_CTRL0, 0x1, 27), + .dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11), + .dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10), +- .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24), ++ .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 24), ++ .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9), ++ .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28), ++ .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25), + }; + + static const struct vop_win_data rk3188_vop_win_data[] = { + +From 6dd7876510c6a23e6d6b1243c730d73e6acb1137 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:44:12 +0200 +Subject: [PATCH] drm: rockchip: add missing registers for RK3066 + +Add dither_up, dsp_lut_en and data_blank registers to enable their +respective functionality for RK3066's VOP. +While at that also fix .rb_swap and .format registers for all windows, +which have to be set though RK3066_SYS_CTRL1. Also remove .scl from +win1: Scaling is only supported on the primary plane. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index f8a898c5bb62..77f8b49a4d17 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -372,8 +372,8 @@ static const struct vop_win_phy rk3066_win0_data = { + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0), +- .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4), +- .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19), ++ .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 4), ++ .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 19), + .act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0), +@@ -384,13 +384,12 @@ static const struct vop_win_phy rk3066_win0_data = { + }; + + static const struct vop_win_phy rk3066_win1_data = { +- .scl = &rk3066_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .format_modifiers = format_modifiers_win_full, + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1), +- .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7), +- .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23), ++ .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 7), ++ .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 23), + .act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0), +@@ -405,8 +404,8 @@ static const struct vop_win_phy rk3066_win2_data = { + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2), +- .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10), +- .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27), ++ .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 10), ++ .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 27), + .dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0), +@@ -431,6 +430,9 @@ static const struct vop_common rk3066_common = { + .dither_down_en = VOP_REG(RK3066_DSP_CTRL0, 0x1, 11), + .dither_down_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 10), + .dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24), ++ .dither_up = VOP_REG(RK3066_DSP_CTRL0, 0x1, 9), ++ .dsp_lut_en = VOP_REG(RK3066_SYS_CTRL1, 0x1, 31), ++ .data_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 25), + }; + + static const struct vop_win_data rk3066_vop_win_data[] = { + +From 08b0db205ddef2853dd75c0691d7d6d6f94c611b Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:13:30 +0200 +Subject: [PATCH] drm: rockchip: add alpha support for RK3036, RK3066, RK3126 + and RK3188 + +With commit 2aae8ed1f390 +("drm/rockchip: Add per-pixel alpha support for the PX30 VOP") alpha +support was introduced for PX30's VOP. +RK3036, RK3066, RK3126 and RK3188 VOPs support alpha blending in the +same manner. +With the exception of RK3066 all of them support pre-multiplied alpha. + +Lets add these registers to make this work for those VOPs as well. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 21 +++++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 77f8b49a4d17..27a04c5bc2fd 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -121,6 +121,9 @@ static const struct vop_win_phy rk3036_win0_data = { + .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 18), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 0), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_phy rk3036_win1_data = { +@@ -136,6 +139,9 @@ static const struct vop_win_phy rk3036_win1_data = { + .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_data rk3036_vop_win_data[] = { +@@ -202,6 +208,9 @@ static const struct vop_win_phy rk3126_win1_data = { + .dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3036_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_data rk3126_vop_win_data[] = { +@@ -381,6 +390,8 @@ static const struct vop_win_phy rk3066_win0_data = { + .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 21), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 0), + }; + + static const struct vop_win_phy rk3066_win1_data = { +@@ -397,6 +408,8 @@ static const struct vop_win_phy rk3066_win1_data = { + .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0), + .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 22), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 1), + }; + + static const struct vop_win_phy rk3066_win2_data = { +@@ -410,6 +423,8 @@ static const struct vop_win_phy rk3066_win2_data = { + .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0), ++ .alpha_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 23), ++ .alpha_en = VOP_REG(RK3066_BLEND_CTRL, 0x1, 2), + }; + + static const struct vop_modeset rk3066_modeset = { +@@ -495,6 +510,9 @@ static const struct vop_win_phy rk3188_win0_data = { + .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0), ++ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 18), ++ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 0), ++ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_win_phy rk3188_win1_data = { +@@ -509,6 +527,9 @@ static const struct vop_win_phy rk3188_win1_data = { + .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16), ++ .alpha_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 19), ++ .alpha_en = VOP_REG(RK3188_ALPHA_CTRL, 0x1, 1), ++ .alpha_pre_mul = VOP_REG(RK3188_DSP_CTRL0, 0x1, 29), + }; + + static const struct vop_modeset rk3188_modeset = { +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +index 6e9fa5815d4d..0b3cd65ba5c1 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +@@ -955,6 +955,7 @@ + #define RK3188_DSP_CTRL0 0x04 + #define RK3188_DSP_CTRL1 0x08 + #define RK3188_INT_STATUS 0x10 ++#define RK3188_ALPHA_CTRL 0x14 + #define RK3188_WIN0_YRGB_MST0 0x20 + #define RK3188_WIN0_CBR_MST0 0x24 + #define RK3188_WIN0_YRGB_MST1 0x28 + +From 9be348c6cade7e709be7347d336c7638bf603b46 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sat, 15 Aug 2020 23:38:05 +0200 +Subject: [PATCH] rockchip/drm: add dsp_data_swap register for RK3188 + +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index 27a04c5bc2fd..b47f036d4a2c 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -555,6 +555,7 @@ static const struct vop_common rk3188_common = { + .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9), + .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28), + .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25), ++ .dsp_data_swap = VOP_REG(RK3188_DSP_CTRL1, 0x1f, 26), + }; + + static const struct vop_win_data rk3188_vop_win_data[] = { + +From 195b202dbc5abe9c65e029826a7f3e2a2d71067a Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 22 Jul 2020 20:22:02 +0200 +Subject: [PATCH] rockchip/drm: add dsp_data_swap register for RK3066 + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index b47f036d4a2c..ae4a27704ad6 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -448,6 +448,7 @@ static const struct vop_common rk3066_common = { + .dither_up = VOP_REG(RK3066_DSP_CTRL0, 0x1, 9), + .dsp_lut_en = VOP_REG(RK3066_SYS_CTRL1, 0x1, 31), + .data_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 25), ++ .dsp_data_swap = VOP_REG(RK3066_DSP_CTRL1, 0x1f, 26), + }; + + static const struct vop_win_data rk3066_vop_win_data[] = { + +From 526739e44d5b0936db93bb92d2a98835723502c3 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 00:55:19 +0200 +Subject: [PATCH] drm/rockchip: inno hdmi - add audio support - add required + aclk - fix video timing - fix phy pre-emphasis + +--- + .../display/rockchip/inno_hdmi-rockchip.txt | 6 +- + arch/arm/boot/dts/rk3036.dtsi | 24 +- + drivers/gpu/drm/rockchip/inno_hdmi.c | 266 +++++++++++++++++- + drivers/gpu/drm/rockchip/inno_hdmi.h | 2 + + 4 files changed, 279 insertions(+), 19 deletions(-) + +diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +index cec21714f0e0..b022c931e186 100644 +--- a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt ++++ b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +@@ -7,7 +7,7 @@ Required properties: + - reg: + Physical base address and length of the controller's registers. + - clocks, clock-names: +- Phandle to hdmi controller clock, name should be "pclk" ++ Phandle to hdmi controller clock, name should be "aclk" and "pclk". + - interrupts: + HDMI interrupt number + - ports: +@@ -21,8 +21,8 @@ hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; +- clocks = <&cru PCLK_HDMI>; +- clock-names = "pclk"; ++ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>; ++ clock-names = "aclk", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; + +diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi +index d7668a437c70..a86e1dc7fb5b 100644 +--- a/arch/arm/boot/dts/rk3036.dtsi ++++ b/arch/arm/boot/dts/rk3036.dtsi +@@ -397,11 +397,14 @@ hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; +- clocks = <&cru PCLK_HDMI>; +- clock-names = "pclk"; ++ clocks = <&cru ACLK_VIO>, <&cru PCLK_HDMI>; ++ clock-names = "aclk", "pclk"; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + hdmi_in: port { +@@ -414,6 +417,23 @@ hdmi_in_vop: endpoint@0 { + }; + }; + ++ hdmi_sound: hdmi-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "HDMI"; ++ status = "disabled"; ++ ++ simple-audio-card,dai-link { ++ format = "i2s"; ++ mclk-fs = <256>; ++ cpu { ++ sound-dai = <&i2s>; ++ }; ++ codec { ++ sound-dai = <&hdmi>; ++ }; ++ }; ++ }; ++ + timer: timer@20044000 { + compatible = "rockchip,rk3036-timer", "rockchip,rk3288-timer"; + reg = <0x20044000 0x20>; +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c +index 7afdc54eb3ec..7e93208609a0 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.c ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -21,6 +22,8 @@ + #include + #include + ++#include ++ + #include "rockchip_drm_drv.h" + #include "rockchip_drm_vop.h" + +@@ -28,6 +31,12 @@ + + #define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x) + ++struct audio_info { ++ int sample_rate; ++ int channels; ++ int sample_width; ++}; ++ + struct hdmi_data_info { + int vic; + bool sink_is_hdmi; +@@ -52,8 +61,10 @@ struct inno_hdmi { + struct drm_device *drm_dev; + + int irq; ++ struct clk *aclk; + struct clk *pclk; + void __iomem *regs; ++ struct regmap *regmap; + + struct drm_connector connector; + struct drm_encoder encoder; +@@ -63,6 +74,9 @@ struct inno_hdmi { + + unsigned int tmds_rate; + ++ struct platform_device *audio_pdev; ++ bool audio_enable; ++ + struct hdmi_data_info hdmi_data; + struct drm_display_mode previous_mode; + }; +@@ -189,11 +203,17 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable) + + static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) + { ++ ++ u8 value; ++ + switch (mode) { + case NORMAL: + inno_hdmi_sys_power(hdmi, false); +- +- hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); ++ if (hdmi->tmds_rate > 140000000) ++ value = 0x6f; ++ else ++ value = 0x3f; ++ hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, value); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); + + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +@@ -301,6 +321,21 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, + return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0); + } + ++static int inno_hdmi_config_audio_aai(struct inno_hdmi *hdmi, ++ struct audio_info *audio) ++{ ++ struct hdmi_audio_infoframe *faudio; ++ union hdmi_infoframe frame; ++ int rc; ++ ++ rc = hdmi_audio_infoframe_init(&frame.audio); ++ faudio = (struct hdmi_audio_infoframe *)&frame; ++ ++ faudio->channels = audio->channels; ++ ++ return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AAI, 0, 0, 0); ++} ++ + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) + { + struct hdmi_data_info *data = &hdmi->hdmi_data; +@@ -383,6 +418,11 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + { + int value; + ++ value = BIT(20) | BIT(21); ++ value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BIT(4) : 0; ++ value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BIT(5) : 0; ++ regmap_write(hdmi->regmap, 0x148, value); ++ + /* Set detail external video timing polarity and interlace mode */ + value = v_EXTERANL_VIDEO(1); + value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? +@@ -402,7 +442,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); + +- value = mode->hsync_start - mode->hdisplay; ++ value = mode->htotal - mode->hsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); + +@@ -417,7 +457,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + value = mode->vtotal - mode->vdisplay; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); + +- value = mode->vsync_start - mode->vdisplay; ++ value = mode->vtotal - mode->vsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); + + value = mode->vsync_end - mode->vsync_start; +@@ -473,8 +513,9 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, + inno_hdmi_i2c_init(hdmi); + + /* Unmute video and audio output */ +- hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, +- v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_VIDEO_BLACK, v_VIDEO_MUTE(0)); ++ if (hdmi->audio_enable) ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE, v_AUDIO_MUTE(0)); + + return 0; + } +@@ -521,6 +562,7 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + + s->output_mode = ROCKCHIP_OUT_MODE_P888; + s->output_type = DRM_MODE_CONNECTOR_HDMIA; ++ s->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + return 0; + } +@@ -597,6 +639,175 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { + .mode_valid = inno_hdmi_connector_mode_valid, + }; + ++int inno_hdmi_audio_config_set(struct inno_hdmi *hdmi, struct audio_info *audio) ++{ ++ int rate, N, channel; ++ ++ if (audio->channels < 3) ++ channel = I2S_CHANNEL_1_2; ++ else if (audio->channels < 5) ++ channel = I2S_CHANNEL_3_4; ++ else if (audio->channels < 7) ++ channel = I2S_CHANNEL_5_6; ++ else ++ channel = I2S_CHANNEL_7_8; ++ ++ switch (audio->sample_rate) { ++ case 32000: ++ rate = AUDIO_32K; ++ N = N_32K; ++ break; ++ case 44100: ++ rate = AUDIO_441K; ++ N = N_441K; ++ break; ++ case 48000: ++ rate = AUDIO_48K; ++ N = N_48K; ++ break; ++ case 88200: ++ rate = AUDIO_882K; ++ N = N_882K; ++ break; ++ case 96000: ++ rate = AUDIO_96K; ++ N = N_96K; ++ break; ++ case 176400: ++ rate = AUDIO_1764K; ++ N = N_1764K; ++ break; ++ case 192000: ++ rate = AUDIO_192K; ++ N = N_192K; ++ break; ++ default: ++ dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", ++ __func__, audio->sample_rate); ++ return -ENOENT; ++ } ++ ++ /* set_audio source I2S */ ++ hdmi_writeb(hdmi, HDMI_AUDIO_CTRL1, 0x01); ++ hdmi_writeb(hdmi, AUDIO_SAMPLE_RATE, rate); ++ hdmi_writeb(hdmi, AUDIO_I2S_MODE, v_I2S_MODE(I2S_STANDARD) | ++ v_I2S_CHANNEL(channel)); ++ ++ hdmi_writeb(hdmi, AUDIO_I2S_MAP, 0x00); ++ hdmi_writeb(hdmi, AUDIO_I2S_SWAPS_SPDIF, 0); ++ ++ /* Set N value */ ++ hdmi_writeb(hdmi, AUDIO_N_H, (N >> 16) & 0x0F); ++ hdmi_writeb(hdmi, AUDIO_N_M, (N >> 8) & 0xFF); ++ hdmi_writeb(hdmi, AUDIO_N_L, N & 0xFF); ++ ++ /*Set hdmi nlpcm mode to support hdmi bitstream*/ ++ hdmi_writeb(hdmi, HDMI_AUDIO_CHANNEL_STATUS, v_AUDIO_STATUS_NLPCM(0)); ++ ++ return inno_hdmi_config_audio_aai(hdmi, audio); ++} ++ ++static int inno_hdmi_audio_hw_params(struct device *dev, void *data, ++ struct hdmi_codec_daifmt *daifmt, ++ struct hdmi_codec_params *params) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ struct audio_info audio = { ++ .sample_width = params->sample_width, ++ .sample_rate = params->sample_rate, ++ .channels = params->channels, ++ }; ++ ++ if (!hdmi->hdmi_data.sink_has_audio) { ++ dev_err(hdmi->dev, "Sink do not support audio!\n"); ++ return -ENODEV; ++ } ++ ++ if (!hdmi->encoder.crtc) ++ return -ENODEV; ++ ++ switch (daifmt->fmt) { ++ case HDMI_I2S: ++ break; ++ default: ++ dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); ++ return -EINVAL; ++ } ++ ++ return inno_hdmi_audio_config_set(hdmi, &audio); ++} ++ ++static void inno_hdmi_audio_shutdown(struct device *dev, void *data) ++{ ++ /* do nothing */ ++} ++ ++static int inno_hdmi_audio_digital_mute(struct device *dev, void *data, bool mute) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ ++ if (!hdmi->hdmi_data.sink_has_audio) { ++ dev_err(hdmi->dev, "Sink do not support audio!\n"); ++ return -ENODEV; ++ } ++ ++ hdmi->audio_enable = !mute; ++ ++ if (mute) ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD, ++ v_AUDIO_MUTE(1) | v_AUDIO_PD(1)); ++ else ++ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_AUDIO_PD, ++ v_AUDIO_MUTE(0) | v_AUDIO_PD(0)); ++ ++ return 0; ++} ++ ++static int inno_hdmi_audio_get_eld(struct device *dev, void *data, ++ uint8_t *buf, size_t len) ++{ ++ struct inno_hdmi *hdmi = dev_get_drvdata(dev); ++ struct drm_mode_config *config = &hdmi->encoder.dev->mode_config; ++ struct drm_connector *connector; ++ int ret = -ENODEV; ++ ++ mutex_lock(&config->mutex); ++ list_for_each_entry(connector, &config->connector_list, head) { ++ if (&hdmi->encoder == connector->encoder) { ++ memcpy(buf, connector->eld, ++ min(sizeof(connector->eld), len)); ++ ret = 0; ++ } ++ } ++ mutex_unlock(&config->mutex); ++ ++ return ret; ++} ++ ++static const struct hdmi_codec_ops audio_codec_ops = { ++ .hw_params = inno_hdmi_audio_hw_params, ++ .audio_shutdown = inno_hdmi_audio_shutdown, ++ //.digital_mute = inno_hdmi_audio_digital_mute, ++ .get_eld = inno_hdmi_audio_get_eld, ++}; ++ ++static int inno_hdmi_audio_codec_init(struct inno_hdmi *hdmi, ++ struct device *dev) ++{ ++ struct hdmi_codec_pdata codec_data = { ++ .i2s = 1, ++ .ops = &audio_codec_ops, ++ .max_i2s_channels = 8, ++ }; ++ ++ hdmi->audio_enable = false; ++ hdmi->audio_pdev = platform_device_register_data( ++ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_NONE, ++ &codec_data, sizeof(codec_data)); ++ ++ return PTR_ERR_OR_ZERO(hdmi->audio_pdev); ++} ++ + static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) + { + struct drm_encoder *encoder = &hdmi->encoder; +@@ -627,6 +838,8 @@ static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) + + drm_connector_attach_encoder(&hdmi->connector, encoder); + ++ inno_hdmi_audio_codec_init(hdmi, dev); ++ + return 0; + } + +@@ -826,23 +1039,44 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->regs)) + return PTR_ERR(hdmi->regs); + ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ hdmi->aclk = devm_clk_get(hdmi->dev, "aclk"); ++ if (IS_ERR(hdmi->aclk)) { ++ dev_err(hdmi->dev, "Unable to get HDMI aclk clk\n"); ++ return PTR_ERR(hdmi->aclk); ++ } ++ + hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); + if (IS_ERR(hdmi->pclk)) { + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); + return PTR_ERR(hdmi->pclk); + } + ++ ret = clk_prepare_enable(hdmi->aclk); ++ if (ret) { ++ DRM_DEV_ERROR(hdmi->dev, ++ "Cannot enable HDMI aclk clock: %d\n", ret); ++ return ret; ++ } ++ ++ + ret = clk_prepare_enable(hdmi->pclk); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI pclk clock: %d\n", ret); +- return ret; ++ goto err_disable_aclk; + } + +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) { +- ret = irq; +- goto err_disable_clk; ++ hdmi->regmap = ++ syscon_regmap_lookup_by_phandle(hdmi->dev->of_node, ++ "rockchip,grf"); ++ if (IS_ERR(hdmi->regmap)) { ++ dev_err(hdmi->dev, "Unable to get rockchip,grf\n"); ++ ret = PTR_ERR(hdmi->regmap); ++ goto err_disable_aclk; + } + + inno_hdmi_reset(hdmi); +@@ -851,7 +1085,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + if (IS_ERR(hdmi->ddc)) { + ret = PTR_ERR(hdmi->ddc); + hdmi->ddc = NULL; +- goto err_disable_clk; ++ goto err_disable_pclk; + } + + /* +@@ -884,9 +1118,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, + hdmi->encoder.funcs->destroy(&hdmi->encoder); + err_put_adapter: + i2c_put_adapter(hdmi->ddc); +-err_disable_clk: ++err_disable_pclk: + clk_disable_unprepare(hdmi->pclk); +- return ret; ++err_disable_aclk: ++ clk_disable_unprepare(hdmi->aclk); ++ ++return ret; + } + + static void inno_hdmi_unbind(struct device *dev, struct device *master, +@@ -899,6 +1136,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master, + + i2c_put_adapter(hdmi->ddc); + clk_disable_unprepare(hdmi->pclk); ++ clk_disable_unprepare(hdmi->aclk); + } + + static const struct component_ops inno_hdmi_ops = { +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h +index 93245b55f967..b722afc4e41f 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.h ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.h +@@ -96,11 +96,13 @@ enum { + #define HDMI_AV_MUTE 0x05 + #define m_AVMUTE_CLEAR (1 << 7) + #define m_AVMUTE_ENABLE (1 << 6) ++#define m_AUDIO_PD (1 << 2) + #define m_AUDIO_MUTE (1 << 1) + #define m_VIDEO_BLACK (1 << 0) + #define v_AVMUTE_CLEAR(n) (n << 7) + #define v_AVMUTE_ENABLE(n) (n << 6) + #define v_AUDIO_MUTE(n) (n << 1) ++#define v_AUDIO_PD(n) (n << 2) + #define v_VIDEO_MUTE(n) (n << 0) + + #define HDMI_VIDEO_TIMING_CTL 0x08 + +From a8d962000848a237f8e8f0de8395d4e7df2a7197 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Sun, 16 Aug 2020 23:40:24 +0200 +Subject: [PATCH] WIP: ARM: dts: rockchip add vpll clock to RK322Xs hdmi node + +--- + arch/arm/boot/dts/rk322x.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi +index 4bc631881c05..f98a945c68d3 100644 +--- a/arch/arm/boot/dts/rk322x.dtsi ++++ b/arch/arm/boot/dts/rk322x.dtsi +@@ -766,8 +766,8 @@ hdmi: hdmi@200a0000 { + interrupts = ; + assigned-clocks = <&cru SCLK_HDMI_PHY>; + assigned-clock-parents = <&hdmi_phy>; +- clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>; +- clock-names = "isfr", "iahb", "cec"; ++ clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&hdmi_phy>, <&cru SCLK_HDMI_CEC>; ++ clock-names = "isfr", "iahb", "vpll", "cec"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>; + resets = <&cru SRST_HDMI_P>; + +From 30c781872a7b883b18193fa5aed75c312b06f4ab Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 18 Nov 2017 11:09:39 +0100 +Subject: [PATCH] rockchip: vop: force skip lines if image too big + +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index 9b1cc0f413fc..a34ff7593e1f 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -932,6 +932,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + int format; + int is_yuv = fb->format->is_yuv; + int i; ++ int skiplines = 0; + + /* + * can't update plane when vop is disabled. +@@ -950,8 +951,14 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + obj = fb->obj[0]; + rk_obj = to_rockchip_obj(obj); + ++ /* ++ * Force skip lines when image is yuv and 3840 width, ++ * fixes a "jumping" green lines issue on RK3328. ++ */ + actual_w = drm_rect_width(src) >> 16; +- actual_h = drm_rect_height(src) >> 16; ++ if (actual_w == 3840 && is_yuv) ++ skiplines = 1; ++ actual_h = drm_rect_height(src) >> (16 + skiplines); + act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); + + dsp_info = (drm_rect_height(dest) - 1) << 16; +@@ -993,7 +1000,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + + VOP_WIN_SET(vop, win, format, format); + VOP_WIN_SET(vop, win, fmt_10, is_fmt_10(fb->format->format)); +- VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); ++ VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4 >> skiplines)); + VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); + VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); + VOP_WIN_SET(vop, win, y_mir_en, +@@ -1017,7 +1024,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, + offset += (src->y1 >> 16) * fb->pitches[1] / vsub; + + dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; +- VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); ++ VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4 >> skiplines)); + VOP_WIN_SET(vop, win, uv_mst, dma_addr); + + for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) { + +From b26ffb40570c456d0f84a3fa7886e2120c0397c2 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 26 May 2020 13:48:12 +0200 +Subject: [PATCH] drm: bridge: it66121: add IT66121FN variant + +--- + drivers/gpu/drm/bridge/ite-it66121.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 7e1a90319a6a..68f7e50fdddd 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -242,6 +242,11 @@ static const struct it66121_conf it66121_conf_simple = { + .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, + }; + ++static const struct it66121_conf it66121fn_conf_simple = { ++ .input_mode_reg = IT66121_INPUT_MODE_RGB, ++ .input_conversion_reg = IT66121_INPUT_CSC_NO_CONV, ++}; ++ + static void it66121_hw_reset(struct it66121_ctx *ctx) + { + gpiod_set_value(ctx->gpio_reset, 1); +@@ -970,6 +975,9 @@ static const struct of_device_id it66121_dt_match[] = { + { .compatible = "ite,it66121", + .data = &it66121_conf_simple, + }, ++ { .compatible = "ite,it66121fn", ++ .data = &it66121fn_conf_simple, ++ }, + { }, + }; + MODULE_DEVICE_TABLE(of, it66121_dt_match); + +From a52fbdfbb0bccb1202beb25b58bdc29517c178d2 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 23:15:45 +0200 +Subject: [PATCH] HACK: drm/rockchip: return false in ... if no platform device + is found + +This check will perfectly fail for bridges which are connected via i2c +and are therefore no platform devices. +TODO: look for a smarter solution + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +index b7654f5e4225..44ec8003e2a4 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +@@ -274,7 +274,7 @@ int rockchip_drm_endpoint_is_subdriver(struct device_node *ep) + pdev = of_find_device_by_node(node); + of_node_put(node); + if (!pdev) +- return -ENODEV; ++ return false; + + /* + * All rockchip subdrivers have probed at this point, so + +From 1fca49c650ba0441613da75e43323afb5525c8de Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 14:22:32 +0200 +Subject: [PATCH] drm/bridge: it66121 fix regmap config + +registers 0x00~0x2f don't need/must not have a selector +also: fix regmap range +--- + drivers/gpu/drm/bridge/ite-it66121.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 68f7e50fdddd..90f0881818d6 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -218,21 +218,21 @@ struct it66121_ctx { + + static const struct regmap_range_cfg it66121_regmap_banks[] = { + { +- .name = "it66121", +- .range_min = 0x00, +- .range_max = 0x1FF, ++ .name = "it66121-banks", ++ .range_min = 0x30, ++ .range_max = 0x1bf, + .selector_reg = IT66121_CLK_BANK_REG, + .selector_mask = 0x1, + .selector_shift = 0, +- .window_start = 0x00, +- .window_len = 0x130, ++ .window_start = 0x30, ++ .window_len = 0xcf, + }, + }; + + static const struct regmap_config it66121_regmap_config = { + .val_bits = 8, + .reg_bits = 8, +- .max_register = 0x1FF, ++ .max_register = 0x1bf, + .ranges = it66121_regmap_banks, + .num_ranges = ARRAY_SIZE(it66121_regmap_banks), + }; + +From 525f46ff24e5db028d341d04d1aede0cfc672c39 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 17:29:54 +0200 +Subject: [PATCH] drm/bridge: it66121 add detection message + +--- + drivers/gpu/drm/bridge/ite-it66121.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 90f0881818d6..650dd2f063cc 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -936,8 +936,11 @@ static int it66121_probe(struct i2c_client *client, + ids[2] != IT66121_DEVICE_ID0 || + ((ids[3] & IT66121_DEVICE_MASK) != IT66121_DEVICE_ID1)) { + ite66121_power_off(ctx); ++ DRM_INFO("HDMITX it66121 could not be indentified.\n"); + return -ENODEV; +- } ++ } else ++ DRM_INFO("HDMITX it66121 rev %d succsessfully indentified.\n", ++ ids[3] >> 4); + + ctx->bridge.funcs = &it66121_bridge_funcs; + ctx->bridge.of_node = dev->of_node; + +From ff31ba7e3c18672f7fa3ac17f9399301cc55cacb Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 22:28:21 +0200 +Subject: [PATCH] drm/bridge it66121 add AFE_XP_PLL_CTRL settings + +Add IT66121_AFE_XP_PLL_CTRL settings, it's unknown what they actualy +mean, since there is no documentation about it. Values have been taken +from vendor driver and it helps stablize signal at 1080p modes. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/bridge/ite-it66121.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 650dd2f063cc..bc6ca85e5ee1 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -72,6 +72,10 @@ + #define IT66121_AFE_XP_EC1_REG 0x68 + #define IT66121_AFE_XP_EC1_LOWCLK BIT(4) + ++#define IT66121_AFE_XP_PLL_CTRL 0x6a ++#define IT66121_AFE_XP_PLL_HIGH_CLK_MASK (BIT(4) | BIT(5) | \ ++ BIT(6)) ++ + #define IT66121_SW_RST_REG 0x04 + #define IT66121_SW_RST_REF BIT(5) + #define IT66121_SW_RST_AREF BIT(4) +@@ -325,6 +329,13 @@ static int it66121_configure_afe(struct it66121_ctx *ctx, + IT66121_AFE_XP_EC1_LOWCLK, 0x80); + if (ret) + return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_PLL_CTRL, ++ IT66121_AFE_XP_PLL_HIGH_CLK_MASK, ++ IT66121_AFE_XP_PLL_HIGH_CLK_MASK); ++ if (ret) ++ return ret; ++ + } else { + ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG, + IT66121_AFE_XP_GAINBIT | +@@ -346,6 +357,13 @@ static int it66121_configure_afe(struct it66121_ctx *ctx, + IT66121_AFE_XP_EC1_LOWCLK); + if (ret) + return ret; ++ ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_PLL_CTRL, ++ IT66121_AFE_XP_PLL_HIGH_CLK_MASK, ++ ~(IT66121_AFE_XP_PLL_HIGH_CLK_MASK) & 0xff); ++ if (ret) ++ return ret; + } + + /* Clear reset flags */ + +From 2a962b60c92993e1a1c82e74a403b33641d1cfbd Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Wed, 19 Aug 2020 19:02:02 +0200 +Subject: [PATCH] drm/bridge it66121 fire_afe if IT66121_SYS_STATUS_VID_STABLE + +There is an interrupt if video is stable - we should fire afe after that +arrived. + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/bridge/ite-it66121.c | 101 ++++++++++++++++++++++----- + 1 file changed, 83 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index bc6ca85e5ee1..81d1f53d50f5 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -95,12 +95,30 @@ + #define IT66121_HDCP_EN1P1FEAT BIT(1) + + #define IT66121_INT_STATUS1_REG 0x06 +-#define IT66121_INT_STATUS1_AUD_OVF BIT(7) +-#define IT66121_INT_STATUS1_DDC_NOACK BIT(5) +-#define IT66121_INT_STATUS1_DDC_FIFOERR BIT(4) +-#define IT66121_INT_STATUS1_DDC_BUSHANG BIT(2) +-#define IT66121_INT_STATUS1_RX_SENS_STATUS BIT(1) +-#define IT66121_INT_STATUS1_HPD_STATUS BIT(0) ++#define IT66121_INT_STATUS1_AUD_OVF BIT(7) ++#define IT66121_INT_STATUS1_DDC_NOACK BIT(5) ++#define IT66121_INT_STATUS1_DDC_FIFOERR BIT(4) ++#define IT66121_INT_STATUS1_DDC_BUSHANG BIT(2) ++#define IT66121_INT_STATUS1_RX_SENS_STATUS BIT(1) ++#define IT66121_INT_STATUS1_HPD_STATUS BIT(0) ++ ++#define IT66121_INT_STATUS2_REG 0x07 ++#define IT66121_INT_STATUS2_PKT_3D BIT(7) ++#define IT66121_INT_STATUS2_VID_UNSTABLE BIT(6) ++#define IT66121_INT_STATUS2_PKT_ACP BIT(5) ++#define IT66121_INT_STATUS2_PKT_NULL BIT(4) ++#define IT66121_INT_STATUS2_PKT_GEN BIT(3) ++#define IT66121_INT_STATUS2_CHK_KSV_LIST BIT(2) ++#define IT66121_INT_STATUS2_AUTH_DONE BIT(1) ++#define IT66121_INT_STATUS2_AUTH_FAIL BIT(0) ++ ++#define IT66121_INT_STATUS3_REG 0x08 ++#define IT66121_INT_STATUS3_AUD_CTS BIT(6) ++#define IT66121_INT_STATUS3_VSYNC BIT(5) ++#define IT66121_INT_STATUS3_VID_STABLE BIT(4) ++#define IT66121_INT_STATUS2_PKT_MPEG BIT(3) ++#define IT66121_INT_STATUS3_PKT_AUD BIT(1) ++#define IT66121_INT_STATUS3_PKT_AVI BIT(0) + + #define IT66121_DDC_HEADER_REG 0x11 + #define IT66121_DDC_HEADER_HDCP 0x74 +@@ -132,16 +150,43 @@ + #define IT66121_INT_MASK1_RX_SENS BIT(1) + #define IT66121_INT_MASK1_HPD BIT(0) + ++#define IT66121_INT_MASK2_REG 0x0a ++#define IT66121_INT_MASK2_PKT_AVI BIT(7) ++#define IT66121_INT_MASK2_VID_UNSTABLE BIT(6) ++#define IT66121_INT_MASK2_PKT_ACP BIT(5) ++#define IT66121_INT_MASK2_PKT_NULL BIT(4) ++#define IT66121_INT_MASK2_PKT_GEN BIT(3) ++#define IT66121_INT_MASK2_CHK_KSV_LIST BIT(2) ++#define IT66121_INT_MASK2_AUTH_DONE BIT(1) ++#define IT66121_INT_MASK2_AUTH_FAIL BIT(0) ++ ++#define IT66121_INT_MASK3_REG 0x0b ++#define IT66121_INT_MASK3_PKT_3D BIT(6) ++#define IT66121_INT_MASK3_AUD_CTS BIT(5) ++#define IT66121_INT_MASK3_VSYNC BIT(4) ++#define IT66121_INT_MASK3_VID_STABLE BIT(3) ++#define IT66121_INT_MASK3_PKT_MPEG BIT(2) ++#define IT66121_INT_MASK3_PKT_AUD BIT(0) ++ + #define IT66121_INT_CLR1_REG 0x0C +-#define IT66121_INT_CLR1_PKTACP BIT(7) +-#define IT66121_INT_CLR1_PKTNULL BIT(6) +-#define IT66121_INT_CLR1_PKTGEN BIT(5) +-#define IT66121_INT_CLR1_KSVLISTCHK BIT(4) +-#define IT66121_INT_CLR1_AUTHDONE BIT(3) +-#define IT66121_INT_CLR1_AUTHFAIL BIT(2) ++#define IT66121_INT_CLR1_PKT_ACP BIT(7) ++#define IT66121_INT_CLR1_PKT_NULL BIT(6) ++#define IT66121_INT_CLR1_PKT_GEN BIT(5) ++#define IT66121_INT_CLR1_CHK_KSV_LIST BIT(4) ++#define IT66121_INT_CLR1_AUTH_DONE BIT(3) ++#define IT66121_INT_CLR1_AUTH_FAIL BIT(2) + #define IT66121_INT_CLR1_RX_SENS BIT(1) + #define IT66121_INT_CLR1_HPD BIT(0) + ++#define IT66121_INT_CLR2_REG 0x0d ++#define IT66121_INT_CLR2_VSYNC BIT(7) ++#define IT66121_INT_CLR2_VID_STABLE BIT(6) ++#define IT66121_INT_CLR2_PKT_MPEG BIT(5) ++#define IT66121_INT_CLR2_PKT_AUD BIT(3) ++#define IT66121_INT_CLR2_PKT_AVI BIT(2) ++#define IT66121_INT_CLR2_PKT_3D BIT(1) ++#define IT66121_INT_CLR2_VID_UNSTABLE BIT(0) ++ + #define IT66121_AV_MUTE_REG 0xC1 + #define IT66121_AV_MUTE_ON BIT(0) + #define IT66121_AV_MUTE_BLUESCR BIT(1) +@@ -371,10 +416,9 @@ static int it66121_configure_afe(struct it66121_ctx *ctx, + IT66121_SW_RST_REF | IT66121_SW_RST_VID, + ~(IT66121_SW_RST_REF | IT66121_SW_RST_VID) & + 0xFF); +- if (ret) +- return ret; + +- return it66121_fire_afe(ctx); ++ return ret; ++ + } + + static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx) +@@ -711,6 +755,12 @@ static int it66121_bridge_attach(struct drm_bridge *bridge, + return ret; + + /* Start interrupts */ ++ ret = regmap_write_bits(ctx->regmap, IT66121_INT_MASK3_REG, ++ IT66121_INT_MASK3_VID_STABLE, ++ ~(IT66121_INT_MASK3_VID_STABLE) & 0xff); ++ if (ret) ++ return ret; ++ + return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, + IT66121_INT_MASK1_DDC_NOACK | + IT66121_INT_MASK1_HPD | +@@ -847,18 +897,18 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = { + static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) + { + int ret; +- unsigned int val; ++ unsigned int val, sys_status; + struct it66121_ctx *ctx = dev_id; + struct device *dev = ctx->dev; + bool event = false; + + mutex_lock(&ctx->lock); + +- ret = regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &val); ++ ret = regmap_read(ctx->regmap, IT66121_SYS_STATUS_REG, &sys_status); + if (ret) + goto unlock; + +- if (val & IT66121_SYS_STATUS_ACTIVE_IRQ) { ++ if (sys_status & IT66121_SYS_STATUS_ACTIVE_IRQ) { + ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val); + if (ret) { + dev_err(dev, "Cannot read STATUS1_REG %d\n", ret); +@@ -882,6 +932,21 @@ static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) + } + } + ++ ret = regmap_read(ctx->regmap, IT66121_INT_STATUS3_REG, &val); ++ if (ret) { ++ dev_err(dev, "Cannot read STATUS3_REG %d\n", ret); ++ } else if (val) { ++ if (val & IT66121_INT_STATUS3_VID_STABLE) { ++ if (sys_status & IT66121_SYS_STATUS_VID_STABLE) ++ it66121_fire_afe(ctx); ++ ++ regmap_write_bits(ctx->regmap, ++ IT66121_INT_CLR2_REG, ++ IT66121_INT_CLR2_VID_STABLE, ++ IT66121_INT_CLR2_VID_STABLE); ++ } ++ } ++ + regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG, + IT66121_SYS_STATUS_CLEAR_IRQ, + IT66121_SYS_STATUS_CLEAR_IRQ); + +From 2ec0caed703ceb5aad46c162c1f3fde4789fd635 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 22:44:12 +0200 +Subject: [PATCH] drm/bridge it66121: add I2S sound support + +Add sound support for it66121 - todos: + - TODOs + - refactor some huge functions + - smarter error handling (whole driver) + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/bridge/Kconfig | 1 + + drivers/gpu/drm/bridge/ite-it66121.c | 685 +++++++++++++++++++++++++++ + 2 files changed, 686 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig +index 6fe281070602..fd026f7cb4ba 100644 +--- a/drivers/gpu/drm/bridge/Kconfig ++++ b/drivers/gpu/drm/bridge/Kconfig +@@ -64,6 +64,7 @@ config DRM_LONTIUM_LT9611 + config DRM_ITE_IT66121 + tristate "ITE IT66121 HDMI bridge" + depends on OF ++ select SND_SOC_HDMI_CODEC if SND_SOC + select DRM_KMS_HELPER + select REGMAP_I2C + help +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 81d1f53d50f5..98f3d68fe01f 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* ++ * Copyright (C) 2020 Alex Bee + * Copyright (C) 2020 BayLibre, SAS + * Author: Phong LE + * Copyright (C) 2018-2019, Artem Mygaiev +@@ -26,6 +27,9 @@ + #include + #include + ++#include ++#include ++ + #define IT66121_MASTER_SEL_REG 0x10 + #define IT66121_MASTER_SEL_HOST BIT(0) + +@@ -245,11 +249,149 @@ + #define IT66121_EDID_FIFO_SIZE 32 + #define IT66121_AFE_CLK_HIGH 80000 + ++#define IT66121_AUD_CLK_CTRL_REG 0x58 ++#define IT66121_AUD_AUT_IP_CLK BIT(0) ++#define IT66121_AUD_AUT_OVR_SMPL_CLK BIT(4) ++#define IT66121_AUD_EXT_MCLK_128FS (0 << 2) ++#define IT66121_AUD_EXT_MCLK_256FS BIT(2) ++#define IT66121_AUD_EXT_MCLK_512FS (2 << 2) ++#define IT66121_AUD_EXT_MCLK_1024FS (3 << 2) ++ ++#define IT66121_AUD_INFO_REG_SZ 5 ++#define IT66121_AUD_INFO_DB1_REG 0x168 ++#define IT66121_AUD_INFO_DB2_REG 0x169 ++#define IT66121_AUD_INFO_DB3_REG 0x16a ++#define IT66121_AUD_INFO_DB4_REG 0x16b ++#define IT66121_AUD_INFO_DB5_REG 0x16c ++#define IT66121_AUD_INFO_CSUM_REG 0x16d ++ ++#define IT66121_AUD_INFO_PKT_REG 0xce ++#define IT66121_AUD_INFO_PKT_ON BIT(0) ++#define IT66121_AUD_INFO_PKT_RPT BIT(1) ++ ++#define IT66121_AUD_PKT_N1_REG 0x133 ++#define IT66121_AUD_PKT_N2_REG 0x134 ++#define IT66121_AUD_PKT_N3_REG 0x135 ++ ++#define IT66121_AUD_PKT_CTS_MODE_REG 0xc5 ++#define IT66121_AUD_PKT_CTS_MODE_USER BIT(1) ++#define IT66121_AUD_PKT_CTS_MODE_AUTO_VAL 0 ++#define IT66121_AUD_PKT_CTS1_REG 0x130 ++#define IT66121_AUD_PKT_CTS2_REG 0x131 ++#define IT66121_AUD_PKT_CTS3_REG 0x132 ++#define IT66121_AUD_PKT_AUTO_CNT_CTS1_REG 0x135 ++#define IT66121_AUD_PKT_AUTO_CNT_CTS2_REG 0x136 ++#define IT66121_AUD_PKT_AUTO_CNT_CTS3_REG 0x137 ++ ++#define IT66121_AUD_CHST_MODE_REG 0x191 ++#define IT66121_AUD_CHST_MODE_NLPCM BIT(1) ++#define IT66121_AUD_CHST_CAT_REG 0x192 ++#define IT66121_AUD_CHST_SRCNUM_REG 0x193 ++#define IT66121_AUD_CHST_CHTNUM_REG 0x194 ++#define IT66121_AUD_CHST_CA_FS_REG 0x198 ++#define IT66121_AUD_CHST_OFS_WL_REG 0x199 ++ ++#define IT66121_AUD_CTRL0_REG 0xe0 ++#define IT66121_AUD_SWL_16BIT (0 << 6) ++#define IT66121_AUD_SWL_18BIT BIT(6) ++#define IT66121_AUD_SWL_20BIT (2 << 6) ++#define IT66121_AUD_SWL_24BIT (3 << 6) ++#define IT66121_AUD_SWL_MASK IT66121_AUD_SWL_24BIT ++#define IT66121_AUD_SPDIFTC BIT(5) ++#define IT66121_AUD_SPDIF BIT(4) ++#define IT66121_AUD_I2S (0 << 4) ++#define IT66121_AUD_TYPE_MASK IT66121_AUD_SPDIF ++#define IT66121_AUD_EN_I2S3 BIT(3) ++#define IT66121_AUD_EN_I2S2 BIT(2) ++#define IT66121_AUD_EN_I2S1 BIT(1) ++#define IT66121_AUD_EN_I2S0 BIT(0) ++#define IT66121_AUD_EN_I2S_MASK 0x0f ++#define IT66121_AUD_EN_SPDIF 1 ++ ++#define IT66121_AUD_CTRL1_REG 0xe1 ++#define IT66121_AUD_FMT_STD_I2S (0 << 0) ++#define IT66121_AUD_FMT_32BIT_I2S BIT(0) ++#define IT66121_AUD_FMT_LEFT_JUSTIFY (0 << 1) ++#define IT66121_AUD_FMT_RIGHT_JUSTIFY BIT(1) ++#define IT66121_AUD_FMT_DELAY_1T_TO_WS (0 << 2) ++#define IT66121_AUD_FMT_NO_DELAY_TO_WS BIT(2) ++#define IT66121_AUD_FMT_WS0_LEFT (0 << 3) ++#define IT66121_AUD_FMT_WS0_RIGHT BIT(3) ++#define IT66121_AUD_FMT_MSB_SHIFT_FIRST (0 << 4) ++#define IT66121_AUD_FMT_LSB_SHIFT_FIRST BIT(4) ++#define IT66121_AUD_FMT_RISE_EDGE_SAMPLE_WS (0 << 5) ++#define IT66121_AUD_FMT_FALL_EDGE_SAMPLE_WS BIT(5) ++#define IT66121_AUD_FMT_FULLPKT BIT(6) ++ ++#define IT66121_AUD_FIFOMAP_REG 0xe2 ++#define IT66121_AUD_FIFO3_SEL 6 ++#define IT66121_AUD_FIFO2_SEL 4 ++#define IT66121_AUD_FIFO1_SEL 2 ++#define IT66121_AUD_FIFO0_SEL 0 ++#define IT66121_AUD_FIFO_SELSRC3 3 ++#define IT66121_AUD_FIFO_SELSRC2 2 ++#define IT66121_AUD_FIFO_SELSRC1 1 ++#define IT66121_AUD_FIFO_SELSRC0 0 ++#define IT66121_AUD_FIFOMAP_DEFAULT (IT66121_AUD_FIFO_SELSRC0 \ ++ << IT66121_AUD_FIFO0_SEL | \ ++ IT66121_AUD_FIFO_SELSRC1 \ ++ << IT66121_AUD_FIFO1_SEL | \ ++ IT66121_AUD_FIFO_SELSRC2 \ ++ << IT66121_AUD_FIFO2_SEL | \ ++ IT66121_AUD_FIFO_SELSRC3 \ ++ << IT66121_AUD_FIFO3_SEL) ++ ++#define IT66121_AUD_CTRL3_REG 0xe3 ++#define IT66121_AUD_MULCH BIT(7) ++#define IT66121_AUD_ZERO_CTS BIT(6) ++#define IT66121_AUD_CHSTSEL BIT(4) ++#define IT66121_AUD_S3RLCHG BIT(3) ++#define IT66121_AUD_S2RLCHG BIT(2) ++#define IT66121_AUD_S1RLCHG BIT(1) ++#define IT66121_AUD_S0RLCHG BIT(0) ++#define IT66121_AUD_SRLCHG_MASK 0x0f ++#define IT66121_AUD_SRLCHG_DEFAULT ((~IT66121_AUD_S0RLCHG & \ ++ ~IT66121_AUD_S1RLCHG & \ ++ ~IT66121_AUD_S2RLCHG & \ ++ ~IT66121_AUD_S3RLCHG) & \ ++ IT66121_AUD_SRLCHG_MASK) ++ ++#define IT66121_AUD_SRC_VALID_FLAT_REG 0xe4 ++#define IT66121_AUD_SPXFLAT_SRC3 BIT(7) ++#define IT66121_AUD_SPXFLAT_SRC2 BIT(6) ++#define IT66121_AUD_SPXFLAT_SRC1 BIT(5) ++#define IT66121_AUD_SPXFLAT_SRC0 BIT(4) ++#define IT66121_AUD_SPXFLAT_MASK 0xf0 ++#define IT66121_AUD_SPXFLAT_SRC_ALL (IT66121_AUD_SPXFLAT_SRC0 | \ ++ IT66121_AUD_SPXFLAT_SRC1 | \ ++ IT66121_AUD_SPXFLAT_SRC2 | \ ++ IT66121_AUD_SPXFLAT_SRC3) ++#define IT66121_AUD_ERR2FLAT BIT(3) ++#define IT66121_AUD_S3VALID BIT(2) ++#define IT66121_AUD_S2VALID BIT(1) ++#define IT66121_AUD_S1VALID BIT(0) ++ ++#define IT66121_AUD_HDAUDIO_REG 0xe5 ++#define IT66121_AUD_HBR BIT(3) ++#define IT66121_AUD_DSD BIT(1) ++ + struct it66121_conf { + unsigned int input_mode_reg; + unsigned int input_conversion_reg; + }; + ++struct it66121_audio { ++ struct platform_device *pdev; ++ unsigned int sources; ++ unsigned int n; ++ unsigned int cts; ++ unsigned int format; ++ unsigned int sample_wl; ++ bool is_hbr; ++ struct hdmi_audio_infoframe audio_infoframe; ++ struct snd_aes_iec958 aes_iec958; ++}; ++ + struct it66121_ctx { + struct regmap *regmap; + struct drm_bridge bridge; +@@ -260,6 +402,8 @@ struct it66121_ctx { + struct regulator_bulk_data supplies[3]; + bool dual_edge; + const struct it66121_conf *conf; ++ bool sink_has_audio; ++ struct it66121_audio audio; + struct mutex lock; /* Protects fields below and device registers */ + struct edid *edid; + struct hdmi_avi_infoframe hdmi_avi_infoframe; +@@ -610,6 +754,7 @@ static int it66121_connector_get_modes(struct drm_connector *connector) + } + + num_modes = drm_add_edid_modes(connector, ctx->edid); ++ ctx->sink_has_audio = drm_detect_monitor_audio(ctx->edid); + + unlock: + mutex_unlock(&ctx->lock); +@@ -894,6 +1039,536 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = { + .mode_set = it66121_bridge_mode_set, + }; + ++/* Audio related functions */ ++ ++static int it66121_audio_reset_fifo(struct it66121_ctx *ctx) ++{ ++ int ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_AUD, ++ IT66121_SW_RST_AUD); ++ if (ret) ++ return ret; ++ ++ usleep_range(2000, 4000); ++ ++ return regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_AUD, ++ ~(IT66121_SW_RST_AUD) & 0xff); ++} ++ ++static int it66121_audio_set_infoframe(struct it66121_ctx *ctx) ++{ ++ int i, ret; ++ u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; ++ ++ const u16 audioinfo_reg[IT66121_AUD_INFO_REG_SZ] = { ++ IT66121_AUD_INFO_DB1_REG, ++ IT66121_AUD_INFO_DB2_REG, ++ IT66121_AUD_INFO_DB3_REG, ++ IT66121_AUD_INFO_DB4_REG, ++ IT66121_AUD_INFO_DB5_REG ++ }; ++ ++ ret = hdmi_audio_infoframe_pack(&ctx->audio.audio_infoframe, infoframe_buf, ++ sizeof(infoframe_buf)); ++ if (ret < 0) { ++ dev_err(ctx->dev, "%s: failed to pack audio infoframe: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ for (i = 0; i < IT66121_AUD_INFO_REG_SZ; i++) { ++ ret = regmap_write(ctx->regmap, audioinfo_reg[i], ++ infoframe_buf[i + HDMI_INFOFRAME_HEADER_SIZE]); ++ if (ret) ++ return ret; ++ } ++ ++ /* ++ * TODO: linux defines 10 bytes; currently only 5 are filled ++ * if that ever changes checksum will differ since ++ * it66121 takes max 5 bytes -> calc checksum here???? ++ */ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_INFO_CSUM_REG, infoframe_buf[3]); ++ ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, IT66121_AUD_INFO_PKT_REG, ++ IT66121_AUD_INFO_PKT_ON | IT66121_AUD_INFO_PKT_RPT); ++} ++ ++static int it66121_audio_set_cts_n(struct it66121_ctx *ctx) ++{ ++ int ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_N1_REG, ++ ctx->audio.n & 0xff); ++ if (ret) ++ return ret; ++ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_N2_REG, ++ (ctx->audio.n >> 8) & 0xff); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_N3_REG, ++ (ctx->audio.n >> 16) & 0xf); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_CTS1_REG, ++ ctx->audio.cts & 0xff); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_CTS2_REG, ++ (ctx->audio.cts >> 8) & 0xff); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_PKT_CTS3_REG, ++ (ctx->audio.cts >> 16) & 0xf); ++ if (ret) ++ return ret; ++ ++ /* ++ * magic values ("password") have to be written to ++ * f8 register to enable writing to IT66121_AUD_PKT_CTS_MODE_REG ++ */ ++ ++ ret = regmap_write(ctx->regmap, 0xf8, 0xc3); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, 0xf8, 0xa5); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, ++ IT66121_AUD_PKT_CTS_MODE_REG, ++ IT66121_AUD_PKT_CTS_MODE_USER, ++ ctx->audio.cts == IT66121_AUD_PKT_CTS_MODE_AUTO_VAL ++ ? ~IT66121_AUD_PKT_CTS_MODE_USER & 0xff ++ : IT66121_AUD_PKT_CTS_MODE_USER); ++ if (ret) ++ return ret; ++ ++ /* ++ * disabling write to IT66121_AUD_PKT_CTS_MODE_REG ++ * again by overwriting perviously set "password" ++ */ ++ return regmap_write(ctx->regmap, 0xf8, 0xff); ++} ++ ++static int it66121_audio_set_channel_status(struct it66121_ctx *ctx) ++{ ++ int ret; ++ unsigned int val; ++ ++ /* TODO: check: always use NLPCM - would to cover LPCM also?*/ ++ val = IT66121_AUD_CHST_MODE_NLPCM; ++ val |= ctx->audio.aes_iec958.status[0] & IEC958_AES0_CON_NOT_COPYRIGHT ++ ? BIT(3) ++ : (0 << 3); ++ val |= (ctx->audio.aes_iec958.status[0] & IEC958_AES0_CON_EMPHASIS) << 4; ++ ret = regmap_write(ctx->regmap, ++ IT66121_AUD_CHST_MODE_REG, ++ val); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, ++ IT66121_AUD_CHST_CAT_REG, ++ ctx->audio.aes_iec958.status[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, ++ IT66121_AUD_CHST_SRCNUM_REG, ++ ctx->audio.aes_iec958.status[2] & ++ IEC958_AES2_CON_SOURCE); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, ++ IT66121_AUD_CHST_CHTNUM_REG, ++ ((ctx->audio.aes_iec958.status[2] & ++ IEC958_AES2_CON_CHANNEL) >> 4)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, ++ IT66121_AUD_CHST_CA_FS_REG, ++ (ctx->audio.aes_iec958.status[3] & ++ IEC958_AES3_CON_CLOCK) << 2 | ++ (ctx->audio.aes_iec958.status[3] & ++ IEC958_AES3_CON_FS)); ++ if (ret) ++ return ret; ++ ++ return regmap_write(ctx->regmap, ++ IT66121_AUD_CHST_OFS_WL_REG, ++ ctx->audio.aes_iec958.status[4]); ++} ++ ++static int it66121_audio_mute(struct it66121_ctx *ctx, bool enable) ++{ ++ return regmap_write_bits(ctx->regmap, IT66121_AUD_CTRL0_REG, ++ IT66121_AUD_EN_I2S_MASK, ++ enable ? 0x0 : ctx->audio.sources); ++} ++ ++static int it66121_audio_set_controls(struct it66121_ctx *ctx) ++{ ++ int ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AUD_CTRL0_REG, ++ IT66121_AUD_TYPE_MASK | IT66121_AUD_SWL_MASK, ++ IT66121_AUD_I2S | ctx->audio.sample_wl); ++ ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_CTRL1_REG, ++ ctx->audio.format); ++ if (ret) ++ return ret; ++ ++ /* default fifo mapping: fifo0 => source0, fifo1 => source1, ... */ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_FIFOMAP_REG, ++ IT66121_AUD_FIFOMAP_DEFAULT); ++ if (ret) ++ return ret; ++ ++ /* Do not swap R/L for any source */ ++ ret = regmap_write_bits(ctx->regmap, IT66121_AUD_CTRL3_REG, ++ IT66121_AUD_SRLCHG_MASK, ++ IT66121_AUD_SRLCHG_DEFAULT); ++ if (ret) ++ return ret; ++ ++ /* "unflat" all sources */ ++ ret = regmap_write_bits(ctx->regmap, ++ IT66121_AUD_SRC_VALID_FLAT_REG, ++ IT66121_AUD_SPXFLAT_MASK, ++ ~IT66121_AUD_SPXFLAT_SRC_ALL & 0xff); ++ if (ret) ++ return ret; ++ ++ /* TODO: check if we really support HBR audio yet */ ++ return regmap_write_bits(ctx->regmap, IT66121_AUD_HDAUDIO_REG, ++ IT66121_AUD_HBR, ++ ctx->audio.is_hbr ++ ? IT66121_AUD_HBR ++ : ~IT66121_AUD_HBR & 0xff); ++} ++ ++static int it66121_audio_hw_params(struct device *dev, void *data, ++ struct hdmi_codec_daifmt *daifmt, ++ struct hdmi_codec_params *params) ++{ ++ int ret; ++ unsigned int sources = 0; ++ ++ struct it66121_ctx *ctx = dev_get_drvdata(dev); ++ ++ if (!ctx->sink_has_audio) { ++ dev_err(ctx->dev, "%s: sink has no audio", __func__); ++ return -EINVAL; ++ } ++ ++ /* for now i2s only */ ++ if (daifmt->bit_clk_master | daifmt->frame_clk_master) { ++ dev_err(ctx->dev, ++ "%s: only clk_master and frame_clk_master formats are supported\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ /* TODO: move all these switches in functions ? */ ++ switch (daifmt->fmt) { ++ case HDMI_I2S: ++ ctx->audio.format = IT66121_AUD_FMT_32BIT_I2S; ++ break; ++ case HDMI_RIGHT_J: ++ ctx->audio.format = IT66121_AUD_FMT_RIGHT_JUSTIFY; ++ break; ++ case HDMI_LEFT_J: ++ ctx->audio.format = IT66121_AUD_FMT_LEFT_JUSTIFY; ++ break; ++ default: ++ dev_err(ctx->dev, "%s: unsupported daiformat: %u\n", ++ __func__, daifmt->fmt); ++ return -EINVAL; ++ } ++ ++ switch (params->channels) { ++ case 7 ... 8: ++ ctx->audio.sources |= IT66121_AUD_EN_I2S3; ++ sources++; ++ fallthrough; ++ case 5 ... 6: ++ ctx->audio.sources |= IT66121_AUD_EN_I2S2; ++ sources++; ++ fallthrough; ++ case 3 ... 4: ++ ctx->audio.sources |= IT66121_AUD_EN_I2S1; ++ sources++; ++ fallthrough; ++ case 1 ... 2: ++ ctx->audio.sources |= IT66121_AUD_EN_I2S0; ++ sources++; ++ break; ++ default: ++ dev_err(ctx->dev, "%s: unsupported channel count: %d\n", ++ __func__, params->channels); ++ return -EINVAL; ++ } ++ ++ switch (params->sample_width) { ++ case 16: ++ ctx->audio.sample_wl = IT66121_AUD_SWL_16BIT; ++ break; ++ case 18: ++ ctx->audio.sample_wl = IT66121_AUD_SWL_18BIT; ++ break; ++ case 20: ++ ctx->audio.sample_wl = IT66121_AUD_SWL_20BIT; ++ break; ++ case 24: ++ case 32: ++ /* assume 24 bit wordlength for 32 bit width */ ++ ctx->audio.sample_wl = IT66121_AUD_SWL_24BIT; ++ break; ++ default: ++ dev_err(ctx->dev, "%s: unsupported sample width: %d\n", ++ __func__, params->channels); ++ return -EINVAL; ++ } ++ ++ switch (params->sample_rate) { ++ case 32000: ++ case 48000: ++ case 96000: ++ case 192000: ++ ctx->audio.n = 128 * params->sample_rate / 1000; ++ ctx->audio.is_hbr = false; ++ break; ++ case 44100: ++ case 88200: ++ case 176400: ++ ctx->audio.n = 128 * params->sample_rate / 900; ++ ctx->audio.is_hbr = false; ++ break; ++ case 768000: ++ ctx->audio.n = 24576; ++ ctx->audio.is_hbr = true; ++ break; ++ default: ++ dev_err(ctx->dev, "%s: unsupported sample_rate: %d\n", ++ __func__, params->sample_rate); ++ return -EINVAL; ++ } ++ ++ /* not all bits are correctly filled in snd_aes_iec958 - fill them here */ ++ if ((params->iec.status[2] & IEC958_AES2_CON_SOURCE) == IEC958_AES2_CON_SOURCE_UNSPEC) ++ params->iec.status[2] |= sources; ++ ++ if ((params->iec.status[2] & IEC958_AES2_CON_CHANNEL) == IEC958_AES2_CON_CHANNEL_UNSPEC) ++ params->iec.status[2] |= params->channels << 4; ++ ++ /* OFs is 1-complement of Fs */ ++ if ((params->iec.status[4] & IEC958_AES4_CON_ORIGFS) == IEC958_AES4_CON_ORIGFS_NOTID && ++ (params->iec.status[3] & IEC958_AES3_CON_FS) != IEC958_AES3_CON_FS_NOTID) ++ params->iec.status[4] |= (~(params->iec.status[3] & IEC958_AES3_CON_FS) & 0xf) << 4; ++ ++ ctx->audio.format |= IT66121_AUD_FMT_FULLPKT; ++ ctx->audio.cts = IT66121_AUD_PKT_CTS_MODE_AUTO_VAL; ++ ctx->audio.audio_infoframe = params->cea; ++ ctx->audio.aes_iec958 = params->iec; ++ ++ ret = it66121_audio_reset_fifo(ctx); ++ if (ret) ++ return ret; ++ ++ ret = it66121_audio_set_infoframe(ctx); ++ if (ret) { ++ dev_err(ctx->dev, ++ "%s: failed to assemble/enable audio infoframe: %d\n", ++ __func__, ret); ++ /* TODO: Really fail here? */ ++ return ret; ++ } ++ ++ ret = it66121_audio_set_cts_n(ctx); ++ if (ret) { ++ dev_err(ctx->dev, ++ "%s: failed to write cts/n values: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ ret = it66121_audio_set_channel_status(ctx); ++ if (ret) { ++ dev_err(ctx->dev, ++ "%s: failed to write channel_status %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ ret = it66121_audio_set_controls(ctx); ++ if (ret) { ++ dev_err(ctx->dev, ++ "%s: failed to write audio controls %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static void it66121_audio_shutdown(struct device *dev, void *data) ++{ ++ struct it66121_ctx *ctx = dev_get_drvdata(dev); ++ ++ regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF, ++ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF); ++ ++ regmap_write(ctx->regmap, IT66121_AUD_CLK_CTRL_REG, 0x0); ++ ++ regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, ++ IT66121_INT_MASK1_AUD_OVF, ++ IT66121_INT_MASK1_AUD_OVF); ++ ++ regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_ACLK, ++ IT66121_CLK_BANK_PWROFF_ACLK); ++ ++ regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF, ++ ~(IT66121_SW_RST_AUD | IT66121_SW_RST_AREF) & 0xff); ++} ++ ++static int it66121_audio_startup(struct device *dev, void *data) ++{ ++ int ret; ++ ++ struct it66121_ctx *ctx = dev_get_drvdata(dev); ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF, ++ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF); ++ if (ret) ++ return ret; ++ /* TODO: check how to determine Fs at runtime -> only for spdif???*/ ++ ret = regmap_write(ctx->regmap, IT66121_AUD_CLK_CTRL_REG, ++ IT66121_AUD_AUT_OVR_SMPL_CLK | ++ IT66121_AUD_EXT_MCLK_256FS); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, ++ IT66121_CLK_BANK_PWROFF_ACLK, ++ ~IT66121_CLK_BANK_PWROFF_ACLK & 0xff); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG, ++ IT66121_INT_MASK1_AUD_OVF, ++ ~IT66121_INT_MASK1_AUD_OVF & 0xff); ++ if (ret) ++ return ret; ++ ++ return regmap_write_bits(ctx->regmap, IT66121_SW_RST_REG, ++ IT66121_SW_RST_AUD | IT66121_SW_RST_AREF, ++ ~(IT66121_SW_RST_AUD | IT66121_SW_RST_AREF) & 0xff); ++} ++ ++int it66121_audio_mute_stream(struct device *dev, void *data, bool enable, ++ int direction) ++{ ++ struct it66121_ctx *ctx = dev_get_drvdata(dev); ++ ++ return it66121_audio_mute(ctx, enable); ++} ++ ++static int it66121_audio_get_dai_id(struct snd_soc_component *component, ++ struct device_node *endpoint) ++{ ++ struct of_endpoint of_ep; ++ int ret; ++ ++ ret = of_graph_parse_endpoint(endpoint, &of_ep); ++ if (ret < 0) ++ return ret; ++ ++ /* ++ * HDMI sound should be located as reg = <2> ++ * Then, it is sound port 0 ++ */ ++ if (of_ep.port == 2) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int it66121_audio_get_eld(struct device *dev, void *data, ++ u8 *buf, size_t len) ++{ ++ struct it66121_ctx *ctx = dev_get_drvdata(dev); ++ ++ memcpy(buf, ctx->connector.eld, ++ min(sizeof(ctx->connector.eld), len)); ++ ++ return 0; ++} ++ ++static const struct hdmi_codec_ops it66121_audio_codec_ops = { ++ .audio_shutdown = it66121_audio_shutdown, ++ .audio_startup = it66121_audio_startup, ++ .mute_stream = it66121_audio_mute_stream, ++ .no_capture_mute = 1, ++ .hw_params = it66121_audio_hw_params, ++ .get_eld = it66121_audio_get_eld, ++ .get_dai_id = it66121_audio_get_dai_id, ++}; ++ ++static const struct hdmi_codec_pdata codec_data = { ++ .ops = &it66121_audio_codec_ops, ++ .i2s = 1, /* Only i2s support for now. */ ++ .spdif = 0, ++ .max_i2s_channels = 8, ++}; ++ ++static int it66121_audio_codec_init(struct it66121_ctx *it66121, ++ struct device *dev) ++{ ++ struct it66121_ctx *ctx = dev_get_drvdata(dev); ++ ++ ctx->audio.pdev = platform_device_register_data( ++ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, ++ &codec_data, sizeof(codec_data)); ++ ++ if (IS_ERR(ctx->audio.pdev)) ++ return PTR_ERR(ctx->audio.pdev); ++ ++ DRM_INFO("%s has been bound to to HDMITX it66121\n", ++ HDMI_CODEC_DRV_NAME); ++ ++ return 0; ++} ++ ++static void it66121_audio_codec_exit(struct it66121_ctx *ctx) ++{ ++ if (ctx->audio.pdev) { ++ platform_device_unregister(ctx->audio.pdev); ++ ctx->audio.pdev = NULL; ++ } ++} ++ + static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) + { + int ret; +@@ -930,6 +1605,8 @@ static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id) + } + event = true; + } ++ if (val & IT66121_INT_STATUS1_AUD_OVF) ++ it66121_audio_reset_fifo(ctx); + } + + ret = regmap_read(ctx->regmap, IT66121_INT_STATUS3_REG, &val); +@@ -1042,6 +1719,12 @@ static int it66121_probe(struct i2c_client *client, + + drm_bridge_add(&ctx->bridge); + ++ ret = it66121_audio_codec_init(ctx, dev); ++ if (ret) { ++ dev_err(dev, "Failed to initialize audio codec %d\n", ret); ++ return ret; ++ } ++ + return 0; + } + +@@ -1049,6 +1732,7 @@ static int it66121_remove(struct i2c_client *client) + { + struct it66121_ctx *ctx = i2c_get_clientdata(client); + ++ it66121_audio_codec_exit(ctx); + ite66121_power_off(ctx); + drm_bridge_remove(&ctx->bridge); + kfree(ctx->edid); +@@ -1086,6 +1770,7 @@ static struct i2c_driver it66121_driver = { + + module_i2c_driver(it66121_driver); + ++MODULE_AUTHOR("Alex Bee"); + MODULE_AUTHOR("Phong LE"); + MODULE_DESCRIPTION("IT66121 HDMI transmitter driver"); + MODULE_LICENSE("GPL v2"); + +From a6545c717b35bb1e53f8df75093e7582d1b75635 Mon Sep 17 00:00:00 2001 +From: Alex Bee +Date: Tue, 18 Aug 2020 22:46:01 +0200 +Subject: [PATCH] drm/bridge: it66121: increase reset time + +Signed-off-by: Alex Bee +--- + drivers/gpu/drm/bridge/ite-it66121.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 98f3d68fe01f..a01d2e46bb0c 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -443,7 +443,7 @@ static const struct it66121_conf it66121fn_conf_simple = { + static void it66121_hw_reset(struct it66121_ctx *ctx) + { + gpiod_set_value(ctx->gpio_reset, 1); +- msleep(20); ++ msleep(50); + gpiod_set_value(ctx->gpio_reset, 0); + } +