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):
"mediatek,<chip>-disp-aal" - adaptive ambient light controller
"mediatek,<chip>-disp-gamma" - gamma correction
"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-ufoe" - data compression engine
"mediatek,<chip>-dsi" - DSI controller, see mediatek,dsi.txt
"mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt
"mediatek,<chip>-disp-mutex" - display mutex
"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
- interrupts: The interrupt signal from the function block (required, except for
merge and split function blocks).
......@@ -66,6 +67,14 @@ Required properties (DMA function blocks):
argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
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:
mmsys: clock-controller@14000000 {
......@@ -103,6 +112,7 @@ rdma0: rdma@1400e000 {
clocks = <&mmsys CLK_MM_DISP_RDMA0>;
iommus = <&iommu M4U_PORT_DISP_RDMA0>;
mediatek,larb = <&larb0>;
mediatek,rdma-fifosize = <8192>;
};
rdma1: rdma@1400f000 {
......
# 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_rdma.o \
mtk_drm_crtc.o \
mtk_drm_ddp.o \
mtk_drm_ddp_comp.o \
mtk_drm_drv.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 @@
#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"
......@@ -36,64 +37,55 @@ struct mtk_disp_color_data {
* @data: platform colour driver data
*/
struct mtk_disp_color {
struct mtk_ddp_comp ddp_comp;
struct drm_crtc *crtc;
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_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);
}
static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
void mtk_color_clk_disable(struct device *dev)
{
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, h, comp, DISP_COLOR_HEIGHT(color));
clk_disable_unprepare(color->clk);
}
static void mtk_color_start(struct mtk_ddp_comp *comp)
void mtk_color_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
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);
writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
comp->regs + DISP_COLOR_CFG_MAIN);
writel(0x1, comp->regs + DISP_COLOR_START(color));
mtk_ddp_write(cmdq_pkt, w, &color->cmdq_reg, color->regs, DISP_COLOR_WIDTH(color));
mtk_ddp_write(cmdq_pkt, h, &color->cmdq_reg, color->regs, DISP_COLOR_HEIGHT(color));
}
static const struct mtk_ddp_comp_funcs mtk_disp_color_funcs = {
.config = mtk_color_config,
.start = mtk_color_start,
};
void mtk_color_start(struct device *dev)
{
struct mtk_disp_color *color = dev_get_drvdata(dev);
writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
color->regs + DISP_COLOR_CFG_MAIN);
writel(0x1, color->regs + DISP_COLOR_START(color));
}
static int mtk_disp_color_bind(struct device *dev, struct device *master,
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;
}
static void mtk_disp_color_unbind(struct device *dev, struct device *master,
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 = {
......@@ -105,31 +97,32 @@ static int mtk_disp_color_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_color *priv;
int comp_id;
struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_COLOR);
if (comp_id < 0) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
return comp_id;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get color clk\n");
return PTR_ERR(priv->clk);
}
ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
&mtk_disp_color_funcs);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to initialize component: %d\n",
ret);
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap color\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_color_component_ops);
......@@ -141,8 +134,6 @@ static int mtk_disp_color_probe(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;
}
......
/* 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 @@
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
......@@ -23,6 +24,7 @@
#define DISP_REG_OVL_RST 0x0014
#define DISP_REG_OVL_ROI_SIZE 0x0020
#define DISP_REG_OVL_DATAPATH_CON 0x0024
#define OVL_LAYER_SMI_ID_EN BIT(0)
#define OVL_BGCLR_SEL_IN BIT(2)
#define DISP_REG_OVL_ROI_BGCLR 0x0028
#define DISP_REG_OVL_SRC_CON 0x002c
......@@ -61,6 +63,7 @@ struct mtk_disp_ovl_data {
unsigned int gmc_bits;
unsigned int layer_nr;
bool fmt_rgb565_is_0;
bool smi_id_en;
};
/**
......@@ -70,88 +73,124 @@ struct mtk_disp_ovl_data {
* @data: platform data
*/
struct mtk_disp_ovl {
struct mtk_ddp_comp ddp_comp;
struct drm_crtc *crtc;
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_ovl_data *data;
void (*vblank_cb)(void *data);
void *vblank_cb_data;
};
static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp)
{
return container_of(comp, struct mtk_disp_ovl, ddp_comp);
}
static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
{
struct mtk_disp_ovl *priv = dev_id;
struct mtk_ddp_comp *ovl = &priv->ddp_comp;
/* Clear frame completion interrupt */
writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
writel(0x0, priv->regs + DISP_REG_OVL_INTSTA);
if (!priv->crtc)
if (!priv->vblank_cb)
return IRQ_NONE;
mtk_crtc_ddp_irq(priv->crtc, ovl);
priv->vblank_cb(priv->vblank_cb_data);
return IRQ_HANDLED;
}
static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp,
struct drm_crtc *crtc)
void mtk_ovl_enable_vblank(struct device *dev,
void (*vblank_cb)(void *),
void *vblank_cb_data)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
ovl->vblank_cb = vblank_cb;
ovl->vblank_cb_data = vblank_cb_data;
writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN);
}
void mtk_ovl_disable_vblank(struct device *dev)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
ovl->vblank_cb = NULL;
ovl->vblank_cb_data = NULL;
writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
}
int mtk_ovl_clk_enable(struct device *dev)
{
struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
ovl->crtc = crtc;
writel(0x0, comp->regs + DISP_REG_OVL_INTSTA);
writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN);
return clk_prepare_enable(ovl->clk);
}
static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp)
void mtk_ovl_clk_disable(struct device *dev)
{
struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
ovl->crtc = NULL;
writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN);
clk_disable_unprepare(ovl->clk);
}
static void mtk_ovl_start(struct mtk_ddp_comp *comp)
void mtk_ovl_start(struct device *dev)
{
writel_relaxed(0x1, comp->regs + DISP_REG_OVL_EN);
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
if (ovl->data->smi_id_en) {
unsigned int reg;
reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
reg = reg | OVL_LAYER_SMI_ID_EN;
writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
}
writel_relaxed(0x1, ovl->regs + DISP_REG_OVL_EN);
}
static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
void mtk_ovl_stop(struct device *dev)
{
writel_relaxed(0x0, comp->regs + DISP_REG_OVL_EN);
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_EN);
if (ovl->data->smi_id_en) {
unsigned int reg;
reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
reg = reg & ~OVL_LAYER_SMI_ID_EN;
writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
}
}
static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
void mtk_ovl_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
if (w != 0 && h != 0)
mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, comp,
mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_ROI_SIZE);
mtk_ddp_write_relaxed(cmdq_pkt, 0x0, comp, DISP_REG_OVL_ROI_BGCLR);
mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR);
mtk_ddp_write(cmdq_pkt, 0x1, comp, DISP_REG_OVL_RST);
mtk_ddp_write(cmdq_pkt, 0x0, comp, DISP_REG_OVL_RST);
mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
}
static unsigned int mtk_ovl_layer_nr(struct mtk_ddp_comp *comp)
unsigned int mtk_ovl_layer_nr(struct device *dev)
{
struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
return ovl->data->layer_nr;
}
static unsigned int mtk_ovl_supported_rotations(struct mtk_ddp_comp *comp)
unsigned int mtk_ovl_supported_rotations(struct device *dev)
{
return DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
}
static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx,
struct mtk_plane_state *mtk_state)
int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
struct mtk_plane_state *mtk_state)
{
struct drm_plane_state *state = &mtk_state->base;
unsigned int rotation = 0;
......@@ -178,15 +217,15 @@ static int mtk_ovl_layer_check(struct mtk_ddp_comp *comp, unsigned int idx,
return 0;
}
static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx,
struct cmdq_pkt *cmdq_pkt)
void mtk_ovl_layer_on(struct device *dev, unsigned int idx,
struct cmdq_pkt *cmdq_pkt)
{
unsigned int gmc_thrshd_l;
unsigned int gmc_thrshd_h;
unsigned int gmc_value;
struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, 0x1, comp,
mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_RDMA_CTRL(idx));
gmc_thrshd_l = GMC_THRESHOLD_LOW >>
(GMC_THRESHOLD_BITS - ovl->data->gmc_bits);
......@@ -198,17 +237,19 @@ static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx,
gmc_value = gmc_thrshd_l | gmc_thrshd_l << 8 |
gmc_thrshd_h << 16 | gmc_thrshd_h << 24;
mtk_ddp_write(cmdq_pkt, gmc_value,
comp, DISP_REG_OVL_RDMA_GMC(idx));
mtk_ddp_write_mask(cmdq_pkt, BIT(idx), comp,
&ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_GMC(idx));
mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_SRC_CON, BIT(idx));
}
static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx,
struct cmdq_pkt *cmdq_pkt)
void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
struct cmdq_pkt *cmdq_pkt)
{
mtk_ddp_write_mask(cmdq_pkt, 0, comp,
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_SRC_CON, BIT(idx));
mtk_ddp_write(cmdq_pkt, 0, comp,
mtk_ddp_write(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_RDMA_CTRL(idx));
}
......@@ -248,11 +289,11 @@ static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
}
}
static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt)
void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt)
{
struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
struct mtk_plane_pending_state *pending = &state->pending;
unsigned int addr = pending->addr;
unsigned int pitch = pending->pitch & 0xffff;
......@@ -262,12 +303,12 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
unsigned int con;
if (!pending->enable) {
mtk_ovl_layer_off(comp, idx, cmdq_pkt);
mtk_ovl_layer_off(dev, idx, cmdq_pkt);
return;
}
con = ovl_fmt_convert(ovl, fmt);
if (state->base.fb->format->has_alpha)
if (state->base.fb && state->base.fb->format->has_alpha)
con |= OVL_CON_AEN | OVL_CON_ALPHA;
if (pending->rotation & DRM_MODE_REFLECT_Y) {
......@@ -280,76 +321,49 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
addr += pending->pitch - 1;
}
mtk_ddp_write_relaxed(cmdq_pkt, con, comp,
mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_CON(idx));
mtk_ddp_write_relaxed(cmdq_pkt, pitch, comp,
mtk_ddp_write_relaxed(cmdq_pkt, pitch, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_PITCH(idx));
mtk_ddp_write_relaxed(cmdq_pkt, src_size, comp,
mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_SRC_SIZE(idx));
mtk_ddp_write_relaxed(cmdq_pkt, offset, comp,
mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_OFFSET(idx));
mtk_ddp_write_relaxed(cmdq_pkt, addr, comp,
mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_ADDR(ovl, idx));
mtk_ovl_layer_on(comp, idx, cmdq_pkt);
mtk_ovl_layer_on(dev, idx, cmdq_pkt);
}
static void mtk_ovl_bgclr_in_on(struct mtk_ddp_comp *comp)
void mtk_ovl_bgclr_in_on(struct device *dev)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
unsigned int reg;
reg = readl(comp->regs + DISP_REG_OVL_DATAPATH_CON);
reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
reg = reg | OVL_BGCLR_SEL_IN;
writel(reg, comp->regs + DISP_REG_OVL_DATAPATH_CON);
writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
}
static void mtk_ovl_bgclr_in_off(struct mtk_ddp_comp *comp)
void mtk_ovl_bgclr_in_off(struct device *dev)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
unsigned int reg;
reg = readl(comp->regs + DISP_REG_OVL_DATAPATH_CON);
reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
reg = reg & ~OVL_BGCLR_SEL_IN;
writel(reg, comp->regs + DISP_REG_OVL_DATAPATH_CON);
writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
}
static const struct mtk_ddp_comp_funcs mtk_disp_ovl_funcs = {
.config = mtk_ovl_config,
.start = mtk_ovl_start,
.stop = mtk_ovl_stop,
.enable_vblank = mtk_ovl_enable_vblank,
.disable_vblank = mtk_ovl_disable_vblank,
.supported_rotations = mtk_ovl_supported_rotations,
.layer_nr = mtk_ovl_layer_nr,
.layer_check = mtk_ovl_layer_check,
.layer_config = mtk_ovl_layer_config,
.bgclr_in_on = mtk_ovl_bgclr_in_on,
.bgclr_in_off = mtk_ovl_bgclr_in_off,
};
static int mtk_disp_ovl_bind(struct device *dev, struct device *master,
void *data)
{
struct mtk_disp_ovl *priv = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
int ret;
ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
if (ret < 0) {
dev_err(dev, "Failed to register component %pOF: %d\n",
dev->of_node, ret);
return ret;
}
return 0;
}
static void mtk_disp_ovl_unbind(struct device *dev, struct device *master,
void *data)
{
struct mtk_disp_ovl *priv = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
}
static const struct component_ops mtk_disp_ovl_component_ops = {
......@@ -361,7 +375,7 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_ovl *priv;
int comp_id;
struct resource *res;
int irq;
int ret;
......@@ -373,27 +387,25 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
priv->data = of_device_get_match_data(dev);
comp_id = mtk_ddp_comp_get_id(dev->of_node,
priv->data->layer_nr == 4 ?
MTK_DISP_OVL :
MTK_DISP_OVL_2L);
if (comp_id < 0) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
return comp_id;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get ovl clk\n");
return PTR_ERR(priv->clk);
}
ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
&mtk_disp_ovl_funcs);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to initialize component: %d\n",
ret);
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap ovl\n");
return PTR_ERR(priv->regs);
}
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
#endif
priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv);
ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
......@@ -412,8 +424,6 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
static int mtk_disp_ovl_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &mtk_disp_ovl_component_ops);
return 0;
}
......@@ -431,11 +441,29 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
.fmt_rgb565_is_0 = true,
};
static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
.addr = DISP_REG_OVL_ADDR_MT8173,
.gmc_bits = 10,
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
};
static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
.addr = DISP_REG_OVL_ADDR_MT8173,
.gmc_bits = 10,
.layer_nr = 2,
.fmt_rgb565_is_0 = true,
};
static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-ovl",
.data = &mt2701_ovl_driver_data},
{ .compatible = "mediatek,mt8173-disp-ovl",
.data = &mt8173_ovl_driver_data},
{ .compatible = "mediatek,mt8183-disp-ovl",
.data = &mt8183_ovl_driver_data},
{ .compatible = "mediatek,mt8183-disp-ovl-2l",
.data = &mt8183_ovl_2l_driver_data},
{},
};
MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
......
......@@ -11,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
......@@ -61,83 +62,105 @@ struct mtk_disp_rdma_data {
* @data: local driver data
*/
struct mtk_disp_rdma {
struct mtk_ddp_comp ddp_comp;
struct drm_crtc *crtc;
struct clk *clk;
void __iomem *regs;
struct cmdq_client_reg cmdq_reg;
const struct mtk_disp_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)
{
struct mtk_disp_rdma *priv = dev_id;
struct mtk_ddp_comp *rdma = &priv->ddp_comp;
/* 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;
mtk_crtc_ddp_irq(priv->crtc, rdma);
priv->vblank_cb(priv->vblank_cb_data);
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 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);
writel(tmp, comp->regs + reg);
writel(tmp, rdma->regs + reg);
}
static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp,
struct drm_crtc *crtc)
void mtk_rdma_enable_vblank(struct device *dev,
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_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
rdma->vblank_cb = vblank_cb;
rdma->vblank_cb_data = vblank_cb_data;
rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, 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;
rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
return clk_prepare_enable(rdma->clk);
}
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);
}
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,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
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 threshold;
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);
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);
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.
* 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,
*/
threshold = width * height * vrefresh * 4 * 7 / 1000000;
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);
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,
......@@ -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;
}
static void mtk_rdma_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt)
void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
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;
unsigned int addr = pending->addr;
unsigned int pitch = pending->pitch & 0xffff;
......@@ -205,53 +228,34 @@ static void mtk_rdma_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
unsigned int con;
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) {
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,
RDMA_MATRIX_ENABLE);
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);
} 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,
RDMA_MATRIX_ENABLE);
}
mtk_ddp_write_relaxed(cmdq_pkt, addr, comp, DISP_RDMA_MEM_START_ADDR);
mtk_ddp_write_relaxed(cmdq_pkt, pitch, comp, DISP_RDMA_MEM_SRC_PITCH);
mtk_ddp_write(cmdq_pkt, RDMA_MEM_GMC, comp,
mtk_ddp_write_relaxed(cmdq_pkt, addr, &rdma->cmdq_reg, rdma->regs,
DISP_RDMA_MEM_START_ADDR);
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);
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);
}
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,
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;
}
......@@ -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,
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 = {
......@@ -274,7 +274,7 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_rdma *priv;
int comp_id;
struct resource *res;
int irq;
int ret;
......@@ -286,25 +286,37 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_RDMA);
if (comp_id < 0) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
return comp_id;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get rdma clk\n");
return PTR_ERR(priv->clk);
}
ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
&mtk_disp_rdma_funcs);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to initialize component: %d\n",
ret);
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap rdma\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
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;
}
}
/* Disable and clear pending interrupts */
writel(0x0, priv->ddp_comp.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_ENABLE);
writel(0x0, priv->regs + DISP_REG_RDMA_INT_STATUS);
ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler,
IRQF_TRIGGER_NONE, dev_name(dev), priv);
......@@ -339,11 +351,17 @@ static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = {
.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[] = {
{ .compatible = "mediatek,mt2701-disp-rdma",
.data = &mt2701_rdma_driver_data},
{ .compatible = "mediatek,mt8173-disp-rdma",
.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);
......
......@@ -20,10 +20,12 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_of.h>
#include <drm/drm_simple_kms_helper.h>
#include "mtk_disp_drv.h"
#include "mtk_dpi_regs.h"
#include "mtk_drm_ddp_comp.h"
......@@ -62,10 +64,10 @@ enum mtk_dpi_out_color_format {
};
struct mtk_dpi {
struct mtk_ddp_comp ddp_comp;
struct drm_encoder encoder;
struct drm_bridge bridge;
struct drm_bridge *next_bridge;
struct drm_connector *connector;
void __iomem *regs;
struct device *dev;
struct clk *engine_clk;
......@@ -562,53 +564,50 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = {
.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);
}
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);
}
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)
{
struct mtk_dpi *dpi = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
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,
DRM_MODE_ENCODER_TMDS);
if (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) {
dev_err(dev, "Failed to attach bridge: %d\n", ret);
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->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_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)
err_cleanup:
drm_encoder_cleanup(&dpi->encoder);
err_unregister:
mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp);
return ret;
}
......@@ -627,10 +624,8 @@ static void mtk_dpi_unbind(struct device *dev, struct device *master,
void *data)
{
struct mtk_dpi *dpi = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
drm_encoder_cleanup(&dpi->encoder);
mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp);
}
static const struct component_ops mtk_dpi_component_ops = {
......@@ -691,7 +686,6 @@ static int mtk_dpi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mtk_dpi *dpi;
struct resource *mem;
int comp_id;
int ret;
dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL);
......@@ -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);
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);
dpi->bridge.funcs = &mtk_dpi_bridge_funcs;
......
......@@ -7,6 +7,7 @@
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
#include <asm/barrier.h>
#include <soc/mediatek/smi.h>
......@@ -19,7 +20,6 @@
#include "mtk_drm_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp.h"
#include "mtk_drm_ddp_comp.h"
#include "mtk_drm_gem.h"
#include "mtk_drm_plane.h"
......@@ -55,7 +55,7 @@ struct mtk_drm_crtc {
#endif
struct device *mmsys_dev;
struct mtk_disp_mutex *mutex;
struct mtk_mutex *mutex;
unsigned int ddp_comp_nr;
struct mtk_ddp_comp **ddp_comp;
......@@ -107,7 +107,7 @@ static void mtk_drm_crtc_destroy(struct drm_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);
}
......@@ -169,31 +169,13 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
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)
{
int ret;
int 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) {
DRM_ERROR("Failed to enable clock %d: %d\n", i, ret);
goto err;
......@@ -203,7 +185,7 @@ static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc)
return 0;
err:
while (--i >= 0)
clk_disable_unprepare(mtk_crtc->ddp_comp[i]->clk);
mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
return ret;
}
......@@ -212,7 +194,7 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc)
int 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
......@@ -283,7 +265,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
return ret;
}
ret = mtk_disp_mutex_prepare(mtk_crtc->mutex);
ret = mtk_mutex_prepare(mtk_crtc->mutex);
if (ret < 0) {
DRM_ERROR("Failed to enable mutex clock: %d\n", ret);
goto err_pm_runtime_put;
......@@ -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_crtc->ddp_comp[i]->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_disp_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
mtk_disp_mutex_enable(mtk_crtc->mutex);
mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
mtk_mutex_enable(mtk_crtc->mutex);
for (i = 0; i < mtk_crtc->ddp_comp_nr; 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)
return 0;
err_mutex_unprepare:
mtk_disp_mutex_unprepare(mtk_crtc->mutex);
mtk_mutex_unprepare(mtk_crtc->mutex);
err_pm_runtime_put:
pm_runtime_put(crtc->dev->dev);
return ret;
......@@ -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++)
mtk_disp_mutex_remove_comp(mtk_crtc->mutex,
mtk_mutex_remove_comp(mtk_crtc->mutex,
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++) {
mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev,
mtk_crtc->ddp_comp[i]->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_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_disp_mutex_unprepare(mtk_crtc->mutex);
mtk_mutex_unprepare(mtk_crtc->mutex);
pm_runtime_put(drm->dev);
......@@ -475,9 +457,9 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
mtk_crtc->pending_async_planes = true;
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_disp_mutex_release(mtk_crtc->mutex);
mtk_mutex_release(mtk_crtc->mutex);
}
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (mtk_crtc->cmdq_client) {
......@@ -493,6 +475,40 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
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,
struct mtk_plane_state *state)
{
......@@ -661,21 +677,6 @@ static int mtk_drm_crtc_init(struct drm_device *drm,
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,
int comp_idx)
{
......@@ -771,7 +772,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
if (!mtk_crtc->ddp_comp)
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)) {
ret = PTR_ERR(mtk_crtc->mutex);
dev_err(dev, "Failed to get mutex: %d\n", ret);
......@@ -784,7 +785,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
struct device_node *node;
node = priv->comp_node[comp_id];
comp = priv->ddp_comp[comp_id];
comp = &priv->ddp_comp[comp_id];
if (!comp) {
dev_err(dev, "Component %pOF not initialized\n", node);
ret = -ENODEV;
......
......@@ -15,7 +15,6 @@
#define MTK_MIN_BPC 3
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,
const enum mtk_ddp_comp_id *path,
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 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <drm/drm_print.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_drv.h"
#include "mtk_drm_plane.h"
#include "mtk_drm_ddp_comp.h"
......@@ -35,31 +35,13 @@
#define DISP_AAL_EN 0x0000
#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 DITHER_EN BIT(0)
#define DISP_DITHER_CFG 0x0020
#define DITHER_RELAY_MODE BIT(0)
#define DITHER_ENGINE_EN BIT(1)
#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 OD_RELAYMODE BIT(0)
......@@ -68,9 +50,6 @@
#define AAL_EN BIT(0)
#define GAMMA_EN BIT(0)
#define GAMMA_LUT_EN BIT(1)
#define DISP_DITHERING BIT(2)
#define DITHER_LSB_ERR_SHIFT_R(x) (((x) & 0x7) << 28)
#define DITHER_OVFLW_BIT_R(x) (((x) & 0x7) << 24)
......@@ -86,262 +65,233 @@
#define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4)
#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,
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 (cmdq_pkt)
cmdq_pkt_write(cmdq_pkt, comp->subsys,
comp->regs_pa + offset, value);
cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys,
cmdq_reg->offset + offset, value);
else
#endif
writel(value, comp->regs + offset);
writel(value, regs + offset);
}
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)
{
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (cmdq_pkt)
cmdq_pkt_write(cmdq_pkt, comp->subsys,
comp->regs_pa + offset, value);
cmdq_pkt_write(cmdq_pkt, cmdq_reg->subsys,
cmdq_reg->offset + offset, value);
else
#endif
writel_relaxed(value, comp->regs + offset);
writel_relaxed(value, regs + offset);
}
void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt,
unsigned int value,
struct mtk_ddp_comp *comp,
unsigned int offset,
unsigned int mask)
void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value,
struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
unsigned int offset, unsigned int mask)
{
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (cmdq_pkt) {
cmdq_pkt_write_mask(cmdq_pkt, comp->subsys,
comp->regs_pa + offset, value, mask);
cmdq_pkt_write_mask(cmdq_pkt, cmdq_reg->subsys,
cmdq_reg->offset + offset, value, mask);
} else {
#endif
u32 tmp = readl(comp->regs + offset);
u32 tmp = readl(regs + offset);
tmp = (tmp & ~mask) | (value & mask);
writel(tmp, comp->regs + offset);
writel(tmp, regs + offset);
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
}
#endif
}
void mtk_dither_set(struct mtk_ddp_comp *comp, unsigned int bpc,
unsigned int CFG, struct cmdq_pkt *cmdq_pkt)
static int mtk_ddp_clk_enable(struct device *dev)
{
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 == 0)
return;
if (bpc >= MTK_MIN_BPC) {
mtk_ddp_write(cmdq_pkt, 0, comp, DISP_DITHER_5);
mtk_ddp_write(cmdq_pkt, 0, comp, DISP_DITHER_7);
mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_DITHER_5);
mtk_ddp_write(cmdq_pkt, 0, cmdq_reg, regs, DISP_DITHER_7);
mtk_ddp_write(cmdq_pkt,
DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC - bpc) |
DITHER_ADD_LSHIFT_R(MTK_MAX_BPC - bpc) |
DITHER_NEW_BIT_MODE,
comp, DISP_DITHER_15);
cmdq_reg, regs, DISP_DITHER_15);
mtk_ddp_write(cmdq_pkt,
DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC - bpc) |
DITHER_ADD_LSHIFT_B(MTK_MAX_BPC - bpc) |
DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC - bpc) |
DITHER_ADD_LSHIFT_G(MTK_MAX_BPC - bpc),
comp, DISP_DITHER_16);
mtk_ddp_write(cmdq_pkt, DISP_DITHERING, comp, CFG);
cmdq_reg, regs, DISP_DITHER_16);
mtk_ddp_write(cmdq_pkt, dither_en, cmdq_reg, regs, cfg);
}
}
static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
static void mtk_dither_set(struct device *dev, unsigned int bpc,
unsigned int cfg, struct cmdq_pkt *cmdq_pkt)
{
mtk_ddp_write(cmdq_pkt, w << 16 | h, comp, DISP_OD_SIZE);
mtk_ddp_write(cmdq_pkt, OD_RELAYMODE, comp, DISP_OD_CFG);
mtk_dither_set(comp, bpc, DISP_OD_CFG, cmdq_pkt);
}
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
static void mtk_od_start(struct mtk_ddp_comp *comp)
{
writel(1, comp->regs + DISP_OD_EN);
mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, cfg,
DISP_DITHERING, cmdq_pkt);
}
static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
static void mtk_od_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
}
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
static void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_AAL_SIZE);
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);
static void mtk_aal_stop(struct mtk_ddp_comp *comp)
{
writel_relaxed(0x0, comp->regs + DISP_AAL_EN);
writel(1, priv->regs + DISP_OD_EN);
}
static void mtk_ccorr_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
static void mtk_ufoe_start(struct device *dev)
{
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_CCORR_SIZE);
mtk_ddp_write(cmdq_pkt, CCORR_ENGINE_EN, comp, DISP_CCORR_CFG);
}
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
static void mtk_ccorr_start(struct mtk_ddp_comp *comp)
{
writel(CCORR_EN, comp->regs + DISP_CCORR_EN);
writel(UFO_BYPASS, priv->regs + DISP_REG_UFO_START);
}
static void mtk_ccorr_stop(struct mtk_ddp_comp *comp)
static void mtk_aal_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
writel_relaxed(0x0, comp->regs + DISP_CCORR_EN);
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_AAL_SIZE);
}
/* Converts a DRM S31.32 value to the HW S1.10 format. */
static u16 mtk_ctm_s31_32_to_s1_10(u64 in)
static void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state)
{
u16 r;
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
/* Sign bit. */
r = in & BIT_ULL(63) ? BIT(11) : 0;
mtk_gamma_set_common(priv->regs, state);
}
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);
}
static void mtk_aal_start(struct device *dev)
{
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
return r;
writel(AAL_EN, priv->regs + DISP_AAL_EN);
}
static void mtk_ccorr_ctm_set(struct mtk_ddp_comp *comp,
struct drm_crtc_state *state)
static void mtk_aal_stop(struct device *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;
if (!blob)
return;
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
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_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);
writel_relaxed(0x0, priv->regs + DISP_AAL_EN);
}
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 bpc, struct cmdq_pkt *cmdq_pkt)
{
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_DITHER_SIZE);
mtk_ddp_write(cmdq_pkt, DITHER_RELAY_MODE, comp, DISP_DITHER_CFG);
}
static void mtk_dither_start(struct mtk_ddp_comp *comp)
{
writel(DITHER_EN, comp->regs + DISP_DITHER_EN);
}
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
static void mtk_dither_stop(struct mtk_ddp_comp *comp)
{
writel_relaxed(0x0, comp->regs + DISP_DITHER_EN);
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);
mtk_dither_set_common(priv->regs, &priv->cmdq_reg, bpc, DISP_DITHER_CFG,
DITHER_ENGINE_EN, cmdq_pkt);
}
static void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
static void mtk_dither_start(struct device *dev)
{
mtk_ddp_write(cmdq_pkt, h << 16 | w, comp, DISP_GAMMA_SIZE);
mtk_dither_set(comp, bpc, DISP_GAMMA_CFG, cmdq_pkt);
}
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
static void mtk_gamma_start(struct mtk_ddp_comp *comp)
{
writel(GAMMA_EN, comp->regs + DISP_GAMMA_EN);
writel(DITHER_EN, priv->regs + DISP_DITHER_EN);
}
static void mtk_gamma_stop(struct mtk_ddp_comp *comp)
static void mtk_dither_stop(struct device *dev)
{
writel_relaxed(0x0, comp->regs + DISP_GAMMA_EN);
}
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
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));
}
}
writel_relaxed(0x0, priv->regs + DISP_DITHER_EN);
}
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,
.start = mtk_aal_start,
.stop = mtk_aal_stop,
};
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,
.start = mtk_ccorr_start,
.stop = mtk_ccorr_stop,
.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 = {
.clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
.config = mtk_dither_config,
.start = mtk_dither_start,
.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 = {
.clk_enable = mtk_gamma_clk_enable,
.clk_disable = mtk_gamma_clk_disable,
.gamma_set = mtk_gamma_set,
.config = mtk_gamma_config,
.start = mtk_gamma_start,
......@@ -349,11 +299,43 @@ static const struct mtk_ddp_comp_funcs ddp_gamma = {
};
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,
.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 = {
.clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
.start = mtk_ufoe_start,
};
......@@ -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_BLS] = { MTK_DISP_BLS, 0, NULL },
[DDP_COMPONENT_CCORR] = { MTK_DISP_CCORR, 0, &ddp_ccorr },
[DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, NULL },
[DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, NULL },
[DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color },
[DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color },
[DDP_COMPONENT_DITHER] = { MTK_DISP_DITHER, 0, &ddp_dither },
[DDP_COMPONENT_DPI0] = { MTK_DPI, 0, NULL },
[DDP_COMPONENT_DPI1] = { MTK_DPI, 1, NULL },
[DDP_COMPONENT_DSI0] = { MTK_DSI, 0, NULL },
[DDP_COMPONENT_DSI1] = { MTK_DSI, 1, NULL },
[DDP_COMPONENT_DSI2] = { MTK_DSI, 2, NULL },
[DDP_COMPONENT_DSI3] = { MTK_DSI, 3, NULL },
[DDP_COMPONENT_DPI0] = { MTK_DPI, 0, &ddp_dpi },
[DDP_COMPONENT_DPI1] = { MTK_DPI, 1, &ddp_dpi },
[DDP_COMPONENT_DSI0] = { MTK_DSI, 0, &ddp_dsi },
[DDP_COMPONENT_DSI1] = { MTK_DSI, 1, &ddp_dsi },
[DDP_COMPONENT_DSI2] = { MTK_DSI, 2, &ddp_dsi },
[DDP_COMPONENT_DSI3] = { MTK_DSI, 3, &ddp_dsi },
[DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma },
[DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od },
[DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od },
[DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, NULL },
[DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, NULL },
[DDP_COMPONENT_OVL_2L0] = { MTK_DISP_OVL_2L, 0, NULL },
[DDP_COMPONENT_OVL_2L1] = { MTK_DISP_OVL_2L, 1, NULL },
[DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, &ddp_ovl },
[DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, &ddp_ovl },
[DDP_COMPONENT_OVL_2L0] = { MTK_DISP_OVL_2L, 0, &ddp_ovl },
[DDP_COMPONENT_OVL_2L1] = { MTK_DISP_OVL_2L, 1, &ddp_ovl },
[DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL },
[DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL },
[DDP_COMPONENT_PWM2] = { MTK_DISP_PWM, 2, NULL },
[DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, NULL },
[DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, NULL },
[DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, NULL },
[DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, &ddp_rdma },
[DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, &ddp_rdma },
[DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, &ddp_rdma },
[DDP_COMPONENT_UFOE] = { MTK_DISP_UFOE, 0, &ddp_ufoe },
[DDP_COMPONENT_WDMA0] = { MTK_DISP_WDMA, 0, 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,
unsigned int path_len)
unsigned int path_len,
struct mtk_ddp_comp *ddp_comp)
{
unsigned int i;
......@@ -424,7 +407,7 @@ static bool mtk_drm_find_comp_in_ddp(struct mtk_ddp_comp ddp_comp,
return false;
for (i = 0U; i < path_len; i++)
if (ddp_comp.id == path[i])
if (dev == ddp_comp[path[i]].dev)
return true;
return false;
......@@ -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,
struct mtk_ddp_comp ddp_comp)
struct device *dev)
{
struct mtk_drm_private *private = drm->dev_private;
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);
else if (mtk_drm_find_comp_in_ddp(ddp_comp, private->data->ext_path,
private->data->ext_len))
else if (mtk_drm_find_comp_in_ddp(dev, private->data->ext_path,
private->data->ext_len, private->ddp_comp))
ret = BIT(1);
else if (mtk_drm_find_comp_in_ddp(ddp_comp, private->data->third_path,
private->data->third_len))
else if (mtk_drm_find_comp_in_ddp(dev, private->data->third_path,
private->data->third_len, private->ddp_comp))
ret = BIT(2);
else
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,
return ret;
}
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id,
const struct mtk_ddp_comp_funcs *funcs)
static int mtk_ddp_get_larb_dev(struct device_node *node, struct mtk_ddp_comp *comp,
struct device *dev)
{
enum mtk_ddp_comp_type type;
struct device_node *larb_node;
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);
if (!larb_node) {
dev_err(dev,
"Missing mediadek,larb phandle in %pOF node\n", node);
dev_err(dev, "Missing mediadek,larb phandle in %pOF node\n", node);
return -EINVAL;
}
......@@ -528,40 +468,71 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
return -EPROBE_DEFER;
}
of_node_put(larb_node);
comp->larb_dev = &larb_pdev->dev;
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
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);
return -EINVAL;
}
comp->regs_pa = res.start;
ret = cmdq_dev_get_client_reg(dev, &cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
else
comp->subsys = cmdq_reg.subsys;
#endif
return 0;
}
int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp)
int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp,
enum mtk_ddp_comp_id comp_id)
{
struct mtk_drm_private *private = drm->dev_private;
struct platform_device *comp_pdev;
enum mtk_ddp_comp_type type;
struct mtk_ddp_comp_dev *priv;
int ret;
if (private->ddp_comp[comp->id])
return -EBUSY;
if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
return -EINVAL;
private->ddp_comp[comp->id] = comp;
return 0;
}
type = mtk_ddp_matches[comp_id].type;
void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp)
{
struct mtk_drm_private *private = drm->dev_private;
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->dev = &comp_pdev->dev;
private->ddp_comp[comp->id] = NULL;
/* 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)
return ret;
}
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;
priv = devm_kzalloc(comp->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regs = of_iomap(node, 0);
priv->clk = of_clk_get(node, 0);
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
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
platform_set_drvdata(comp_pdev, priv);
return 0;
}
......@@ -7,6 +7,7 @@
#define MTK_DRM_DDP_COMP_H
#include <linux/io.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
struct device;
......@@ -39,79 +40,95 @@ enum mtk_ddp_comp_type {
struct mtk_ddp_comp;
struct cmdq_pkt;
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 bpc, struct cmdq_pkt *cmdq_pkt);
void (*start)(struct mtk_ddp_comp *comp);
void (*stop)(struct mtk_ddp_comp *comp);
void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc);
void (*disable_vblank)(struct mtk_ddp_comp *comp);
unsigned int (*supported_rotations)(struct mtk_ddp_comp *comp);
unsigned int (*layer_nr)(struct mtk_ddp_comp *comp);
int (*layer_check)(struct mtk_ddp_comp *comp,
void (*start)(struct device *dev);
void (*stop)(struct device *dev);
void (*enable_vblank)(struct device *dev,
void (*vblank_cb)(void *),
void *vblank_cb_data);
void (*disable_vblank)(struct device *dev);
unsigned int (*supported_rotations)(struct device *dev);
unsigned int (*layer_nr)(struct device *dev);
int (*layer_check)(struct device *dev,
unsigned int idx,
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 cmdq_pkt *cmdq_pkt);
void (*gamma_set)(struct mtk_ddp_comp *comp,
void (*gamma_set)(struct device *dev,
struct drm_crtc_state *state);
void (*bgclr_in_on)(struct mtk_ddp_comp *comp);
void (*bgclr_in_off)(struct mtk_ddp_comp *comp);
void (*ctm_set)(struct mtk_ddp_comp *comp,
void (*bgclr_in_on)(struct device *dev);
void (*bgclr_in_off)(struct device *dev);
void (*ctm_set)(struct device *dev,
struct drm_crtc_state *state);
};
struct mtk_ddp_comp {
struct clk *clk;
void __iomem *regs;
struct device *dev;
int irq;
struct device *larb_dev;
enum mtk_ddp_comp_id id;
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,
unsigned int w, unsigned int h,
unsigned int vrefresh, unsigned int bpc,
struct cmdq_pkt *cmdq_pkt)
{
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)
{
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)
{
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,
struct drm_crtc *crtc)
void (*vblank_cb)(void *),
void *vblank_cb_data)
{
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)
{
if (comp->funcs && comp->funcs->disable_vblank)
comp->funcs->disable_vblank(comp);
comp->funcs->disable_vblank(comp->dev);
}
static inline
unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->supported_rotations)
return comp->funcs->supported_rotations(comp);
return comp->funcs->supported_rotations(comp->dev);
return 0;
}
......@@ -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)
{
if (comp->funcs && comp->funcs->layer_nr)
return comp->funcs->layer_nr(comp);
return comp->funcs->layer_nr(comp->dev);
return 0;
}
......@@ -129,7 +146,7 @@ static inline int mtk_ddp_comp_layer_check(struct mtk_ddp_comp *comp,
struct mtk_plane_state *state)
{
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;
}
......@@ -139,52 +156,49 @@ static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp,
struct cmdq_pkt *cmdq_pkt)
{
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,
struct drm_crtc_state *state)
{
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)
{
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)
{
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,
struct drm_crtc_state *state)
{
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,
enum mtk_ddp_comp_type comp_type);
unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm,
struct mtk_ddp_comp ddp_comp);
int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node,
struct mtk_ddp_comp *comp, 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);
struct device *dev);
int mtk_ddp_comp_init(struct device_node *comp_node, struct mtk_ddp_comp *comp,
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,
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,
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,
struct mtk_ddp_comp *comp, unsigned int offset,
unsigned int mask);
struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
unsigned int offset, unsigned int mask);
#endif /* MTK_DRM_DDP_COMP_H */
......@@ -10,7 +10,6 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/dma-mapping.h>
#include <drm/drm_atomic.h>
......@@ -26,7 +25,6 @@
#include <drm/drm_vblank.h>
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp.h"
#include "mtk_drm_ddp_comp.h"
#include "mtk_drm_drv.h"
#include "mtk_drm_gem.h"
......@@ -131,6 +129,24 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_ext[] = {
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 = {
.main_path = 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 = {
.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)
{
struct mtk_drm_private *private = drm->dev_private;
......@@ -377,12 +400,20 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_OVL },
{ .compatible = "mediatek,mt8173-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",
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8173-disp-rdma",
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8183-disp-rdma",
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8173-disp-wdma",
.data = (void *)MTK_DISP_WDMA },
{ .compatible = "mediatek,mt8183-disp-ccorr",
.data = (void *)MTK_DISP_CCORR },
{ .compatible = "mediatek,mt2701-disp-color",
.data = (void *)MTK_DISP_COLOR },
{ .compatible = "mediatek,mt8173-disp-color",
......@@ -391,22 +422,32 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_AAL},
{ .compatible = "mediatek,mt8173-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",
.data = (void *)MTK_DISP_UFOE },
{ .compatible = "mediatek,mt2701-dsi",
.data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8173-dsi",
.data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt8183-dsi",
.data = (void *)MTK_DSI },
{ .compatible = "mediatek,mt2701-dpi",
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8173-dpi",
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8183-dpi",
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt2701-disp-mutex",
.data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt2712-disp-mutex",
.data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8173-disp-mutex",
.data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8183-disp-mutex",
.data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt2701-disp-pwm",
.data = (void *)MTK_DISP_BLS },
{ .compatible = "mediatek,mt8173-disp-pwm",
......@@ -425,6 +466,8 @@ static const struct of_device_id mtk_drm_of_ids[] = {
.data = &mt2712_mmsys_driver_data},
{ .compatible = "mediatek,mt8173-mmsys",
.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)
private->comp_node[comp_id] = of_node_get(node);
/*
* Currently only the COLOR, OVL, RDMA, DSI, and DPI blocks have
* separate component platform drivers and initialize their own
* Currently only the CCORR, COLOR, GAMMA, OVL, RDMA, DSI, and DPI
* blocks have separate component platform drivers and initialize their own
* 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_2L ||
comp_type == MTK_DISP_RDMA ||
......@@ -502,24 +547,12 @@ static int mtk_drm_probe(struct platform_device *pdev)
node);
drm_of_component_match_add(dev, &match, compare_of,
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,
comp_id, NULL);
if (ret) {
of_node_put(node);
goto err_node;
}
private->ddp_comp[comp_id] = comp;
}
ret = mtk_ddp_comp_init(node, &private->ddp_comp[comp_id], comp_id);
if (ret) {
of_node_put(node);
goto err_node;
}
}
......@@ -545,10 +578,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
of_node_put(private->mutex_node);
for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) {
of_node_put(private->comp_node[i]);
if (private->ddp_comp[i]) {
put_device(private->ddp_comp[i]->larb_dev);
private->ddp_comp[i] = NULL;
}
if (private->ddp_comp[i].larb_dev)
put_device(private->ddp_comp[i].larb_dev);
}
return ret;
}
......@@ -604,8 +635,9 @@ static struct platform_driver mtk_drm_platform_driver = {
};
static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_ddp_driver,
&mtk_disp_ccorr_driver,
&mtk_disp_color_driver,
&mtk_disp_gamma_driver,
&mtk_disp_ovl_driver,
&mtk_disp_rdma_driver,
&mtk_dpi_driver,
......
......@@ -41,13 +41,14 @@ struct mtk_drm_private {
struct device *mutex_dev;
struct device *mmsys_dev;
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;
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_gamma_driver;
extern struct platform_driver mtk_disp_ovl_driver;
extern struct platform_driver mtk_disp_rdma_driver;
extern struct platform_driver mtk_dpi_driver;
......
......@@ -25,6 +25,7 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "mtk_disp_drv.h"
#include "mtk_drm_ddp_comp.h"
#define DSI_START 0x00
......@@ -178,7 +179,6 @@ struct mtk_dsi_driver_data {
};
struct mtk_dsi {
struct mtk_ddp_comp ddp_comp;
struct device *dev;
struct mipi_dsi_host host;
struct drm_encoder encoder;
......@@ -767,25 +767,20 @@ static const struct drm_bridge_funcs mtk_dsi_bridge_funcs = {
.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);
}
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);
}
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,
struct mipi_dsi_device *device)
{
......@@ -952,7 +947,7 @@ static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
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,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
......@@ -980,32 +975,17 @@ static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
struct drm_device *drm = data;
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);
if (ret)
goto err_unregister;
return 0;
err_unregister:
mtk_ddp_comp_unregister(drm, &dsi->ddp_comp);
return ret;
}
static void mtk_dsi_unbind(struct device *dev, struct device *master,
void *data)
{
struct drm_device *drm = data;
struct mtk_dsi *dsi = dev_get_drvdata(dev);
drm_encoder_cleanup(&dsi->encoder);
mtk_ddp_comp_unregister(drm, &dsi->ddp_comp);
}
static const struct component_ops mtk_dsi_component_ops = {
......@@ -1020,7 +1000,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
struct drm_panel *panel;
struct resource *regs;
int irq_num;
int comp_id;
int ret;
dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
......@@ -1090,20 +1069,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
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);
if (irq_num < 0) {
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)
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,
IRQF_TRIGGER_LOW, dev_name(&pdev->dev), dsi);
IRQF_TRIGGER_NONE, dev_name(&pdev->dev), dsi);
if (ret) {
dev_err(&pdev->dev, "failed to request mediatek dsi irq\n");
goto err_unregister_host;
......
......@@ -6,3 +6,4 @@ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
......@@ -9,12 +9,11 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
#include "mtk_drm_ddp.h"
#include "mtk_drm_ddp_comp.h"
#define MT2701_DISP_MUTEX0_MOD0 0x2c
#define MT2701_DISP_MUTEX0_SOF0 0x30
#define MT2701_MUTEX0_MOD0 0x2c
#define MT2701_MUTEX0_SOF0 0x30
#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
......@@ -79,33 +78,32 @@
#define MT2701_MUTEX_MOD_DISP_RDMA0 10
#define MT2701_MUTEX_MOD_DISP_RDMA1 12
#define MUTEX_SOF_SINGLE_MODE 0
#define MUTEX_SOF_DSI0 1
#define MUTEX_SOF_DSI1 2
#define MUTEX_SOF_DPI0 3
#define MUTEX_SOF_DPI1 4
#define MUTEX_SOF_DSI2 5
#define MUTEX_SOF_DSI3 6
#define MT8167_MUTEX_SOF_DPI0 2
#define MT8167_MUTEX_SOF_DPI1 3
struct mtk_disp_mutex {
#define MT2712_MUTEX_SOF_SINGLE_MODE 0
#define MT2712_MUTEX_SOF_DSI0 1
#define MT2712_MUTEX_SOF_DSI1 2
#define MT2712_MUTEX_SOF_DPI0 3
#define MT2712_MUTEX_SOF_DPI1 4
#define MT2712_MUTEX_SOF_DSI2 5
#define MT2712_MUTEX_SOF_DSI3 6
#define MT8167_MUTEX_SOF_DPI0 2
#define MT8167_MUTEX_SOF_DPI1 3
struct mtk_mutex {
int id;
bool claimed;
};
enum mtk_ddp_mutex_sof_id {
DDP_MUTEX_SOF_SINGLE_MODE,
DDP_MUTEX_SOF_DSI0,
DDP_MUTEX_SOF_DSI1,
DDP_MUTEX_SOF_DPI0,
DDP_MUTEX_SOF_DPI1,
DDP_MUTEX_SOF_DSI2,
DDP_MUTEX_SOF_DSI3,
enum mtk_mutex_sof_id {
MUTEX_SOF_SINGLE_MODE,
MUTEX_SOF_DSI0,
MUTEX_SOF_DSI1,
MUTEX_SOF_DPI0,
MUTEX_SOF_DPI1,
MUTEX_SOF_DSI2,
MUTEX_SOF_DSI3,
};
struct mtk_ddp_data {
struct mtk_mutex_data {
const unsigned int *mutex_mod;
const unsigned int *mutex_sof;
const unsigned int mutex_mod_reg;
......@@ -113,12 +111,12 @@ struct mtk_ddp_data {
const bool no_clk;
};
struct mtk_ddp {
struct mtk_mutex_ctx {
struct device *dev;
struct clk *clk;
void __iomem *regs;
struct mtk_disp_mutex mutex[10];
const struct mtk_ddp_data *data;
struct mtk_mutex mutex[10];
const struct mtk_mutex_data *data;
};
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] = {
[DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
};
static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_DSI3 + 1] = {
[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,
static const unsigned int mt2712_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
[MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0,
[MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1,
[MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2,
[MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3,
};
static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_DSI3 + 1] = {
[DDP_MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[DDP_MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[DDP_MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0,
[DDP_MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1,
static const unsigned int mt8167_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
[MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0,
[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_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
.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_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
.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_sof = mt8167_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_MUTEX0_SOF0,
.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_sof = mt2712_mutex_sof,
.mutex_mod_reg = MT2701_DISP_MUTEX0_MOD0,
.mutex_sof_reg = MT2701_DISP_MUTEX0_SOF0,
.mutex_mod_reg = MT2701_MUTEX0_MOD0,
.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);
if (id >= 10)
return ERR_PTR(-EINVAL);
if (ddp->mutex[id].claimed)
return ERR_PTR(-EBUSY);
struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
int i;
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,
mutex[mutex->id]);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
WARN_ON(&ddp->mutex[mutex->id] != mutex);
WARN_ON(&mtx->mutex[mutex->id] != mutex);
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,
mutex[mutex->id]);
return clk_prepare_enable(ddp->clk);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
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,
mutex[mutex->id]);
clk_disable_unprepare(ddp->clk);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
clk_disable_unprepare(mtx->clk);
}
EXPORT_SYMBOL_GPL(mtk_mutex_unprepare);
void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
enum mtk_ddp_comp_id id)
void mtk_mutex_add_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id)
{
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
mutex[mutex->id]);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
unsigned int reg;
unsigned int sof_id;
unsigned int offset;
WARN_ON(&ddp->mutex[mutex->id] != mutex);
WARN_ON(&mtx->mutex[mutex->id] != mutex);
switch (id) {
case DDP_COMPONENT_DSI0:
sof_id = DDP_MUTEX_SOF_DSI0;
sof_id = MUTEX_SOF_DSI0;
break;
case DDP_COMPONENT_DSI1:
sof_id = DDP_MUTEX_SOF_DSI0;
sof_id = MUTEX_SOF_DSI0;
break;
case DDP_COMPONENT_DSI2:
sof_id = DDP_MUTEX_SOF_DSI2;
sof_id = MUTEX_SOF_DSI2;
break;
case DDP_COMPONENT_DSI3:
sof_id = DDP_MUTEX_SOF_DSI3;
sof_id = MUTEX_SOF_DSI3;
break;
case DDP_COMPONENT_DPI0:
sof_id = DDP_MUTEX_SOF_DPI0;
sof_id = MUTEX_SOF_DPI0;
break;
case DDP_COMPONENT_DPI1:
sof_id = DDP_MUTEX_SOF_DPI1;
sof_id = MUTEX_SOF_DPI1;
break;
default:
if (ddp->data->mutex_mod[id] < 32) {
offset = DISP_REG_MUTEX_MOD(ddp->data->mutex_mod_reg,
if (mtx->data->mutex_mod[id] < 32) {
offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
mutex->id);
reg = readl_relaxed(ddp->regs + offset);
reg |= 1 << ddp->data->mutex_mod[id];
writel_relaxed(reg, ddp->regs + offset);
reg = readl_relaxed(mtx->regs + offset);
reg |= 1 << mtx->data->mutex_mod[id];
writel_relaxed(reg, mtx->regs + offset);
} else {
offset = DISP_REG_MUTEX_MOD2(mutex->id);
reg = readl_relaxed(ddp->regs + offset);
reg |= 1 << (ddp->data->mutex_mod[id] - 32);
writel_relaxed(reg, ddp->regs + offset);
reg = readl_relaxed(mtx->regs + offset);
reg |= 1 << (mtx->data->mutex_mod[id] - 32);
writel_relaxed(reg, mtx->regs + offset);
}
return;
}
writel_relaxed(ddp->data->mutex_sof[sof_id],
ddp->regs +
DISP_REG_MUTEX_SOF(ddp->data->mutex_sof_reg, mutex->id));
writel_relaxed(mtx->data->mutex_sof[sof_id],
mtx->regs +
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,
enum mtk_ddp_comp_id id)
void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
enum mtk_ddp_comp_id id)
{
struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
mutex[mutex->id]);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
unsigned int reg;
unsigned int offset;
WARN_ON(&ddp->mutex[mutex->id] != mutex);
WARN_ON(&mtx->mutex[mutex->id] != mutex);
switch (id) {
case DDP_COMPONENT_DSI0:
......@@ -336,129 +339,136 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
case DDP_COMPONENT_DPI0:
case DDP_COMPONENT_DPI1:
writel_relaxed(MUTEX_SOF_SINGLE_MODE,
ddp->regs +
DISP_REG_MUTEX_SOF(ddp->data->mutex_sof_reg,
mtx->regs +
DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg,
mutex->id));
break;
default:
if (ddp->data->mutex_mod[id] < 32) {
offset = DISP_REG_MUTEX_MOD(ddp->data->mutex_mod_reg,
if (mtx->data->mutex_mod[id] < 32) {
offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
mutex->id);
reg = readl_relaxed(ddp->regs + offset);
reg &= ~(1 << ddp->data->mutex_mod[id]);
writel_relaxed(reg, ddp->regs + offset);
reg = readl_relaxed(mtx->regs + offset);
reg &= ~(1 << mtx->data->mutex_mod[id]);
writel_relaxed(reg, mtx->regs + offset);
} else {
offset = DISP_REG_MUTEX_MOD2(mutex->id);
reg = readl_relaxed(ddp->regs + offset);
reg &= ~(1 << (ddp->data->mutex_mod[id] - 32));
writel_relaxed(reg, ddp->regs + offset);
reg = readl_relaxed(mtx->regs + offset);
reg &= ~(1 << (mtx->data->mutex_mod[id] - 32));
writel_relaxed(reg, mtx->regs + offset);
}
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,
mutex[mutex->id]);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
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,
mutex[mutex->id]);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
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,
mutex[mutex->id]);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
mutex[mutex->id]);
u32 tmp;
writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
if (readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id),
writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
writel(1, mtx->regs + DISP_REG_MUTEX(mutex->id));
if (readl_poll_timeout_atomic(mtx->regs + DISP_REG_MUTEX(mutex->id),
tmp, tmp & INT_MUTEX, 1, 10000))
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,
mutex[mutex->id]);
struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
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 mtk_ddp *ddp;
struct mtk_mutex_ctx *mtx;
struct resource *regs;
int i;
ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL);
if (!ddp)
mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
if (!mtx)
return -ENOMEM;
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) {
ddp->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ddp->clk)) {
if (PTR_ERR(ddp->clk) != -EPROBE_DEFER)
if (!mtx->data->no_clk) {
mtx->clk = devm_clk_get(dev, NULL);
if (IS_ERR(mtx->clk)) {
if (PTR_ERR(mtx->clk) != -EPROBE_DEFER)
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);
ddp->regs = devm_ioremap_resource(dev, regs);
if (IS_ERR(ddp->regs)) {
mtx->regs = devm_ioremap_resource(dev, regs);
if (IS_ERR(mtx->regs)) {
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;
}
static int mtk_ddp_remove(struct platform_device *pdev)
static int mtk_mutex_remove(struct platform_device *pdev)
{
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",
.data = &mt2701_ddp_driver_data},
.data = &mt2701_mutex_driver_data},
{ .compatible = "mediatek,mt2712-disp-mutex",
.data = &mt2712_ddp_driver_data},
.data = &mt2712_mutex_driver_data},
{ .compatible = "mediatek,mt8167-disp-mutex",
.data = &mt8167_ddp_driver_data},
.data = &mt8167_mutex_driver_data},
{ .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 = {
.probe = mtk_ddp_probe,
.remove = mtk_ddp_remove,
struct platform_driver mtk_mutex_driver = {
.probe = mtk_mutex_probe,
.remove = mtk_mutex_remove,
.driver = {
.name = "mediatek-ddp",
.name = "mediatek-mutex",
.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