From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 06 Nov 2023 03:04:41 +0000
Subject: [PATCH] rk3568 rt init

---
 kernel/drivers/gpu/drm/rockchip/rockchip_drm_tve.c |  509 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 443 insertions(+), 66 deletions(-)

diff --git a/kernel/drivers/gpu/drm/rockchip/rockchip_drm_tve.c b/kernel/drivers/gpu/drm/rockchip/rockchip_drm_tve.c
index 0a223dd..990b9cf 100644
--- a/kernel/drivers/gpu/drm/rockchip/rockchip_drm_tve.c
+++ b/kernel/drivers/gpu/drm/rockchip/rockchip_drm_tve.c
@@ -38,6 +38,76 @@
 		   .vrefresh = 60, 0, },
 };
 
+struct env_config {
+	u32 offset;
+	u32 value;
+};
+
+static struct env_config ntsc_bt656_config[] = {
+	{ BT656_DECODER_CROP, 0x00000000 },
+	{ BT656_DECODER_SIZE, 0x01e002d0 },
+	{ BT656_DECODER_HTOTAL_HS_END, 0x035a003e },
+	{ BT656_DECODER_VACT_ST_HACT_ST, 0x00160069 },
+	{ BT656_DECODER_VTOTAL_VS_END, 0x020d0003 },
+	{ BT656_DECODER_VS_ST_END_F1, 0x01060109 },
+	{ BT656_DECODER_DBG_REG, 0x024002d0 },
+	{ BT656_DECODER_CTRL, 0x00000009 },
+};
+
+static struct env_config ntsc_tve_config[] = {
+	{ TVE_MODE_CTRL, 0x000af906 },
+	{ TVE_HOR_TIMING1, 0x00c07a81 },
+	{ TVE_HOR_TIMING2, 0x169810fc },
+	{ TVE_HOR_TIMING3, 0x96b40000 },
+	{ TVE_SUB_CAR_FRQ, 0x21f07bd7 },
+	{ TVE_IMAGE_POSITION, 0x001500d6 },
+	{ TVE_ROUTING, 0x10088880 },
+	{ TVE_SYNC_ADJUST, 0x00000000 },
+	{ TVE_STATUS, 0x00000000 },
+	{ TVE_CTRL, 0x00000000 },
+	{ TVE_INTR_STATUS, 0x00000000 },
+	{ TVE_INTR_EN, 0x00000000 },
+	{ TVE_INTR_CLR, 0x00000000 },
+	{ TVE_COLOR_BUSRT_SAT, 0x0052543c },
+	{ TVE_CHROMA_BANDWIDTH, 0x00000002 },
+	{ TVE_BRIGHTNESS_CONTRAST, 0x00008300 },
+	{ TVE_CLAMP, 0x00000000 },
+};
+
+static struct env_config pal_bt656_config[] = {
+	{ BT656_DECODER_CROP, 0x00000000 },
+	{ BT656_DECODER_SIZE, 0x024002d0 },
+	{ BT656_DECODER_HTOTAL_HS_END, 0x0360003f },
+	{ BT656_DECODER_VACT_ST_HACT_ST, 0x0016006f },
+	{ BT656_DECODER_VTOTAL_VS_END, 0x02710003 },
+	{ BT656_DECODER_VS_ST_END_F1, 0x0138013b },
+	{ BT656_DECODER_DBG_REG, 0x024002d0 },
+	{ BT656_DECODER_CTRL, 0x00000009 },
+};
+
+static struct env_config pal_tve_config[] = {
+	{ TVE_MODE_CTRL, 0x010ab906 },
+	{ TVE_HOR_TIMING1, 0x00c28381 },
+	{ TVE_HOR_TIMING2, 0x267d111d },
+	{ TVE_HOR_TIMING3, 0x66c00880 },
+	{ TVE_SUB_CAR_FRQ, 0x2a098acb },
+	{ TVE_IMAGE_POSITION, 0x001500f6 },
+	{ TVE_ROUTING, 0x10008882 },
+	{ TVE_SYNC_ADJUST, 0x00000000 },
+	{ TVE_STATUS, 0x000000b0 },
+	{ TVE_CTRL, 0x00000000 },
+	{ TVE_INTR_STATUS, 0x00000000 },
+	{ TVE_INTR_EN, 0x00000000 },
+	{ TVE_INTR_CLR, 0x00000000 },
+	{ TVE_COLOR_BUSRT_SAT, 0x00356245 },
+	{ TVE_CHROMA_BANDWIDTH, 0x00000022 },
+	{ TVE_BRIGHTNESS_CONTRAST, 0x0000aa00 },
+	{ TVE_CLAMP, 0x00000000 },
+};
+
+#define BT656_ENV_CONFIG_SIZE		(sizeof(ntsc_bt656_config) / sizeof(struct env_config))
+#define TVE_ENV_CONFIG_SIZE		(sizeof(ntsc_tve_config) / sizeof(struct env_config))
+
 #define tve_writel(offset, v)		writel_relaxed(v, tve->regbase + (offset))
 #define tve_readl(offset)		readl_relaxed(tve->regbase + (offset))
 
@@ -54,6 +124,14 @@
 	int input_format;
 	int soc_type;
 };
+
+static void tve_write_block(struct rockchip_tve *tve, struct env_config *config, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		tve_writel(config[i].offset, config[i].value);
+}
 
 static int
 rockchip_tve_get_modes(struct drm_connector *connector)
@@ -107,61 +185,106 @@
 
 static void tve_set_mode(struct rockchip_tve *tve)
 {
+	struct env_config *bt656_cfg, *tve_cfg;
 	int mode = tve->tv_format;
 
-	dev_dbg(tve->dev, "tve set mode:%d\n", mode);
-	if (tve->input_format == INPUT_FORMAT_RGB)
-		tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) |
-			   v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) |
-			   v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(0));
-	else
-		tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) |
-			   v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) |
-			   v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(3));
+	if (tve->soc_type == SOC_RK3528) {
+		tve_writel(TVE_LUMA_FILTER1, tve->lumafilter0);
+		tve_writel(TVE_LUMA_FILTER2, tve->lumafilter1);
+		tve_writel(TVE_LUMA_FILTER3, tve->lumafilter2);
+		tve_writel(TVE_LUMA_FILTER4, tve->lumafilter3);
+		tve_writel(TVE_LUMA_FILTER5, tve->lumafilter4);
+		tve_writel(TVE_LUMA_FILTER6, tve->lumafilter5);
+		tve_writel(TVE_LUMA_FILTER7, tve->lumafilter6);
+		tve_writel(TVE_LUMA_FILTER8, tve->lumafilter7);
+	} else {
+		dev_dbg(tve->dev, "tve set mode:%d\n", mode);
+		if (tve->input_format == INPUT_FORMAT_RGB)
+			tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) |
+				   v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) |
+				   v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(0));
+		else
+			tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) |
+				   v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) |
+				   v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(3));
 
-	tve_writel(TV_LUMA_FILTER0, tve->lumafilter0);
-	tve_writel(TV_LUMA_FILTER1, tve->lumafilter1);
-	tve_writel(TV_LUMA_FILTER2, tve->lumafilter2);
+		tve_writel(TV_LUMA_FILTER0, tve->lumafilter0);
+		tve_writel(TV_LUMA_FILTER1, tve->lumafilter1);
+		tve_writel(TV_LUMA_FILTER2, tve->lumafilter2);
+	}
 
 	if (mode == TVOUT_CVBS_NTSC) {
 		dev_dbg(tve->dev, "NTSC MODE\n");
-		tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(1) |
-			v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) |
-			v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode));
-		tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_NTSC) |
-			v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
-		tve_writel(TV_SATURATION, 0x0042543C);
-		if (tve->test_mode)
-			tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00008300);
-		else
-			tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00007900);
 
-		tve_writel(TV_FREQ_SC,	0x21F07BD7);
-		tve_writel(TV_SYNC_TIMING, 0x00C07a81);
-		tve_writel(TV_ADJ_TIMING, 0x96B40000 | 0x70);
-		tve_writel(TV_ACT_ST,	0x001500D6);
-		tve_writel(TV_ACT_TIMING, 0x069800FC | (1 << 12) | (1 << 28));
+		if (tve->soc_type == SOC_RK3528) {
+			bt656_cfg = ntsc_bt656_config;
+			tve_cfg = ntsc_tve_config;
 
+			tve_write_block(tve, bt656_cfg, BT656_ENV_CONFIG_SIZE);
+			tve_write_block(tve, tve_cfg, TVE_ENV_CONFIG_SIZE);
+		} else {
+			tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(1) |
+				   v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) |
+				   v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode));
+			tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_NTSC) |
+				   v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
+			tve_writel(TV_SATURATION, 0x0042543C);
+			if (tve->test_mode)
+				tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00008300);
+			else
+				tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00007900);
+
+			tve_writel(TV_FREQ_SC,	0x21F07BD7);
+			tve_writel(TV_SYNC_TIMING, 0x00C07a81);
+			tve_writel(TV_ADJ_TIMING, 0x96B40000 | 0x70);
+			tve_writel(TV_ACT_ST,	0x001500D6);
+			tve_writel(TV_ACT_TIMING, 0x069800FC | (1 << 12) | (1 << 28));
+		}
 	} else if (mode == TVOUT_CVBS_PAL) {
 		dev_dbg(tve->dev, "PAL MODE\n");
-		tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(0) |
-			v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) |
-			v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode));
-		tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_PAL) |
-			v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
 
-		tve_writel(TV_SATURATION, tve->saturation);
-		tve_writel(TV_BRIGHTNESS_CONTRAST, tve->brightcontrast);
+		if (tve->soc_type == SOC_RK3528) {
+			bt656_cfg = pal_bt656_config;
+			tve_cfg = pal_tve_config;
 
-		tve_writel(TV_FREQ_SC,	0x2A098ACB);
-		tve_writel(TV_SYNC_TIMING, 0x00C28381);
-		tve_writel(TV_ADJ_TIMING, (0xc << 28) | 0x06c00800 | 0x80);
-		tve_writel(TV_ACT_ST,	0x001500F6);
-		tve_writel(TV_ACT_TIMING, 0x0694011D | (1 << 12) | (2 << 28));
+			tve_write_block(tve, bt656_cfg, BT656_ENV_CONFIG_SIZE);
+			tve_write_block(tve, tve_cfg, TVE_ENV_CONFIG_SIZE);
+		} else {
+			tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(0) |
+				   v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) |
+				   v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode));
+			tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_PAL) |
+				   v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
 
-		tve_writel(TV_ADJ_TIMING, tve->adjtiming);
-		tve_writel(TV_ACT_TIMING, 0x0694011D |
-			   (1 << 12) | (2 << 28));
+			tve_writel(TV_SATURATION, tve->saturation);
+			tve_writel(TV_BRIGHTNESS_CONTRAST, tve->brightcontrast);
+
+			tve_writel(TV_FREQ_SC,	0x2A098ACB);
+			tve_writel(TV_SYNC_TIMING, 0x00C28381);
+			tve_writel(TV_ADJ_TIMING, (0xc << 28) | 0x06c00800 | 0x80);
+			tve_writel(TV_ACT_ST,	0x001500F6);
+			tve_writel(TV_ACT_TIMING, 0x0694011D | (1 << 12) | (2 << 28));
+
+			tve_writel(TV_ADJ_TIMING, tve->adjtiming);
+			tve_writel(TV_ACT_TIMING, 0x0694011D | (1 << 12) | (2 << 28));
+		}
+	}
+
+	if (tve->soc_type == SOC_RK3528) {
+		u32 upsample_mode = 0;
+		u32 mask = 0;
+		u32 val = 0;
+		bool upsample_en;
+
+		upsample_en = tve->upsample_mode ? 1 : 0;
+		if (upsample_en)
+			upsample_mode = tve->upsample_mode - 1;
+		mask = m_TVE_DCLK_POL | m_TVE_DCLK_EN | m_DCLK_UPSAMPLE_2X4X |
+		       m_DCLK_UPSAMPLE_EN | m_TVE_MODE | m_TVE_EN;
+		val = v_TVE_DCLK_POL(0) | v_TVE_DCLK_EN(1) | v_DCLK_UPSAMPLE_2X4X(upsample_mode) |
+		      v_DCLK_UPSAMPLE_EN(upsample_en) | v_TVE_MODE(tve->tv_format) | v_TVE_EN(1);
+
+		tve_dac_grf_writel(RK3528_VO_GRF_CVBS_CON, (mask << 16) | val);
 	}
 }
 
@@ -178,36 +301,57 @@
 	u32 mask = 0;
 	u32 val = 0;
 	u32 grfreg = 0;
+	u32 offset = 0;
 
 	if (enable) {
 		dev_dbg(tve->dev, "dac enable\n");
 
-		mask = m_VBG_EN | m_DAC_EN | m_DAC_GAIN;
 		if (tve->soc_type == SOC_RK3036) {
+			mask = m_VBG_EN | m_DAC_EN | m_DAC_GAIN;
 			val = m_VBG_EN | m_DAC_EN | v_DAC_GAIN(tve->daclevel);
 			grfreg = RK3036_GRF_SOC_CON3;
 		} else if (tve->soc_type == SOC_RK312X) {
+			mask = m_VBG_EN | m_DAC_EN | m_DAC_GAIN;
 			val = m_VBG_EN | m_DAC_EN | v_DAC_GAIN(tve->daclevel);
 			grfreg = RK312X_GRF_TVE_CON;
 		} else if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) {
 			val = v_CUR_REG(tve->dac1level) | v_DR_PWR_DOWN(0) | v_BG_PWR_DOWN(0);
+			offset = VDAC_VDAC1;
+		} else if (tve->soc_type == SOC_RK3528) {
+			/*
+			 * Reset the vdac
+			 */
+			tve_dac_writel(VDAC_CLK_RST, v_ANALOG_RST(0) | v_DIGITAL_RST(0));
+			msleep(20);
+			tve_dac_writel(VDAC_CLK_RST, v_ANALOG_RST(1) | v_DIGITAL_RST(1));
+
+			tve_dac_writel(VDAC_CURRENT_CTRL, v_OUT_CURRENT(tve->vdac_out_current));
+
+			val = v_REF_VOLTAGE(7) | v_DAC_PWN(1) | v_BIAS_PWN(1);
+			offset = VDAC_PWM_REF_CTRL;
 		}
 	} else {
 		dev_dbg(tve->dev, "dac disable\n");
 
-		mask = m_VBG_EN | m_DAC_EN;
-		if (tve->soc_type == SOC_RK312X)
+		if (tve->soc_type == SOC_RK312X) {
+			mask = m_VBG_EN | m_DAC_EN;
 			grfreg = RK312X_GRF_TVE_CON;
-		else if (tve->soc_type == SOC_RK3036)
+		} else if (tve->soc_type == SOC_RK3036) {
+			mask = m_VBG_EN | m_DAC_EN;
 			grfreg = RK3036_GRF_SOC_CON3;
-		else if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328)
+		} else if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) {
 			val = v_CUR_REG(tve->dac1level) | m_DR_PWR_DOWN | m_BG_PWR_DOWN;
+			offset = VDAC_VDAC1;
+		} else if (tve->soc_type == SOC_RK3528) {
+			val = v_DAC_PWN(0) | v_BIAS_PWN(0);
+			offset = VDAC_PWM_REF_CTRL;
+		}
 	}
 
 	if (grfreg)
 		tve_dac_grf_writel(grfreg, (mask << 16) | val);
 	else if (tve->vdacbase)
-		tve_dac_writel(VDAC_VDAC1, val);
+		tve_dac_writel(offset, val);
 }
 
 static int cvbs_set_disable(struct rockchip_tve *tve)
@@ -229,6 +373,18 @@
 	return 0;
 }
 
+/*
+ * RK3528 supports bt656 to cvbs, and the others support rgb to cvbs.
+ *
+ *  ┌──────────┐
+ *  │ rgb data ├─────────────────────────────────────┐
+ *  └──────────┘                                     │
+ *                                                   ▼
+ * ┌────────────┐    ┌───────────────┐    ┌───────────────────┐    ┌──────┐    ┌────────┐
+ * │ bt656 data ├───►│ bt656 decoder ├───►│ cvbs(tve) encoder ├───►│ vdac ├───►│ screen │
+ * └────────────┘    └───────────────┘    └───────────────────┘    └──────┘    └────────┘
+ *
+ */
 static int cvbs_set_enable(struct rockchip_tve *tve)
 {
 	int ret = 0;
@@ -242,8 +398,9 @@
 		dev_err(tve->dev, "failed to get pm runtime: %d\n", ret);
 		return ret;
 	}
-	dac_enable(tve, true);
 	tve_set_mode(tve);
+	msleep(1000);
+	dac_enable(tve, true);
 	tve->enable = 1;
 
 	return 0;
@@ -264,6 +421,8 @@
 static void rockchip_tve_encoder_disable(struct drm_encoder *encoder)
 {
 	struct rockchip_tve *tve = encoder_to_tve(encoder);
+	struct drm_crtc *crtc = encoder->crtc;
+	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
 
 	mutex_lock(&tve->suspend_lock);
 
@@ -271,6 +430,8 @@
 	cvbs_set_disable(tve);
 
 	mutex_unlock(&tve->suspend_lock);
+
+	s->output_if &= ~VOP_OUTPUT_IF_TV;
 }
 
 static void rockchip_tve_encoder_mode_set(struct drm_encoder *encoder,
@@ -309,6 +470,7 @@
 				  struct drm_connector_state *conn_state)
 {
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+	struct rockchip_tve *tve = encoder_to_tve(encoder);
 	struct drm_connector *connector = conn_state->connector;
 	struct drm_display_info *info = &connector->display_info;
 
@@ -319,6 +481,14 @@
 	else
 		s->bus_format = MEDIA_BUS_FMT_YUV8_1X24;
 
+	/*
+	 * For RK3528:
+	 * VOP -> BT656 output -> BT656 decoder -> TVE encoder -> CVBS output
+	 */
+	if (tve->soc_type == SOC_RK3528)
+		s->output_if |= VOP_OUTPUT_IF_BT656;
+	else
+		s->output_if |= VOP_OUTPUT_IF_TV;
 	s->color_space = V4L2_COLORSPACE_SMPTE170M;
 	s->tv_state = &conn_state->tv;
 
@@ -354,8 +524,118 @@
 	.atomic_check = rockchip_tve_encoder_atomic_check,
 };
 
-static int tve_parse_dt(struct device_node *np,
-			struct rockchip_tve *tve)
+static int tve_read_otp_by_name(struct rockchip_tve *tve, char *name, u8 *val, u8 default_val)
+{
+	struct nvmem_cell *cell;
+	size_t len;
+	unsigned char *efuse_buf;
+	int ret = -EINVAL;
+
+	*val = default_val;
+	cell = nvmem_cell_get(tve->dev, name);
+	if (!IS_ERR(cell)) {
+		efuse_buf = nvmem_cell_read(cell, &len);
+		nvmem_cell_put(cell);
+		if (!IS_ERR(efuse_buf)) {
+			*val = efuse_buf[0];
+			kfree(efuse_buf);
+			return 0;
+		}
+	}
+
+	dev_err(tve->dev, "failed to read %s from otp, use default\n", name);
+
+	return ret;
+}
+
+static int tve_parse_dt(struct device_node *np, struct rockchip_tve *tve)
+{
+	int ret, val;
+	u8 out_current, version;
+
+	ret = of_property_read_u32(np, "rockchip,tvemode", &val);
+	if (ret < 0) {
+		tve->preferred_mode = 0;
+	} else if (val > 1) {
+		dev_err(tve->dev, "tve mode value invalid\n");
+		return -EINVAL;
+	}
+	tve->preferred_mode = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter0", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter0 = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter1", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter1 = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter2", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter2 = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter3", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter3 = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter4", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter4 = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter5", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter5 = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter6", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter6 = val;
+
+	ret = of_property_read_u32(np, "rockchip,lumafilter7", &val);
+	if (val == 0 || ret < 0)
+		return -EINVAL;
+	tve->lumafilter7 = val;
+
+	ret = of_property_read_u32(np, "rockchip,tve-upsample", &val);
+	if (val > DCLK_UPSAMPLEx4 || ret < 0)
+		return -EINVAL;
+	tve->upsample_mode = val;
+
+	/*
+	 * Read vdac output current from OTP if exists, and the default
+	 * current val is 0xd2.
+	 */
+	ret = tve_read_otp_by_name(tve, "out-current", &out_current, 0xd2);
+	if (!ret) {
+		if (out_current) {
+			/*
+			 * If test version is 0x0, the value of vdac out current
+			 * needs to be reduced by one.
+			 */
+			ret = tve_read_otp_by_name(tve, "version", &version, 0x0);
+			if (!ret) {
+				if (version == 0x0)
+					out_current -= 1;
+			}
+		} else {
+			/*
+			 * If the current value read from OTP is 0, set it to default.
+			 */
+			out_current = 0xd2;
+		}
+	}
+	tve->vdac_out_current = out_current;
+
+	return 0;
+}
+
+static int tve_parse_dt_legacy(struct device_node *np, struct rockchip_tve *tve)
 {
 	int ret, val;
 	u32 getdac = 0;
@@ -441,9 +721,52 @@
 	return 0;
 }
 
+static bool tve_check_lumafilter(struct rockchip_tve *tve)
+{
+	int lumafilter[8] = {INT_MAX};
+
+	/*
+	 * The default lumafilter value is 0. If lumafilter value
+	 * is equal to the dts value, uboot logo is enabled.
+	 */
+	if (tve->soc_type == SOC_RK3528) {
+		lumafilter[0] = tve_readl(TVE_LUMA_FILTER1);
+		lumafilter[1] = tve_readl(TVE_LUMA_FILTER2);
+		lumafilter[2] = tve_readl(TVE_LUMA_FILTER3);
+		lumafilter[3] = tve_readl(TVE_LUMA_FILTER4);
+		lumafilter[4] = tve_readl(TVE_LUMA_FILTER5);
+		lumafilter[5] = tve_readl(TVE_LUMA_FILTER6);
+		lumafilter[6] = tve_readl(TVE_LUMA_FILTER7);
+		lumafilter[7] = tve_readl(TVE_LUMA_FILTER8);
+
+		if (lumafilter[0] == tve->lumafilter0 &&
+		    lumafilter[1] == tve->lumafilter1 &&
+		    lumafilter[2] == tve->lumafilter2 &&
+		    lumafilter[3] == tve->lumafilter3 &&
+		    lumafilter[4] == tve->lumafilter4 &&
+		    lumafilter[5] == tve->lumafilter5 &&
+		    lumafilter[6] == tve->lumafilter6 &&
+		    lumafilter[7] == tve->lumafilter7) {
+			return true;
+		}
+	} else {
+		lumafilter[0] = tve_readl(TV_LUMA_FILTER0);
+		lumafilter[1] = tve_readl(TV_LUMA_FILTER1);
+		lumafilter[2] = tve_readl(TV_LUMA_FILTER2);
+
+		if (lumafilter[0] == tve->lumafilter0 &&
+		    lumafilter[1] == tve->lumafilter1 &&
+		    lumafilter[2] == tve->lumafilter2) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
 static void check_uboot_logo(struct rockchip_tve *tve)
 {
-	int lumafilter0, lumafilter1, lumafilter2, vdac;
+	int vdac;
 
 	if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) {
 		vdac = tve_dac_readl(VDAC_VDAC1);
@@ -454,17 +777,7 @@
 		}
 	}
 
-	lumafilter0 = tve_readl(TV_LUMA_FILTER0);
-	lumafilter1 = tve_readl(TV_LUMA_FILTER1);
-	lumafilter2 = tve_readl(TV_LUMA_FILTER2);
-
-	/*
-	 * The default lumafilter value is 0. If lumafilter value
-	 * is equal to the dts value, uboot logo is enabled.
-	 */
-	if (lumafilter0 == tve->lumafilter0 &&
-	    lumafilter1 == tve->lumafilter1 &&
-	    lumafilter2 == tve->lumafilter2) {
+	if (tve_check_lumafilter(tve)) {
 		tve->connector.dpms = DRM_MODE_DPMS_ON;
 		return;
 	}
@@ -495,11 +808,17 @@
 	.input_format = INPUT_FORMAT_YUV,
 };
 
+static const struct rockchip_tve_data rk3528_tve = {
+	.soc_type = SOC_RK3528,
+	.input_format = INPUT_FORMAT_YUV,
+};
+
 static const struct of_device_id rockchip_tve_dt_ids[] = {
 	{ .compatible = "rockchip,rk3036-tve", .data = &rk3036_tve },
 	{ .compatible = "rockchip,rk312x-tve", .data = &rk312x_tve },
 	{ .compatible = "rockchip,rk322x-tve", .data = &rk322x_tve },
 	{ .compatible = "rockchip,rk3328-tve", .data = &rk3328_tve },
+	{ .compatible = "rockchip,rk3528-tve", .data = &rk3528_tve },
 	{}
 };
 
@@ -536,14 +855,16 @@
 		tve->input_format = tve_data->input_format;
 	}
 
-	ret = tve_parse_dt(np, tve);
+	if (tve->soc_type == SOC_RK3528)
+		ret = tve_parse_dt(np, tve);
+	else
+		ret = tve_parse_dt_legacy(np, tve);
 	if (ret) {
 		dev_err(tve->dev, "TVE parse dts error!");
 		return -EINVAL;
 	}
 
 	tve->enable = 0;
-	platform_set_drvdata(pdev, tve);
 	tve->drm_dev = drm_dev;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	tve->reg_phy_base = res->start;
@@ -555,7 +876,8 @@
 		return PTR_ERR(tve->regbase);
 	}
 
-	if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328) {
+	if (tve->soc_type == SOC_RK322X || tve->soc_type == SOC_RK3328 ||
+	    tve->soc_type == SOC_RK3528) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 		tve->len = resource_size(res);
 		tve->vdacbase = devm_ioremap(tve->dev, res->start, tve->len);
@@ -576,6 +898,56 @@
 		if (ret) {
 			dev_err(tve->dev, "Cannot enable tve aclk: %d\n", ret);
 			return ret;
+		}
+	} else if (tve->soc_type == SOC_RK3528) {
+		tve->hclk = devm_clk_get(tve->dev, "hclk");
+		if (IS_ERR(tve->hclk)) {
+			dev_err(tve->dev, "Unable to get tve hclk\n");
+			return PTR_ERR(tve->hclk);
+		}
+
+		ret = clk_prepare_enable(tve->hclk);
+		if (ret) {
+			dev_err(tve->dev, "Cannot enable tve hclk: %d\n", ret);
+			return ret;
+		}
+
+		tve->pclk_vdac = devm_clk_get(tve->dev, "pclk_vdac");
+		if (IS_ERR(tve->pclk_vdac)) {
+			dev_err(tve->dev, "Unable to get vdac pclk\n");
+			return PTR_ERR(tve->pclk_vdac);
+		}
+
+		ret = clk_prepare_enable(tve->pclk_vdac);
+		if (ret) {
+			dev_err(tve->dev, "Cannot enable vdac pclk: %d\n", ret);
+			return ret;
+		}
+
+		tve->dclk = devm_clk_get(tve->dev, "dclk");
+		if (IS_ERR(tve->dclk)) {
+			dev_err(tve->dev, "Unable to get tve dclk\n");
+			return PTR_ERR(tve->dclk);
+		}
+
+		ret = clk_prepare_enable(tve->dclk);
+		if (ret) {
+			dev_err(tve->dev, "Cannot enable tve dclk: %d\n", ret);
+			return ret;
+		}
+
+		if (tve->upsample_mode == DCLK_UPSAMPLEx4) {
+			tve->dclk_4x = devm_clk_get(tve->dev, "dclk_4x");
+			if (IS_ERR(tve->dclk_4x)) {
+				dev_err(tve->dev, "Unable to get tve dclk_4x\n");
+				return PTR_ERR(tve->dclk_4x);
+			}
+
+			ret = clk_prepare_enable(tve->dclk_4x);
+			if (ret) {
+				dev_err(tve->dev, "Cannot enable tve dclk_4x: %d\n", ret);
+				return ret;
+			}
 		}
 	}
 
@@ -621,6 +993,7 @@
 	rockchip_drm_register_sub_dev(&tve->sub_dev);
 
 	pm_runtime_enable(dev);
+	dev_set_drvdata(dev, tve);
 	dev_dbg(tve->dev, "%s tv encoder probe ok\n", match->compatible);
 
 	return 0;
@@ -648,6 +1021,7 @@
 	drm_encoder_cleanup(&tve->encoder);
 
 	pm_runtime_disable(dev);
+	dev_set_drvdata(dev, NULL);
 }
 
 static const struct component_ops rockchip_tve_component_ops = {
@@ -666,6 +1040,9 @@
 {
 	struct rockchip_tve *tve = dev_get_drvdata(&pdev->dev);
 
+	if (!tve)
+		return;
+
 	mutex_lock(&tve->suspend_lock);
 
 	dev_dbg(tve->dev, "tve shutdown\n");

--
Gitblit v1.6.2