Skip to content

Commit 3e89a8c

Browse files
Andy Yanmmind
authored andcommitted
drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568
The all video ports of rk3568/rk3588 share the same OVL_LAYER_SEL and OVL_PORT_SEL registers, and the configuration of these two registers can be set to take effect when the vsync signal arrives at a certain Video Port. If two threads for two display output choose to update these two registers simultaneously to meet their own plane adjustment requirements(change plane zpos or switch plane from one crtc to another), then no matter which Video Port'svsync signal we choose to follow for these two registers, the display output of the other Video Port will be abnormal. This is because the configuration of this Video Port does not take effect at the right time (its configuration should take effect when its VSYNC signal arrives). In order to solve this problem, when performing plane migration or change the zpos of planes, there are two things to be observed and followed: 1. When a plane is migrated from one VP to another, the configuration of the layer can only take effect after the Port mux configuration is enabled. 2. When change the zpos of planes, we must ensure that the change for the previous VP takes effect before we proceed to change the next VP. Otherwise, the new configuration might overwrite the previous one for the previous VP, or it could lead to the configuration of the previous VP being take effect along with the VSYNC of the new VP. This issue only occurs in scenarios where multi-display output is enabled. Fixes: c5996e4 ("drm/rockchip: vop2: Make overlay layer select register configuration take effect by vsync") Signed-off-by: Andy Yan <[email protected]> Signed-off-by: Heiko Stuebner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 6a1b922 commit 3e89a8c

File tree

3 files changed

+122
-25
lines changed

3 files changed

+122
-25
lines changed

drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -146,25 +146,6 @@ static void vop2_unlock(struct vop2 *vop2)
146146
mutex_unlock(&vop2->vop2_lock);
147147
}
148148

149-
/*
150-
* Note:
151-
* The write mask function is documented but missing on rk3566/8, writes
152-
* to these bits have no effect. For newer soc(rk3588 and following) the
153-
* write mask is needed for register writes.
154-
*
155-
* GLB_CFG_DONE_EN has no write mask bit.
156-
*
157-
*/
158-
static void vop2_cfg_done(struct vop2_video_port *vp)
159-
{
160-
struct vop2 *vop2 = vp->vop2;
161-
u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
162-
163-
val |= BIT(vp->id) | (BIT(vp->id) << 16);
164-
165-
regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
166-
}
167-
168149
static void vop2_win_disable(struct vop2_win *win)
169150
{
170151
vop2_win_write(win, VOP2_WIN_ENABLE, 0);
@@ -854,6 +835,11 @@ static void vop2_enable(struct vop2 *vop2)
854835
if (vop2->version == VOP_VERSION_RK3588)
855836
rk3588_vop2_power_domain_enable_all(vop2);
856837

838+
if (vop2->version <= VOP_VERSION_RK3588) {
839+
vop2->old_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
840+
vop2->old_port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
841+
}
842+
857843
vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
858844

859845
/*
@@ -2728,6 +2714,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
27282714
return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n");
27292715

27302716
mutex_init(&vop2->vop2_lock);
2717+
mutex_init(&vop2->ovl_lock);
27312718

27322719
ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
27332720
if (ret)

drivers/gpu/drm/rockchip/rockchip_drm_vop2.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,19 @@ struct vop2 {
334334
/* optional internal rgb encoder */
335335
struct rockchip_rgb *rgb;
336336

337+
/*
338+
* Used to record layer selection configuration on rk356x/rk3588
339+
* as register RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are
340+
* shared for all the Video Ports.
341+
*/
342+
u32 old_layer_sel;
343+
u32 old_port_sel;
344+
/*
345+
* Ensure that the updates to these two registers(RKK3568_OVL_LAYER_SEL/RK3568_OVL_PORT_SEL)
346+
* take effect in sequence.
347+
*/
348+
struct mutex ovl_lock;
349+
337350
/* must be put at the end of the struct */
338351
struct vop2_win win[];
339352
};
@@ -727,6 +740,7 @@ enum dst_factor_mode {
727740
#define RK3588_OVL_PORT_SEL__CLUSTER2 GENMASK(21, 20)
728741
#define RK3568_OVL_PORT_SEL__CLUSTER1 GENMASK(19, 18)
729742
#define RK3568_OVL_PORT_SEL__CLUSTER0 GENMASK(17, 16)
743+
#define RK3588_OVL_PORT_SET__PORT3_MUX GENMASK(15, 12)
730744
#define RK3568_OVL_PORT_SET__PORT2_MUX GENMASK(11, 8)
731745
#define RK3568_OVL_PORT_SET__PORT1_MUX GENMASK(7, 4)
732746
#define RK3568_OVL_PORT_SET__PORT0_MUX GENMASK(3, 0)
@@ -831,4 +845,23 @@ static inline struct vop2_win *to_vop2_win(struct drm_plane *p)
831845
return container_of(p, struct vop2_win, base);
832846
}
833847

848+
/*
849+
* Note:
850+
* The write mask function is documented but missing on rk3566/8, writes
851+
* to these bits have no effect. For newer soc(rk3588 and following) the
852+
* write mask is needed for register writes.
853+
*
854+
* GLB_CFG_DONE_EN has no write mask bit.
855+
*
856+
*/
857+
static inline void vop2_cfg_done(struct vop2_video_port *vp)
858+
{
859+
struct vop2 *vop2 = vp->vop2;
860+
u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
861+
862+
val |= BIT(vp->id) | (BIT(vp->id) << 16);
863+
864+
regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
865+
}
866+
834867
#endif /* _ROCKCHIP_DRM_VOP2_H */

drivers/gpu/drm/rockchip/rockchip_vop2_reg.c

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,12 +2052,55 @@ static void vop2_setup_alpha(struct vop2_video_port *vp)
20522052
}
20532053
}
20542054

2055+
static u32 rk3568_vop2_read_port_mux(struct vop2 *vop2)
2056+
{
2057+
return vop2_readl(vop2, RK3568_OVL_PORT_SEL);
2058+
}
2059+
2060+
static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2)
2061+
{
2062+
u32 port_mux_sel;
2063+
int ret;
2064+
2065+
/*
2066+
* Spin until the previous port_mux figuration is done.
2067+
*/
2068+
ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel,
2069+
port_mux_sel == vop2->old_port_sel, 0, 50 * 1000);
2070+
if (ret)
2071+
DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n",
2072+
port_mux_sel, vop2->old_port_sel);
2073+
}
2074+
2075+
static u32 rk3568_vop2_read_layer_cfg(struct vop2 *vop2)
2076+
{
2077+
return vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
2078+
}
2079+
2080+
static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg)
2081+
{
2082+
u32 atv_layer_cfg;
2083+
int ret;
2084+
2085+
/*
2086+
* Spin until the previous layer configuration is done.
2087+
*/
2088+
ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg,
2089+
atv_layer_cfg == cfg, 0, 50 * 1000);
2090+
if (ret)
2091+
DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n",
2092+
atv_layer_cfg, cfg);
2093+
}
2094+
20552095
static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
20562096
{
20572097
struct vop2 *vop2 = vp->vop2;
20582098
struct drm_plane *plane;
20592099
u32 layer_sel = 0;
20602100
u32 port_sel;
2101+
u32 old_layer_sel = 0;
2102+
u32 atv_layer_sel = 0;
2103+
u32 old_port_sel = 0;
20612104
u8 layer_id;
20622105
u8 old_layer_id;
20632106
u8 layer_sel_id;
@@ -2069,19 +2112,18 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
20692112
struct vop2_video_port *vp2 = &vop2->vps[2];
20702113
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
20712114

2115+
mutex_lock(&vop2->ovl_lock);
20722116
ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL);
20732117
ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;
20742118
ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL;
2075-
ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
20762119

20772120
if (vcstate->yuv_overlay)
20782121
ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id);
20792122
else
20802123
ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(vp->id);
20812124

2082-
vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
2083-
2084-
port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
2125+
old_port_sel = vop2->old_port_sel;
2126+
port_sel = old_port_sel;
20852127
port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
20862128

20872129
if (vp0->nlayers)
@@ -2102,7 +2144,13 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
21022144
else
21032145
port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8);
21042146

2105-
layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
2147+
/* Fixed value for rk3588 */
2148+
if (vop2->version == VOP_VERSION_RK3588)
2149+
port_sel |= FIELD_PREP(RK3588_OVL_PORT_SET__PORT3_MUX, 7);
2150+
2151+
atv_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
2152+
old_layer_sel = vop2->old_layer_sel;
2153+
layer_sel = old_layer_sel;
21062154

21072155
ofs = 0;
21082156
for (i = 0; i < vp->id; i++)
@@ -2186,8 +2234,37 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
21862234
old_win->data->layer_sel_id[vp->id]);
21872235
}
21882236

2237+
vop2->old_layer_sel = layer_sel;
2238+
vop2->old_port_sel = port_sel;
2239+
/*
2240+
* As the RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are shared by all Video Ports,
2241+
* and the configuration take effect by one Video Port's vsync.
2242+
* When performing layer migration or change the zpos of layers, there are two things
2243+
* to be observed and followed:
2244+
* 1. When a layer is migrated from one VP to another, the configuration of the layer
2245+
* can only take effect after the Port mux configuration is enabled.
2246+
*
2247+
* 2. When we change the zpos of layers, we must ensure that the change for the previous
2248+
* VP takes effect before we proceed to change the next VP. Otherwise, the new
2249+
* configuration might overwrite the previous one for the previous VP, or it could
2250+
* lead to the configuration of the previous VP being take effect along with the VSYNC
2251+
* of the new VP.
2252+
*/
2253+
if (layer_sel != old_layer_sel || port_sel != old_port_sel)
2254+
ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
2255+
vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
2256+
2257+
if (port_sel != old_port_sel) {
2258+
vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
2259+
vop2_cfg_done(vp);
2260+
rk3568_vop2_wait_for_port_mux_done(vop2);
2261+
}
2262+
2263+
if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel)
2264+
rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
2265+
21892266
vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
2190-
vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
2267+
mutex_unlock(&vop2->ovl_lock);
21912268
}
21922269

21932270
static void rk3568_vop2_setup_dly_for_windows(struct vop2_video_port *vp)

0 commit comments

Comments
 (0)