drm/mediatek: Add vblank register/unregister callback functions
We encountered a kernel panic issue that callback data will be NULL when it's using in ovl irq handler. There is a timing issue between mtk_disp_ovl_irq_handler() and mtk_ovl_disable_vblank(). To resolve this issue, we use the flow to register/unregister vblank cb: - Register callback function and callback data when crtc creates. - Unregister callback function and callback data when crtc destroies. With this solution, we can assure callback data will not be NULL when vblank is disable. Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20220321072320.15019-1-rex-bc.chen@mediatek.com/ Fixes: 9b0704988b15 ("drm/mediatek: Register vblank callback function") Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com> Reviewed-by: jason-jh.lin <jason-jh.lin@mediatek.com> Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
This commit is contained in:
parent
07fb1e5bab
commit
b74d921b90
@ -76,9 +76,11 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
|
||||
void mtk_ovl_start(struct device *dev);
|
||||
void mtk_ovl_stop(struct device *dev);
|
||||
unsigned int mtk_ovl_supported_rotations(struct device *dev);
|
||||
void mtk_ovl_enable_vblank(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data);
|
||||
void mtk_ovl_register_vblank_cb(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data);
|
||||
void mtk_ovl_unregister_vblank_cb(struct device *dev);
|
||||
void mtk_ovl_enable_vblank(struct device *dev);
|
||||
void mtk_ovl_disable_vblank(struct device *dev);
|
||||
|
||||
void mtk_rdma_bypass_shadow(struct device *dev);
|
||||
@ -93,9 +95,11 @@ void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
|
||||
struct cmdq_pkt *cmdq_pkt);
|
||||
void mtk_rdma_start(struct device *dev);
|
||||
void mtk_rdma_stop(struct device *dev);
|
||||
void mtk_rdma_enable_vblank(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data);
|
||||
void mtk_rdma_register_vblank_cb(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data);
|
||||
void mtk_rdma_unregister_vblank_cb(struct device *dev);
|
||||
void mtk_rdma_enable_vblank(struct device *dev);
|
||||
void mtk_rdma_disable_vblank(struct device *dev);
|
||||
|
||||
#endif
|
||||
|
@ -97,14 +97,28 @@ static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void mtk_ovl_enable_vblank(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data)
|
||||
void mtk_ovl_register_vblank_cb(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data)
|
||||
{
|
||||
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
|
||||
|
||||
ovl->vblank_cb = vblank_cb;
|
||||
ovl->vblank_cb_data = vblank_cb_data;
|
||||
}
|
||||
|
||||
void mtk_ovl_unregister_vblank_cb(struct device *dev)
|
||||
{
|
||||
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
|
||||
|
||||
ovl->vblank_cb = NULL;
|
||||
ovl->vblank_cb_data = NULL;
|
||||
}
|
||||
|
||||
void mtk_ovl_enable_vblank(struct device *dev)
|
||||
{
|
||||
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
|
||||
|
||||
writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
|
||||
writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN);
|
||||
}
|
||||
@ -113,8 +127,6 @@ void mtk_ovl_disable_vblank(struct device *dev)
|
||||
{
|
||||
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
|
||||
|
||||
ovl->vblank_cb = NULL;
|
||||
ovl->vblank_cb_data = NULL;
|
||||
writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
|
||||
}
|
||||
|
||||
|
@ -95,24 +95,32 @@ static void rdma_update_bits(struct device *dev, unsigned int reg,
|
||||
writel(tmp, rdma->regs + reg);
|
||||
}
|
||||
|
||||
void mtk_rdma_enable_vblank(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data)
|
||||
void mtk_rdma_register_vblank_cb(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data)
|
||||
{
|
||||
struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
|
||||
|
||||
rdma->vblank_cb = vblank_cb;
|
||||
rdma->vblank_cb_data = vblank_cb_data;
|
||||
}
|
||||
|
||||
void mtk_rdma_unregister_vblank_cb(struct device *dev)
|
||||
{
|
||||
struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
|
||||
|
||||
rdma->vblank_cb = NULL;
|
||||
rdma->vblank_cb_data = NULL;
|
||||
}
|
||||
|
||||
void mtk_rdma_enable_vblank(struct device *dev)
|
||||
{
|
||||
rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
|
||||
RDMA_FRAME_END_INT);
|
||||
}
|
||||
|
||||
void mtk_rdma_disable_vblank(struct device *dev)
|
||||
{
|
||||
struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
|
||||
|
||||
rdma->vblank_cb = NULL;
|
||||
rdma->vblank_cb_data = NULL;
|
||||
rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,7 @@ static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
|
||||
static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
||||
int i;
|
||||
|
||||
mtk_mutex_put(mtk_crtc->mutex);
|
||||
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
|
||||
@ -162,6 +163,14 @@ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
|
||||
mtk_crtc->cmdq_client.chan = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
|
||||
struct mtk_ddp_comp *comp;
|
||||
|
||||
comp = mtk_crtc->ddp_comp[i];
|
||||
mtk_ddp_comp_unregister_vblank_cb(comp);
|
||||
}
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
}
|
||||
|
||||
@ -618,7 +627,7 @@ static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
||||
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
|
||||
|
||||
mtk_ddp_comp_enable_vblank(comp, mtk_crtc_ddp_irq, &mtk_crtc->base);
|
||||
mtk_ddp_comp_enable_vblank(comp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -927,6 +936,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
|
||||
if (comp->funcs->ctm_set)
|
||||
has_ctm = true;
|
||||
}
|
||||
|
||||
mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
|
||||
&mtk_crtc->base);
|
||||
}
|
||||
|
||||
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
|
||||
|
@ -297,6 +297,8 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
|
||||
.config = mtk_ovl_config,
|
||||
.start = mtk_ovl_start,
|
||||
.stop = mtk_ovl_stop,
|
||||
.register_vblank_cb = mtk_ovl_register_vblank_cb,
|
||||
.unregister_vblank_cb = mtk_ovl_unregister_vblank_cb,
|
||||
.enable_vblank = mtk_ovl_enable_vblank,
|
||||
.disable_vblank = mtk_ovl_disable_vblank,
|
||||
.supported_rotations = mtk_ovl_supported_rotations,
|
||||
@ -321,6 +323,8 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = {
|
||||
.config = mtk_rdma_config,
|
||||
.start = mtk_rdma_start,
|
||||
.stop = mtk_rdma_stop,
|
||||
.register_vblank_cb = mtk_rdma_register_vblank_cb,
|
||||
.unregister_vblank_cb = mtk_rdma_unregister_vblank_cb,
|
||||
.enable_vblank = mtk_rdma_enable_vblank,
|
||||
.disable_vblank = mtk_rdma_disable_vblank,
|
||||
.layer_nr = mtk_rdma_layer_nr,
|
||||
|
@ -48,9 +48,11 @@ struct mtk_ddp_comp_funcs {
|
||||
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
|
||||
void (*start)(struct device *dev);
|
||||
void (*stop)(struct device *dev);
|
||||
void (*enable_vblank)(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data);
|
||||
void (*register_vblank_cb)(struct device *dev,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data);
|
||||
void (*unregister_vblank_cb)(struct device *dev);
|
||||
void (*enable_vblank)(struct device *dev);
|
||||
void (*disable_vblank)(struct device *dev);
|
||||
unsigned int (*supported_rotations)(struct device *dev);
|
||||
unsigned int (*layer_nr)(struct device *dev);
|
||||
@ -110,12 +112,25 @@ static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp)
|
||||
comp->funcs->stop(comp->dev);
|
||||
}
|
||||
|
||||
static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data)
|
||||
static inline void mtk_ddp_comp_register_vblank_cb(struct mtk_ddp_comp *comp,
|
||||
void (*vblank_cb)(void *),
|
||||
void *vblank_cb_data)
|
||||
{
|
||||
if (comp->funcs && comp->funcs->register_vblank_cb)
|
||||
comp->funcs->register_vblank_cb(comp->dev, vblank_cb,
|
||||
vblank_cb_data);
|
||||
}
|
||||
|
||||
static inline void mtk_ddp_comp_unregister_vblank_cb(struct mtk_ddp_comp *comp)
|
||||
{
|
||||
if (comp->funcs && comp->funcs->unregister_vblank_cb)
|
||||
comp->funcs->unregister_vblank_cb(comp->dev);
|
||||
}
|
||||
|
||||
static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp)
|
||||
{
|
||||
if (comp->funcs && comp->funcs->enable_vblank)
|
||||
comp->funcs->enable_vblank(comp->dev, vblank_cb, vblank_cb_data);
|
||||
comp->funcs->enable_vblank(comp->dev);
|
||||
}
|
||||
|
||||
static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp)
|
||||
|
Loading…
x
Reference in New Issue
Block a user