summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/mediatek/Makefile4
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_drv.h20
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_merge.c320
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_rdma.c8
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi.c260
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi_regs.h18
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c69
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h3
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.c184
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.h8
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_plane.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_plane.h1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c101
-rw-r--r--drivers/gpu/drm/mediatek/mtk_mdp_rdma.c315
-rw-r--r--drivers/gpu/drm/mediatek/mtk_mdp_rdma.h20
15 files changed, 1213 insertions, 119 deletions
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 29098d7c8307..6e604a933ed0 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -4,6 +4,7 @@ mediatek-drm-y := mtk_disp_aal.o \
mtk_disp_ccorr.o \
mtk_disp_color.o \
mtk_disp_gamma.o \
+ mtk_disp_merge.o \
mtk_disp_ovl.o \
mtk_disp_rdma.o \
mtk_drm_crtc.o \
@@ -12,7 +13,8 @@ mediatek-drm-y := mtk_disp_aal.o \
mtk_drm_gem.o \
mtk_drm_plane.o \
mtk_dsi.o \
- mtk_dpi.o
+ mtk_dpi.o \
+ mtk_mdp_rdma.o
obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 763be99e8d33..33e61a136bbc 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -8,6 +8,7 @@
#include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_drm_plane.h"
+#include "mtk_mdp_rdma.h"
int mtk_aal_clk_enable(struct device *dev);
void mtk_aal_clk_disable(struct device *dev);
@@ -55,6 +56,19 @@ void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, bool
void mtk_gamma_start(struct device *dev);
void mtk_gamma_stop(struct device *dev);
+int mtk_merge_clk_enable(struct device *dev);
+void mtk_merge_clk_disable(struct device *dev);
+void mtk_merge_config(struct device *dev, unsigned int width,
+ unsigned int height, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+void mtk_merge_start(struct device *dev);
+void mtk_merge_stop(struct device *dev);
+void mtk_merge_advance_config(struct device *dev, unsigned int l_w, unsigned int r_w,
+ unsigned int h, unsigned int vrefresh, unsigned int bpc,
+ struct cmdq_pkt *cmdq_pkt);
+void mtk_merge_start_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt);
+void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt);
+
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);
@@ -102,4 +116,10 @@ void mtk_rdma_unregister_vblank_cb(struct device *dev);
void mtk_rdma_enable_vblank(struct device *dev);
void mtk_rdma_disable_vblank(struct device *dev);
+int mtk_mdp_rdma_clk_enable(struct device *dev);
+void mtk_mdp_rdma_clk_disable(struct device *dev);
+void mtk_mdp_rdma_start(struct device *dev, struct cmdq_pkt *cmdq_pkt);
+void mtk_mdp_rdma_stop(struct device *dev, struct cmdq_pkt *cmdq_pkt);
+void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg,
+ struct cmdq_pkt *cmdq_pkt);
#endif
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_merge.c b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
new file mode 100644
index 000000000000..6428b6203ffe
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
+#include "mtk_disp_drv.h"
+
+#define DISP_REG_MERGE_CTRL 0x000
+#define MERGE_EN 1
+#define DISP_REG_MERGE_CFG_0 0x010
+#define DISP_REG_MERGE_CFG_1 0x014
+#define DISP_REG_MERGE_CFG_4 0x020
+#define DISP_REG_MERGE_CFG_10 0x038
+/* no swap */
+#define SWAP_MODE 0
+#define FLD_SWAP_MODE GENMASK(4, 0)
+#define DISP_REG_MERGE_CFG_12 0x040
+#define CFG_10_10_1PI_2PO_BUF_MODE 6
+#define CFG_10_10_2PI_2PO_BUF_MODE 8
+#define CFG_11_10_1PI_2PO_MERGE 18
+#define FLD_CFG_MERGE_MODE GENMASK(4, 0)
+#define DISP_REG_MERGE_CFG_24 0x070
+#define DISP_REG_MERGE_CFG_25 0x074
+#define DISP_REG_MERGE_CFG_26 0x078
+#define DISP_REG_MERGE_CFG_27 0x07c
+#define DISP_REG_MERGE_CFG_36 0x0a0
+#define ULTRA_EN BIT(0)
+#define PREULTRA_EN BIT(4)
+#define DISP_REG_MERGE_CFG_37 0x0a4
+/* 0: Off, 1: SRAM0, 2: SRAM1, 3: SRAM0 + SRAM1 */
+#define BUFFER_MODE 3
+#define FLD_BUFFER_MODE GENMASK(1, 0)
+/*
+ * For the ultra and preultra settings, 6us ~ 9us is experience value
+ * and the maximum frequency of mmsys clock is 594MHz.
+ */
+#define DISP_REG_MERGE_CFG_40 0x0b0
+/* 6 us, 594M pixel/sec */
+#define ULTRA_TH_LOW (6 * 594)
+/* 8 us, 594M pixel/sec */
+#define ULTRA_TH_HIGH (8 * 594)
+#define FLD_ULTRA_TH_LOW GENMASK(15, 0)
+#define FLD_ULTRA_TH_HIGH GENMASK(31, 16)
+#define DISP_REG_MERGE_CFG_41 0x0b4
+/* 8 us, 594M pixel/sec */
+#define PREULTRA_TH_LOW (8 * 594)
+/* 9 us, 594M pixel/sec */
+#define PREULTRA_TH_HIGH (9 * 594)
+#define FLD_PREULTRA_TH_LOW GENMASK(15, 0)
+#define FLD_PREULTRA_TH_HIGH GENMASK(31, 16)
+
+#define DISP_REG_MERGE_MUTE_0 0xf00
+
+struct mtk_disp_merge {
+ void __iomem *regs;
+ struct clk *clk;
+ struct clk *async_clk;
+ struct cmdq_client_reg cmdq_reg;
+ bool fifo_en;
+ bool mute_support;
+ struct reset_control *reset_ctl;
+};
+
+void mtk_merge_start(struct device *dev)
+{
+ mtk_merge_start_cmdq(dev, NULL);
+}
+
+void mtk_merge_stop(struct device *dev)
+{
+ mtk_merge_stop_cmdq(dev, NULL);
+}
+
+void mtk_merge_start_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_merge *priv = dev_get_drvdata(dev);
+
+ if (priv->mute_support)
+ mtk_ddp_write(cmdq_pkt, 0x0, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_MUTE_0);
+
+ mtk_ddp_write(cmdq_pkt, 1, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CTRL);
+}
+
+void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_merge *priv = dev_get_drvdata(dev);
+
+ if (priv->mute_support)
+ mtk_ddp_write(cmdq_pkt, 0x1, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_MUTE_0);
+
+ mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CTRL);
+
+ if (priv->async_clk)
+ reset_control_reset(priv->reset_ctl);
+}
+
+static void mtk_merge_fifo_setting(struct mtk_disp_merge *priv,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ mtk_ddp_write(cmdq_pkt, ULTRA_EN | PREULTRA_EN,
+ &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_36);
+
+ mtk_ddp_write_mask(cmdq_pkt, BUFFER_MODE,
+ &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_37,
+ FLD_BUFFER_MODE);
+
+ mtk_ddp_write_mask(cmdq_pkt, ULTRA_TH_LOW | ULTRA_TH_HIGH << 16,
+ &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_40,
+ FLD_ULTRA_TH_LOW | FLD_ULTRA_TH_HIGH);
+
+ mtk_ddp_write_mask(cmdq_pkt, PREULTRA_TH_LOW | PREULTRA_TH_HIGH << 16,
+ &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_41,
+ FLD_PREULTRA_TH_LOW | FLD_PREULTRA_TH_HIGH);
+}
+
+void mtk_merge_config(struct device *dev, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ mtk_merge_advance_config(dev, w, 0, h, vrefresh, bpc, cmdq_pkt);
+}
+
+void mtk_merge_advance_config(struct device *dev, unsigned int l_w, unsigned int r_w,
+ unsigned int h, unsigned int vrefresh, unsigned int bpc,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_merge *priv = dev_get_drvdata(dev);
+ unsigned int mode = CFG_10_10_1PI_2PO_BUF_MODE;
+
+ if (!h || !l_w) {
+ dev_err(dev, "%s: input width(%d) or height(%d) is invalid\n", __func__, l_w, h);
+ return;
+ }
+
+ if (priv->fifo_en) {
+ mtk_merge_fifo_setting(priv, cmdq_pkt);
+ mode = CFG_10_10_2PI_2PO_BUF_MODE;
+ }
+
+ if (r_w)
+ mode = CFG_11_10_1PI_2PO_MERGE;
+
+ mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_0);
+ mtk_ddp_write(cmdq_pkt, h << 16 | r_w, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_1);
+ mtk_ddp_write(cmdq_pkt, h << 16 | (l_w + r_w), &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_4);
+ /*
+ * DISP_REG_MERGE_CFG_24 is merge SRAM0 w/h
+ * DISP_REG_MERGE_CFG_25 is merge SRAM1 w/h.
+ * If r_w > 0, the merge is in merge mode (input0 and input1 merge together),
+ * the input0 goes to SRAM0, and input1 goes to SRAM1.
+ * If r_w = 0, the merge is in buffer mode, the input goes through SRAM0 and
+ * then to SRAM1. Both SRAM0 and SRAM1 are set to the same size.
+ */
+ mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_24);
+ if (r_w)
+ mtk_ddp_write(cmdq_pkt, h << 16 | r_w, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_25);
+ else
+ mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_25);
+
+ /*
+ * DISP_REG_MERGE_CFG_26 and DISP_REG_MERGE_CFG_27 is only used in LR merge.
+ * Only take effect when the merge is setting to merge mode.
+ */
+ mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_26);
+ mtk_ddp_write(cmdq_pkt, h << 16 | r_w, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_27);
+
+ mtk_ddp_write_mask(cmdq_pkt, SWAP_MODE, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_10, FLD_SWAP_MODE);
+ mtk_ddp_write_mask(cmdq_pkt, mode, &priv->cmdq_reg, priv->regs,
+ DISP_REG_MERGE_CFG_12, FLD_CFG_MERGE_MODE);
+}
+
+int mtk_merge_clk_enable(struct device *dev)
+{
+ int ret = 0;
+ struct mtk_disp_merge *priv = dev_get_drvdata(dev);
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "merge clk prepare enable failed\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(priv->async_clk);
+ if (ret) {
+ /* should clean up the state of priv->clk */
+ clk_disable_unprepare(priv->clk);
+
+ dev_err(dev, "async clk prepare enable failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+void mtk_merge_clk_disable(struct device *dev)
+{
+ struct mtk_disp_merge *priv = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(priv->async_clk);
+ clk_disable_unprepare(priv->clk);
+}
+
+static int mtk_disp_merge_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ return 0;
+}
+
+static void mtk_disp_merge_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+}
+
+static const struct component_ops mtk_disp_merge_component_ops = {
+ .bind = mtk_disp_merge_bind,
+ .unbind = mtk_disp_merge_unbind,
+};
+
+static int mtk_disp_merge_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct mtk_disp_merge *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ 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 merge\n");
+ return PTR_ERR(priv->regs);
+ }
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get merge clk\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ priv->async_clk = devm_clk_get_optional(dev, "merge_async");
+ if (IS_ERR(priv->async_clk)) {
+ dev_err(dev, "failed to get merge async clock\n");
+ return PTR_ERR(priv->async_clk);
+ }
+
+ if (priv->async_clk) {
+ priv->reset_ctl = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(priv->reset_ctl))
+ return PTR_ERR(priv->reset_ctl);
+ }
+
+#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->fifo_en = of_property_read_bool(dev->of_node,
+ "mediatek,merge-fifo-en");
+
+ priv->mute_support = of_property_read_bool(dev->of_node,
+ "mediatek,merge-mute");
+ platform_set_drvdata(pdev, priv);
+
+ ret = component_add(dev, &mtk_disp_merge_component_ops);
+ if (ret != 0)
+ dev_err(dev, "Failed to add component: %d\n", ret);
+
+ return ret;
+}
+
+static int mtk_disp_merge_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_disp_merge_component_ops);
+
+ return 0;
+}
+
+static const struct of_device_id mtk_disp_merge_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8195-disp-merge", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, mtk_disp_merge_driver_dt_match);
+
+struct platform_driver mtk_disp_merge_driver = {
+ .probe = mtk_disp_merge_probe,
+ .remove = mtk_disp_merge_remove,
+ .driver = {
+ .name = "mediatek-disp-merge",
+ .owner = THIS_MODULE,
+ .of_match_table = mtk_disp_merge_driver_dt_match,
+ },
+};
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 2cb90466798c..0ec2e4049e07 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -370,8 +370,8 @@ static const struct mtk_disp_rdma_data mt8183_rdma_driver_data = {
.fifo_size = 5 * SZ_1K,
};
-static const struct mtk_disp_rdma_data mt8192_rdma_driver_data = {
- .fifo_size = 5 * SZ_1K,
+static const struct mtk_disp_rdma_data mt8195_rdma_driver_data = {
+ .fifo_size = 1920,
};
static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
@@ -381,8 +381,8 @@ static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
.data = &mt8173_rdma_driver_data},
{ .compatible = "mediatek,mt8183-disp-rdma",
.data = &mt8183_rdma_driver_data},
- { .compatible = "mediatek,mt8192-disp-rdma",
- .data = &mt8192_rdma_driver_data},
+ { .compatible = "mediatek,mt8195-disp-rdma",
+ .data = &mt8195_rdma_driver_data},
{},
};
MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 6dafa6116546..630a4e301ef6 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -23,6 +23,7 @@
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_simple_kms_helper.h>
@@ -56,12 +57,7 @@ enum mtk_dpi_out_channel_swap {
enum mtk_dpi_out_color_format {
MTK_DPI_COLOR_FORMAT_RGB,
- MTK_DPI_COLOR_FORMAT_RGB_FULL,
- MTK_DPI_COLOR_FORMAT_YCBCR_444,
- MTK_DPI_COLOR_FORMAT_YCBCR_422,
- MTK_DPI_COLOR_FORMAT_XV_YCC,
- MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL,
- MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL
+ MTK_DPI_COLOR_FORMAT_YCBCR_422
};
struct mtk_dpi {
@@ -119,6 +115,27 @@ struct mtk_dpi_yc_limit {
u16 c_bottom;
};
+/**
+ * struct mtk_dpi_conf - Configuration of mediatek dpi.
+ * @cal_factor: Callback function to calculate factor value.
+ * @reg_h_fre_con: Register address of frequency control.
+ * @max_clock_khz: Max clock frequency supported for this SoCs in khz units.
+ * @edge_sel_en: Enable of edge selection.
+ * @output_fmts: Array of supported output formats.
+ * @num_output_fmts: Quantity of supported output formats.
+ * @is_ck_de_pol: Support CK/DE polarity.
+ * @swap_input_support: Support input swap function.
+ * @support_direct_pin: IP supports direct connection to dpi panels.
+ * @input_2pixel: Input pixel of dp_intf is 2 pixel per round, so enable this
+ * config to enable this feature.
+ * @dimension_mask: Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH
+ * (no shift).
+ * @hvsize_mask: Mask of HSIZE and VSIZE mask (no shift).
+ * @channel_swap_shift: Shift value of channel swap.
+ * @yuv422_en_bit: Enable bit of yuv422.
+ * @csc_enable_bit: Enable bit of CSC.
+ * @pixels_per_iter: Quantity of transferred pixels per iteration.
+ */
struct mtk_dpi_conf {
unsigned int (*cal_factor)(int clock);
u32 reg_h_fre_con;
@@ -126,6 +143,16 @@ struct mtk_dpi_conf {
bool edge_sel_en;
const u32 *output_fmts;
u32 num_output_fmts;
+ bool is_ck_de_pol;
+ bool swap_input_support;
+ bool support_direct_pin;
+ bool input_2pixel;
+ u32 dimension_mask;
+ u32 hvsize_mask;
+ u32 channel_swap_shift;
+ u32 yuv422_en_bit;
+ u32 csc_enable_bit;
+ u32 pixels_per_iter;
};
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
@@ -154,12 +181,12 @@ static void mtk_dpi_disable(struct mtk_dpi *dpi)
static void mtk_dpi_config_hsync(struct mtk_dpi *dpi,
struct mtk_dpi_sync_param *sync)
{
- mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH,
- sync->sync_width << HPW, HPW_MASK);
- mtk_dpi_mask(dpi, DPI_TGEN_HPORCH,
- sync->back_porch << HBP, HBP_MASK);
+ mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH, sync->sync_width << HPW,
+ dpi->conf->dimension_mask << HPW);
+ mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->back_porch << HBP,
+ dpi->conf->dimension_mask << HBP);
mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->front_porch << HFP,
- HFP_MASK);
+ dpi->conf->dimension_mask << HFP);
}
static void mtk_dpi_config_vsync(struct mtk_dpi *dpi,
@@ -167,17 +194,17 @@ static void mtk_dpi_config_vsync(struct mtk_dpi *dpi,
u32 width_addr, u32 porch_addr)
{
mtk_dpi_mask(dpi, width_addr,
- sync->sync_width << VSYNC_WIDTH_SHIFT,
- VSYNC_WIDTH_MASK);
- mtk_dpi_mask(dpi, width_addr,
sync->shift_half_line << VSYNC_HALF_LINE_SHIFT,
VSYNC_HALF_LINE_MASK);
+ mtk_dpi_mask(dpi, width_addr,
+ sync->sync_width << VSYNC_WIDTH_SHIFT,
+ dpi->conf->dimension_mask << VSYNC_WIDTH_SHIFT);
mtk_dpi_mask(dpi, porch_addr,
sync->back_porch << VSYNC_BACK_PORCH_SHIFT,
- VSYNC_BACK_PORCH_MASK);
+ dpi->conf->dimension_mask << VSYNC_BACK_PORCH_SHIFT);
mtk_dpi_mask(dpi, porch_addr,
sync->front_porch << VSYNC_FRONT_PORCH_SHIFT,
- VSYNC_FRONT_PORCH_MASK);
+ dpi->conf->dimension_mask << VSYNC_FRONT_PORCH_SHIFT);
}
static void mtk_dpi_config_vsync_lodd(struct mtk_dpi *dpi,
@@ -211,13 +238,20 @@ static void mtk_dpi_config_pol(struct mtk_dpi *dpi,
struct mtk_dpi_polarities *dpi_pol)
{
unsigned int pol;
+ unsigned int mask;
- pol = (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ? 0 : CK_POL) |
- (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ? 0 : DE_POL) |
- (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) |
+ mask = HSYNC_POL | VSYNC_POL;
+ pol = (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) |
(dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VSYNC_POL);
- mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol,
- CK_POL | DE_POL | HSYNC_POL | VSYNC_POL);
+ if (dpi->conf->is_ck_de_pol) {
+ mask |= CK_POL | DE_POL;
+ pol |= (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ?
+ 0 : CK_POL) |
+ (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ?
+ 0 : DE_POL);
+ }
+
+ mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol, mask);
}
static void mtk_dpi_config_3d(struct mtk_dpi *dpi, bool en_3d)
@@ -232,20 +266,36 @@ static void mtk_dpi_config_interface(struct mtk_dpi *dpi, bool inter)
static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height)
{
- mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE, HSIZE_MASK);
- mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, VSIZE_MASK);
+ mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE,
+ dpi->conf->hvsize_mask << HSIZE);
+ mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE,
+ dpi->conf->hvsize_mask << VSIZE);
}
-static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi,
- struct mtk_dpi_yc_limit *limit)
+static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi)
{
- mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_bottom << Y_LIMINT_BOT,
+ struct mtk_dpi_yc_limit limit;
+
+ if (drm_default_rgb_quant_range(&dpi->mode) ==
+ HDMI_QUANTIZATION_RANGE_LIMITED) {
+ limit.y_bottom = 0x10;
+ limit.y_top = 0xfe0;
+ limit.c_bottom = 0x10;
+ limit.c_top = 0xfe0;
+ } else {
+ limit.y_bottom = 0;
+ limit.y_top = 0xfff;
+ limit.c_bottom = 0;
+ limit.c_top = 0xfff;
+ }
+
+ mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit.y_bottom << Y_LIMINT_BOT,
Y_LIMINT_BOT_MASK);
- mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_top << Y_LIMINT_TOP,
+ mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit.y_top << Y_LIMINT_TOP,
Y_LIMINT_TOP_MASK);
- mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_bottom << C_LIMIT_BOT,
+ mtk_dpi_mask(dpi, DPI_C_LIMIT, limit.c_bottom << C_LIMIT_BOT,
C_LIMIT_BOT_MASK);
- mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_top << C_LIMIT_TOP,
+ mtk_dpi_mask(dpi, DPI_C_LIMIT, limit.c_top << C_LIMIT_TOP,
C_LIMIT_TOP_MASK);
}
@@ -333,17 +383,21 @@ static void mtk_dpi_config_channel_swap(struct mtk_dpi *dpi,
break;
}
- mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << CH_SWAP, CH_SWAP_MASK);
+ mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING,
+ val << dpi->conf->channel_swap_shift,
+ CH_SWAP_MASK << dpi->conf->channel_swap_shift);
}
static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable)
{
- mtk_dpi_mask(dpi, DPI_CON, enable ? YUV422_EN : 0, YUV422_EN);
+ mtk_dpi_mask(dpi, DPI_CON, enable ? dpi->conf->yuv422_en_bit : 0,
+ dpi->conf->yuv422_en_bit);
}
static void mtk_dpi_config_csc_enable(struct mtk_dpi *dpi, bool enable)
{
- mtk_dpi_mask(dpi, DPI_CON, enable ? CSC_ENABLE : 0, CSC_ENABLE);
+ mtk_dpi_mask(dpi, DPI_CON, enable ? dpi->conf->csc_enable_bit : 0,
+ dpi->conf->csc_enable_bit);
}
static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable)
@@ -365,23 +419,24 @@ static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
enum mtk_dpi_out_color_format format)
{
- if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_444) ||
- (format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) {
- mtk_dpi_config_yuv422_enable(dpi, false);
- mtk_dpi_config_csc_enable(dpi, true);
- mtk_dpi_config_swap_input(dpi, false);
- mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR);
- } else if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_422) ||
- (format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) {
+ mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
+
+ if (format == MTK_DPI_COLOR_FORMAT_YCBCR_422) {
mtk_dpi_config_yuv422_enable(dpi, true);
mtk_dpi_config_csc_enable(dpi, true);
- mtk_dpi_config_swap_input(dpi, true);
- mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
+
+ /*
+ * If height is smaller than 720, we need to use RGB_TO_BT601
+ * to transfer to yuv422. Otherwise, we use RGB_TO_JPEG.
+ */
+ mtk_dpi_mask(dpi, DPI_MATRIX_SET, dpi->mode.hdisplay <= 720 ?
+ MATRIX_SEL_RGB_TO_BT601 : MATRIX_SEL_RGB_TO_JPEG,
+ INT_MATRIX_SEL_MASK);
} else {
mtk_dpi_config_yuv422_enable(dpi, false);
mtk_dpi_config_csc_enable(dpi, false);
- mtk_dpi_config_swap_input(dpi, false);
- mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB);
+ if (dpi->conf->swap_input_support)
+ mtk_dpi_config_swap_input(dpi, false);
}
}
@@ -437,7 +492,6 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi)
if (dpi->pinctrl && dpi->pins_dpi)
pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
- mtk_dpi_enable(dpi);
return 0;
err_pixel:
@@ -450,7 +504,6 @@ err_refcount:
static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
struct drm_display_mode *mode)
{
- struct mtk_dpi_yc_limit limit;
struct mtk_dpi_polarities dpi_pol;
struct mtk_dpi_sync_param hsync;
struct mtk_dpi_sync_param vsync_lodd = { 0 };
@@ -472,7 +525,14 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
clk_set_rate(dpi->tvd_clk, pll_rate);
pll_rate = clk_get_rate(dpi->tvd_clk);
+ /*
+ * Depending on the IP version, we may output a different amount of
+ * pixels for each iteration: divide the clock by this number and
+ * adjust the display porches accordingly.
+ */
vm.pixelclock = pll_rate / factor;
+ vm.pixelclock /= dpi->conf->pixels_per_iter;
+
if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
(dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2);
@@ -485,20 +545,22 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n",
pll_rate, vm.pixelclock);
- limit.c_bottom = 0x0010;
- limit.c_top = 0x0FE0;
- limit.y_bottom = 0x0010;
- limit.y_top = 0x0FE0;
-
dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING;
dpi_pol.de_pol = MTK_DPI_POLARITY_RISING;
dpi_pol.hsync_pol = vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ?
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
dpi_pol.vsync_pol = vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ?
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
- hsync.sync_width = vm.hsync_len;
- hsync.back_porch = vm.hback_porch;
- hsync.front_porch = vm.hfront_porch;
+
+ /*
+ * Depending on the IP version, we may output a different amount of
+ * pixels for each iteration: divide the clock by this number and
+ * adjust the display porches accordingly.
+ */
+ hsync.sync_width = vm.hsync_len / dpi->conf->pixels_per_iter;
+ hsync.back_porch = vm.hback_porch / dpi->conf->pixels_per_iter;
+ hsync.front_porch = vm.hfront_porch / dpi->conf->pixels_per_iter;
+
hsync.shift_half_line = false;
vsync_lodd.sync_width = vm.vsync_len;
vsync_lodd.back_porch = vm.vback_porch;
@@ -537,14 +599,20 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
else
mtk_dpi_config_fb_size(dpi, vm.hactive, vm.vactive);
- mtk_dpi_config_channel_limit(dpi, &limit);
+ mtk_dpi_config_channel_limit(dpi);
mtk_dpi_config_bit_num(dpi, dpi->bit_num);
mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
- mtk_dpi_config_yc_map(dpi, dpi->yc_map);
mtk_dpi_config_color_format(dpi, dpi->color_format);
- mtk_dpi_config_2n_h_fre(dpi);
- mtk_dpi_dual_edge(dpi);
- mtk_dpi_config_disable_edge(dpi);
+ if (dpi->conf->support_direct_pin) {
+ mtk_dpi_config_yc_map(dpi, dpi->yc_map);
+ mtk_dpi_config_2n_h_fre(dpi);
+ mtk_dpi_dual_edge(dpi);
+ mtk_dpi_config_disable_edge(dpi);
+ }
+ if (dpi->conf->input_2pixel) {
+ mtk_dpi_mask(dpi, DPI_CON, DPINTF_INPUT_2P_EN,
+ DPINTF_INPUT_2P_EN);
+ }
mtk_dpi_sw_reset(dpi, false);
return 0;
@@ -623,7 +691,10 @@ static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
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;
- dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
+ if (out_bus_format == MEDIA_BUS_FMT_YUYV8_1X16)
+ dpi->color_format = MTK_DPI_COLOR_FORMAT_YCBCR_422;
+ else
+ dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB;
return 0;
}
@@ -659,6 +730,7 @@ static void mtk_dpi_bridge_enable(struct drm_bridge *bridge)
mtk_dpi_power_on(dpi);
mtk_dpi_set_display_mode(dpi, &dpi->mode);
+ mtk_dpi_enable(dpi);
}
static enum drm_mode_status
@@ -782,6 +854,16 @@ static unsigned int mt8183_calculate_factor(int clock)
return 2;
}
+static unsigned int mt8195_dpintf_calculate_factor(int clock)
+{
+ if (clock < 70000)
+ return 4;
+ else if (clock < 200000)
+ return 2;
+ else
+ return 1;
+}
+
static const u32 mt8173_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_1X24,
};
@@ -791,12 +873,26 @@ static const u32 mt8183_output_fmts[] = {
MEDIA_BUS_FMT_RGB888_2X12_BE,
};
+static const u32 mt8195_output_fmts[] = {
+ MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_YUYV8_1X16,
+};
+
static const struct mtk_dpi_conf mt8173_conf = {
.cal_factor = mt8173_calculate_factor,
.reg_h_fre_con = 0xe0,
.max_clock_khz = 300000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .pixels_per_iter = 1,
+ .is_ck_de_pol = true,
+ .swap_input_support = true,
+ .support_direct_pin = true,
+ .dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
};
static const struct mtk_dpi_conf mt2701_conf = {
@@ -806,6 +902,15 @@ static const struct mtk_dpi_conf mt2701_conf = {
.max_clock_khz = 150000,
.output_fmts = mt8173_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8173_output_fmts),
+ .pixels_per_iter = 1,
+ .is_ck_de_pol = true,
+ .swap_input_support = true,
+ .support_direct_pin = true,
+ .dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
};
static const struct mtk_dpi_conf mt8183_conf = {
@@ -814,6 +919,15 @@ static const struct mtk_dpi_conf mt8183_conf = {
.max_clock_khz = 100000,
.output_fmts = mt8183_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
+ .pixels_per_iter = 1,
+ .is_ck_de_pol = true,
+ .swap_input_support = true,
+ .support_direct_pin = true,
+ .dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
};
static const struct mtk_dpi_conf mt8192_conf = {
@@ -822,6 +936,29 @@ static const struct mtk_dpi_conf mt8192_conf = {
.max_clock_khz = 150000,
.output_fmts = mt8183_output_fmts,
.num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
+ .pixels_per_iter = 1,
+ .is_ck_de_pol = true,
+ .swap_input_support = true,
+ .support_direct_pin = true,
+ .dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
+};
+
+static const struct mtk_dpi_conf mt8195_dpintf_conf = {
+ .cal_factor = mt8195_dpintf_calculate_factor,
+ .max_clock_khz = 600000,
+ .output_fmts = mt8195_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts),
+ .pixels_per_iter = 4,
+ .input_2pixel = true,
+ .dimension_mask = DPINTF_HPW_MASK,
+ .hvsize_mask = DPINTF_HSIZE_MASK,
+ .channel_swap_shift = DPINTF_CH_SWAP,
+ .yuv422_en_bit = DPINTF_YUV422_EN,
+ .csc_enable_bit = DPINTF_CSC_ENABLE,
};
static int mtk_dpi_probe(struct platform_device *pdev)
@@ -946,6 +1083,9 @@ static const struct of_device_id mtk_dpi_of_ids[] = {
{ .compatible = "mediatek,mt8192-dpi",
.data = &mt8192_conf,
},
+ { .compatible = "mediatek,mt8195-dp-intf",
+ .data = &mt8195_dpintf_conf,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids);
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
index 3a02fabe1662..62bd4931b344 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_regs.h
@@ -40,9 +40,13 @@
#define FAKE_DE_LEVEN BIT(21)
#define FAKE_DE_RODD BIT(22)
#define FAKE_DE_REVEN BIT(23)
+#define DPINTF_YUV422_EN BIT(24)
+#define DPINTF_CSC_ENABLE BIT(26)
+#define DPINTF_INPUT_2P_EN BIT(29)
#define DPI_OUTPUT_SETTING 0x14
#define CH_SWAP 0
+#define DPINTF_CH_SWAP 1
#define CH_SWAP_MASK (0x7 << 0)
#define SWAP_RGB 0x00
#define SWAP_GBR 0x01
@@ -80,8 +84,10 @@
#define DPI_SIZE 0x18
#define HSIZE 0
#define HSIZE_MASK (0x1FFF << 0)
+#define DPINTF_HSIZE_MASK (0xFFFF << 0)
#define VSIZE 16
#define VSIZE_MASK (0x1FFF << 16)
+#define DPINTF_VSIZE_MASK (0xFFFF << 16)
#define DPI_DDR_SETTING 0x1C
#define DDR_EN BIT(0)
@@ -93,24 +99,30 @@
#define DPI_TGEN_HWIDTH 0x20
#define HPW 0
#define HPW_MASK (0xFFF << 0)
+#define DPINTF_HPW_MASK (0xFFFF << 0)
#define DPI_TGEN_HPORCH 0x24
#define HBP 0
#define HBP_MASK (0xFFF << 0)
+#define DPINTF_HBP_MASK (0xFFFF << 0)
#define HFP 16
#define HFP_MASK (0