aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/mediatek/mtk_disp_ovl.c')
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl.c254
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);