4576 lines
153 KiB
Diff
4576 lines
153 KiB
Diff
From 0af28d066edbb4297d5140ff4c93db7b0bc0b182 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <ykk@rock-chips.com>
|
|
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 <ykk@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
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 <nickey.yang@rock-chips.com>
|
|
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 <nickey.yang@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
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 <dianders@chromium.org>
|
|
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 <dianders@chromium.org>
|
|
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
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 <dianders@chromium.org>
|
|
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 <http://crosreview.com/285855> 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 <dianders@chromium.org>
|
|
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
Date: Sun, 3 May 2020 22:36:23 +0000
|
|
Subject: [PATCH] drm/rockchip: dw-hdmi: limit resolution to 3840x2160
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <nickey.yang@rock-chips.com>
|
|
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 <nickey.yang@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
Date: Wed, 15 Jul 2020 15:24:47 +0000
|
|
Subject: [PATCH] drm/rockchip: vop: fix crtc duplicate state
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <jonas@kwiboo.se>
|
|
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 <jonas@kwiboo.se>
|
|
---
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
---
|
|
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 08b0db205ddef2853dd75c0691d7d6d6f94c611b Mon Sep 17 00:00:00 2001
|
|
From: Alex Bee <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
---
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
---
|
|
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 <knaerzche@gmail.com>
|
|
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 = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
|
- 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 = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
|
- 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 <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/of_device.h>
|
|
+#include <linux/regmap.h>
|
|
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_edid.h>
|
|
@@ -21,6 +22,8 @@
|
|
#include <drm/drm_probe_helper.h>
|
|
#include <drm/drm_simple_kms_helper.h>
|
|
|
|
+#include <sound/hdmi-codec.h>
|
|
+
|
|
#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 <knaerzche@gmail.com>
|
|
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 = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
|
|
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 <jonas@kwiboo.se>
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
---
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
---
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
---
|
|
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 <knaerzche@gmail.com>
|
|
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 <knaerzche@gmail.com>
|
|
---
|
|
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 <knaerzche@gmail.com>
|
|
* Copyright (C) 2020 BayLibre, SAS
|
|
* Author: Phong LE <ple@baylibre.com>
|
|
* Copyright (C) 2018-2019, Artem Mygaiev
|
|
@@ -26,6 +27,9 @@
|
|
#include <drm/drm_print.h>
|
|
#include <drm/drm_probe_helper.h>
|
|
|
|
+#include <sound/asoundef.h>
|
|
+#include <sound/hdmi-codec.h>
|
|
+
|
|
#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 <knaerzche@gmail.com>
|
|
Date: Tue, 18 Aug 2020 22:46:01 +0200
|
|
Subject: [PATCH] drm/bridge: it66121: increase reset time
|
|
|
|
Signed-off-by: Alex Bee <knaerzche@gmail.com>
|
|
---
|
|
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);
|
|
}
|
|
|