Commit 5a028e8f authored by Andy Yan's avatar Andy Yan Committed by Heiko Stuebner
Browse files

drm/rockchip: vop2: Add support for rk3588



VOP2 on rk3588:

Four video ports:
VP0 Max 4096x2160
VP1 Max 4096x2160
VP2 Max 4096x2160
VP3 Max 2048x1080

4 4K Cluster windows with AFBC/line RGB and AFBC-only YUV support
4 4K Esmart windows with line RGB/YUV support

Signed-off-by: default avatarAndy Yan <andy.yan@rock-chips.com>
Reviewed-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarHeiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20231211115919.1785435-1-andyshrk@163.com
parent dc7226ac
Loading
Loading
Loading
Loading
+394 −6
Original line number Diff line number Diff line
@@ -191,6 +191,9 @@ struct vop2 {
	struct regmap *map;

	struct regmap *sys_grf;
	struct regmap *vop_grf;
	struct regmap *vo1_grf;
	struct regmap *sys_pmu;

	/* physical map length of vop2 register */
	u32 len;
@@ -209,6 +212,7 @@ struct vop2 {
	unsigned int enable_count;
	struct clk *hclk;
	struct clk *aclk;
	struct clk *pclk;

	/* optional internal rgb encoder */
	struct rockchip_rgb *rgb;
@@ -217,6 +221,23 @@ struct vop2 {
	struct vop2_win win[];
};

#define vop2_output_if_is_hdmi(x)	((x) == ROCKCHIP_VOP2_EP_HDMI0 || \
					 (x) == ROCKCHIP_VOP2_EP_HDMI1)

#define vop2_output_if_is_dp(x)		((x) == ROCKCHIP_VOP2_EP_DP0 || \
					 (x) == ROCKCHIP_VOP2_EP_DP1)

#define vop2_output_if_is_edp(x)	((x) == ROCKCHIP_VOP2_EP_EDP0 || \
					 (x) == ROCKCHIP_VOP2_EP_EDP1)

#define vop2_output_if_is_mipi(x)	((x) == ROCKCHIP_VOP2_EP_MIPI0 || \
					 (x) == ROCKCHIP_VOP2_EP_MIPI1)

#define vop2_output_if_is_lvds(x)	((x) == ROCKCHIP_VOP2_EP_LVDS0 || \
					 (x) == ROCKCHIP_VOP2_EP_LVDS1)

#define vop2_output_if_is_dpi(x)	((x) == ROCKCHIP_VOP2_EP_RGB0)

static const struct regmap_config vop2_regmap_config;

static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
@@ -475,6 +496,17 @@ static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode)
		return false;
}

static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format)
{
	if (vop2->data->soc_id == 3588) {
		if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
		    bus_format == MEDIA_BUS_FMT_YUV10_1X30)
			return true;
	}

	return false;
}

static bool is_yuv_output(u32 bus_format)
{
	switch (bus_format) {
@@ -879,13 +911,32 @@ static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
		goto err;
	}

	ret = clk_prepare_enable(vop2->pclk);
	if (ret < 0) {
		drm_err(vop2->drm, "failed to enable pclk - %d\n", ret);
		goto err1;
	}

	return 0;
err1:
	clk_disable_unprepare(vop2->aclk);
err:
	clk_disable_unprepare(vop2->hclk);

	return ret;
}

static void rk3588_vop2_power_domain_enable_all(struct vop2 *vop2)
{
	u32 pd;

	pd = vop2_readl(vop2, RK3588_SYS_PD_CTRL);
	pd &= ~(VOP2_PD_CLUSTER0 | VOP2_PD_CLUSTER1 | VOP2_PD_CLUSTER2 |
		VOP2_PD_CLUSTER3 | VOP2_PD_ESMART);

	vop2_writel(vop2, RK3588_SYS_PD_CTRL, pd);
}

static void vop2_enable(struct vop2 *vop2)
{
	int ret;
@@ -917,6 +968,9 @@ static void vop2_enable(struct vop2 *vop2)
	if (vop2->data->soc_id == 3566)
		vop2_writel(vop2, RK3568_OTP_WIN_EN, 1);

	if (vop2->data->soc_id == 3588)
		rk3588_vop2_power_domain_enable_all(vop2);

	vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);

	/*
@@ -942,6 +996,7 @@ static void vop2_disable(struct vop2 *vop2)

	pm_runtime_put_sync(vop2->dev);

	clk_disable_unprepare(vop2->pclk);
	clk_disable_unprepare(vop2->aclk);
	clk_disable_unprepare(vop2->hclk);
}
@@ -1309,7 +1364,19 @@ static void vop2_plane_atomic_update(struct drm_plane *plane,
			vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1);
		vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format);
		vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap);
		/*
		 * On rk3566/8, this bit is auto gating enable,
		 * but this function is not work well so we need
		 * to disable it for these two platform.
		 * On rk3588, and the following new soc(rk3528/rk3576),
		 * this bit is gating disable, we should write 1 to
		 * disable gating when enable afbc.
		 */
		if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
			vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0);
		else
			vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1);

		vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0);
		transform_offset = vop2_afbc_transform_offset(pstate, half_block_en);
		vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst);
@@ -1507,10 +1574,10 @@ static void vop2_post_config(struct drm_crtc *crtc)
	vop2_vp_write(vp, RK3568_VP_DSP_BG, 0);
}

static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
				u32 polflags)
static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
{
	struct vop2 *vop2 = vp->vop2;
	struct drm_crtc *crtc = &vp->crtc;
	u32 die, dip;

	die = vop2_readl(vop2, RK3568_DSP_IF_EN);
@@ -1572,13 +1639,281 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id,
		break;
	default:
		drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id);
		return;
		return 0;
	}

	dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;

	vop2_writel(vop2, RK3568_DSP_IF_EN, die);
	vop2_writel(vop2, RK3568_DSP_IF_POL, dip);

	return crtc->state->adjusted_mode.crtc_clock  * 1000LL;
}

/*
 * calc the dclk on rk3588
 * the available div of dclk is 1, 2, 4
 */
static unsigned long rk3588_calc_dclk(unsigned long child_clk, unsigned long max_dclk)
{
	if (child_clk * 4 <= max_dclk)
		return child_clk * 4;
	else if (child_clk * 2 <= max_dclk)
		return child_clk * 2;
	else if (child_clk <= max_dclk)
		return child_clk;
	else
		return 0;
}

/*
 * 4 pixclk/cycle on rk3588
 * RGB/eDP/HDMI: if_pixclk >= dclk_core
 * DP: dp_pixclk = dclk_out <= dclk_core
 * DSI: mipi_pixclk <= dclk_out <= dclk_core
 */
static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id,
					 int *dclk_core_div, int *dclk_out_div,
					 int *if_pixclk_div, int *if_dclk_div)
{
	struct vop2 *vop2 = vp->vop2;
	struct drm_crtc *crtc = &vp->crtc;
	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
	int output_mode = vcstate->output_mode;
	unsigned long v_pixclk = adjusted_mode->crtc_clock * 1000LL; /* video timing pixclk */
	unsigned long dclk_core_rate = v_pixclk >> 2;
	unsigned long dclk_rate = v_pixclk;
	unsigned long dclk_out_rate;
	unsigned long if_dclk_rate;
	unsigned long if_pixclk_rate;
	int K = 1;

	if (vop2_output_if_is_hdmi(id)) {
		/*
		 * K = 2: dclk_core = if_pixclk_rate > if_dclk_rate
		 * K = 1: dclk_core = hdmie_edp_dclk > if_pixclk_rate
		 */
		if (output_mode == ROCKCHIP_OUT_MODE_YUV420) {
			dclk_rate = dclk_rate >> 1;
			K = 2;
		}

		if_pixclk_rate = (dclk_core_rate << 1) / K;
		if_dclk_rate = dclk_core_rate / K;
		/*
		 * *if_pixclk_div = dclk_rate / if_pixclk_rate;
		 * *if_dclk_div = dclk_rate / if_dclk_rate;
		 */
		 *if_pixclk_div = 2;
		 *if_dclk_div = 4;
	} else if (vop2_output_if_is_edp(id)) {
		/*
		 * edp_pixclk = edp_dclk > dclk_core
		 */
		if_pixclk_rate = v_pixclk / K;
		dclk_rate = if_pixclk_rate * K;
		/*
		 * *if_pixclk_div = dclk_rate / if_pixclk_rate;
		 * *if_dclk_div = *if_pixclk_div;
		 */
		*if_pixclk_div = K;
		*if_dclk_div = K;
	} else if (vop2_output_if_is_dp(id)) {
		if (output_mode == ROCKCHIP_OUT_MODE_YUV420)
			dclk_out_rate = v_pixclk >> 3;
		else
			dclk_out_rate = v_pixclk >> 2;

		dclk_rate = rk3588_calc_dclk(dclk_out_rate, 600000);
		if (!dclk_rate) {
			drm_err(vop2->drm, "DP dclk_out_rate out of range, dclk_out_rate: %ld KHZ\n",
				dclk_out_rate);
			return 0;
		}
		*dclk_out_div = dclk_rate / dclk_out_rate;
	} else if (vop2_output_if_is_mipi(id)) {
		if_pixclk_rate = dclk_core_rate / K;
		/*
		 * dclk_core = dclk_out * K = if_pixclk * K = v_pixclk / 4
		 */
		dclk_out_rate = if_pixclk_rate;
		/*
		 * dclk_rate = N * dclk_core_rate N = (1,2,4 ),
		 * we get a little factor here
		 */
		dclk_rate = rk3588_calc_dclk(dclk_out_rate, 600000);
		if (!dclk_rate) {
			drm_err(vop2->drm, "MIPI dclk out of range, dclk_out_rate: %ld KHZ\n",
				dclk_out_rate);
			return 0;
		}
		*dclk_out_div = dclk_rate / dclk_out_rate;
		/*
		 * mipi pixclk == dclk_out
		 */
		*if_pixclk_div = 1;
	} else if (vop2_output_if_is_dpi(id)) {
		dclk_rate = v_pixclk;
	}

	*dclk_core_div = dclk_rate / dclk_core_rate;
	*if_pixclk_div = ilog2(*if_pixclk_div);
	*if_dclk_div = ilog2(*if_dclk_div);
	*dclk_core_div = ilog2(*dclk_core_div);
	*dclk_out_div = ilog2(*dclk_out_div);

	drm_dbg(vop2->drm, "dclk: %ld, pixclk_div: %d, dclk_div: %d\n",
		dclk_rate, *if_pixclk_div, *if_dclk_div);

	return dclk_rate;
}

/*
 * MIPI port mux on rk3588:
 * 0: Video Port2
 * 1: Video Port3
 * 3: Video Port 1(MIPI1 only)
 */
static u32 rk3588_get_mipi_port_mux(int vp_id)
{
	if (vp_id == 1)
		return 3;
	else if (vp_id == 3)
		return 1;
	else
		return 0;
}

static u32 rk3588_get_hdmi_pol(u32 flags)
{
	u32 val;

	val = (flags & DRM_MODE_FLAG_NHSYNC) ? BIT(HSYNC_POSITIVE) : 0;
	val |= (flags & DRM_MODE_FLAG_NVSYNC) ? BIT(VSYNC_POSITIVE) : 0;

	return val;
}

static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
{
	struct vop2 *vop2 = vp->vop2;
	int dclk_core_div, dclk_out_div, if_pixclk_div, if_dclk_div;
	unsigned long clock;
	u32 die, dip, div, vp_clk_div, val;

	clock = rk3588_calc_cru_cfg(vp, id, &dclk_core_div, &dclk_out_div,
				    &if_pixclk_div, &if_dclk_div);
	if (!clock)
		return 0;

	vp_clk_div = FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_CORE_DIV, dclk_core_div);
	vp_clk_div |= FIELD_PREP(RK3588_VP_CLK_CTRL__DCLK_OUT_DIV, dclk_out_div);

	die = vop2_readl(vop2, RK3568_DSP_IF_EN);
	dip = vop2_readl(vop2, RK3568_DSP_IF_POL);
	div = vop2_readl(vop2, RK3568_DSP_IF_CTRL);

	switch (id) {
	case ROCKCHIP_VOP2_EP_HDMI0:
		div &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV;
		div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV;
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);
		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX;
		die |= RK3588_SYS_DSP_INFACE_EN_HDMI0 |
			    FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id);
		val = rk3588_get_hdmi_pol(polflags);
		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 1, 1));
		regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 6, 5));
		break;
	case ROCKCHIP_VOP2_EP_HDMI1:
		div &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV;
		div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV;
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV, if_dclk_div);
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV, if_pixclk_div);
		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX;
		die |= RK3588_SYS_DSP_INFACE_EN_HDMI1 |
			    FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id);
		val = rk3588_get_hdmi_pol(polflags);
		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 4, 4));
		regmap_write(vop2->vo1_grf, RK3588_GRF_VO1_CON0, HIWORD_UPDATE(val, 8, 7));
		break;
	case ROCKCHIP_VOP2_EP_EDP0:
		div &= ~RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV;
		div &= ~RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV;
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);
		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX;
		die |= RK3588_SYS_DSP_INFACE_EN_EDP0 |
			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX, vp->id);
		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 0, 0));
		break;
	case ROCKCHIP_VOP2_EP_EDP1:
		div &= ~RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV;
		div &= ~RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV;
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV, if_dclk_div);
		div |= FIELD_PREP(RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV, if_pixclk_div);
		die &= ~RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX;
		die |= RK3588_SYS_DSP_INFACE_EN_EDP1 |
			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX, vp->id);
		regmap_write(vop2->vop_grf, RK3588_GRF_VOP_CON2, HIWORD_UPDATE(1, 3, 3));
		break;
	case ROCKCHIP_VOP2_EP_MIPI0:
		div &= ~RK3588_DSP_IF_MIPI0_PCLK_DIV;
		div |= FIELD_PREP(RK3588_DSP_IF_MIPI0_PCLK_DIV, if_pixclk_div);
		die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX;
		val = rk3588_get_mipi_port_mux(vp->id);
		die |= RK3588_SYS_DSP_INFACE_EN_MIPI0 |
			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX, !!val);
		break;
	case ROCKCHIP_VOP2_EP_MIPI1:
		div &= ~RK3588_DSP_IF_MIPI1_PCLK_DIV;
		div |= FIELD_PREP(RK3588_DSP_IF_MIPI1_PCLK_DIV, if_pixclk_div);
		die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX;
		val = rk3588_get_mipi_port_mux(vp->id);
		die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 |
			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, val);
		break;
	case ROCKCHIP_VOP2_EP_DP0:
		die &= ~RK3588_SYS_DSP_INFACE_EN_DP0_MUX;
		die |= RK3588_SYS_DSP_INFACE_EN_DP0 |
			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_DP0_MUX, vp->id);
		dip &= ~RK3588_DSP_IF_POL__DP0_PIN_POL;
		dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP0_PIN_POL, polflags);
		break;
	case ROCKCHIP_VOP2_EP_DP1:
		die &= ~RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX;
		die |= RK3588_SYS_DSP_INFACE_EN_MIPI1 |
			   FIELD_PREP(RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id);
		dip &= ~RK3588_DSP_IF_POL__DP1_PIN_POL;
		dip |= FIELD_PREP(RK3588_DSP_IF_POL__DP1_PIN_POL, polflags);
		break;
	default:
		drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id);
		return 0;
	}

	dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD;

	vop2_vp_write(vp, RK3588_VP_CLK_CTRL, vp_clk_div);
	vop2_writel(vop2, RK3568_DSP_IF_EN, die);
	vop2_writel(vop2, RK3568_DSP_IF_CTRL, div);
	vop2_writel(vop2, RK3568_DSP_IF_POL, dip);

	return clock;
}

static unsigned long vop2_set_intf_mux(struct vop2_video_port *vp, int ep_id, u32 polflags)
{
	struct vop2 *vop2 = vp->vop2;

	if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568)
		return rk3568_set_intf_mux(vp, ep_id, polflags);
	else if (vop2->data->soc_id == 3588)
		return rk3588_set_intf_mux(vp, ep_id, polflags);
	else
		return 0;
}

static int us_to_vertical_line(struct drm_display_mode *mode, int us)
@@ -1648,9 +1983,17 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
	drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) {
		struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);

		rk3568_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);
		/*
		 * for drive a high resolution(4KP120, 8K), vop on rk3588/rk3576 need
		 * process multi(1/2/4/8) pixels per cycle, so the dclk feed by the
		 * system cru may be the 1/2 or 1/4 of mode->clock.
		 */
		clock = vop2_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags);
	}

	if (!clock)
		return;

	if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
	    !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT))
		out_mode = ROCKCHIP_OUT_MODE_P888;
@@ -1661,6 +2004,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,

	if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode))
		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP;
	if (vop2_output_rg_swap(vop2, vcstate->bus_format))
		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RG_SWAP;

	if (vcstate->yuv_overlay)
		dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y;
@@ -2022,6 +2367,14 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
			port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1;
			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id);
			break;
		case ROCKCHIP_VOP2_CLUSTER2:
			port_sel &= ~RK3588_OVL_PORT_SEL__CLUSTER2;
			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__CLUSTER2, vp->id);
			break;
		case ROCKCHIP_VOP2_CLUSTER3:
			port_sel &= ~RK3588_OVL_PORT_SEL__CLUSTER3;
			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__CLUSTER3, vp->id);
			break;
		case ROCKCHIP_VOP2_ESMART0:
			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0;
			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id);
@@ -2030,6 +2383,14 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
			port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1;
			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id);
			break;
		case ROCKCHIP_VOP2_ESMART2:
			port_sel &= ~RK3588_OVL_PORT_SEL__ESMART2;
			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__ESMART2, vp->id);
			break;
		case ROCKCHIP_VOP2_ESMART3:
			port_sel &= ~RK3588_OVL_PORT_SEL__ESMART3;
			port_sel |= FIELD_PREP(RK3588_OVL_PORT_SEL__ESMART3, vp->id);
			break;
		case ROCKCHIP_VOP2_SMART0:
			port_sel &= ~RK3568_OVL_PORT_SEL__SMART0;
			port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id);
@@ -2766,8 +3127,29 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
		if (IS_ERR(vop2->lut_regs))
			return PTR_ERR(vop2->lut_regs);
	}

	if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_GRF) {
		vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
		if (IS_ERR(vop2->sys_grf))
			return dev_err_probe(dev, PTR_ERR(vop2->sys_grf), "cannot get sys_grf");
	}

	if (vop2_data->feature & VOP2_FEATURE_HAS_VOP_GRF) {
		vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf");
		if (IS_ERR(vop2->vop_grf))
			return dev_err_probe(dev, PTR_ERR(vop2->vop_grf), "cannot get vop_grf");
	}

	if (vop2_data->feature & VOP2_FEATURE_HAS_VO1_GRF) {
		vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf");
		if (IS_ERR(vop2->vo1_grf))
			return dev_err_probe(dev, PTR_ERR(vop2->vo1_grf), "cannot get vo1_grf");
	}

	if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_PMU) {
		vop2->sys_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu");
		if (IS_ERR(vop2->sys_pmu))
			return dev_err_probe(dev, PTR_ERR(vop2->sys_pmu), "cannot get sys_pmu");
	}

	vop2->hclk = devm_clk_get(vop2->dev, "hclk");
	if (IS_ERR(vop2->hclk)) {
@@ -2781,6 +3163,12 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
		return PTR_ERR(vop2->aclk);
	}

	vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk_vop");
	if (IS_ERR(vop2->pclk)) {
		drm_err(vop2->drm, "failed to get pclk source\n");
		return PTR_ERR(vop2->pclk);
	}

	vop2->irq = platform_get_irq(pdev, 0);
	if (vop2->irq < 0) {
		drm_err(vop2->drm, "cannot find irq for vop2\n");
+81 −0
Original line number Diff line number Diff line
@@ -13,9 +13,16 @@

#define VOP_FEATURE_OUTPUT_10BIT        BIT(0)

#define VOP2_FEATURE_HAS_SYS_GRF	BIT(0)
#define VOP2_FEATURE_HAS_VO0_GRF	BIT(1)
#define VOP2_FEATURE_HAS_VO1_GRF	BIT(2)
#define VOP2_FEATURE_HAS_VOP_GRF	BIT(3)
#define VOP2_FEATURE_HAS_SYS_PMU	BIT(4)

#define WIN_FEATURE_AFBDC		BIT(0)
#define WIN_FEATURE_CLUSTER		BIT(1)

#define HIWORD_UPDATE(v, h, l)  ((GENMASK(h, l) << 16) | ((v) << (l)))
/*
 *  the delay number of a window in different mode.
 */
@@ -38,6 +45,18 @@ enum vop2_scale_down_mode {
	VOP2_SCALE_DOWN_AVG,
};

/*
 * vop2 internal power domain id,
 * should be all none zero, 0 will be treat as invalid;
 */
#define VOP2_PD_CLUSTER0	BIT(0)
#define VOP2_PD_CLUSTER1	BIT(1)
#define VOP2_PD_CLUSTER2	BIT(2)
#define VOP2_PD_CLUSTER3	BIT(3)
#define VOP2_PD_DSC_8K		BIT(5)
#define VOP2_PD_DSC_4K		BIT(6)
#define VOP2_PD_ESMART		BIT(7)

enum vop2_win_regs {
	VOP2_WIN_ENABLE,
	VOP2_WIN_FORMAT,
@@ -138,6 +157,7 @@ struct vop2_video_port_data {

struct vop2_data {
	u8 nr_vps;
	u64 feature;
	const struct vop2_win_data *win;
	const struct vop2_video_port_data *vp;
	struct vop_rect max_input;
@@ -192,6 +212,11 @@ enum dst_factor_mode {
};

#define RK3568_GRF_VO_CON1			0x0364

#define RK3588_GRF_SOC_CON1			0x0304
#define RK3588_GRF_VOP_CON2			0x08
#define RK3588_GRF_VO1_CON0			0x00

/* System registers definition */
#define RK3568_REG_CFG_DONE			0x000
#define RK3568_VERSION_INFO			0x004
@@ -200,6 +225,7 @@ enum dst_factor_mode {
#define RK3568_DSP_IF_EN			0x028
#define RK3568_DSP_IF_CTRL			0x02c
#define RK3568_DSP_IF_POL			0x030
#define RK3588_SYS_PD_CTRL			0x034
#define RK3568_WB_CTRL				0x40
#define RK3568_WB_XSCAL_FACTOR			0x44
#define RK3568_WB_YRGB_MST			0x48
@@ -220,9 +246,14 @@ enum dst_factor_mode {
#define RK3568_VP_INT_RAW_STATUS(vp)		(0xAC + (vp) * 0x10)

/* Video Port registers definition */
#define RK3568_VP0_CTRL_BASE			0x0C00
#define RK3568_VP1_CTRL_BASE			0x0D00
#define RK3568_VP2_CTRL_BASE			0x0E00
#define RK3588_VP3_CTRL_BASE			0x0F00
#define RK3568_VP_DSP_CTRL			0x00
#define RK3568_VP_MIPI_CTRL			0x04
#define RK3568_VP_COLOR_BAR_CTRL		0x08
#define RK3588_VP_CLK_CTRL			0x0C
#define RK3568_VP_3D_LUT_CTRL			0x10
#define RK3568_VP_3D_LUT_MST			0x20
#define RK3568_VP_DSP_BG			0x2C
@@ -264,6 +295,17 @@ enum dst_factor_mode {
#define RK3568_SMART_DLY_NUM			0x6F8

/* Cluster register definition, offset relative to window base */
#define RK3568_CLUSTER0_CTRL_BASE		0x1000
#define RK3568_CLUSTER1_CTRL_BASE		0x1200
#define RK3588_CLUSTER2_CTRL_BASE		0x1400
#define RK3588_CLUSTER3_CTRL_BASE		0x1600
#define RK3568_ESMART0_CTRL_BASE		0x1800
#define RK3568_ESMART1_CTRL_BASE		0x1A00
#define RK3568_SMART0_CTRL_BASE			0x1C00
#define RK3568_SMART1_CTRL_BASE			0x1E00
#define RK3588_ESMART2_CTRL_BASE		0x1C00
#define RK3588_ESMART3_CTRL_BASE		0x1E00

#define RK3568_CLUSTER_WIN_CTRL0		0x00
#define RK3568_CLUSTER_WIN_CTRL1		0x04
#define RK3568_CLUSTER_WIN_YRGB_MST		0x10
@@ -357,13 +399,18 @@ enum dst_factor_mode {
#define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN		BIT(17)
#define RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN		BIT(16)
#define RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y		BIT(15)
#define RK3568_VP_DSP_CTRL__DSP_RG_SWAP			BIT(10)
#define RK3568_VP_DSP_CTRL__DSP_RB_SWAP			BIT(9)
#define RK3568_VP_DSP_CTRL__DSP_BG_SWAP			BIT(8)
#define RK3568_VP_DSP_CTRL__DSP_INTERLACE		BIT(7)
#define RK3568_VP_DSP_CTRL__DSP_FILED_POL		BIT(6)
#define RK3568_VP_DSP_CTRL__P2I_EN			BIT(5)
#define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV		BIT(4)
#define RK3568_VP_DSP_CTRL__OUT_MODE			GENMASK(3, 0)

#define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV		GENMASK(3, 2)
#define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV		GENMASK(1, 0)

#define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN		BIT(1)
#define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN		BIT(0)

@@ -382,11 +429,37 @@ enum dst_factor_mode {
#define RK3568_SYS_DSP_INFACE_EN_HDMI			BIT(1)
#define RK3568_SYS_DSP_INFACE_EN_RGB			BIT(0)

#define RK3588_SYS_DSP_INFACE_EN_MIPI1_MUX		GENMASK(22, 21)
#define RK3588_SYS_DSP_INFACE_EN_MIPI0_MUX		GENMASK(20, 20)
#define RK3588_SYS_DSP_INFACE_EN_EDP_HDMI1_MUX		GENMASK(19, 18)
#define RK3588_SYS_DSP_INFACE_EN_EDP_HDMI0_MUX		GENMASK(17, 16)
#define RK3588_SYS_DSP_INFACE_EN_DP1_MUX		GENMASK(15, 14)
#define RK3588_SYS_DSP_INFACE_EN_DP0_MUX		GENMASK(13, 12)
#define RK3588_SYS_DSP_INFACE_EN_DPI			GENMASK(9, 8)
#define RK3588_SYS_DSP_INFACE_EN_MIPI1			BIT(7)
#define RK3588_SYS_DSP_INFACE_EN_MIPI0			BIT(6)
#define RK3588_SYS_DSP_INFACE_EN_HDMI1			BIT(5)
#define RK3588_SYS_DSP_INFACE_EN_EDP1			BIT(4)
#define RK3588_SYS_DSP_INFACE_EN_HDMI0			BIT(3)
#define RK3588_SYS_DSP_INFACE_EN_EDP0			BIT(2)
#define RK3588_SYS_DSP_INFACE_EN_DP1			BIT(1)
#define RK3588_SYS_DSP_INFACE_EN_DP0			BIT(0)

#define RK3588_DSP_IF_MIPI1_PCLK_DIV			GENMASK(27, 26)
#define RK3588_DSP_IF_MIPI0_PCLK_DIV			GENMASK(25, 24)
#define RK3588_DSP_IF_EDP_HDMI1_PCLK_DIV		GENMASK(22, 22)
#define RK3588_DSP_IF_EDP_HDMI1_DCLK_DIV		GENMASK(21, 20)
#define RK3588_DSP_IF_EDP_HDMI0_PCLK_DIV		GENMASK(18, 18)
#define RK3588_DSP_IF_EDP_HDMI0_DCLK_DIV		GENMASK(17, 16)

#define RK3568_DSP_IF_POL__MIPI_PIN_POL			GENMASK(19, 16)
#define RK3568_DSP_IF_POL__EDP_PIN_POL			GENMASK(15, 12)
#define RK3568_DSP_IF_POL__HDMI_PIN_POL			GENMASK(7, 4)
#define RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL		GENMASK(3, 0)

#define RK3588_DSP_IF_POL__DP1_PIN_POL			GENMASK(14, 12)
#define RK3588_DSP_IF_POL__DP0_PIN_POL			GENMASK(10, 8)

#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK	BIT(5)
#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2			BIT(4)

@@ -408,8 +481,12 @@ enum dst_factor_mode {
#define RK3568_OVL_PORT_SEL__SEL_PORT			GENMASK(31, 16)
#define RK3568_OVL_PORT_SEL__SMART1			GENMASK(31, 30)
#define RK3568_OVL_PORT_SEL__SMART0			GENMASK(29, 28)
#define RK3588_OVL_PORT_SEL__ESMART3			GENMASK(31, 30)
#define RK3588_OVL_PORT_SEL__ESMART2			GENMASK(29, 28)
#define RK3568_OVL_PORT_SEL__ESMART1			GENMASK(27, 26)
#define RK3568_OVL_PORT_SEL__ESMART0			GENMASK(25, 24)
#define RK3588_OVL_PORT_SEL__CLUSTER3			GENMASK(23, 22)
#define RK3588_OVL_PORT_SEL__CLUSTER2			GENMASK(21, 20)
#define RK3568_OVL_PORT_SEL__CLUSTER1			GENMASK(19, 18)
#define RK3568_OVL_PORT_SEL__CLUSTER0			GENMASK(17, 16)
#define RK3568_OVL_PORT_SET__PORT2_MUX			GENMASK(11, 8)
@@ -422,6 +499,10 @@ enum dst_factor_mode {
#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_1		GENMASK(15, 8)
#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_0		GENMASK(7, 0)

#define RK3568_CLUSTER_WIN_CTRL0__WIN0_EN		BIT(0)

#define RK3568_SMART_REGION0_CTRL__WIN0_EN		BIT(0)

#define RK3568_SMART_DLY_NUM__SMART1			GENMASK(31, 24)
#define RK3568_SMART_DLY_NUM__SMART0			GENMASK(23, 16)
#define RK3568_SMART_DLY_NUM__ESMART1			GENMASK(15, 8)
+221 −0

File changed.

Preview size limit exceeded, changes collapsed.