diff options
Diffstat (limited to 'drivers/gpu/drm/mediatek/mtk_disp_ovl.c')
-rw-r--r-- | drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 254 |
1 files changed, 141 insertions, 113 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c index 74ef6fc0528b..961f87f8d4d1 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/soc/mediatek/mtk-cmdq.h> +#include "mtk_disp_drv.h" #include "mtk_drm_crtc.h" #include "mtk_drm_ddp_comp.h" @@ -23,6 +24,7 @@ #define DISP_REG_OVL_RST 0x0014 #define DISP_REG_OVL_ROI_SIZE 0x0020 #define DISP_REG_OVL_DATAPATH_CON 0x0024 +#define OVL_LAYER_SMI_ID_EN BIT(0) #define OVL_BGCLR_SEL_IN BIT(2) #define DISP_REG_OVL_ROI_BGCLR 0x0028 #define DISP_REG_OVL_SRC_CON 0x002c @@ -61,6 +63,7 @@ struct mtk_disp_ovl_data { unsigned int gmc_bits; unsigned int layer_nr; bool fmt_rgb565_is_0; + bool smi_id_en; }; /** @@ -70,88 +73,124 @@ struct mtk_disp_ovl_data { * @data: platform data */ struct mtk_disp_ovl { - struct mtk_ddp_comp ddp_comp; struct drm_crtc *crtc; + struct clk *clk; + void __iomem *regs; + struct cmdq_client_reg cmdq_reg; const struct mtk_disp_ovl_data *data; + void (*vblank_cb)(void *data); + void *vblank_cb_data; }; -static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp) -{ - return container_of(comp, struct mtk_disp_ovl, ddp_comp); -} - static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) { struct mtk_disp_ovl *priv = dev_id; - struct mtk_ddp_comp *ovl = &priv->ddp_comp; /* Clear frame completion interrupt */ - writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA); + writel(0x0, priv->regs + DISP_REG_OVL_INTSTA); - if (!priv->crtc) + if (!priv->vblank_cb) return IRQ_NONE; - mtk_crtc_ddp_irq(priv->crtc, ovl); + priv->vblank_cb(priv->vblank_cb_data); return IRQ_HANDLED; } -static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp, - struct drm_crtc *crtc) +void mtk_ovl_enable_vblank(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; + writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA); + writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN); +} + +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); +} + +int mtk_ovl_clk_enable(struct device *dev) { - struct mtk_disp_ovl *ovl = comp_to_ovl(comp); + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); - ovl->crtc = crtc; - writel(0x0, comp->regs + DISP_REG_OVL_INTSTA); - writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN); + return clk_prepare_enable(ovl->clk); } -static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp) +void mtk_ovl_clk_disable(struct device *dev) { - struct mtk_disp_ovl *ovl = comp_to_ovl(comp); + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); - ovl->crtc = NULL; - writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN); + clk_disable_unprepare(ovl->clk); } -static void mtk_ovl_start(struct mtk_ddp_comp *comp) +void mtk_ovl_start(struct device *dev) { - writel_relaxed(0x1, comp->regs + DISP_REG_OVL_EN); + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); + + if (ovl->data->smi_id_en) { + unsigned int reg; + + reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); + reg = reg | OVL_LAYER_SMI_ID_EN; + writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); + } + writel_relaxed(0x1, ovl->regs + DISP_REG_OVL_EN); } -static void mtk_ovl_stop(struct mtk_ddp_comp *comp) +void mtk_ovl_stop(struct device *dev) { - writel_relaxed(0x0, comp->regs + DISP_REG_OVL_EN); + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); + + writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_EN); + if (ovl->data->smi_id_en) { + unsigned int reg; + + reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); + reg = reg & ~OVL_LAYER_SMI_ID_EN; + writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); + } + } -static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w, - unsigned int h, unsigned int vrefresh, - unsigned int bpc, struct cmdq_pkt *cmdq_pkt) +void mtk_ovl_config(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt) { + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); + if (w != 0 && h != 0) - mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, comp, + mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_SIZE); - mtk_ddp_write_relaxed(cmdq_pkt, 0x0, comp, DISP_REG_OVL_ROI_BGCLR); + mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR); - mtk_ddp_write(cmdq_pkt, 0x1, comp, DISP_REG_OVL_RST); - mtk_ddp_write(cmdq_pkt, 0x0, comp, DISP_REG_OVL_RST); + mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); + mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST); } -static unsigned int mtk_ovl_layer_nr(struct mtk_ddp_comp *comp) +unsigned int mtk_ovl_layer_nr(struct device *dev) { - struct mtk_disp_ovl *ovl = comp_to_ovl(comp); + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); return ovl->data->layer_nr; } -static unsigned int mtk_ovl_supported_rotations(struct mtk_ddp_comp *comp) +unsigned int mtk_ovl_supported_rotations(struct device *dev) { return DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; } -static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx, - struct mtk_plane_state *mtk_state) +int mtk_ovl_layer_check(struct device *dev, unsigned int idx, + struct mtk_plane_state *mtk_state) { struct drm_plane_state *state = &mtk_state->base; unsigned int rotation = 0; @@ -178,15 +217,15 @@ static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx, return 0; } -static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx, - struct cmdq_pkt *cmdq_pkt) +void mtk_ovl_layer_on(struct device *dev, unsigned int idx, + struct cmdq_pkt *cmdq_pkt) { unsigned int gmc_thrshd_l; unsigned int gmc_thrshd_h; unsigned int gmc_value; - struct mtk_disp_ovl *ovl = comp_to_ovl(comp); + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); - mtk_ddp_write(cmdq_pkt, 0x1, comp, + mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_CTRL(idx)); gmc_thrshd_l = GMC_THRESHOLD_LOW >> (GMC_THRESHOLD_BITS - ovl->data->gmc_bits); @@ -198,17 +237,19 @@ static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx, gmc_value = gmc_thrshd_l | gmc_thrshd_l << 8 | gmc_thrshd_h << 16 | gmc_thrshd_h << 24; mtk_ddp_write(cmdq_pkt, gmc_value, - comp, DISP_REG_OVL_RDMA_GMC(idx)); - mtk_ddp_write_mask(cmdq_pkt, BIT(idx), comp, + &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_GMC(idx)); + mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_SRC_CON, BIT(idx)); } -static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx, - struct cmdq_pkt *cmdq_pkt) +void mtk_ovl_layer_off(struct device *dev, unsigned int idx, + struct cmdq_pkt *cmdq_pkt) { - mtk_ddp_write_mask(cmdq_pkt, 0, comp, + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); + + mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_SRC_CON, BIT(idx)); - mtk_ddp_write(cmdq_pkt, 0, comp, + mtk_ddp_write(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_CTRL(idx)); } @@ -248,11 +289,11 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt) } } -static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, - struct mtk_plane_state *state, - struct cmdq_pkt *cmdq_pkt) +void mtk_ovl_layer_config(struct device *dev, unsigned int idx, + struct mtk_plane_state *state, + struct cmdq_pkt *cmdq_pkt) { - struct mtk_disp_ovl *ovl = comp_to_ovl(comp); + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); struct mtk_plane_pending_state *pending = &state->pending; unsigned int addr = pending->addr; unsigned int pitch = pending->pitch & 0xffff; @@ -262,12 +303,12 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, unsigned int con; if (!pending->enable) { - mtk_ovl_layer_off(comp, idx, cmdq_pkt); + mtk_ovl_layer_off(dev, idx, cmdq_pkt); return; } con = ovl_fmt_convert(ovl, fmt); - if (state->base.fb->format->has_alpha) + if (state->base.fb && state->base.fb->format->has_alpha) con |= OVL_CON_AEN | OVL_CON_ALPHA; if (pending->rotation & DRM_MODE_REFLECT_Y) { @@ -280,76 +321,49 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, addr += pending->pitch - 1; } - mtk_ddp_write_relaxed(cmdq_pkt, con, comp, + mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_CON(idx)); - mtk_ddp_write_relaxed(cmdq_pkt, pitch, comp, + mtk_ddp_write_relaxed(cmdq_pkt, pitch, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx)); - mtk_ddp_write_relaxed(cmdq_pkt, src_size, comp, + mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_SRC_SIZE(idx)); - mtk_ddp_write_relaxed(cmdq_pkt, offset, comp, + mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_OFFSET(idx)); - mtk_ddp_write_relaxed(cmdq_pkt, addr, comp, + mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ADDR(ovl, idx)); - mtk_ovl_layer_on(comp, idx, cmdq_pkt); + mtk_ovl_layer_on(dev, idx, cmdq_pkt); } -static void mtk_ovl_bgclr_in_on(struct mtk_ddp_comp *comp) +void mtk_ovl_bgclr_in_on(struct device *dev) { + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); unsigned int reg; - reg = readl(comp->regs + DISP_REG_OVL_DATAPATH_CON); + reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); reg = reg | OVL_BGCLR_SEL_IN; - writel(reg, comp->regs + DISP_REG_OVL_DATAPATH_CON); + writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); } -static void mtk_ovl_bgclr_in_off(struct mtk_ddp_comp *comp) +void mtk_ovl_bgclr_in_off(struct device *dev) { + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); unsigned int reg; - reg = readl(comp->regs + DISP_REG_OVL_DATAPATH_CON); + reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON); reg = reg & ~OVL_BGCLR_SEL_IN; - writel(reg, comp->regs + DISP_REG_OVL_DATAPATH_CON); + writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON); } -static const struct mtk_ddp_comp_funcs mtk_disp_ovl_funcs = { - .config = mtk_ovl_config, - .start = mtk_ovl_start, - .stop = mtk_ovl_stop, - .enable_vblank = mtk_ovl_enable_vblank, - .disable_vblank = mtk_ovl_disable_vblank, - .supported_rotations = mtk_ovl_supported_rotations, - .layer_nr = mtk_ovl_layer_nr, - .layer_check = mtk_ovl_layer_check, - .layer_config = mtk_ovl_layer_config, - .bgclr_in_on = mtk_ovl_bgclr_in_on, - .bgclr_in_off = mtk_ovl_bgclr_in_off, -}; - static int mtk_disp_ovl_bind(struct device *dev, struct device *master, void *data) { - struct mtk_disp_ovl *priv = dev_get_drvdata(dev); - struct drm_device *drm_dev = data; - int ret; - - ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp); - if (ret < 0) { - dev_err(dev, "Failed to register component %pOF: %d\n", - dev->of_node, ret); - return ret; - } - return 0; } static void mtk_disp_ovl_unbind(struct device *dev, struct device *master, void *data) { - struct mtk_disp_ovl *priv = dev_get_drvdata(dev); - struct drm_device *drm_dev = data; - - mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp); } static const struct component_ops mtk_disp_ovl_component_ops = { @@ -361,7 +375,7 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_disp_ovl *priv; - int comp_id; + struct resource *res; int irq; int ret; @@ -373,27 +387,25 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) if (irq < 0) return irq; - priv->data = of_device_get_match_data(dev); - - comp_id = mtk_ddp_comp_get_id(dev->of_node, - priv->data->layer_nr == 4 ? - MTK_DISP_OVL : - MTK_DISP_OVL_2L); - if (comp_id < 0) { - dev_err(dev, "Failed to identify by alias: %d\n", comp_id); - return comp_id; + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get ovl clk\n"); + return PTR_ERR(priv->clk); } - ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, - &mtk_disp_ovl_funcs); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to initialize component: %d\n", - ret); - - return ret; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->regs)) { + dev_err(dev, "failed to ioremap ovl\n"); + return PTR_ERR(priv->regs); } +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0); + if (ret) + dev_dbg(dev, "get mediatek,gce-client-reg fail!\n"); +#endif + priv->data = of_device_get_match_data(dev); platform_set_drvdata(pdev, priv); ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, @@ -412,8 +424,6 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) static int mtk_disp_ovl_remove(struct platform_device *pdev) { - component_del(&pdev->dev, &mtk_disp_ovl_component_ops); - return 0; } @@ -431,11 +441,29 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = { .fmt_rgb565_is_0 = true, }; +static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = { + .addr = DISP_REG_OVL_ADDR_MT8173, + .gmc_bits = 10, + .layer_nr = 4, + .fmt_rgb565_is_0 = true, +}; + +static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = { + .addr = DISP_REG_OVL_ADDR_MT8173, + .gmc_bits = 10, + .layer_nr = 2, + .fmt_rgb565_is_0 = true, +}; + static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = { { .compatible = "mediatek,mt2701-disp-ovl", .data = &mt2701_ovl_driver_data}, { .compatible = "mediatek,mt8173-disp-ovl", .data = &mt8173_ovl_driver_data}, + { .compatible = "mediatek,mt8183-disp-ovl", + .data = &mt8183_ovl_driver_data}, + { .compatible = "mediatek,mt8183-disp-ovl-2l", + .data = &mt8183_ovl_2l_driver_data}, {}, }; MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match); |