1
0
This repository has been archived on 2024-11-10. You can view files and clone it, but cannot push or open issues or pull requests.
Moretz 698ae89d26 upd
upd
2024-11-08 17:39:59 -03:00

777 lines
25 KiB
Diff

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 PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>;
- clock-names = "iahb", "isfr", "cec";
+ clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&hdmi_phy>, <&cru SCLK_HDMI_CEC>;
+ clock-names = "iahb", "isfr", "vpll", "cec";
pinctrl-names = "default";
pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>;
resets = <&cru SRST_HDMI_P>;
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