Commit 54c820d0 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'mediatek-drm-next-5.12' of...

Merge tag 'mediatek-drm-next-5.12' of https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux into drm-next

Mediatek DRM Next for Linux 5.12

1. Decouple Mediatek DRM sub driver
2. Share mtk mutex driver for both DRM and MDP
3. Add support for SoC MT8183
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Chun-Kuang Hu <chunkuang.hu@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210204151750.7550-1-chunkuang.hu@kernel.org
parents ce7c3bde 738ed415
...@@ -37,13 +37,14 @@ Required properties (all function blocks): ...@@ -37,13 +37,14 @@ Required properties (all function blocks):
"mediatek,<chip>-disp-aal" - adaptive ambient light controller "mediatek,<chip>-disp-aal" - adaptive ambient light controller
"mediatek,<chip>-disp-gamma" - gamma correction "mediatek,<chip>-disp-gamma" - gamma correction
"mediatek,<chip>-disp-merge" - merge streams from two RDMA sources "mediatek,<chip>-disp-merge" - merge streams from two RDMA sources
"mediatek,<chip>-disp-postmask" - control round corner for display frame
"mediatek,<chip>-disp-split" - split stream to two encoders "mediatek,<chip>-disp-split" - split stream to two encoders
"mediatek,<chip>-disp-ufoe" - data compression engine "mediatek,<chip>-disp-ufoe" - data compression engine
"mediatek,<chip>-dsi" - DSI controller, see mediatek,dsi.txt "mediatek,<chip>-dsi" - DSI controller, see mediatek,dsi.txt
"mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt "mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt
"mediatek,<chip>-disp-mutex" - display mutex "mediatek,<chip>-disp-mutex" - display mutex
"mediatek,<chip>-disp-od" - overdrive "mediatek,<chip>-disp-od" - overdrive
the supported chips are mt2701, mt7623, mt2712, mt8167 and mt8173. the supported chips are mt2701, mt7623, mt2712, mt8167, mt8173, mt8183 and mt8192.
- reg: Physical base address and length of the function block register space - reg: Physical base address and length of the function block register space
- interrupts: The interrupt signal from the function block (required, except for - interrupts: The interrupt signal from the function block (required, except for
merge and split function blocks). merge and split function blocks).
...@@ -66,6 +67,14 @@ Required properties (DMA function blocks): ...@@ -66,6 +67,14 @@ Required properties (DMA function blocks):
argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
for details. for details.
Optional properties (RDMA function blocks):
- mediatek,rdma-fifo-size: rdma fifo size may be different even in same SOC, add this
property to the corresponding rdma
the value is the Max value which defined in hardware data sheet.
mediatek,rdma-fifo-size of mt8173-rdma0 is 8K
mediatek,rdma-fifo-size of mt8183-rdma0 is 5K
mediatek,rdma-fifo-size of mt8183-rdma1 is 2K
Examples: Examples:
mmsys: clock-controller@14000000 { mmsys: clock-controller@14000000 {
...@@ -103,6 +112,7 @@ rdma0: rdma@1400e000 { ...@@ -103,6 +112,7 @@ rdma0: rdma@1400e000 {
clocks = <&mmsys CLK_MM_DISP_RDMA0>; clocks = <&mmsys CLK_MM_DISP_RDMA0>;
iommus = <&iommu M4U_PORT_DISP_RDMA0>; iommus = <&iommu M4U_PORT_DISP_RDMA0>;
mediatek,larb = <&larb0>; mediatek,larb = <&larb0>;
mediatek,rdma-fifosize = <8192>;
}; };
rdma1: rdma@1400f000 { rdma1: rdma@1400f000 {
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
mediatek-drm-y := mtk_disp_color.o \ mediatek-drm-y := mtk_disp_ccorr.o \
mtk_disp_color.o \
mtk_disp_gamma.o \
mtk_disp_ovl.o \ mtk_disp_ovl.o \
mtk_disp_rdma.o \ mtk_disp_rdma.o \
mtk_drm_crtc.o \ mtk_drm_crtc.o \
mtk_drm_ddp.o \
mtk_drm_ddp_comp.o \ mtk_drm_ddp_comp.o \
mtk_drm_drv.o \ mtk_drm_drv.o \
mtk_drm_gem.o \ mtk_drm_gem.o \
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#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"
#define DISP_CCORR_EN 0x0000
#define CCORR_EN BIT(0)
#define DISP_CCORR_CFG 0x0020
#define CCORR_RELAY_MODE BIT(0)
#define CCORR_ENGINE_EN BIT(1)
#define CCORR_GAMMA_OFF BIT(2)
#define CCORR_WGAMUT_SRC_CLIP BIT(3)
#define DISP_CCORR_SIZE 0x0030
#define DISP_CCORR_COEF_0 0x0080
#define DISP_CCORR_COEF_1 0x0084
#define DISP_CCORR_COEF_2 0x0088
#define DISP_CCORR_COEF_3 0x008C
#define DISP_CCORR_COEF_4 0x0090
struct mtk_disp_ccorr_data {
u32 matrix_bits;
};
/**
* struct mtk_disp_ccorr - DISP_CCORR driver structure
* @ddp_comp - structure containing type enum and hardware resources
* @crtc - associated crtc to report irq events to
*/
struct mtk_disp_ccorr {
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_ccorr_data *data;
};
int mtk_ccorr_clk_enable(struct device *dev)
{
struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
return clk_prepare_enable(ccorr->clk);
}
void mtk_ccorr_clk_disable(struct device *dev)
{
struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
clk_disable_unprepare(ccorr->clk);
}
void mtk_ccorr_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, w << 16 | h, &ccorr->cmdq_reg, ccorr->regs,
DISP_CCORR_SIZE);
mtk_ddp_write(cmdq_pkt, CCORR_ENGINE_EN, &ccorr->cmdq_reg, ccorr->regs,
DISP_CCORR_CFG);
}
void mtk_ccorr_start(struct device *dev)
{
struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
writel(CCORR_EN, ccorr->regs + DISP_CCORR_EN);
}
void mtk_ccorr_stop(struct device *dev)
{
struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
writel_relaxed(0x0, ccorr->regs + DISP_CCORR_EN);
}
/* Converts a DRM S31.32 value to the HW S1.n format. */
static u16 mtk_ctm_s31_32_to_s1_n(u64 in, u32 n)
{
u16 r;
/* Sign bit. */
r = in & BIT_ULL(63) ? BIT(n + 1) : 0;
if ((in & GENMASK_ULL(62, 33)) > 0) {
/* identity value 0x100000000 -> 0x400(mt8183), */
/* identity value 0x100000000 -> 0x800(mt8192), */
/* if bigger this, set it to max 0x7ff. */
r |= GENMASK(n, 0);
} else {
/* take the n+1 most important bits. */
r |= (in >> (32 - n)) & GENMASK(n, 0);
}
return r;
}
void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state)
{
struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
struct drm_property_blob *blob = state->ctm;
struct drm_color_ctm *ctm;
const u64 *input;
uint16_t coeffs[9] = { 0 };
int i;
struct cmdq_pkt *cmdq_pkt = NULL;
u32 matrix_bits = ccorr->data->matrix_bits;
if (!blob)
return;
ctm = (struct drm_color_ctm *)blob->data;
input = ctm->matrix;
for (i = 0; i < ARRAY_SIZE(coeffs); i++)
coeffs[i] = mtk_ctm_s31_32_to_s1_n(input[i], matrix_bits);
mtk_ddp_write(cmdq_pkt, coeffs[0] << 16 | coeffs[1],
&ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_0);
mtk_ddp_write(cmdq_pkt, coeffs[2] << 16 | coeffs[3],
&ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_1);
mtk_ddp_write(cmdq_pkt, coeffs[4] << 16 | coeffs[5],
&ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_2);
mtk_ddp_write(cmdq_pkt, coeffs[6] << 16 | coeffs[7],
&ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_3);
mtk_ddp_write(cmdq_pkt, coeffs[8] << 16,
&ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_4);
}
static int mtk_disp_ccorr_bind(struct device *dev, struct device *master,
void *data)
{
return 0;
}
static void mtk_disp_ccorr_unbind(struct device *dev, struct device *master,
void *data)
{
}
static const struct component_ops mtk_disp_ccorr_component_ops = {
.bind = mtk_disp_ccorr_bind,
.unbind = mtk_disp_ccorr_unbind,
};
static int mtk_disp_ccorr_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_ccorr *priv;
struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get ccorr clk\n");
return PTR_ERR(priv->clk);
}
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 ccorr\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 = component_add(dev, &mtk_disp_ccorr_component_ops);
if (ret)
dev_err(dev, "Failed to add component: %d\n", ret);
return ret;
}
static int mtk_disp_ccorr_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &mtk_disp_ccorr_component_ops);
return 0;
}
static const struct mtk_disp_ccorr_data mt8183_ccorr_driver_data = {
.matrix_bits = 10,
};
static const struct of_device_id mtk_disp_ccorr_driver_dt_match[] = {
{ .compatible = "mediatek,mt8183-disp-ccorr",
.data = &mt8183_ccorr_driver_data},
{},
};
MODULE_DEVICE_TABLE(of, mtk_disp_ccorr_driver_dt_match);
struct platform_driver mtk_disp_ccorr_driver = {
.probe = mtk_disp_ccorr_probe,
.remove = mtk_disp_ccorr_remove,
.driver = {
.name = "mediatek-disp-ccorr",
.owner = THIS_MODULE,
.of_match_table = mtk_disp_ccorr_driver_dt_match,
},
};
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h> #include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h" #include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
...@@ -36,64 +37,55 @@ struct mtk_disp_color_data { ...@@ -36,64 +37,55 @@ struct mtk_disp_color_data {
* @data: platform colour driver data * @data: platform colour driver data
*/ */
struct mtk_disp_color { struct mtk_disp_color {
struct mtk_ddp_comp ddp_comp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_color_data *data; const struct mtk_disp_color_data *data;
}; };
static inline struct mtk_disp_color *comp_to_color(struct mtk_ddp_comp *comp) int mtk_color_clk_enable(struct device *dev)
{ {
return container_of(comp, struct mtk_disp_color, ddp_comp); struct mtk_disp_color *color = dev_get_drvdata(dev);
return clk_prepare_enable(color->clk);
}
void mtk_color_clk_disable(struct device *dev)
{
struct mtk_disp_color *color = dev_get_drvdata(dev);
clk_disable_unprepare(color->clk);
} }
static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w, void mtk_color_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh, unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt) unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{ {
struct mtk_disp_color *color = comp_to_color(comp); struct mtk_disp_color *color = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, w, comp, DISP_COLOR_WIDTH(color)); mtk_ddp_write(cmdq_pkt, w, &color->cmdq_reg, color->regs, DISP_COLOR_WIDTH(color));
mtk_ddp_write(cmdq_pkt, h, comp, DISP_COLOR_HEIGHT(color)); mtk_ddp_write(cmdq_pkt, h, &color->cmdq_reg, color->regs, DISP_COLOR_HEIGHT(color));
} }
static void mtk_color_start(struct mtk_ddp_comp *comp) void mtk_color_start(struct device *dev)
{ {
struct mtk_disp_color *color = comp_to_color(comp); struct mtk_disp_color *color = dev_get_drvdata(dev);
writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL, writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
comp->regs + DISP_COLOR_CFG_MAIN); color->regs + DISP_COLOR_CFG_MAIN);
writel(0x1, comp->regs + DISP_COLOR_START(color)); writel(0x1, color->regs + DISP_COLOR_START(color));
} }
static const struct mtk_ddp_comp_funcs mtk_disp_color_funcs = {
.config = mtk_color_config,
.start = mtk_color_start,
};
static int mtk_disp_color_bind(struct device *dev, struct device *master, static int mtk_disp_color_bind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct mtk_disp_color *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; return 0;
} }
static void mtk_disp_color_unbind(struct device *dev, struct device *master, static void mtk_disp_color_unbind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct mtk_disp_color *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_color_component_ops = { static const struct component_ops mtk_disp_color_component_ops = {
...@@ -105,31 +97,32 @@ static int mtk_disp_color_probe(struct platform_device *pdev) ...@@ -105,31 +97,32 @@ static int mtk_disp_color_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mtk_disp_color *priv; struct mtk_disp_color *priv;
int comp_id; struct resource *res;
int ret; int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_COLOR); priv->clk = devm_clk_get(dev, NULL);
if (comp_id < 0) { if (IS_ERR(priv->clk)) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id); dev_err(dev, "failed to get color clk\n");
return comp_id; return PTR_ERR(priv->clk);
} }
ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
&mtk_disp_color_funcs); priv->regs = devm_ioremap_resource(dev, res);
if (ret) { if (IS_ERR(priv->regs)) {
if (ret != -EPROBE_DEFER) dev_err(dev, "failed to ioremap color\n");
dev_err(dev, "Failed to initialize component: %d\n", return PTR_ERR(priv->regs);
ret);
return ret;
} }
#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); priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
ret = component_add(dev, &mtk_disp_color_component_ops); ret = component_add(dev, &mtk_disp_color_component_ops);
...@@ -141,8 +134,6 @@ static int mtk_disp_color_probe(struct platform_device *pdev) ...@@ -141,8 +134,6 @@ static int mtk_disp_color_probe(struct platform_device *pdev)
static int mtk_disp_color_remove(struct platform_device *pdev) static int mtk_disp_color_remove(struct platform_device *pdev)
{ {
component_del(&pdev->dev, &mtk_disp_color_component_ops);
return 0; return 0;
} }
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#ifndef _MTK_DISP_DRV_H_
#define _MTK_DISP_DRV_H_
#include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_drm_plane.h"
void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state);
int mtk_ccorr_clk_enable(struct device *dev);
void mtk_ccorr_clk_disable(struct device *dev);
void mtk_ccorr_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_ccorr_start(struct device *dev);
void mtk_ccorr_stop(struct device *dev);
void mtk_color_bypass_shadow(struct device *dev);
int mtk_color_clk_enable(struct device *dev);
void mtk_color_clk_disable(struct device *dev);
void mtk_color_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_color_start(struct device *dev);
void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg,
unsigned int bpc, unsigned int cfg,
unsigned int dither_en, struct cmdq_pkt *cmdq_pkt);
void mtk_dpi_start(struct device *dev);
void mtk_dpi_stop(struct device *dev);
void mtk_dsi_ddp_start(struct device *dev);
void mtk_dsi_ddp_stop(struct device *dev);
int mtk_gamma_clk_enable(struct device *dev);
void mtk_gamma_clk_disable(struct device *dev);
void mtk_gamma_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state);
void mtk_gamma_start(struct device *dev);
void mtk_gamma_stop(struct device *dev);
void mtk_ovl_bgclr_in_on(struct device *dev);
void mtk_ovl_bgclr_in_off(struct device *dev);
void mtk_ovl_bypass_shadow(struct device *dev);
int mtk_ovl_clk_enable(struct device *dev);
void mtk_ovl_clk_disable(struct device *dev);
void mtk_ovl_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
struct mtk_plane_state *mtk_state);
void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt);
unsigned int mtk_ovl_layer_nr(struct device *dev);
void mtk_ovl_layer_on(struct device *dev, unsigned int idx,
struct cmdq_pkt *cmdq_pkt);
void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
struct cmdq_pkt *cmdq_pkt);
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_disable_vblank(struct device *dev);
void mtk_rdma_bypass_shadow(struct device *dev);
int mtk_rdma_clk_enable(struct device *dev);
void mtk_rdma_clk_disable(struct device *dev);
void mtk_rdma_config(struct device *dev, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
unsigned int mtk_rdma_layer_nr(struct device *dev);
void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
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_disable_vblank(struct device *dev);
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#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"
#define DISP_GAMMA_EN 0x0000
#define GAMMA_EN BIT(0)
#define DISP_GAMMA_CFG 0x0020
#define GAMMA_LUT_EN BIT(1)
#define GAMMA_DITHERING BIT(2)
#define DISP_GAMMA_SIZE 0x0030
#define DISP_GAMMA_LUT 0x0700
#define LUT_10BIT_MASK 0x03ff
struct mtk_disp_gamma_data {
bool has_dither;
};
/**
* struct mtk_disp_gamma - DISP_GAMMA driver structure
* @ddp_comp - structure containing type enum and hardware resources
* @crtc - associated crtc to report irq events to
*/
struct mtk_disp_gamma {
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_gamma_data *data;
};
int mtk_gamma_clk_enable(struct device *dev)
{
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
return clk_prepare_enable(gamma->clk);
}
void mtk_gamma_clk_disable(struct device *dev)
{
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
clk_disable_unprepare(gamma->clk);
}
void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state)
{
unsigned int i, reg;
struct drm_color_lut *lut;
void __iomem *lut_base;
u32 word;
if (state->gamma_lut) {
reg = readl(regs + DISP_GAMMA_CFG);
reg = reg | GAMMA_LUT_EN;
writel(reg, regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
for (i = 0; i < MTK_LUT_SIZE; i++) {
word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
(((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
((lut[i].blue >> 6) & LUT_10BIT_MASK);
writel(word, (lut_base + i * 4));
}
}
}
void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
{
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
mtk_gamma_set_common(gamma->regs, state);
}
void mtk_gamma_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, h << 16 | w, &gamma->cmdq_reg, gamma->regs,
DISP_GAMMA_SIZE);
if (gamma->data && gamma->data->has_dither)
mtk_dither_set_common(gamma->regs, &gamma->cmdq_reg, bpc,
DISP_GAMMA_CFG, GAMMA_DITHERING, cmdq_pkt);
}
void mtk_gamma_start(struct device *dev)
{
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
writel(GAMMA_EN, gamma->regs + DISP_GAMMA_EN);
}
void mtk_gamma_stop(struct device *dev)
{
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
writel_relaxed(0x0, gamma->regs + DISP_GAMMA_EN);
}
static int mtk_disp_gamma_bind(struct device *dev, struct device *master,
void *data)
{
return 0;
}
static void mtk_disp_gamma_unbind(struct device *dev, struct device *master,
void *data)
{
}
static const struct component_ops mtk_disp_gamma_component_ops = {
.bind = mtk_disp_gamma_bind,
.unbind = mtk_disp_gamma_unbind,
};
static int mtk_disp_gamma_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_gamma *priv;
struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get gamma clk\n");
return PTR_ERR(priv->clk);
}
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 gamma\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 = component_add(dev, &mtk_disp_gamma_component_ops);
if (ret)
dev_err(dev, "Failed to add component: %d\n", ret);
return ret;
}
static int mtk_disp_gamma_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &mtk_disp_gamma_component_ops);
return 0;
}
static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = {
.has_dither = true,
};
static const struct of_device_id mtk_disp_gamma_driver_dt_match[] = {
{ .compatible = "mediatek,mt8173-disp-gamma",
.data = &mt8173_gamma_driver_data},
{ .compatible = "mediatek,mt8183-disp-gamma"},
{},
};
MODULE_DEVICE_TABLE(of, mtk_disp_gamma_driver_dt_match);
struct platform_driver mtk_disp_gamma_driver = {
.probe = mtk_disp_gamma_probe,
.remove = mtk_disp_gamma_remove,
.driver = {
.name = "mediatek-disp-gamma",
.owner = THIS_MODULE,
.of_match_table = mtk_disp_gamma_driver_dt_match,
},
};
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h> #include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h" #include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#define DISP_REG_OVL_RST 0x0014 #define DISP_REG_OVL_RST 0x0014
#define DISP_REG_OVL_ROI_SIZE 0x0020 #define DISP_REG_OVL_ROI_SIZE 0x0020
#define DISP_REG_OVL_DATAPATH_CON 0x0024 #define DISP_REG_OVL_DATAPATH_CON 0x0024
#define OVL_LAYER_SMI_ID_EN BIT(0)
#define OVL_BGCLR_SEL_IN BIT(2) #define OVL_BGCLR_SEL_IN BIT(2)
#define DISP_REG_OVL_ROI_BGCLR 0x0028 #define DISP_REG_OVL_ROI_BGCLR 0x0028
#define DISP_REG_OVL_SRC_CON 0x002c #define DISP_REG_OVL_SRC_CON 0x002c
...@@ -61,6 +63,7 @@ struct mtk_disp_ovl_data { ...@@ -61,6 +63,7 @@ struct mtk_disp_ovl_data {
unsigned int gmc_bits; unsigned int gmc_bits;
unsigned int layer_nr; unsigned int layer_nr;
bool fmt_rgb565_is_0; bool fmt_rgb565_is_0;
bool smi_id_en;
}; };
/** /**
...@@ -70,87 +73,123 @@ struct mtk_disp_ovl_data { ...@@ -70,87 +73,123 @@ struct mtk_disp_ovl_data {
* @data: platform data * @data: platform data
*/ */
struct mtk_disp_ovl { struct mtk_disp_ovl {
struct mtk_ddp_comp ddp_comp;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_ovl_data *data; 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) static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
{ {
struct mtk_disp_ovl *priv = dev_id; struct mtk_disp_ovl *priv = dev_id;
struct mtk_ddp_comp *ovl = &priv->ddp_comp;
/* Clear frame completion interrupt */ /* 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; return IRQ_NONE;
mtk_crtc_ddp_irq(priv->crtc, ovl); priv->vblank_cb(priv->vblank_cb_data);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp, void mtk_ovl_enable_vblank(struct device *dev,
struct drm_crtc *crtc) void (*vblank_cb)(void *),
void *vblank_cb_data)
{ {
struct mtk_disp_ovl *ovl = comp_to_ovl(comp); struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
ovl->crtc = crtc; ovl->vblank_cb = vblank_cb;
writel(0x0, comp->regs + DISP_REG_OVL_INTSTA); ovl->vblank_cb_data = vblank_cb_data;
writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN); writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN);
} }
static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp) void mtk_ovl_disable_vblank(struct device *dev)
{ {
struct mtk_disp_ovl *ovl = comp_to_ovl(comp); struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
ovl->crtc = NULL; ovl->vblank_cb = NULL;
writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN); ovl->vblank_cb_data = NULL;
writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
} }
static void mtk_ovl_start(struct mtk_ddp_comp *comp) int mtk_ovl_clk_enable(struct device *dev)
{ {
writel_relaxed(0x1, comp->regs + DISP_REG_OVL_EN); struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
return clk_prepare_enable(ovl->clk);
} }
static void mtk_ovl_stop(struct mtk_ddp_comp *comp) void mtk_ovl_clk_disable(struct device *dev)
{ {
writel_relaxed(0x0, comp->regs + DISP_REG_OVL_EN); struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
clk_disable_unprepare(ovl->clk);
} }
static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w, void mtk_ovl_start(struct device *dev)
{
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);
}
void mtk_ovl_stop(struct device *dev)
{
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);
}
}
void mtk_ovl_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh, unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt) unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{ {
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
if (w != 0 && h != 0) 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); 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, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
mtk_ddp_write(cmdq_pkt, 0x0, comp, 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; 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 | return DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
} }
static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx, int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
struct mtk_plane_state *mtk_state) struct mtk_plane_state *mtk_state)
{ {
struct drm_plane_state *state = &mtk_state->base; struct drm_plane_state *state = &mtk_state->base;
...@@ -178,15 +217,15 @@ static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx, ...@@ -178,15 +217,15 @@ static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx,
return 0; return 0;
} }
static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx, void mtk_ovl_layer_on(struct device *dev, unsigned int idx,
struct cmdq_pkt *cmdq_pkt) struct cmdq_pkt *cmdq_pkt)
{ {
unsigned int gmc_thrshd_l; unsigned int gmc_thrshd_l;
unsigned int gmc_thrshd_h; unsigned int gmc_thrshd_h;
unsigned int gmc_value; 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)); DISP_REG_OVL_RDMA_CTRL(idx));
gmc_thrshd_l = GMC_THRESHOLD_LOW >> gmc_thrshd_l = GMC_THRESHOLD_LOW >>
(GMC_THRESHOLD_BITS - ovl->data->gmc_bits); (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, ...@@ -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_value = gmc_thrshd_l | gmc_thrshd_l << 8 |
gmc_thrshd_h << 16 | gmc_thrshd_h << 24; gmc_thrshd_h << 16 | gmc_thrshd_h << 24;
mtk_ddp_write(cmdq_pkt, gmc_value, mtk_ddp_write(cmdq_pkt, gmc_value,
comp, DISP_REG_OVL_RDMA_GMC(idx)); &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_GMC(idx));
mtk_ddp_write_mask(cmdq_pkt, BIT(idx), comp, mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_SRC_CON, BIT(idx)); DISP_REG_OVL_SRC_CON, BIT(idx));
} }
static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx, void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
struct cmdq_pkt *cmdq_pkt) 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)); 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)); DISP_REG_OVL_RDMA_CTRL(idx));
} }
...@@ -248,11 +289,11 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt) ...@@ -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, void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state, struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt) 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; struct mtk_plane_pending_state *pending = &state->pending;
unsigned int addr = pending->addr; unsigned int addr = pending->addr;
unsigned int pitch = pending->pitch & 0xffff; unsigned int pitch = pending->pitch & 0xffff;
...@@ -262,12 +303,12 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, ...@@ -262,12 +303,12 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
unsigned int con; unsigned int con;
if (!pending->enable) { if (!pending->enable) {
mtk_ovl_layer_off(comp, idx, cmdq_pkt); mtk_ovl_layer_off(dev, idx, cmdq_pkt);
return; return;
} }
con = ovl_fmt_convert(ovl, fmt); 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; con |= OVL_CON_AEN | OVL_CON_ALPHA;
if (pending->rotation & DRM_MODE_REFLECT_Y) { 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, ...@@ -280,76 +321,49 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
addr += pending->pitch - 1; 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)); 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)); 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)); 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)); 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)); 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; 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; 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; 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; 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, static int mtk_disp_ovl_bind(struct device *dev, struct device *master,
void *data) 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; return 0;
} }
static void mtk_disp_ovl_unbind(struct device *dev, struct device *master, static void mtk_disp_ovl_unbind(struct device *dev, struct device *master,
void *data) 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 = { static const struct component_ops mtk_disp_ovl_component_ops = {
...@@ -361,7 +375,7 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) ...@@ -361,7 +375,7 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mtk_disp_ovl *priv; struct mtk_disp_ovl *priv;
int comp_id; struct resource *res;
int irq; int irq;
int ret; int ret;
...@@ -373,27 +387,25 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) ...@@ -373,27 +387,25 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
if (irq < 0) if (irq < 0)
return irq; return irq;
priv->data = of_device_get_match_data(dev); priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
comp_id = mtk_ddp_comp_get_id(dev->of_node, dev_err(dev, "failed to get ovl clk\n");
priv->data->layer_nr == 4 ? return PTR_ERR(priv->clk);
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;
} }
ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
&mtk_disp_ovl_funcs); priv->regs = devm_ioremap_resource(dev, res);
if (ret) { if (IS_ERR(priv->regs)) {
if (ret != -EPROBE_DEFER) dev_err(dev, "failed to ioremap ovl\n");
dev_err(dev, "Failed to initialize component: %d\n", return PTR_ERR(priv->regs);
ret);
return ret;
} }
#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); platform_set_drvdata(pdev, priv);
ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, 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) ...@@ -412,8 +424,6 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
static int mtk_disp_ovl_remove(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; return 0;
} }
...@@ -431,11 +441,29 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = { ...@@ -431,11 +441,29 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
.fmt_rgb565_is_0 = true, .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[] = { static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-ovl", { .compatible = "mediatek,mt2701-disp-ovl",
.data = &mt2701_ovl_driver_data}, .data = &mt2701_ovl_driver_data},
{ .compatible = "mediatek,mt8173-disp-ovl", { .compatible = "mediatek,mt8173-disp-ovl",
.data = &mt8173_ovl_driver_data}, .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); MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h> #include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h" #include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
...@@ -61,83 +62,105 @@ struct mtk_disp_rdma_data { ...@@ -61,83 +62,105 @@ struct mtk_disp_rdma_data {
* @data: local driver data * @data: local driver data
*/ */
struct mtk_disp_rdma { struct mtk_disp_rdma {
struct mtk_ddp_comp ddp_comp; struct clk *clk;
struct drm_crtc *crtc; void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_rdma_data *data; const struct mtk_disp_rdma_data *data;
void (*vblank_cb)(void *data);
void *vblank_cb_data;
u32 fifo_size;
}; };
static inline struct mtk_disp_rdma *comp_to_rdma(struct mtk_ddp_comp *comp)
{
return container_of(comp, struct mtk_disp_rdma, ddp_comp);
}
static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id) static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id)
{ {
struct mtk_disp_rdma *priv = dev_id; struct mtk_disp_rdma *priv = dev_id;
struct mtk_ddp_comp *rdma = &priv->ddp_comp;
/* Clear frame completion interrupt */ /* Clear frame completion interrupt */
writel(0x0, rdma->regs + DISP_REG_RDMA_INT_STATUS); writel(0x0, priv->regs + DISP_REG_RDMA_INT_STATUS);
if (!priv->crtc) if (!priv->vblank_cb)
return IRQ_NONE; return IRQ_NONE;
mtk_crtc_ddp_irq(priv->crtc, rdma); priv->vblank_cb(priv->vblank_cb_data);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void rdma_update_bits(struct mtk_ddp_comp *comp, unsigned int reg, static void rdma_update_bits(struct device *dev, unsigned int reg,
unsigned int mask, unsigned int val) unsigned int mask, unsigned int val)
{ {
unsigned int tmp = readl(comp->regs + reg); struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
unsigned int tmp = readl(rdma->regs + reg);
tmp = (tmp & ~mask) | (val & mask); tmp = (tmp & ~mask) | (val & mask);
writel(tmp, comp->regs + reg); writel(tmp, rdma->regs + reg);
} }
static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp, void mtk_rdma_enable_vblank(struct device *dev,
struct drm_crtc *crtc) void (*vblank_cb)(void *),
void *vblank_cb_data)
{ {
struct mtk_disp_rdma *rdma = comp_to_rdma(comp); struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
rdma->crtc = crtc; rdma->vblank_cb = vblank_cb;
rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, rdma->vblank_cb_data = vblank_cb_data;
rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
RDMA_FRAME_END_INT); RDMA_FRAME_END_INT);
} }
static void mtk_rdma_disable_vblank(struct mtk_ddp_comp *comp) 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);
}
int mtk_rdma_clk_enable(struct device *dev)
{ {
struct mtk_disp_rdma *rdma = comp_to_rdma(comp); struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
rdma->crtc = NULL; return clk_prepare_enable(rdma->clk);
rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
} }
static void mtk_rdma_start(struct mtk_ddp_comp *comp) void mtk_rdma_clk_disable(struct device *dev)
{ {
rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
clk_disable_unprepare(rdma->clk);
}
void mtk_rdma_start(struct device *dev)
{
rdma_update_bits(dev, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN,
RDMA_ENGINE_EN); RDMA_ENGINE_EN);
} }
static void mtk_rdma_stop(struct mtk_ddp_comp *comp) void mtk_rdma_stop(struct device *dev)
{ {
rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 0); rdma_update_bits(dev, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 0);
} }
static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width, void mtk_rdma_config(struct device *dev, unsigned int width,
unsigned int height, unsigned int vrefresh, unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt) unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{ {
unsigned int threshold; unsigned int threshold;
unsigned int reg; unsigned int reg;
struct mtk_disp_rdma *rdma = comp_to_rdma(comp); struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
u32 rdma_fifo_size;
mtk_ddp_write_mask(cmdq_pkt, width, comp, mtk_ddp_write_mask(cmdq_pkt, width, &rdma->cmdq_reg, rdma->regs,
DISP_REG_RDMA_SIZE_CON_0, 0xfff); DISP_REG_RDMA_SIZE_CON_0, 0xfff);
mtk_ddp_write_mask(cmdq_pkt, height, comp, mtk_ddp_write_mask(cmdq_pkt, height, &rdma->cmdq_reg, rdma->regs,
DISP_REG_RDMA_SIZE_CON_1, 0xfffff); DISP_REG_RDMA_SIZE_CON_1, 0xfffff);
if (rdma->fifo_size)
rdma_fifo_size = rdma->fifo_size;
else
rdma_fifo_size = RDMA_FIFO_SIZE(rdma);
/* /*
* Enable FIFO underflow since DSI and DPI can't be blocked. * Enable FIFO underflow since DSI and DPI can't be blocked.
* Keep the FIFO pseudo size reset default of 8 KiB. Set the * Keep the FIFO pseudo size reset default of 8 KiB. Set the
...@@ -146,9 +169,9 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width, ...@@ -146,9 +169,9 @@ static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
*/ */
threshold = width * height * vrefresh * 4 * 7 / 1000000; threshold = width * height * vrefresh * 4 * 7 / 1000000;
reg = RDMA_FIFO_UNDERFLOW_EN | reg = RDMA_FIFO_UNDERFLOW_EN |
RDMA_FIFO_PSEUDO_SIZE(RDMA_FIFO_SIZE(rdma)) | RDMA_FIFO_PSEUDO_SIZE(rdma_fifo_size) |
RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold); RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
mtk_ddp_write(cmdq_pkt, reg, comp, DISP_REG_RDMA_FIFO_CON); mtk_ddp_write(cmdq_pkt, reg, &rdma->cmdq_reg, rdma->regs, DISP_REG_RDMA_FIFO_CON);
} }
static unsigned int rdma_fmt_convert(struct mtk_disp_rdma *rdma, static unsigned int rdma_fmt_convert(struct mtk_disp_rdma *rdma,
...@@ -188,16 +211,16 @@ static unsigned int rdma_fmt_convert(struct mtk_disp_rdma *rdma, ...@@ -188,16 +211,16 @@ static unsigned int rdma_fmt_convert(struct mtk_disp_rdma *rdma,
} }
} }
static unsigned int mtk_rdma_layer_nr(struct mtk_ddp_comp *comp) unsigned int mtk_rdma_layer_nr(struct device *dev)
{ {
return 1; return 1;
} }
static void mtk_rdma_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state, struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt) struct cmdq_pkt *cmdq_pkt)
{ {
struct mtk_disp_rdma *rdma = comp_to_rdma(comp); struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
struct mtk_plane_pending_state *pending = &state->pending; struct mtk_plane_pending_state *pending = &state->pending;
unsigned int addr = pending->addr; unsigned int addr = pending->addr;
unsigned int pitch = pending->pitch & 0xffff; unsigned int pitch = pending->pitch & 0xffff;
...@@ -205,53 +228,34 @@ static void mtk_rdma_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, ...@@ -205,53 +228,34 @@ static void mtk_rdma_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
unsigned int con; unsigned int con;
con = rdma_fmt_convert(rdma, fmt); con = rdma_fmt_convert(rdma, fmt);
mtk_ddp_write_relaxed(cmdq_pkt, con, comp, DISP_RDMA_MEM_CON); mtk_ddp_write_relaxed(cmdq_pkt, con, &rdma->cmdq_reg, rdma->regs, DISP_RDMA_MEM_CON);
if (fmt == DRM_FORMAT_UYVY || fmt == DRM_FORMAT_YUYV) { if (fmt == DRM_FORMAT_UYVY || fmt == DRM_FORMAT_YUYV) {
mtk_ddp_write_mask(cmdq_pkt, RDMA_MATRIX_ENABLE, comp, mtk_ddp_write_mask(cmdq_pkt, RDMA_MATRIX_ENABLE, &rdma->cmdq_reg, rdma->regs,
DISP_REG_RDMA_SIZE_CON_0, DISP_REG_RDMA_SIZE_CON_0,
RDMA_MATRIX_ENABLE); RDMA_MATRIX_ENABLE);
mtk_ddp_write_mask(cmdq_pkt, RDMA_MATRIX_INT_MTX_BT601_to_RGB, mtk_ddp_write_mask(cmdq_pkt, RDMA_MATRIX_INT_MTX_BT601_to_RGB,
comp, DISP_REG_RDMA_SIZE_CON_0, &rdma->cmdq_reg, rdma->regs, DISP_REG_RDMA_SIZE_CON_0,
RDMA_MATRIX_INT_MTX_SEL); RDMA_MATRIX_INT_MTX_SEL);
} else { } else {
mtk_ddp_write_mask(cmdq_pkt, 0, comp, mtk_ddp_write_mask(cmdq_pkt, 0, &rdma->cmdq_reg, rdma->regs,
DISP_REG_RDMA_SIZE_CON_0, DISP_REG_RDMA_SIZE_CON_0,
RDMA_MATRIX_ENABLE); RDMA_MATRIX_ENABLE);
} }
mtk_ddp_write_relaxed(cmdq_pkt, addr, comp, DISP_RDMA_MEM_START_ADDR); mtk_ddp_write_relaxed(cmdq_pkt, addr, &rdma->cmdq_reg, rdma->regs,
mtk_ddp_write_relaxed(cmdq_pkt, pitch, comp, DISP_RDMA_MEM_SRC_PITCH); DISP_RDMA_MEM_START_ADDR);
mtk_ddp_write(cmdq_pkt, RDMA_MEM_GMC, comp, mtk_ddp_write_relaxed(cmdq_pkt, pitch, &rdma->cmdq_reg, rdma->regs,
DISP_RDMA_MEM_SRC_PITCH);
mtk_ddp_write(cmdq_pkt, RDMA_MEM_GMC, &rdma->cmdq_reg, rdma->regs,
DISP_RDMA_MEM_GMC_SETTING_0); DISP_RDMA_MEM_GMC_SETTING_0);
mtk_ddp_write_mask(cmdq_pkt, RDMA_MODE_MEMORY, comp, mtk_ddp_write_mask(cmdq_pkt, RDMA_MODE_MEMORY, &rdma->cmdq_reg, rdma->regs,
DISP_REG_RDMA_GLOBAL_CON, RDMA_MODE_MEMORY); DISP_REG_RDMA_GLOBAL_CON, RDMA_MODE_MEMORY);
} }
static const struct mtk_ddp_comp_funcs mtk_disp_rdma_funcs = {
.config = mtk_rdma_config,
.start = mtk_rdma_start,
.stop = mtk_rdma_stop,
.enable_vblank = mtk_rdma_enable_vblank,
.disable_vblank = mtk_rdma_disable_vblank,
.layer_nr = mtk_rdma_layer_nr,
.layer_config = mtk_rdma_layer_config,
};
static int mtk_disp_rdma_bind(struct device *dev, struct device *master, static int mtk_disp_rdma_bind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct mtk_disp_rdma *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; return 0;
} }
...@@ -259,10 +263,6 @@ static int mtk_disp_rdma_bind(struct device *dev, struct device *master, ...@@ -259,10 +263,6 @@ static int mtk_disp_rdma_bind(struct device *dev, struct device *master,
static void mtk_disp_rdma_unbind(struct device *dev, struct device *master, static void mtk_disp_rdma_unbind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct mtk_disp_rdma *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_rdma_component_ops = { static const struct component_ops mtk_disp_rdma_component_ops = {
...@@ -274,7 +274,7 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev) ...@@ -274,7 +274,7 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mtk_disp_rdma *priv; struct mtk_disp_rdma *priv;
int comp_id; struct resource *res;
int irq; int irq;
int ret; int ret;
...@@ -286,25 +286,37 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev) ...@@ -286,25 +286,37 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
if (irq < 0) if (irq < 0)
return irq; return irq;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_RDMA); priv->clk = devm_clk_get(dev, NULL);
if (comp_id < 0) { if (IS_ERR(priv->clk)) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id); dev_err(dev, "failed to get rdma clk\n");
return comp_id; return PTR_ERR(priv->clk);
} }
ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
&mtk_disp_rdma_funcs); priv->regs = devm_ioremap_resource(dev, res);
if (ret) { if (IS_ERR(priv->regs)) {
if (ret != -EPROBE_DEFER) dev_err(dev, "failed to ioremap rdma\n");
dev_err(dev, "Failed to initialize component: %d\n", return PTR_ERR(priv->regs);
ret); }
#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
if (of_find_property(dev->of_node, "mediatek,rdma-fifo-size", &ret)) {
ret = of_property_read_u32(dev->of_node,
"mediatek,rdma-fifo-size",
&priv->fifo_size);
if (ret) {
dev_err(dev, "Failed to get rdma fifo size\n");
return ret; return ret;
} }
}
/* Disable and clear pending interrupts */ /* Disable and clear pending interrupts */
writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_ENABLE); writel(0x0, priv->regs + DISP_REG_RDMA_INT_ENABLE);
writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_STATUS); writel(0x0, priv->regs + DISP_REG_RDMA_INT_STATUS);
ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler, ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler,
IRQF_TRIGGER_NONE, dev_name(dev), priv); IRQF_TRIGGER_NONE, dev_name(dev), priv);
...@@ -339,11 +351,17 @@ static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = { ...@@ -339,11 +351,17 @@ static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = {
.fifo_size = SZ_8K, .fifo_size = SZ_8K,
}; };
static const struct mtk_disp_rdma_data mt8183_rdma_driver_data = {
.fifo_size = 5 * SZ_1K,
};
static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = { static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-rdma", { .compatible = "mediatek,mt2701-disp-rdma",
.data = &mt2701_rdma_driver_data}, .data = &mt2701_rdma_driver_data},
{ .compatible = "mediatek,mt8173-disp-rdma", { .compatible = "mediatek,mt8173-disp-rdma",
.data = &mt8173_rdma_driver_data}, .data = &mt8173_rdma_driver_data},
{ .compatible = "mediatek,mt8183-disp-rdma",
.data = &mt8183_rdma_driver_data},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match); MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
......
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <drm/drm_simple_kms_helper.h> #include <drm/drm_simple_kms_helper.h>
#include "mtk_disp_drv.h"
#include "mtk_dpi_regs.h" #include "mtk_dpi_regs.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
...@@ -62,10 +64,10 @@ enum mtk_dpi_out_color_format { ...@@ -62,10 +64,10 @@ enum mtk_dpi_out_color_format {
}; };
struct mtk_dpi { struct mtk_dpi {
struct mtk_ddp_comp ddp_comp;
struct drm_encoder encoder; struct drm_encoder encoder;
struct drm_bridge bridge; struct drm_bridge bridge;
struct drm_bridge *next_bridge; struct drm_bridge *next_bridge;
struct drm_connector *connector;
void __iomem *regs; void __iomem *regs;
struct device *dev; struct device *dev;
struct clk *engine_clk; struct clk *engine_clk;
...@@ -562,53 +564,50 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = { ...@@ -562,53 +564,50 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = {
.enable = mtk_dpi_bridge_enable, .enable = mtk_dpi_bridge_enable,
}; };
static void mtk_dpi_start(struct mtk_ddp_comp *comp) void mtk_dpi_start(struct device *dev)
{ {
struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); struct mtk_dpi *dpi = dev_get_drvdata(dev);
mtk_dpi_power_on(dpi); mtk_dpi_power_on(dpi);
} }
static void mtk_dpi_stop(struct mtk_ddp_comp *comp) void mtk_dpi_stop(struct device *dev)
{ {
struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); struct mtk_dpi *dpi = dev_get_drvdata(dev);
mtk_dpi_power_off(dpi); mtk_dpi_power_off(dpi);
} }
static const struct mtk_ddp_comp_funcs mtk_dpi_funcs = {
.start = mtk_dpi_start,
.stop = mtk_dpi_stop,
};
static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
{ {
struct mtk_dpi *dpi = dev_get_drvdata(dev); struct mtk_dpi *dpi = dev_get_drvdata(dev);
struct drm_device *drm_dev = data; struct drm_device *drm_dev = data;
int ret; int ret;
ret = mtk_ddp_comp_register(drm_dev, &dpi->ddp_comp);
if (ret < 0) {
dev_err(dev, "Failed to register component %pOF: %d\n",
dev->of_node, ret);
return ret;
}
ret = drm_simple_encoder_init(drm_dev, &dpi->encoder, ret = drm_simple_encoder_init(drm_dev, &dpi->encoder,
DRM_MODE_ENCODER_TMDS); DRM_MODE_ENCODER_TMDS);
if (ret) { if (ret) {
dev_err(dev, "Failed to initialize decoder: %d\n", ret); dev_err(dev, "Failed to initialize decoder: %d\n", ret);
goto err_unregister; return ret;
} }
dpi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm_dev, dpi->ddp_comp); dpi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm_dev, dpi->dev);
ret = drm_bridge_attach(&dpi->encoder, &dpi->bridge, NULL, 0); ret = drm_bridge_attach(&dpi->encoder, &dpi->bridge, NULL,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) { if (ret) {
dev_err(dev, "Failed to attach bridge: %d\n", ret); dev_err(dev, "Failed to attach bridge: %d\n", ret);
goto err_cleanup; goto err_cleanup;
} }
dpi->connector = drm_bridge_connector_init(drm_dev, &dpi->encoder);
if (IS_ERR(dpi->connector)) {
dev_err(dev, "Unable to create bridge connector\n");
ret = PTR_ERR(dpi->connector);
goto err_cleanup;
}
drm_connector_attach_encoder(dpi->connector, &dpi->encoder);
dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS; dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS;
dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB; dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB;
dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB; dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
...@@ -618,8 +617,6 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) ...@@ -618,8 +617,6 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
err_cleanup: err_cleanup:
drm_encoder_cleanup(&dpi->encoder); drm_encoder_cleanup(&dpi->encoder);
err_unregister:
mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp);
return ret; return ret;
} }
...@@ -627,10 +624,8 @@ static void mtk_dpi_unbind(struct device *dev, struct device *master, ...@@ -627,10 +624,8 @@ static void mtk_dpi_unbind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct mtk_dpi *dpi = dev_get_drvdata(dev); struct mtk_dpi *dpi = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
drm_encoder_cleanup(&dpi->encoder); drm_encoder_cleanup(&dpi->encoder);
mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp);
} }
static const struct component_ops mtk_dpi_component_ops = { static const struct component_ops mtk_dpi_component_ops = {
...@@ -691,7 +686,6 @@ static int mtk_dpi_probe(struct platform_device *pdev) ...@@ -691,7 +686,6 @@ static int mtk_dpi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mtk_dpi *dpi; struct mtk_dpi *dpi;
struct resource *mem; struct resource *mem;
int comp_id;
int ret; int ret;
dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
...@@ -769,19 +763,6 @@ static int mtk_dpi_probe(struct platform_device *pdev) ...@@ -769,19 +763,6 @@ static int mtk_dpi_probe(struct platform_device *pdev)
dev_info(dev, "Found bridge node: %pOF\n", dpi->next_bridge->of_node); dev_info(dev, "Found bridge node: %pOF\n", dpi->next_bridge->of_node);
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
if (comp_id < 0) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
return comp_id;
}
ret = mtk_ddp_comp_init(dev, dev->of_node, &dpi->ddp_comp, comp_id,
&mtk_dpi_funcs);
if (ret) {
dev_err(dev, "Failed to initialize component: %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, dpi); platform_set_drvdata(pdev, dpi);
dpi->bridge.funcs = &mtk_dpi_bridge_funcs; dpi->bridge.funcs = &mtk_dpi_bridge_funcs;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h> #include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h> #include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
#include <asm/barrier.h> #include <asm/barrier.h>
#include <soc/mediatek/smi.h> #include <soc/mediatek/smi.h>
...@@ -19,7 +20,6 @@ ...@@ -19,7 +20,6 @@
#include "mtk_drm_drv.h" #include "mtk_drm_drv.h"
#include "mtk_drm_crtc.h" #include "mtk_drm_crtc.h"
#include "mtk_drm_ddp.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
#include "mtk_drm_gem.h" #include "mtk_drm_gem.h"
#include "mtk_drm_plane.h" #include "mtk_drm_plane.h"
...@@ -55,7 +55,7 @@ struct mtk_drm_crtc { ...@@ -55,7 +55,7 @@ struct mtk_drm_crtc {
#endif #endif
struct device *mmsys_dev; struct device *mmsys_dev;
struct mtk_disp_mutex *mutex; struct mtk_mutex *mutex;
unsigned int ddp_comp_nr; unsigned int ddp_comp_nr;
struct mtk_ddp_comp **ddp_comp; struct mtk_ddp_comp **ddp_comp;
...@@ -107,7 +107,7 @@ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) ...@@ -107,7 +107,7 @@ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
{ {
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
mtk_disp_mutex_put(mtk_crtc->mutex); mtk_mutex_put(mtk_crtc->mutex);
drm_crtc_cleanup(crtc); drm_crtc_cleanup(crtc);
} }
...@@ -169,31 +169,13 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) ...@@ -169,31 +169,13 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
state->pending_config = true; state->pending_config = true;
} }
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->base);
return 0;
}
static void mtk_drm_crtc_disable_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_disable_vblank(comp);
}
static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc) static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc)
{ {
int ret; int ret;
int i; int i;
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
ret = clk_prepare_enable(mtk_crtc->ddp_comp[i]->clk); ret = mtk_ddp_comp_clk_enable(mtk_crtc->ddp_comp[i]);
if (ret) { if (ret) {
DRM_ERROR("Failed to enable clock %d: %d\n", i, ret); DRM_ERROR("Failed to enable clock %d: %d\n", i, ret);
goto err; goto err;
...@@ -203,7 +185,7 @@ static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc) ...@@ -203,7 +185,7 @@ static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc)
return 0; return 0;
err: err:
while (--i >= 0) while (--i >= 0)
clk_disable_unprepare(mtk_crtc->ddp_comp[i]->clk); mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
return ret; return ret;
} }
...@@ -212,7 +194,7 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc) ...@@ -212,7 +194,7 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
int i; int i;
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
clk_disable_unprepare(mtk_crtc->ddp_comp[i]->clk); mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
} }
static static
...@@ -283,7 +265,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) ...@@ -283,7 +265,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
return ret; return ret;
} }
ret = mtk_disp_mutex_prepare(mtk_crtc->mutex); ret = mtk_mutex_prepare(mtk_crtc->mutex);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("Failed to enable mutex clock: %d\n", ret); DRM_ERROR("Failed to enable mutex clock: %d\n", ret);
goto err_pm_runtime_put; goto err_pm_runtime_put;
...@@ -299,11 +281,11 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) ...@@ -299,11 +281,11 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev, mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev,
mtk_crtc->ddp_comp[i]->id, mtk_crtc->ddp_comp[i]->id,
mtk_crtc->ddp_comp[i + 1]->id); mtk_crtc->ddp_comp[i + 1]->id);
mtk_disp_mutex_add_comp(mtk_crtc->mutex, mtk_mutex_add_comp(mtk_crtc->mutex,
mtk_crtc->ddp_comp[i]->id); mtk_crtc->ddp_comp[i]->id);
} }
mtk_disp_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
mtk_disp_mutex_enable(mtk_crtc->mutex); mtk_mutex_enable(mtk_crtc->mutex);
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i]; struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
...@@ -332,7 +314,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) ...@@ -332,7 +314,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
return 0; return 0;
err_mutex_unprepare: err_mutex_unprepare:
mtk_disp_mutex_unprepare(mtk_crtc->mutex); mtk_mutex_unprepare(mtk_crtc->mutex);
err_pm_runtime_put: err_pm_runtime_put:
pm_runtime_put(crtc->dev->dev); pm_runtime_put(crtc->dev->dev);
return ret; return ret;
...@@ -351,19 +333,19 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) ...@@ -351,19 +333,19 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc)
} }
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
mtk_disp_mutex_remove_comp(mtk_crtc->mutex, mtk_mutex_remove_comp(mtk_crtc->mutex,
mtk_crtc->ddp_comp[i]->id); mtk_crtc->ddp_comp[i]->id);
mtk_disp_mutex_disable(mtk_crtc->mutex); mtk_mutex_disable(mtk_crtc->mutex);
for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev, mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev,
mtk_crtc->ddp_comp[i]->id, mtk_crtc->ddp_comp[i]->id,
mtk_crtc->ddp_comp[i + 1]->id); mtk_crtc->ddp_comp[i + 1]->id);
mtk_disp_mutex_remove_comp(mtk_crtc->mutex, mtk_mutex_remove_comp(mtk_crtc->mutex,
mtk_crtc->ddp_comp[i]->id); mtk_crtc->ddp_comp[i]->id);
} }
mtk_disp_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
mtk_crtc_ddp_clk_disable(mtk_crtc); mtk_crtc_ddp_clk_disable(mtk_crtc);
mtk_disp_mutex_unprepare(mtk_crtc->mutex); mtk_mutex_unprepare(mtk_crtc->mutex);
pm_runtime_put(drm->dev); pm_runtime_put(drm->dev);
...@@ -475,9 +457,9 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc) ...@@ -475,9 +457,9 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
mtk_crtc->pending_async_planes = true; mtk_crtc->pending_async_planes = true;
if (priv->data->shadow_register) { if (priv->data->shadow_register) {
mtk_disp_mutex_acquire(mtk_crtc->mutex); mtk_mutex_acquire(mtk_crtc->mutex);
mtk_crtc_ddp_config(crtc, NULL); mtk_crtc_ddp_config(crtc, NULL);
mtk_disp_mutex_release(mtk_crtc->mutex); mtk_mutex_release(mtk_crtc->mutex);
} }
#if IS_REACHABLE(CONFIG_MTK_CMDQ) #if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (mtk_crtc->cmdq_client) { if (mtk_crtc->cmdq_client) {
...@@ -493,6 +475,40 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc) ...@@ -493,6 +475,40 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
mutex_unlock(&mtk_crtc->hw_lock); mutex_unlock(&mtk_crtc->hw_lock);
} }
static void mtk_crtc_ddp_irq(void *data)
{
struct drm_crtc *crtc = data;
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_drm_private *priv = crtc->dev->dev_private;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (!priv->data->shadow_register && !mtk_crtc->cmdq_client)
#else
if (!priv->data->shadow_register)
#endif
mtk_crtc_ddp_config(crtc, NULL);
mtk_drm_finish_page_flip(mtk_crtc);
}
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);
return 0;
}
static void mtk_drm_crtc_disable_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_disable_vblank(comp);
}
int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
struct mtk_plane_state *state) struct mtk_plane_state *state)
{ {
...@@ -661,21 +677,6 @@ static int mtk_drm_crtc_init(struct drm_device *drm, ...@@ -661,21 +677,6 @@ static int mtk_drm_crtc_init(struct drm_device *drm,
return ret; return ret;
} }
void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *comp)
{
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_drm_private *priv = crtc->dev->dev_private;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (!priv->data->shadow_register && !mtk_crtc->cmdq_client)
#else
if (!priv->data->shadow_register)
#endif
mtk_crtc_ddp_config(crtc, NULL);
mtk_drm_finish_page_flip(mtk_crtc);
}
static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc, static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc,
int comp_idx) int comp_idx)
{ {
...@@ -771,7 +772,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, ...@@ -771,7 +772,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
if (!mtk_crtc->ddp_comp) if (!mtk_crtc->ddp_comp)
return -ENOMEM; return -ENOMEM;
mtk_crtc->mutex = mtk_disp_mutex_get(priv->mutex_dev, pipe); mtk_crtc->mutex = mtk_mutex_get(priv->mutex_dev);
if (IS_ERR(mtk_crtc->mutex)) { if (IS_ERR(mtk_crtc->mutex)) {
ret = PTR_ERR(mtk_crtc->mutex); ret = PTR_ERR(mtk_crtc->mutex);
dev_err(dev, "Failed to get mutex: %d\n", ret); dev_err(dev, "Failed to get mutex: %d\n", ret);
...@@ -784,7 +785,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, ...@@ -784,7 +785,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
struct device_node *node; struct device_node *node;
node = priv->comp_node[comp_id]; node = priv->comp_node[comp_id];
comp = priv->ddp_comp[comp_id]; comp = &priv->ddp_comp[comp_id];
if (!comp) { if (!comp) {
dev_err(dev, "Component %pOF not initialized\n", node); dev_err(dev, "Component %pOF not initialized\n", node);
ret = -ENODEV; ret = -ENODEV;
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#define MTK_MIN_BPC 3 #define MTK_MIN_BPC 3
void mtk_drm_crtc_commit(struct drm_crtc *crtc); void mtk_drm_crtc_commit(struct drm_crtc *crtc);
void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *comp);
int mtk_drm_crtc_create(struct drm_device *drm_dev, int mtk_drm_crtc_create(struct drm_device *drm_dev,
const enum mtk_ddp_comp_id *path, const enum mtk_ddp_comp_id *path,
unsigned int path_len); unsigned int path_len);
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015 MediaTek Inc.
*/
#ifndef MTK_DRM_DDP_H
#define MTK_DRM_DDP_H
#include "mtk_drm_ddp_comp.h"
struct regmap;
struct device;
struct mtk_disp_mutex;
struct mtk_disp_mutex *mtk_disp_mutex_get(struct device *dev, unsigned int id);
int mtk_disp_mutex_prepare(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
enum mtk_ddp_comp_id id);
void mtk_disp_mutex_enable(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
enum mtk_ddp_comp_id id);
void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex);
void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex);
#endif /* MTK_DRM_DDP_H */
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h> #include <linux/soc/mediatek/mtk-cmdq.h>
#include <drm/drm_print.h> #include <drm/drm_print.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_drv.h" #include "mtk_drm_drv.h"
#include "mtk_drm_plane.h" #include "mtk_drm_plane.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
...@@ -35,31 +35,13 @@ ...@@ -35,31 +35,13 @@
#define DISP_AAL_EN 0x0000 #define DISP_AAL_EN 0x0000
#define DISP_AAL_SIZE 0x0030 #define DISP_AAL_SIZE 0x0030
#define DISP_CCORR_EN 0x0000
#define CCORR_EN BIT(0)
#define DISP_CCORR_CFG 0x0020
#define CCORR_RELAY_MODE BIT(0)
#define CCORR_ENGINE_EN BIT(1)
#define CCORR_GAMMA_OFF BIT(2)
#define CCORR_WGAMUT_SRC_CLIP BIT(3)
#define DISP_CCORR_SIZE 0x0030
#define DISP_CCORR_COEF_0 0x0080
#define DISP_CCORR_COEF_1 0x0084
#define DISP_CCORR_COEF_2 0x0088
#define DISP_CCORR_COEF_3 0x008C
#define DISP_CCORR_COEF_4 0x0090
#define DISP_DITHER_EN 0x0000 #define DISP_DITHER_EN 0x0000
#define DITHER_EN BIT(0) #define DITHER_EN BIT(0)
#define DISP_DITHER_CFG 0x0020 #define DISP_DITHER_CFG 0x0020
#define DITHER_RELAY_MODE BIT(0) #define DITHER_RELAY_MODE BIT(0)
#define DITHER_ENGINE_EN BIT(1)
#define DISP_DITHER_SIZE 0x0030 #define DISP_DITHER_SIZE 0x0030
#define DISP_GAMMA_EN 0x0000
#define DISP_GAMMA_CFG 0x0020
#define DISP_GAMMA_SIZE 0x0030
#define DISP_GAMMA_LUT 0x0700
#define LUT_10BIT_MASK 0x03ff #define LUT_10BIT_MASK 0x03ff
#define OD_RELAYMODE BIT(0) #define OD_RELAYMODE BIT(0)
...@@ -68,9 +50,6 @@ ...@@ -68,9 +50,6 @@
#define AAL_EN BIT(0) #define AAL_EN BIT(0)
#define GAMMA_EN BIT(0)
#define GAMMA_LUT_EN BIT(1)
#define DISP_DITHERING BIT(2) #define DISP_DITHERING BIT(2)
#define DITHER_LSB_ERR_SHIFT_R(x) (((x) & 0x7) << 28) #define DITHER_LSB_ERR_SHIFT_R(x) (((x) & 0x7) << 28)
#define DITHER_OVFLW_BIT_R(x) (((x) & 0x7) << 24) #define DITHER_OVFLW_BIT_R(x) (((x) & 0x7) << 24)
...@@ -86,262 +65,233 @@ ...@@ -86,262 +65,233 @@
#define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4) #define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4)
#define DITHER_ADD_RSHIFT_G(x) (((x) & 0x7) << 0) #define DITHER_ADD_RSHIFT_G(x) (((x) & 0x7) << 0)
struct mtk_ddp_comp_dev {
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
};
void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value, void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value,
struct mtk_ddp_comp *comp, unsigned int offset) struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
unsigned int offset)
{ {
#if IS_REACHABLE(CONFIG_MTK_CMDQ) #if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (cmdq_pkt) if (cmdq_pkt)
cmdq_pkt_write(cmdq_pkt, comp->subsys, cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys,
comp->regs_pa + offset, value); cmdq_reg->offset + offset, value);
else else
#endif #endif
writel(value, comp->regs + offset); writel(value, regs + offset);
} }
void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value, void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value,
struct mtk_ddp_comp *comp, struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
unsigned int offset) unsigned int offset)
{ {
#if IS_REACHABLE(CONFIG_MTK_CMDQ) #if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (cmdq_pkt) if (cmdq_pkt)
cmdq_pkt_write(cmdq_pkt, comp->subsys, cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys,
comp->regs_pa + offset, value); cmdq_reg->offset + offset, value);
else else
#endif #endif
writel_relaxed(value, comp->regs + offset); writel_relaxed(value, regs + offset);
} }
void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value,
unsigned int value, struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
struct mtk_ddp_comp *comp, unsigned int offset, unsigned int mask)
unsigned int offset,
unsigned int mask)
{ {
#if IS_REACHABLE(CONFIG_MTK_CMDQ) #if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (cmdq_pkt) { if (cmdq_pkt) {
cmdq_pkt_write_mask(cmdq_pkt, comp->subsys, cmdq_pkt_write_mask(cmdq_pkt, cmdq_reg->subsys,
comp->regs_pa + offset, value, mask); cmdq_reg->offset + offset, value, mask);
} else { } else {
#endif #endif
u32 tmp = readl(comp->regs + offset); u32 tmp = readl(regs + offset);
tmp = (tmp & ~mask) | (value & mask); tmp = (tmp & ~mask) | (value & mask);
writel(tmp, comp->regs + offset); writel(tmp, regs + offset);
#if IS_REACHABLE(CONFIG_MTK_CMDQ) #if IS_REACHABLE(CONFIG_MTK_CMDQ)
} }
#endif #endif
} }
void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc, static int mtk_ddp_clk_enable(struct device *dev)
unsigned int CFG, struct cmdq_pkt *cmdq_pkt) {
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
return clk_prepare_enable(priv->clk);
}
static void mtk_ddp_clk_disable(struct device *dev)
{
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
clk_disable_unprepare(priv->clk);
}
void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg,
unsigned int bpc, unsigned int cfg,
unsigned int dither_en, struct cmdq_pkt *cmdq_pkt)
{ {
/* If bpc equal to 0, the dithering function didn't be enabled */ /* If bpc equal to 0, the dithering function didn't be enabled */
if (bpc == 0) if (bpc == 0)
return; return;
if (bpc >= MTK_MIN_BPC) { if (bpc >= MTK_MIN_BPC) {
mtk_ddp_write(cmdq_pkt, 0, comp, DISP_DITHER_5); mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_DITHER_5);
mtk_ddp_write(cmdq_pkt, 0, comp, DISP_DITHER_7); mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_DITHER_7);
mtk_ddp_write(cmdq_pkt, mtk_ddp_write(cmdq_pkt,
DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) | DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) |
DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) | DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) |
DITHER_NEW_BIT_MODE, DITHER_NEW_BIT_MODE,
comp, DISP_DITHER_15); cmdq_reg, regs, DISP_DITHER_15);
mtk_ddp_write(cmdq_pkt, mtk_ddp_write(cmdq_pkt,
DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) | DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) |
DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) | DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) |
DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) | DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) |
DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc), DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc),
comp, DISP_DITHER_16); cmdq_reg, regs, DISP_DITHER_16);
mtk_ddp_write(cmdq_pkt, DISP_DITHERING, comp, CFG); mtk_ddp_write(cmdq_pkt, dither_en, cmdq_reg, regs, cfg);
} }
} }
static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w, static void mtk_dither_set(struct device *dev, unsigned int bpc,
unsigned int h, unsigned int vrefresh, unsigned int cfg, struct cmdq_pkt *cmdq_pkt)
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{ {
mtk_ddp_write(cmdq_pkt, w << 16 | h, comp, DISP_OD_SIZE); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, OD_RELAYMODE, comp, DISP_OD_CFG);
mtk_dither_set(comp, bpc, DISP_OD_CFG, cmdq_pkt);
}
static void mtk_od_start(struct mtk_ddp_comp *comp)
{
writel(1, comp->regs + DISP_OD_EN);
}
static void mtk_ufoe_start(struct mtk_ddp_comp *comp) mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, cfg,
{ DISP_DITHERING, cmdq_pkt);
writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
} }
static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w, static void mtk_od_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh, unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt) unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{ {
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_AAL_SIZE); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_OD_SIZE);
mtk_ddp_write(cmdq_pkt, OD_RELAYMODE, &priv->cmdq_reg, priv->regs, DISP_OD_CFG);
mtk_dither_set(dev, bpc, DISP_OD_CFG, cmdq_pkt);
} }
static void mtk_aal_start(struct mtk_ddp_comp *comp) static void mtk_od_start(struct device *dev)
{ {
writel(AAL_EN, comp->regs + DISP_AAL_EN); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
writel(1, priv->regs + DISP_OD_EN);
} }
static void mtk_aal_stop(struct mtk_ddp_comp *comp) static void mtk_ufoe_start(struct device *dev)
{ {
writel_relaxed(0x0, comp->regs + DISP_AAL_EN); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
writel(UFO_BYPASS, priv->regs + DISP_REG_UFO_START);
} }
static void mtk_ccorr_config(struct mtk_ddp_comp *comp, unsigned int w, static void mtk_aal_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh, unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt) unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{ {
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_CCORR_SIZE); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, CCORR_ENGINE_EN, comp, DISP_CCORR_CFG);
}
static void mtk_ccorr_start(struct mtk_ddp_comp *comp) mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_AAL_SIZE);
{
writel(CCORR_EN, comp->regs + DISP_CCORR_EN);
} }
static void mtk_ccorr_stop(struct mtk_ddp_comp *comp) static void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state)
{ {
writel_relaxed(0x0, comp->regs + DISP_CCORR_EN); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
mtk_gamma_set_common(priv->regs, state);
} }
/* Converts a DRM S31.32 value to the HW S1.10 format. */ static void mtk_aal_start(struct device *dev)
static u16 mtk_ctm_s31_32_to_s1_10(u64 in)
{ {
u16 r; struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
/* Sign bit. */ writel(AAL_EN, priv->regs + DISP_AAL_EN);
r = in & BIT_ULL(63) ? BIT(11) : 0;
if ((in & GENMASK_ULL(62, 33)) > 0) {
/* identity value 0x100000000 -> 0x400, */
/* if bigger this, set it to max 0x7ff. */
r |= GENMASK(10, 0);
} else {
/* take the 11 most important bits. */
r |= (in >> 22) & GENMASK(10, 0);
}
return r;
} }
static void mtk_ccorr_ctm_set(struct mtk_ddp_comp *comp, static void mtk_aal_stop(struct device *dev)
struct drm_crtc_state *state)
{ {
struct drm_property_blob *blob = state->ctm; struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
struct drm_color_ctm *ctm;
const u64 *input;
uint16_t coeffs[9] = { 0 };
int i;
struct cmdq_pkt *cmdq_pkt = NULL;
if (!blob)
return;
ctm = (struct drm_color_ctm *)blob->data; writel_relaxed(0x0, priv->regs + DISP_AAL_EN);
input = ctm->matrix;
for (i = 0; i < ARRAY_SIZE(coeffs); i++)
coeffs[i] = mtk_ctm_s31_32_to_s1_10(input[i]);
mtk_ddp_write(cmdq_pkt, coeffs[0] << 16 | coeffs[1],
comp, DISP_CCORR_COEF_0);
mtk_ddp_write(cmdq_pkt, coeffs[2] << 16 | coeffs[3],
comp, DISP_CCORR_COEF_1);
mtk_ddp_write(cmdq_pkt, coeffs[4] << 16 | coeffs[5],
comp, DISP_CCORR_COEF_2);
mtk_ddp_write(cmdq_pkt, coeffs[6] << 16 | coeffs[7],
comp, DISP_CCORR_COEF_3);
mtk_ddp_write(cmdq_pkt, coeffs[8] << 16,
comp, DISP_CCORR_COEF_4);
} }
static void mtk_dither_config(struct mtk_ddp_comp *comp, unsigned int w, static void mtk_dither_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh, unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt) unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{ {
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_DITHER_SIZE); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, DITHER_RELAY_MODE, comp, DISP_DITHER_CFG);
}
static void mtk_dither_start(struct mtk_ddp_comp *comp) mtk_ddp_write(cmdq_pkt, h << 16 | w, &priv->cmdq_reg, priv->regs, DISP_DITHER_SIZE);
{ mtk_ddp_write(cmdq_pkt, DITHER_RELAY_MODE, &priv->cmdq_reg, priv->regs, DISP_DITHER_CFG);
writel(DITHER_EN, comp->regs + DISP_DITHER_EN); mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, DISP_DITHER_CFG,
DITHER_ENGINE_EN, cmdq_pkt);
} }
static void mtk_dither_stop(struct mtk_ddp_comp *comp) static void mtk_dither_start(struct device *dev)
{ {
writel_relaxed(0x0, comp->regs + DISP_DITHER_EN); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
}
static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w, writel(DITHER_EN, priv->regs + DISP_DITHER_EN);
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_GAMMA_SIZE);
mtk_dither_set(comp, bpc, DISP_GAMMA_CFG, cmdq_pkt);
} }
static void mtk_gamma_start(struct mtk_ddp_comp *comp) static void mtk_dither_stop(struct device *dev)
{ {
writel(GAMMA_EN, comp->regs + DISP_GAMMA_EN); struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
}
static void mtk_gamma_stop(struct mtk_ddp_comp *comp) writel_relaxed(0x0, priv->regs + DISP_DITHER_EN);
{
writel_relaxed(0x0, comp->regs + DISP_GAMMA_EN);
}
static void mtk_gamma_set(struct mtk_ddp_comp *comp,
struct drm_crtc_state *state)
{
unsigned int i, reg;
struct drm_color_lut *lut;
void __iomem *lut_base;
u32 word;
if (state->gamma_lut) {
reg = readl(comp->regs + DISP_GAMMA_CFG);
reg = reg | GAMMA_LUT_EN;
writel(reg, comp->regs + DISP_GAMMA_CFG);
lut_base = comp->regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
for (i = 0; i < MTK_LUT_SIZE; i++) {
word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
(((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
((lut[i].blue >> 6) & LUT_10BIT_MASK);
writel(word, (lut_base + i * 4));
}
}
} }
static const struct mtk_ddp_comp_funcs ddp_aal = { static const struct mtk_ddp_comp_funcs ddp_aal = {
.gamma_set = mtk_gamma_set, .clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
.gamma_set = mtk_aal_gamma_set,
.config = mtk_aal_config, .config = mtk_aal_config,
.start = mtk_aal_start, .start = mtk_aal_start,
.stop = mtk_aal_stop, .stop = mtk_aal_stop,
}; };
static const struct mtk_ddp_comp_funcs ddp_ccorr = { static const struct mtk_ddp_comp_funcs ddp_ccorr = {
.clk_enable = mtk_ccorr_clk_enable,
.clk_disable = mtk_ccorr_clk_disable,
.config = mtk_ccorr_config, .config = mtk_ccorr_config,
.start = mtk_ccorr_start, .start = mtk_ccorr_start,
.stop = mtk_ccorr_stop, .stop = mtk_ccorr_stop,
.ctm_set = mtk_ccorr_ctm_set, .ctm_set = mtk_ccorr_ctm_set,
}; };
static const struct mtk_ddp_comp_funcs ddp_color = {
.clk_enable = mtk_color_clk_enable,
.clk_disable = mtk_color_clk_disable,
.config = mtk_color_config,
.start = mtk_color_start,
};
static const struct mtk_ddp_comp_funcs ddp_dither = { static const struct mtk_ddp_comp_funcs ddp_dither = {
.clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
.config = mtk_dither_config, .config = mtk_dither_config,
.start = mtk_dither_start, .start = mtk_dither_start,
.stop = mtk_dither_stop, .stop = mtk_dither_stop,
}; };
static const struct mtk_ddp_comp_funcs ddp_dpi = {
.start = mtk_dpi_start,
.stop = mtk_dpi_stop,
};
static const struct mtk_ddp_comp_funcs ddp_dsi = {
.start = mtk_dsi_ddp_start,
.stop = mtk_dsi_ddp_stop,
};
static const struct mtk_ddp_comp_funcs ddp_gamma = { static const struct mtk_ddp_comp_funcs ddp_gamma = {
.clk_enable = mtk_gamma_clk_enable,
.clk_disable = mtk_gamma_clk_disable,
.gamma_set = mtk_gamma_set, .gamma_set = mtk_gamma_set,
.config = mtk_gamma_config, .config = mtk_gamma_config,
.start = mtk_gamma_start, .start = mtk_gamma_start,
...@@ -349,11 +299,43 @@ static const struct mtk_ddp_comp_funcs ddp_gamma = { ...@@ -349,11 +299,43 @@ static const struct mtk_ddp_comp_funcs ddp_gamma = {
}; };
static const struct mtk_ddp_comp_funcs ddp_od = { static const struct mtk_ddp_comp_funcs ddp_od = {
.clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
.config = mtk_od_config, .config = mtk_od_config,
.start = mtk_od_start, .start = mtk_od_start,
}; };
static const struct mtk_ddp_comp_funcs ddp_ovl = {
.clk_enable = mtk_ovl_clk_enable,
.clk_disable = mtk_ovl_clk_disable,
.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 const struct mtk_ddp_comp_funcs ddp_rdma = {
.clk_enable = mtk_rdma_clk_enable,
.clk_disable = mtk_rdma_clk_disable,
.config = mtk_rdma_config,
.start = mtk_rdma_start,
.stop = mtk_rdma_stop,
.enable_vblank = mtk_rdma_enable_vblank,
.disable_vblank = mtk_rdma_disable_vblank,
.layer_nr = mtk_rdma_layer_nr,
.layer_config = mtk_rdma_layer_config,
};
static const struct mtk_ddp_comp_funcs ddp_ufoe = { static const struct mtk_ddp_comp_funcs ddp_ufoe = {
.clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
.start = mtk_ufoe_start, .start = mtk_ufoe_start,
}; };
...@@ -387,36 +369,37 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { ...@@ -387,36 +369,37 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL1] = { MTK_DISP_AAL, 1, &ddp_aal }, [DDP_COMPONENT_AAL1] = { MTK_DISP_AAL, 1, &ddp_aal },
[DDP_COMPONENT_BLS] = { MTK_DISP_BLS, 0, NULL }, [DDP_COMPONENT_BLS] = { MTK_DISP_BLS, 0, NULL },
[DDP_COMPONENT_CCORR] = { MTK_DISP_CCORR, 0, &ddp_ccorr }, [DDP_COMPONENT_CCORR] = { MTK_DISP_CCORR, 0, &ddp_ccorr },
[DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, NULL }, [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color },
[DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, NULL }, [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color },
[DDP_COMPONENT_DITHER] = { MTK_DISP_DITHER, 0, &ddp_dither }, [DDP_COMPONENT_DITHER] = { MTK_DISP_DITHER, 0, &ddp_dither },
[DDP_COMPONENT_DPI0] = { MTK_DPI, 0, NULL }, [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, &ddp_dpi },
[DDP_COMPONENT_DPI1] = { MTK_DPI, 1, NULL }, [DDP_COMPONENT_DPI1] = { MTK_DPI, 1, &ddp_dpi },
[DDP_COMPONENT_DSI0] = { MTK_DSI, 0, NULL }, [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, &ddp_dsi },
[DDP_COMPONENT_DSI1] = { MTK_DSI, 1, NULL }, [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, &ddp_dsi },
[DDP_COMPONENT_DSI2] = { MTK_DSI, 2, NULL }, [DDP_COMPONENT_DSI2] = { MTK_DSI, 2, &ddp_dsi },
[DDP_COMPONENT_DSI3] = { MTK_DSI, 3, NULL }, [DDP_COMPONENT_DSI3] = { MTK_DSI, 3, &ddp_dsi },
[DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma }, [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma },
[DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od }, [DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od },
[DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od }, [DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od },
[DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, NULL }, [DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, &ddp_ovl },
[DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, NULL }, [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, &ddp_ovl },
[DDP_COMPONENT_OVL_2L0] = { MTK_DISP_OVL_2L, 0, NULL }, [DDP_COMPONENT_OVL_2L0] = { MTK_DISP_OVL_2L, 0, &ddp_ovl },
[DDP_COMPONENT_OVL_2L1] = { MTK_DISP_OVL_2L, 1, NULL }, [DDP_COMPONENT_OVL_2L1] = { MTK_DISP_OVL_2L, 1, &ddp_ovl },
[DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL }, [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL },
[DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL }, [DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL },
[DDP_COMPONENT_PWM2] = { MTK_DISP_PWM, 2, NULL }, [DDP_COMPONENT_PWM2] = { MTK_DISP_PWM, 2, NULL },
[DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, NULL }, [DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, &ddp_rdma },
[DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, NULL }, [DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, &ddp_rdma },
[DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, NULL }, [DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, &ddp_rdma },
[DDP_COMPONENT_UFOE] = { MTK_DISP_UFOE, 0, &ddp_ufoe }, [DDP_COMPONENT_UFOE] = { MTK_DISP_UFOE, 0, &ddp_ufoe },
[DDP_COMPONENT_WDMA0] = { MTK_DISP_WDMA, 0, NULL }, [DDP_COMPONENT_WDMA0] = { MTK_DISP_WDMA, 0, NULL },
[DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL }, [DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL },
}; };
static bool mtk_drm_find_comp_in_ddp(struct mtk_ddp_comp ddp_comp, static bool mtk_drm_find_comp_in_ddp(struct device *dev,
const enum mtk_ddp_comp_id *path, const enum mtk_ddp_comp_id *path,
unsigned int path_len) unsigned int path_len,
struct mtk_ddp_comp *ddp_comp)
{ {
unsigned int i; unsigned int i;
...@@ -424,7 +407,7 @@ static bool mtk_drm_find_comp_in_ddp(struct mtk_ddp_comp ddp_comp, ...@@ -424,7 +407,7 @@ static bool mtk_drm_find_comp_in_ddp(struct mtk_ddp_comp ddp_comp,
return false; return false;
for (i = 0U; i < path_len; i++) for (i = 0U; i < path_len; i++)
if (ddp_comp.id == path[i]) if (dev == ddp_comp[path[i]].dev)
return true; return true;
return false; return false;
...@@ -446,18 +429,19 @@ int mtk_ddp_comp_get_id(struct device_node *node, ...@@ -446,18 +429,19 @@ int mtk_ddp_comp_get_id(struct device_node *node,
} }
unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm,
struct mtk_ddp_comp ddp_comp) struct device *dev)
{ {
struct mtk_drm_private *private = drm->dev_private; struct mtk_drm_private *private = drm->dev_private;
unsigned int ret = 0; unsigned int ret = 0;
if (mtk_drm_find_comp_in_ddp(ddp_comp, private->data->main_path, private->data->main_len)) if (mtk_drm_find_comp_in_ddp(dev, private->data->main_path, private->data->main_len,
private->ddp_comp))
ret = BIT(0); ret = BIT(0);
else if (mtk_drm_find_comp_in_ddp(ddp_comp, private->data->ext_path, else if (mtk_drm_find_comp_in_ddp(dev, private->data->ext_path,
private->data->ext_len)) private->data->ext_len, private->ddp_comp))
ret = BIT(1); ret = BIT(1);
else if (mtk_drm_find_comp_in_ddp(ddp_comp, private->data->third_path, else if (mtk_drm_find_comp_in_ddp(dev, private->data->third_path,
private->data->third_len)) private->data->third_len, private->ddp_comp))
ret = BIT(2); ret = BIT(2);
else else
DRM_INFO("Failed to find comp in ddp table\n"); DRM_INFO("Failed to find comp in ddp table\n");
...@@ -465,59 +449,15 @@ unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, ...@@ -465,59 +449,15 @@ unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm,
return ret; return ret;
} }
int mtk_ddp_comp_init(struct device *dev, struct device_node *node, static int mtk_ddp_get_larb_dev(struct device_node *node, struct mtk_ddp_comp *comp,
struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id, struct device *dev)
const struct mtk_ddp_comp_funcs *funcs)
{ {
enum mtk_ddp_comp_type type;
struct device_node *larb_node; struct device_node *larb_node;
struct platform_device *larb_pdev; struct platform_device *larb_pdev;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
struct resource res;
struct cmdq_client_reg cmdq_reg;
int ret;
#endif
if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
return -EINVAL;
type = mtk_ddp_matches[comp_id].type;
comp->id = comp_id;
comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs;
if (comp_id == DDP_COMPONENT_BLS ||
comp_id == DDP_COMPONENT_DPI0 ||
comp_id == DDP_COMPONENT_DPI1 ||
comp_id == DDP_COMPONENT_DSI0 ||
comp_id == DDP_COMPONENT_DSI1 ||
comp_id == DDP_COMPONENT_DSI2 ||
comp_id == DDP_COMPONENT_DSI3 ||
comp_id == DDP_COMPONENT_PWM0) {
comp->regs = NULL;
comp->clk = NULL;
comp->irq = 0;
return 0;
}
comp->regs = of_iomap(node, 0);
comp->irq = of_irq_get(node, 0);
comp->clk = of_clk_get(node, 0);
if (IS_ERR(comp->clk))
return PTR_ERR(comp->clk);
/* Only DMA capable components need the LARB property */
comp->larb_dev = NULL;
if (type != MTK_DISP_OVL &&
type != MTK_DISP_OVL_2L &&
type != MTK_DISP_RDMA &&
type != MTK_DISP_WDMA)
return 0;
larb_node = of_parse_phandle(node, "mediatek,larb", 0); larb_node = of_parse_phandle(node, "mediatek,larb", 0);
if (!larb_node) { if (!larb_node) {
dev_err(dev, dev_err(dev, "Missing mediadek,larb phandle in %pOF node\n", node);
"Missing mediadek,larb phandle in %pOF node\n", node);
return -EINVAL; return -EINVAL;
} }
...@@ -528,40 +468,71 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, ...@@ -528,40 +468,71 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
of_node_put(larb_node); of_node_put(larb_node);
comp->larb_dev = &larb_pdev->dev; comp->larb_dev = &larb_pdev->dev;
#if IS_REACHABLE(CONFIG_MTK_CMDQ) return 0;
if (of_address_to_resource(node, 0, &res) != 0) { }
dev_err(dev, "Missing reg in %s node\n", node->full_name);
put_device(&larb_pdev->dev); int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp,
enum mtk_ddp_comp_id comp_id)
{
struct platform_device *comp_pdev;
enum mtk_ddp_comp_type type;
struct mtk_ddp_comp_dev *priv;
int ret;
if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
return -EINVAL; return -EINVAL;
type = mtk_ddp_matches[comp_id].type;
comp->id = comp_id;
comp->funcs = mtk_ddp_matches[comp_id].funcs;
comp_pdev = of_find_device_by_node(node);
if (!comp_pdev) {
DRM_INFO("Waiting for device %s\n", node->full_name);
return -EPROBE_DEFER;
} }
comp->regs_pa = res.start; comp->dev = &comp_pdev->dev;
ret = cmdq_dev_get_client_reg(dev, &cmdq_reg, 0); /* Only DMA capable components need the LARB property */
if (type == MTK_DISP_OVL ||
type == MTK_DISP_OVL_2L ||
type == MTK_DISP_RDMA ||
type == MTK_DISP_WDMA) {
ret = mtk_ddp_get_larb_dev(node, comp, comp->dev);
if (ret) if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n"); return ret;
else }
comp->subsys = cmdq_reg.subsys;
#endif if (type == MTK_DISP_BLS ||
type == MTK_DISP_CCORR ||
type == MTK_DISP_COLOR ||
type == MTK_DISP_GAMMA ||
type == MTK_DPI ||
type == MTK_DSI ||
type == MTK_DISP_OVL ||
type == MTK_DISP_OVL_2L ||
type == MTK_DISP_PWM ||
type == MTK_DISP_RDMA)
return 0; return 0;
}
int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp) priv = devm_kzalloc(comp->dev, sizeof(*priv), GFP_KERNEL);
{ if (!priv)
struct mtk_drm_private *private = drm->dev_private; return -ENOMEM;
if (private->ddp_comp[comp->id]) priv->regs = of_iomap(node, 0);
return -EBUSY; priv->clk = of_clk_get(node, 0);
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
private->ddp_comp[comp->id] = comp; #if IS_REACHABLE(CONFIG_MTK_CMDQ)
return 0; ret = cmdq_dev_get_client_reg(comp->dev, &priv->cmdq_reg, 0);
} if (ret)
dev_dbg(comp->dev, "get mediatek,gce-client-reg fail!\n");
#endif
void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp) platform_set_drvdata(comp_pdev, priv);
{
struct mtk_drm_private *private = drm->dev_private;
private->ddp_comp[comp->id] = NULL; return 0;
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define MTK_DRM_DDP_COMP_H #define MTK_DRM_DDP_COMP_H
#include <linux/io.h> #include <linux/io.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h> #include <linux/soc/mediatek/mtk-mmsys.h>
struct device; struct device;
...@@ -39,79 +40,95 @@ enum mtk_ddp_comp_type { ...@@ -39,79 +40,95 @@ enum mtk_ddp_comp_type {
struct mtk_ddp_comp; struct mtk_ddp_comp;
struct cmdq_pkt; struct cmdq_pkt;
struct mtk_ddp_comp_funcs { struct mtk_ddp_comp_funcs {
void (*config)(struct mtk_ddp_comp *comp, unsigned int w, int (*clk_enable)(struct device *dev);
void (*clk_disable)(struct device *dev);
void (*config)(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh, unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt); unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void (*start)(struct mtk_ddp_comp *comp); void (*start)(struct device *dev);
void (*stop)(struct mtk_ddp_comp *comp); void (*stop)(struct device *dev);
void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc); void (*enable_vblank)(struct device *dev,
void (*disable_vblank)(struct mtk_ddp_comp *comp); void (*vblank_cb)(void *),
unsigned int (*supported_rotations)(struct mtk_ddp_comp *comp); void *vblank_cb_data);
unsigned int (*layer_nr)(struct mtk_ddp_comp *comp); void (*disable_vblank)(struct device *dev);
int (*layer_check)(struct mtk_ddp_comp *comp, unsigned int (*supported_rotations)(struct device *dev);
unsigned int (*layer_nr)(struct device *dev);
int (*layer_check)(struct device *dev,
unsigned int idx, unsigned int idx,
struct mtk_plane_state *state); struct mtk_plane_state *state);
void (*layer_config)(struct mtk_ddp_comp *comp, unsigned int idx, void (*layer_config)(struct device *dev, unsigned int idx,
struct mtk_plane_state *state, struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt); struct cmdq_pkt *cmdq_pkt);
void (*gamma_set)(struct mtk_ddp_comp *comp, void (*gamma_set)(struct device *dev,
struct drm_crtc_state *state); struct drm_crtc_state *state);
void (*bgclr_in_on)(struct mtk_ddp_comp *comp); void (*bgclr_in_on)(struct device *dev);
void (*bgclr_in_off)(struct mtk_ddp_comp *comp); void (*bgclr_in_off)(struct device *dev);
void (*ctm_set)(struct mtk_ddp_comp *comp, void (*ctm_set)(struct device *dev,
struct drm_crtc_state *state); struct drm_crtc_state *state);
}; };
struct mtk_ddp_comp { struct mtk_ddp_comp {
struct clk *clk; struct device *dev;
void __iomem *regs;
int irq; int irq;
struct device *larb_dev; struct device *larb_dev;
enum mtk_ddp_comp_id id; enum mtk_ddp_comp_id id;
const struct mtk_ddp_comp_funcs *funcs; const struct mtk_ddp_comp_funcs *funcs;
resource_size_t regs_pa;
u8 subsys;
}; };
static inline int mtk_ddp_comp_clk_enable(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->clk_enable)
return comp->funcs->clk_enable(comp->dev);
return 0;
}
static inline void mtk_ddp_comp_clk_disable(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->clk_disable)
comp->funcs->clk_disable(comp->dev);
}
static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp, static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
unsigned int w, unsigned int h, unsigned int w, unsigned int h,
unsigned int vrefresh, unsigned int bpc, unsigned int vrefresh, unsigned int bpc,
struct cmdq_pkt *cmdq_pkt) struct cmdq_pkt *cmdq_pkt)
{ {
if (comp->funcs && comp->funcs->config) if (comp->funcs && comp->funcs->config)
comp->funcs->config(comp, w, h, vrefresh, bpc, cmdq_pkt); comp->funcs->config(comp->dev, w, h, vrefresh, bpc, cmdq_pkt);
} }
static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp) static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp)
{ {
if (comp->funcs && comp->funcs->start) if (comp->funcs && comp->funcs->start)
comp->funcs->start(comp); comp->funcs->start(comp->dev);
} }
static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp) static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp)
{ {
if (comp->funcs && comp->funcs->stop) if (comp->funcs && comp->funcs->stop)
comp->funcs->stop(comp); comp->funcs->stop(comp->dev);
} }
static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp, static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp,
struct drm_crtc *crtc) void (*vblank_cb)(void *),
void *vblank_cb_data)
{ {
if (comp->funcs && comp->funcs->enable_vblank) if (comp->funcs && comp->funcs->enable_vblank)
comp->funcs->enable_vblank(comp, crtc); comp->funcs->enable_vblank(comp->dev, vblank_cb, vblank_cb_data);
} }
static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp) static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp)
{ {
if (comp->funcs && comp->funcs->disable_vblank) if (comp->funcs && comp->funcs->disable_vblank)
comp->funcs->disable_vblank(comp); comp->funcs->disable_vblank(comp->dev);
} }
static inline static inline
unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp) unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp)
{ {
if (comp->funcs && comp->funcs->supported_rotations) if (comp->funcs && comp->funcs->supported_rotations)
return comp->funcs->supported_rotations(comp); return comp->funcs->supported_rotations(comp->dev);
return 0; return 0;
} }
...@@ -119,7 +136,7 @@ unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp) ...@@ -119,7 +136,7 @@ unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp)
static inline unsigned int mtk_ddp_comp_layer_nr(struct mtk_ddp_comp *comp) static inline unsigned int mtk_ddp_comp_layer_nr(struct mtk_ddp_comp *comp)
{ {
if (comp->funcs && comp->funcs->layer_nr) if (comp->funcs && comp->funcs->layer_nr)
return comp->funcs->layer_nr(comp); return comp->funcs->layer_nr(comp->dev);
return 0; return 0;
} }
...@@ -129,7 +146,7 @@ static inline int mtk_ddp_comp_layer_check(struct mtk_ddp_comp *comp, ...@@ -129,7 +146,7 @@ static inline int mtk_ddp_comp_layer_check(struct mtk_ddp_comp *comp,
struct mtk_plane_state *state) struct mtk_plane_state *state)
{ {
if (comp->funcs && comp->funcs->layer_check) if (comp->funcs && comp->funcs->layer_check)
return comp->funcs->layer_check(comp, idx, state); return comp->funcs->layer_check(comp->dev, idx, state);
return 0; return 0;
} }
...@@ -139,52 +156,49 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp, ...@@ -139,52 +156,49 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp,
struct cmdq_pkt *cmdq_pkt) struct cmdq_pkt *cmdq_pkt)
{ {
if (comp->funcs && comp->funcs->layer_config) if (comp->funcs && comp->funcs->layer_config)
comp->funcs->layer_config(comp, idx, state, cmdq_pkt); comp->funcs->layer_config(comp->dev, idx, state, cmdq_pkt);
} }
static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp, static inline void mtk_ddp_gamma_set(struct mtk_ddp_comp *comp,
struct drm_crtc_state *state) struct drm_crtc_state *state)
{ {
if (comp->funcs && comp->funcs->gamma_set) if (comp->funcs && comp->funcs->gamma_set)
comp->funcs->gamma_set(comp, state); comp->funcs->gamma_set(comp->dev, state);
} }
static inline void mtk_ddp_comp_bgclr_in_on(struct mtk_ddp_comp *comp) static inline void mtk_ddp_comp_bgclr_in_on(struct mtk_ddp_comp *comp)
{ {
if (comp->funcs && comp->funcs->bgclr_in_on) if (comp->funcs && comp->funcs->bgclr_in_on)
comp->funcs->bgclr_in_on(comp); comp->funcs->bgclr_in_on(comp->dev);
} }
static inline void mtk_ddp_comp_bgclr_in_off(struct mtk_ddp_comp *comp) static inline void mtk_ddp_comp_bgclr_in_off(struct mtk_ddp_comp *comp)
{ {
if (comp->funcs && comp->funcs->bgclr_in_off) if (comp->funcs && comp->funcs->bgclr_in_off)
comp->funcs->bgclr_in_off(comp); comp->funcs->bgclr_in_off(comp->dev);
} }
static inline void mtk_ddp_ctm_set(struct mtk_ddp_comp *comp, static inline void mtk_ddp_ctm_set(struct mtk_ddp_comp *comp,
struct drm_crtc_state *state) struct drm_crtc_state *state)
{ {
if (comp->funcs && comp->funcs->ctm_set) if (comp->funcs && comp->funcs->ctm_set)
comp->funcs->ctm_set(comp, state); comp->funcs->ctm_set(comp->dev, state);
} }
int mtk_ddp_comp_get_id(struct device_node *node, int mtk_ddp_comp_get_id(struct device_node *node,
enum mtk_ddp_comp_type comp_type); enum mtk_ddp_comp_type comp_type);
unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm,
struct mtk_ddp_comp ddp_comp); struct device *dev);
int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node, int mtk_ddp_comp_init(struct device_node *comp_node, struct mtk_ddp_comp *comp,
struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id, enum mtk_ddp_comp_id comp_id);
const struct mtk_ddp_comp_funcs *funcs);
int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp);
void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp);
void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
unsigned int CFG, struct cmdq_pkt *cmdq_pkt);
enum mtk_ddp_comp_type mtk_ddp_comp_get_type(enum mtk_ddp_comp_id comp_id); enum mtk_ddp_comp_type mtk_ddp_comp_get_type(enum mtk_ddp_comp_id comp_id);
void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value, void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value,
struct mtk_ddp_comp *comp, unsigned int offset); struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
unsigned int offset);
void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value, void mtk_ddp_write_relaxed(struct cmdq_pkt *cmdq_pkt, unsigned int value,
struct mtk_ddp_comp *comp, unsigned int offset); struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
unsigned int offset);
void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value, void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value,
struct mtk_ddp_comp *comp, unsigned int offset, struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
unsigned int mask); unsigned int offset, unsigned int mask);
#endif /* MTK_DRM_DDP_COMP_H */ #endif /* MTK_DRM_DDP_COMP_H */
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
...@@ -26,7 +25,6 @@ ...@@ -26,7 +25,6 @@
#include <drm/drm_vblank.h> #include <drm/drm_vblank.h>
#include "mtk_drm_crtc.h" #include "mtk_drm_crtc.h"
#include "mtk_drm_ddp.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
#include "mtk_drm_drv.h" #include "mtk_drm_drv.h"
#include "mtk_drm_gem.h" #include "mtk_drm_gem.h"
...@@ -131,6 +129,24 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = { ...@@ -131,6 +129,24 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
DDP_COMPONENT_DPI0, DDP_COMPONENT_DPI0,
}; };
static const enum mtk_ddp_comp_id mt8183_mtk_ddp_main[] = {
DDP_COMPONENT_OVL0,
DDP_COMPONENT_OVL_2L0,
DDP_COMPONENT_RDMA0,
DDP_COMPONENT_COLOR0,
DDP_COMPONENT_CCORR,
DDP_COMPONENT_AAL0,
DDP_COMPONENT_GAMMA,
DDP_COMPONENT_DITHER,
DDP_COMPONENT_DSI0,
};
static const enum mtk_ddp_comp_id mt8183_mtk_ddp_ext[] = {
DDP_COMPONENT_OVL_2L1,
DDP_COMPONENT_RDMA1,
DDP_COMPONENT_DPI0,
};
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.main_path = mt2701_mtk_ddp_main, .main_path = mt2701_mtk_ddp_main,
.main_len = ARRAY_SIZE(mt2701_mtk_ddp_main), .main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
...@@ -163,6 +179,13 @@ static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { ...@@ -163,6 +179,13 @@ static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext), .ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
}; };
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.main_path = mt8183_mtk_ddp_main,
.main_len = ARRAY_SIZE(mt8183_mtk_ddp_main),
.ext_path = mt8183_mtk_ddp_ext,
.ext_len = ARRAY_SIZE(mt8183_mtk_ddp_ext),
};
static int mtk_drm_kms_init(struct drm_device *drm) static int mtk_drm_kms_init(struct drm_device *drm)
{ {
struct mtk_drm_private *private = drm->dev_private; struct mtk_drm_private *private = drm->dev_private;
...@@ -377,12 +400,20 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { ...@@ -377,12 +400,20 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_OVL }, .data = (void *)MTK_DISP_OVL },
{ .compatible = "mediatek,mt8173-disp-ovl", { .compatible = "mediatek,mt8173-disp-ovl",
.data = (void *)MTK_DISP_OVL }, .data = (void *)MTK_DISP_OVL },
{ .compatible = "mediatek,mt8183-disp-ovl",
.data = (void *)MTK_DISP_OVL },
{ .compatible = "mediatek,mt8183-disp-ovl-2l",
.data = (void *)MTK_DISP_OVL_2L },
{ .compatible = "mediatek,mt2701-disp-rdma", { .compatible = "mediatek,mt2701-disp-rdma",
.data = (void *)MTK_DISP_RDMA }, .data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8173-disp-rdma", { .compatible = "mediatek,mt8173-disp-rdma",
.data = (void *)MTK_DISP_RDMA }, .data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8183-disp-rdma",
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8173-disp-wdma", { .compatible = "mediatek,mt8173-disp-wdma",
.data = (void *)MTK_DISP_WDMA }, .data = (void *)MTK_DISP_WDMA },
{ .compatible = "mediatek,mt8183-disp-ccorr",
.data = (void *)MTK_DISP_CCORR },
{ .compatible = "mediatek,mt2701-disp-color", { .compatible = "mediatek,mt2701-disp-color",
.data = (void *)MTK_DISP_COLOR }, .data = (void *)MTK_DISP_COLOR },
{ .compatible = "mediatek,mt8173-disp-color", { .compatible = "mediatek,mt8173-disp-color",
...@@ -391,22 +422,32 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { ...@@ -391,22 +422,32 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_AAL}, .data = (void *)MTK_DISP_AAL},
{ .compatible = "mediatek,mt8173-disp-gamma", { .compatible = "mediatek,mt8173-disp-gamma",
.data = (void *)MTK_DISP_GAMMA, }, .data = (void *)MTK_DISP_GAMMA, },
{ .compatible = "mediatek,mt8183-disp-gamma",
.data = (void *)MTK_DISP_GAMMA, },
{ .compatible = "mediatek,mt8183-disp-dither",
.data = (void *)MTK_DISP_DITHER },
{ .compatible = "mediatek,mt8173-disp-ufoe", { .compatible = "mediatek,mt8173-disp-ufoe",
.data = (void *)MTK_DISP_UFOE }, .data = (void *)MTK_DISP_UFOE },
{ .compatible = "mediatek,mt2701-dsi", { .compatible = "mediatek,mt2701-dsi",
.data = (void *)MTK_DSI }, .data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dsi", { .compatible = "mediatek,mt8173-dsi",
.data = (void *)MTK_DSI }, .data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8183-dsi",
.data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt2701-dpi", { .compatible = "mediatek,mt2701-dpi",
.data = (void *)MTK_DPI }, .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8173-dpi", { .compatible = "mediatek,mt8173-dpi",
.data = (void *)MTK_DPI }, .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8183-dpi",
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt2701-disp-mutex", { .compatible = "mediatek,mt2701-disp-mutex",
.data = (void *)MTK_DISP_MUTEX }, .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt2712-disp-mutex", { .compatible = "mediatek,mt2712-disp-mutex",
.data = (void *)MTK_DISP_MUTEX }, .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8173-disp-mutex", { .compatible = "mediatek,mt8173-disp-mutex",
.data = (void *)MTK_DISP_MUTEX }, .data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8183-disp-mutex",
.data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt2701-disp-pwm", { .compatible = "mediatek,mt2701-disp-pwm",
.data = (void *)MTK_DISP_BLS }, .data = (void *)MTK_DISP_BLS },
{ .compatible = "mediatek,mt8173-disp-pwm", { .compatible = "mediatek,mt8173-disp-pwm",
...@@ -425,6 +466,8 @@ static const struct of_device_id mtk_drm_of_ids[] = { ...@@ -425,6 +466,8 @@ static const struct of_device_id mtk_drm_of_ids[] = {
.data = &mt2712_mmsys_driver_data}, .data = &mt2712_mmsys_driver_data},
{ .compatible = "mediatek,mt8173-mmsys", { .compatible = "mediatek,mt8173-mmsys",
.data = &mt8173_mmsys_driver_data}, .data = &mt8173_mmsys_driver_data},
{ .compatible = "mediatek,mt8183-mmsys",
.data = &mt8183_mmsys_driver_data},
{ } { }
}; };
...@@ -488,11 +531,13 @@ static int mtk_drm_probe(struct platform_device *pdev) ...@@ -488,11 +531,13 @@ static int mtk_drm_probe(struct platform_device *pdev)
private->comp_node[comp_id] = of_node_get(node); private->comp_node[comp_id] = of_node_get(node);
/* /*
* Currently only the COLOR, OVL, RDMA, DSI, and DPI blocks have * Currently only the CCORR, COLOR, GAMMA, OVL, RDMA, DSI, and DPI
* separate component platform drivers and initialize their own * blocks have separate component platform drivers and initialize their own
* DDP component structure. The others are initialized here. * DDP component structure. The others are initialized here.
*/ */
if (comp_type == MTK_DISP_COLOR || if (comp_type == MTK_DISP_CCORR ||
comp_type == MTK_DISP_COLOR ||
comp_type == MTK_DISP_GAMMA ||
comp_type == MTK_DISP_OVL || comp_type == MTK_DISP_OVL ||
comp_type == MTK_DISP_OVL_2L || comp_type == MTK_DISP_OVL_2L ||
comp_type == MTK_DISP_RDMA || comp_type == MTK_DISP_RDMA ||
...@@ -502,25 +547,13 @@ static int mtk_drm_probe(struct platform_device *pdev) ...@@ -502,25 +547,13 @@ static int mtk_drm_probe(struct platform_device *pdev)
node); node);
drm_of_component_match_add(dev, &match, compare_of, drm_of_component_match_add(dev, &match, compare_of,
node); node);
} else {
struct mtk_ddp_comp *comp;
comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
if (!comp) {
ret = -ENOMEM;
of_node_put(node);
goto err_node;
} }
ret = mtk_ddp_comp_init(dev->parent, node, comp, ret = mtk_ddp_comp_init(node, &private->ddp_comp[comp_id], comp_id);
comp_id, NULL);
if (ret) { if (ret) {
of_node_put(node); of_node_put(node);
goto err_node; goto err_node;
} }
private->ddp_comp[comp_id] = comp;
}
} }
if (!private->mutex_node) { if (!private->mutex_node) {
...@@ -545,10 +578,8 @@ static int mtk_drm_probe(struct platform_device *pdev) ...@@ -545,10 +578,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
of_node_put(private->mutex_node); of_node_put(private->mutex_node);
for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) { for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) {
of_node_put(private->comp_node[i]); of_node_put(private->comp_node[i]);
if (private->ddp_comp[i]) { if (private->ddp_comp[i].larb_dev)
put_device(private->ddp_comp[i]->larb_dev); put_device(private->ddp_comp[i].larb_dev);
private->ddp_comp[i] = NULL;
}
} }
return ret; return ret;
} }
...@@ -604,8 +635,9 @@ static struct platform_driver mtk_drm_platform_driver = { ...@@ -604,8 +635,9 @@ static struct platform_driver mtk_drm_platform_driver = {
}; };
static struct platform_driver * const mtk_drm_drivers[] = { static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_ddp_driver, &mtk_disp_ccorr_driver,
&mtk_disp_color_driver, &mtk_disp_color_driver,
&mtk_disp_gamma_driver,
&mtk_disp_ovl_driver, &mtk_disp_ovl_driver,
&mtk_disp_rdma_driver, &mtk_disp_rdma_driver,
&mtk_dpi_driver, &mtk_dpi_driver,
......
...@@ -41,13 +41,14 @@ struct mtk_drm_private { ...@@ -41,13 +41,14 @@ struct mtk_drm_private {
struct device *mutex_dev; struct device *mutex_dev;
struct device *mmsys_dev; struct device *mmsys_dev;
struct device_node *comp_node[DDP_COMPONENT_ID_MAX]; struct device_node *comp_node[DDP_COMPONENT_ID_MAX];
struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX]; struct mtk_ddp_comp ddp_comp[DDP_COMPONENT_ID_MAX];
const struct mtk_mmsys_driver_data *data; const struct mtk_mmsys_driver_data *data;
struct drm_atomic_state *suspend_state; struct drm_atomic_state *suspend_state;
}; };
extern struct platform_driver mtk_ddp_driver; extern struct platform_driver mtk_disp_ccorr_driver;
extern struct platform_driver mtk_disp_color_driver; extern struct platform_driver mtk_disp_color_driver;
extern struct platform_driver mtk_disp_gamma_driver;
extern struct platform_driver mtk_disp_ovl_driver; extern struct platform_driver mtk_disp_ovl_driver;
extern struct platform_driver mtk_disp_rdma_driver; extern struct platform_driver mtk_disp_rdma_driver;
extern struct platform_driver mtk_dpi_driver; extern struct platform_driver mtk_dpi_driver;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h> #include <drm/drm_simple_kms_helper.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_ddp_comp.h" #include "mtk_drm_ddp_comp.h"
#define DSI_START 0x00 #define DSI_START 0x00
...@@ -178,7 +179,6 @@ struct mtk_dsi_driver_data { ...@@ -178,7 +179,6 @@ struct mtk_dsi_driver_data {
}; };
struct mtk_dsi { struct mtk_dsi {
struct mtk_ddp_comp ddp_comp;
struct device *dev; struct device *dev;
struct mipi_dsi_host host; struct mipi_dsi_host host;
struct drm_encoder encoder; struct drm_encoder encoder;
...@@ -767,25 +767,20 @@ static const struct drm_bridge_funcs mtk_dsi_bridge_funcs = { ...@@ -767,25 +767,20 @@ static const struct drm_bridge_funcs mtk_dsi_bridge_funcs = {
.mode_set = mtk_dsi_bridge_mode_set, .mode_set = mtk_dsi_bridge_mode_set,
}; };
static void mtk_dsi_ddp_start(struct mtk_ddp_comp *comp) void mtk_dsi_ddp_start(struct device *dev)
{ {
struct mtk_dsi *dsi = container_of(comp, struct mtk_dsi, ddp_comp); struct mtk_dsi *dsi = dev_get_drvdata(dev);
mtk_dsi_poweron(dsi); mtk_dsi_poweron(dsi);
} }
static void mtk_dsi_ddp_stop(struct mtk_ddp_comp *comp) void mtk_dsi_ddp_stop(struct device *dev)
{ {
struct mtk_dsi *dsi = container_of(comp, struct mtk_dsi, ddp_comp); struct mtk_dsi *dsi = dev_get_drvdata(dev);
mtk_dsi_poweroff(dsi); mtk_dsi_poweroff(dsi);
} }
static const struct mtk_ddp_comp_funcs mtk_dsi_funcs = {
.start = mtk_dsi_ddp_start,
.stop = mtk_dsi_ddp_stop,
};
static int mtk_dsi_host_attach(struct mipi_dsi_host *host, static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device) struct mipi_dsi_device *device)
{ {
...@@ -952,7 +947,7 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) ...@@ -952,7 +947,7 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
return ret; return ret;
} }
dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->ddp_comp); dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev);
ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
DRM_BRIDGE_ATTACH_NO_CONNECTOR); DRM_BRIDGE_ATTACH_NO_CONNECTOR);
...@@ -980,32 +975,17 @@ static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -980,32 +975,17 @@ static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm = data; struct drm_device *drm = data;
struct mtk_dsi *dsi = dev_get_drvdata(dev); struct mtk_dsi *dsi = dev_get_drvdata(dev);
ret = mtk_ddp_comp_register(drm, &dsi->ddp_comp);
if (ret < 0) {
dev_err(dev, "Failed to register component %pOF: %d\n",
dev->of_node, ret);
return ret;
}
ret = mtk_dsi_encoder_init(drm, dsi); ret = mtk_dsi_encoder_init(drm, dsi);
if (ret)
goto err_unregister;
return 0;
err_unregister:
mtk_ddp_comp_unregister(drm, &dsi->ddp_comp);
return ret; return ret;
} }
static void mtk_dsi_unbind(struct device *dev, struct device *master, static void mtk_dsi_unbind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct drm_device *drm = data;
struct mtk_dsi *dsi = dev_get_drvdata(dev); struct mtk_dsi *dsi = dev_get_drvdata(dev);
drm_encoder_cleanup(&dsi->encoder); drm_encoder_cleanup(&dsi->encoder);
mtk_ddp_comp_unregister(drm, &dsi->ddp_comp);
} }
static const struct component_ops mtk_dsi_component_ops = { static const struct component_ops mtk_dsi_component_ops = {
...@@ -1020,7 +1000,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) ...@@ -1020,7 +1000,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
struct drm_panel *panel; struct drm_panel *panel;
struct resource *regs; struct resource *regs;
int irq_num; int irq_num;
int comp_id;
int ret; int ret;
dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
...@@ -1090,20 +1069,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) ...@@ -1090,20 +1069,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
goto err_unregister_host; goto err_unregister_host;
} }
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DSI);
if (comp_id < 0) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
ret = comp_id;
goto err_unregister_host;
}
ret = mtk_ddp_comp_init(dev, dev->of_node, &dsi->ddp_comp, comp_id,
&mtk_dsi_funcs);
if (ret) {
dev_err(dev, "Failed to initialize component: %d\n", ret);
goto err_unregister_host;
}
irq_num = platform_get_irq(pdev, 0); irq_num = platform_get_irq(pdev, 0);
if (irq_num < 0) { if (irq_num < 0) {
dev_err(&pdev->dev, "failed to get dsi irq_num: %d\n", irq_num); dev_err(&pdev->dev, "failed to get dsi irq_num: %d\n", irq_num);
...@@ -1111,9 +1076,8 @@ static int mtk_dsi_probe(struct platform_device *pdev) ...@@ -1111,9 +1076,8 @@ static int mtk_dsi_probe(struct platform_device *pdev)
goto err_unregister_host; goto err_unregister_host;
} }
irq_set_status_flags(irq_num, IRQ_TYPE_LEVEL_LOW);
ret = devm_request_irq(&pdev->dev, irq_num, mtk_dsi_irq, ret = devm_request_irq(&pdev->dev, irq_num, mtk_dsi_irq,
IRQF_TRIGGER_LOW, dev_name(&pdev->dev), dsi); IRQF_TRIGGER_NONE, dev_name(&pdev->dev), dsi);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to request mediatek dsi irq\n"); dev_err(&pdev->dev, "failed to request mediatek dsi irq\n");
goto err_unregister_host; goto err_unregister_host;
......
...@@ -6,3 +6,4 @@ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o ...@@ -6,3 +6,4 @@ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
...@@ -9,12 +9,11 @@ ...@@ -9,12 +9,11 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
#include "mtk_drm_ddp.h" #define MT2701_MUTEX0_MOD0 0x2c
#include "mtk_drm_ddp_comp.h" #define MT2701_MUTEX0_SOF0 0x30
#define MT2701_DISP_MUTEX0_MOD0 0x2c
#define MT2701_DISP_MUTEX0_SOF0 0x30
#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) #define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) #define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
...@@ -79,33 +78,32 @@ ...@@ -79,33 +78,32 @@
#define MT2701_MUTEX_MOD_DISP_RDMA0 10 #define MT2701_MUTEX_MOD_DISP_RDMA0 10
#define MT2701_MUTEX_MOD_DISP_RDMA1 12 #define MT2701_MUTEX_MOD_DISP_RDMA1 12
#define MUTEX_SOF_SINGLE_MODE 0 #define MT2712_MUTEX_SOF_SINGLE_MODE 0
#define MUTEX_SOF_DSI0 1 #define MT2712_MUTEX_SOF_DSI0 1
#define MUTEX_SOF_DSI1 2 #define MT2712_MUTEX_SOF_DSI1 2
#define MUTEX_SOF_DPI0 3 #define MT2712_MUTEX_SOF_DPI0 3
#define MUTEX_SOF_DPI1 4 #define MT2712_MUTEX_SOF_DPI1 4
#define MUTEX_SOF_DSI2 5 #define MT2712_MUTEX_SOF_DSI2 5
#define MUTEX_SOF_DSI3 6 #define MT2712_MUTEX_SOF_DSI3 6
#define MT8167_MUTEX_SOF_DPI0 2 #define MT8167_MUTEX_SOF_DPI0 2
#define MT8167_MUTEX_SOF_DPI1 3 #define MT8167_MUTEX_SOF_DPI1 3
struct mtk_mutex {
struct mtk_disp_mutex {
int id; int id;
bool claimed; bool claimed;
}; };
enum mtk_ddp_mutex_sof_id { enum mtk_mutex_sof_id {
DDP_MUTEX_SOF_SINGLE_MODE, MUTEX_SOF_SINGLE_MODE,
DDP_MUTEX_SOF_DSI0, MUTEX_SOF_DSI0,
DDP_MUTEX_SOF_DSI1, MUTEX_SOF_DSI1,
DDP_MUTEX_SOF_DPI0, MUTEX_SOF_DPI0,
DDP_MUTEX_SOF_DPI1, MUTEX_SOF_DPI1,
DDP_MUTEX_SOF_DSI2, MUTEX_SOF_DSI2,
DDP_MUTEX_SOF_DSI3, MUTEX_SOF_DSI3,
}; };
struct mtk_ddp_data { struct mtk_mutex_data {
const unsigned int *mutex_mod; const unsigned int *mutex_mod;
const unsigned int *mutex_sof; const unsigned int *mutex_sof;
const unsigned int mutex_mod_reg; const unsigned int mutex_mod_reg;
...@@ -113,12 +111,12 @@ struct mtk_ddp_data { ...@@ -113,12 +111,12 @@ struct mtk_ddp_data {
const bool no_clk; const bool no_clk;
}; };
struct mtk_ddp { struct mtk_mutex_ctx {
struct device *dev; struct device *dev;
struct clk *clk; struct clk *clk;
void __iomem *regs; void __iomem *regs;
struct mtk_disp_mutex mutex[10]; struct mtk_mutex mutex[10];
const struct mtk_ddp_data *data; const struct mtk_mutex_data *data;
}; };
static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
...@@ -183,150 +181,155 @@ static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { ...@@ -183,150 +181,155 @@ static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1, [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
}; };
static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_DSI3 + 1] = { static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
[DDP_MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[DDP_MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[DDP_MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1, [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
[DDP_MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0, [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0,
[DDP_MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1, [MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1,
[DDP_MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2, [MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2,
[DDP_MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3, [MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3,
}; };
static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_DSI3 + 1] = { static const unsigned int mt8167_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
[DDP_MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE, [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[DDP_MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0, [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[DDP_MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0, [MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0,
[DDP_MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1, [MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1,
}; };
static const struct mtk_ddp_data mt2701_ddp_driver_data = { static const struct mtk_mutex_data mt2701_mutex_driver_data = {
.mutex_mod = mt2701_mutex_mod, .mutex_mod = mt2701_mutex_mod,
.mutex_sof = mt2712_mutex_sof, .mutex_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0, .mutex_mod_reg = MT2701_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0, .mutex_sof_reg = MT2701_MUTEX0_SOF0,
}; };
static const struct mtk_ddp_data mt2712_ddp_driver_data = { static const struct mtk_mutex_data mt2712_mutex_driver_data = {
.mutex_mod = mt2712_mutex_mod, .mutex_mod = mt2712_mutex_mod,
.mutex_sof = mt2712_mutex_sof, .mutex_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0, .mutex_mod_reg = MT2701_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0, .mutex_sof_reg = MT2701_MUTEX0_SOF0,
}; };
static const struct mtk_ddp_data mt8167_ddp_driver_data = { static const struct mtk_mutex_data mt8167_mutex_driver_data = {
.mutex_mod = mt8167_mutex_mod, .mutex_mod = mt8167_mutex_mod,
.mutex_sof = mt8167_mutex_sof, .mutex_sof = mt8167_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0, .mutex_mod_reg = MT2701_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0, .mutex_sof_reg = MT2701_MUTEX0_SOF0,
.no_clk = true, .no_clk = true,
}; };
static const struct mtk_ddp_data mt8173_ddp_driver_data = { static const struct mtk_mutex_data mt8173_mutex_driver_data = {
.mutex_mod = mt8173_mutex_mod, .mutex_mod = mt8173_mutex_mod,
.mutex_sof = mt2712_mutex_sof, .mutex_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0, .mutex_mod_reg = MT2701_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0, .mutex_sof_reg = MT2701_MUTEX0_SOF0,
}; };
struct mtk_disp_mutex *mtk_disp_mutex_get(struct device *dev, unsigned int id) struct mtk_mutex *mtk_mutex_get(struct device *dev)
{ {
struct mtk_ddp *ddp = dev_get_drvdata(dev); struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
int i;
if (id >= 10)
return ERR_PTR(-EINVAL);
if (ddp->mutex[id].claimed)
return ERR_PTR(-EBUSY);
ddp->mutex[id].claimed = true; for (i = 0; i < 10; i++)
if (!mtx->mutex[i].claimed) {
mtx->mutex[i].claimed = true;
return &mtx->mutex[i];
}
return &ddp->mutex[id]; return ERR_PTR(-EBUSY);
} }
EXPORT_SYMBOL_GPL(mtk_mutex_get);
void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex) void mtk_mutex_put(struct mtk_mutex *mutex)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
WARN_ON(&ddp->mutex[mutex->id] != mutex); WARN_ON(&mtx->mutex[mutex->id] != mutex);
mutex->claimed = false; mutex->claimed = false;
} }
EXPORT_SYMBOL_GPL(mtk_mutex_put);
int mtk_disp_mutex_prepare(struct mtk_disp_mutex *mutex) int mtk_mutex_prepare(struct mtk_mutex *mutex)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
return clk_prepare_enable(ddp->clk); return clk_prepare_enable(mtx->clk);
} }
EXPORT_SYMBOL_GPL(mtk_mutex_prepare);
void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex) void mtk_mutex_unprepare(struct mtk_mutex *mutex)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
clk_disable_unprepare(ddp->clk); clk_disable_unprepare(mtx->clk);
} }
EXPORT_SYMBOL_GPL(mtk_mutex_unprepare);
void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, void mtk_mutex_add_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id) enum mtk_ddp_comp_id id)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
unsigned int reg; unsigned int reg;
unsigned int sof_id; unsigned int sof_id;
unsigned int offset; unsigned int offset;
WARN_ON(&ddp->mutex[mutex->id] != mutex); WARN_ON(&mtx->mutex[mutex->id] != mutex);
switch (id) { switch (id) {
case DDP_COMPONENT_DSI0: case DDP_COMPONENT_DSI0:
sof_id = DDP_MUTEX_SOF_DSI0; sof_id = MUTEX_SOF_DSI0;
break; break;
case DDP_COMPONENT_DSI1: case DDP_COMPONENT_DSI1:
sof_id = DDP_MUTEX_SOF_DSI0; sof_id = MUTEX_SOF_DSI0;
break; break;
case DDP_COMPONENT_DSI2: case DDP_COMPONENT_DSI2:
sof_id = DDP_MUTEX_SOF_DSI2; sof_id = MUTEX_SOF_DSI2;
break; break;
case DDP_COMPONENT_DSI3: case DDP_COMPONENT_DSI3:
sof_id = DDP_MUTEX_SOF_DSI3; sof_id = MUTEX_SOF_DSI3;
break; break;
case DDP_COMPONENT_DPI0: case DDP_COMPONENT_DPI0:
sof_id = DDP_MUTEX_SOF_DPI0; sof_id = MUTEX_SOF_DPI0;
break; break;
case DDP_COMPONENT_DPI1: case DDP_COMPONENT_DPI1:
sof_id = DDP_MUTEX_SOF_DPI1; sof_id = MUTEX_SOF_DPI1;
break; break;
default: default:
if (ddp->data->mutex_mod[id] < 32) { if (mtx->data->mutex_mod[id] < 32) {
offset = DISP_REG_MUTEX_MOD(ddp->data->mutex_mod_reg, offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
mutex->id); mutex->id);
reg = readl_relaxed(ddp->regs + offset); reg = readl_relaxed(mtx->regs + offset);
reg |= 1 << ddp->data->mutex_mod[id]; reg |= 1 << mtx->data->mutex_mod[id];
writel_relaxed(reg, ddp->regs + offset); writel_relaxed(reg, mtx->regs + offset);
} else { } else {
offset = DISP_REG_MUTEX_MOD2(mutex->id); offset = DISP_REG_MUTEX_MOD2(mutex->id);
reg = readl_relaxed(ddp->regs + offset); reg = readl_relaxed(mtx->regs + offset);
reg |= 1 << (ddp->data->mutex_mod[id] - 32); reg |= 1 << (mtx->data->mutex_mod[id] - 32);
writel_relaxed(reg, ddp->regs + offset); writel_relaxed(reg, mtx->regs + offset);
} }
return; return;
} }
writel_relaxed(ddp->data->mutex_sof[sof_id], writel_relaxed(mtx->data->mutex_sof[sof_id],
ddp->regs + mtx->regs +
DISP_REG_MUTEX_SOF(ddp->data->mutex_sof_reg, mutex->id)); DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id));
} }
EXPORT_SYMBOL_GPL(mtk_mutex_add_comp);
void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id) enum mtk_ddp_comp_id id)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
unsigned int reg; unsigned int reg;
unsigned int offset; unsigned int offset;
WARN_ON(&ddp->mutex[mutex->id] != mutex); WARN_ON(&mtx->mutex[mutex->id] != mutex);
switch (id) { switch (id) {
case DDP_COMPONENT_DSI0: case DDP_COMPONENT_DSI0:
...@@ -336,129 +339,136 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, ...@@ -336,129 +339,136 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
case DDP_COMPONENT_DPI0: case DDP_COMPONENT_DPI0:
case DDP_COMPONENT_DPI1: case DDP_COMPONENT_DPI1:
writel_relaxed(MUTEX_SOF_SINGLE_MODE, writel_relaxed(MUTEX_SOF_SINGLE_MODE,
ddp->regs + mtx->regs +
DISP_REG_MUTEX_SOF(ddp->data->mutex_sof_reg, DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg,
mutex->id)); mutex->id));
break; break;
default: default:
if (ddp->data->mutex_mod[id] < 32) { if (mtx->data->mutex_mod[id] < 32) {
offset = DISP_REG_MUTEX_MOD(ddp->data->mutex_mod_reg, offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
mutex->id); mutex->id);
reg = readl_relaxed(ddp->regs + offset); reg = readl_relaxed(mtx->regs + offset);
reg &= ~(1 << ddp->data->mutex_mod[id]); reg &= ~(1 << mtx->data->mutex_mod[id]);
writel_relaxed(reg, ddp->regs + offset); writel_relaxed(reg, mtx->regs + offset);
} else { } else {
offset = DISP_REG_MUTEX_MOD2(mutex->id); offset = DISP_REG_MUTEX_MOD2(mutex->id);
reg = readl_relaxed(ddp->regs + offset); reg = readl_relaxed(mtx->regs + offset);
reg &= ~(1 << (ddp->data->mutex_mod[id] - 32)); reg &= ~(1 << (mtx->data->mutex_mod[id] - 32));
writel_relaxed(reg, ddp->regs + offset); writel_relaxed(reg, mtx->regs + offset);
} }
break; break;
} }
} }
EXPORT_SYMBOL_GPL(mtk_mutex_remove_comp);
void mtk_disp_mutex_enable(struct mtk_disp_mutex *mutex) void mtk_mutex_enable(struct mtk_mutex *mutex)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
WARN_ON(&ddp->mutex[mutex->id] != mutex); WARN_ON(&mtx->mutex[mutex->id] != mutex);
writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
} }
EXPORT_SYMBOL_GPL(mtk_mutex_enable);
void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex) void mtk_mutex_disable(struct mtk_mutex *mutex)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
WARN_ON(&ddp->mutex[mutex->id] != mutex); WARN_ON(&mtx->mutex[mutex->id] != mutex);
writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); writel(0, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
} }
EXPORT_SYMBOL_GPL(mtk_mutex_disable);
void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex) void mtk_mutex_acquire(struct mtk_mutex *mutex)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
u32 tmp; u32 tmp;
writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id)); writel(1, mtx->regs + DISP_REG_MUTEX(mutex->id));
if (readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id), if (readl_poll_timeout_atomic(mtx->regs + DISP_REG_MUTEX(mutex->id),
tmp, tmp & INT_MUTEX, 1, 10000)) tmp, tmp & INT_MUTEX, 1, 10000))
pr_err("could not acquire mutex %d\n", mutex->id); pr_err("could not acquire mutex %d\n", mutex->id);
} }
EXPORT_SYMBOL_GPL(mtk_mutex_acquire);
void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex) void mtk_mutex_release(struct mtk_mutex *mutex)
{ {
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]); mutex[mutex->id]);
writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id)); writel(0, mtx->regs + DISP_REG_MUTEX(mutex->id));
} }
EXPORT_SYMBOL_GPL(mtk_mutex_release);
static int mtk_ddp_probe(struct platform_device *pdev) static int mtk_mutex_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct mtk_ddp *ddp; struct mtk_mutex_ctx *mtx;
struct resource *regs; struct resource *regs;
int i; int i;
ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL); mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
if (!ddp) if (!mtx)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++)
ddp->mutex[i].id = i; mtx->mutex[i].id = i;
ddp->data = of_device_get_match_data(dev); mtx->data = of_device_get_match_data(dev);
if (!ddp->data->no_clk) { if (!mtx->data->no_clk) {
ddp->clk = devm_clk_get(dev, NULL); mtx->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ddp->clk)) { if (IS_ERR(mtx->clk)) {
if (PTR_ERR(ddp->clk) != -EPROBE_DEFER) if (PTR_ERR(mtx->clk) != -EPROBE_DEFER)
dev_err(dev, "Failed to get clock\n"); dev_err(dev, "Failed to get clock\n");
return PTR_ERR(ddp->clk); return PTR_ERR(mtx->clk);
} }
} }
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ddp->regs = devm_ioremap_resource(dev, regs); mtx->regs = devm_ioremap_resource(dev, regs);
if (IS_ERR(ddp->regs)) { if (IS_ERR(mtx->regs)) {
dev_err(dev, "Failed to map mutex registers\n"); dev_err(dev, "Failed to map mutex registers\n");
return PTR_ERR(ddp->regs); return PTR_ERR(mtx->regs);
} }
platform_set_drvdata(pdev, ddp); platform_set_drvdata(pdev, mtx);
return 0; return 0;
} }
static int mtk_ddp_remove(struct platform_device *pdev) static int mtk_mutex_remove(struct platform_device *pdev)
{ {
return 0; return 0;
} }
static const struct of_device_id ddp_driver_dt_match[] = { static const struct of_device_id mutex_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-mutex", { .compatible = "mediatek,mt2701-disp-mutex",
.data = &mt2701_ddp_driver_data}, .data = &mt2701_mutex_driver_data},
{ .compatible = "mediatek,mt2712-disp-mutex", { .compatible = "mediatek,mt2712-disp-mutex",
.data = &mt2712_ddp_driver_data}, .data = &mt2712_mutex_driver_data},
{ .compatible = "mediatek,mt8167-disp-mutex", { .compatible = "mediatek,mt8167-disp-mutex",
.data = &mt8167_ddp_driver_data}, .data = &mt8167_mutex_driver_data},
{ .compatible = "mediatek,mt8173-disp-mutex", { .compatible = "mediatek,mt8173-disp-mutex",
.data = &mt8173_ddp_driver_data}, .data = &mt8173_mutex_driver_data},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, ddp_driver_dt_match); MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
struct platform_driver mtk_ddp_driver = { struct platform_driver mtk_mutex_driver = {
.probe = mtk_ddp_probe, .probe = mtk_mutex_probe,
.remove = mtk_ddp_remove, .remove = mtk_mutex_remove,
.driver = { .driver = {
.name = "mediatek-ddp", .name = "mediatek-mutex",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = ddp_driver_dt_match, .of_match_table = mutex_driver_dt_match,
}, },
}; };
builtin_platform_driver(mtk_mutex_driver);
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015 MediaTek Inc.
*/
#ifndef MTK_MUTEX_H
#define MTK_MUTEX_H
struct regmap;
struct device;
struct mtk_mutex;
struct mtk_mutex *mtk_mutex_get(struct device *dev);
int mtk_mutex_prepare(struct mtk_mutex *mutex);
void mtk_mutex_add_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id);
void mtk_mutex_enable(struct mtk_mutex *mutex);
void mtk_mutex_disable(struct mtk_mutex *mutex);
void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id);
void mtk_mutex_unprepare(struct mtk_mutex *mutex);
void mtk_mutex_put(struct mtk_mutex *mutex);
void mtk_mutex_acquire(struct mtk_mutex *mutex);
void mtk_mutex_release(struct mtk_mutex *mutex);
#endif /* MTK_MUTEX_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment