summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml11
-rw-r--r--Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt62
-rw-r--r--Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml116
-rw-r--r--Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml88
-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
19 files changed, 1423 insertions, 186 deletions
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
index 77ee1b923991..5bb23e97cf33 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
@@ -4,16 +4,16 @@
$id: http://devicetree.org/schemas/display/mediatek/mediatek,dpi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: mediatek DPI Controller Device Tree Bindings
+title: MediaTek DPI and DP_INTF Controller
maintainers:
- CK Hu <ck.hu@mediatek.com>
- Jitao shi <jitao.shi@mediatek.com>
description: |
- The Mediatek DPI function block is a sink of the display subsystem and
- provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a parallel
- output bus.
+ The MediaTek DPI and DP_INTF function blocks are a sink of the display
+ subsystem and provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a
+ parallel output bus.
properties:
compatible:
@@ -24,6 +24,7 @@ properties:
- mediatek,mt8183-dpi
- mediatek,mt8186-dpi
- mediatek,mt8192-dpi
+ - mediatek,mt8195-dp-intf
reg:
maxItems: 1
@@ -55,7 +56,7 @@ properties:
$ref: /schemas/graph.yaml#/properties/port
description:
Output port node. This port should be connected to the input port of an
- attached HDMI or LVDS encoder chip.
+ attached HDMI, LVDS or DisplayPort encoder chip.
required:
- compatible
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt
deleted file mode 100644
index 36b01458f45c..000000000000
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-Mediatek DSI Device
-===================
-
-The Mediatek DSI function block is a sink of the display subsystem and can
-drive up to 4-lane MIPI DSI output. Two DSIs can be synchronized for dual-
-channel output.
-
-Required properties:
-- compatible: "mediatek,<chip>-dsi"
-- the supported chips are mt2701, mt7623, mt8167, mt8173 and mt8183.
-- reg: Physical base address and length of the controller's registers
-- interrupts: The interrupt signal from the function block.
-- clocks: device clocks
- See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
-- clock-names: must contain "engine", "digital", and "hs"
-- phys: phandle link to the MIPI D-PHY controller.
-- phy-names: must contain "dphy"
-- port: Output port node with endpoint definitions as described in
- Documentation/devicetree/bindings/graph.txt. This port should be connected
- to the input port of an attached DSI panel or DSI-to-eDP encoder chip.
-
-Optional properties:
-- resets: list of phandle + reset specifier pair, as described in [1].
-
-[1] Documentation/devicetree/bindings/reset/reset.txt
-
-MIPI TX Configuration Module
-============================
-
-See phy/mediatek,dsi-phy.yaml
-
-Example:
-
-mipi_tx0: mipi-dphy@10215000 {
- compatible = "mediatek,mt8173-mipi-tx";
- reg = <0 0x10215000 0 0x1000>;
- clocks = <&clk26m>;
- clock-output-names = "mipi_tx0_pll";
- #clock-cells = <0>;
- #phy-cells = <0>;
- drive-strength-microamp = <4600>;
- nvmem-cells= <&mipi_tx_calibration>;
- nvmem-cell-names = "calibration-data";
-};
-
-dsi0: dsi@1401b000 {
- compatible = "mediatek,mt8173-dsi";
- reg = <0 0x1401b000 0 0x1000>;
- interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&mmsys MM_DSI0_ENGINE>, <&mmsys MM_DSI0_DIGITAL>,
- <&mipi_tx0>;
- clock-names = "engine", "digital", "hs";
- resets = <&mmsys MT8173_MMSYS_SW0_RST_B_DISP_DSI0>;
- phys = <&mipi_tx0>;
- phy-names = "dphy";
-
- port {
- dsi0_out: endpoint {
- remote-endpoint = <&panel_in>;
- };
- };
-};
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml
new file mode 100644
index 000000000000..b18d6a57c6e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,dsi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek DSI Controller Device Tree Bindings
+
+maintainers:
+ - Chun-Kuang Hu <chunkuang.hu@kernel.org>
+ - Philipp Zabel <p.zabel@pengutronix.de>
+ - Jitao Shi <jitao.shi@mediatek.com>
+ - Xinlei Lee <xinlei.lee@mediatek.com>
+
+description: |
+ The MediaTek DSI function block is a sink of the display subsystem and can
+ drive up to 4-lane MIPI DSI output. Two DSIs can be synchronized for dual-
+ channel output.
+
+allOf:
+ - $ref: /schemas/display/dsi-controller.yaml#
+
+properties:
+ compatible:
+ enum:
+ - mediatek,mt2701-dsi
+ - mediatek,mt7623-dsi
+ - mediatek,mt8167-dsi
+ - mediatek,mt8173-dsi
+ - mediatek,mt8183-dsi
+ - mediatek,mt8186-dsi
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Engine Clock
+ - description: Digital Clock
+ - description: HS Clock
+
+ clock-names:
+ items:
+ - const: engine
+ - const: digital
+ - const: hs
+
+ resets:
+ maxItems: 1
+
+ phys:
+ maxItems: 1
+
+ phy-names:
+ items:
+ - const: dphy
+
+ port:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Output port node. This port should be connected to the input
+ port of an attached DSI panel or DSI-to-eDP encoder chip.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - power-domains
+ - clocks
+ - clock-names
+ - phys
+ - phy-names
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/mt8183-clk.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/power/mt8183-power.h>
+ #include <dt-bindings/phy/phy.h>
+ #include <dt-bindings/reset/mt8183-resets.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ dsi0: dsi@14014000 {
+ compatible = "mediatek,mt8183-dsi";
+ reg = <0 0x14014000 0 0x1000>;
+ interrupts = <GIC_SPI 236 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&spm MT8183_POWER_DOMAIN_DISP>;
+ clocks = <&mmsys CLK_MM_DSI0_MM>,
+ <&mmsys CLK_MM_DSI0_IF>,
+ <&mipi_tx0>;
+ clock-names = "engine", "digital", "hs";
+ resets = <&mmsys MT8183_MMSYS_SW0_RST_B_DISP_DSI0>;
+ phys = <&mipi_tx0>;
+ phy-names = "dphy";
+ port {
+ dsi0_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml
new file mode 100644
index 000000000000..dd12e2ff685c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mdp-rdma.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MDP RDMA
+
+maintainers:
+ - Chun-Kuang Hu <chunkuang.hu@kernel.org>
+ - Philipp Zabel <p.zabel@pengutronix.de>
+
+description:
+ The MediaTek MDP RDMA stands for Read Direct Memory Access.
+ It provides real time data to the back-end panel driver, such as DSI,
+ DPI and DP_INTF.
+ It contains one line buffer to store the sufficient pixel data.
+ RDMA device node must be siblings to the central MMSYS_CONFIG node.
+ For a description of the MMSYS_CONFIG binding, see
+ Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml for details.
+
+properties:
+ compatible:
+ const: mediatek,mt8195-vdo1-rdma
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: RDMA Clock
+
+ iommus:
+ maxItems: 1
+
+ mediatek,gce-client-reg:
+ description:
+ The register of display function block to be set by gce. There are 4 arguments,
+ such as gce node, subsys id, offset and register size. The subsys id that is
+ mapping to the register of display function blocks is defined in the gce header
+ include/dt-bindings/gce/<chip>-gce.h of each chips.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ items:
+ - description: phandle of GCE
+ - description: GCE subsys id
+ - description: register offset
+ - description: register size
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - power-domains
+ - clocks
+ - iommus
+ - mediatek,gce-client-reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mt8195-clk.h>
+ #include <dt-bindings/power/mt8195-power.h>
+ #include <dt-bindings/gce/mt8195-gce.h>
+ #include <dt-bindings/memory/mt8195-memory-port.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ rdma@1c104000 {
+ compatible = "mediatek,mt8195-vdo1-rdma";
+ reg = <0 0x1c104000 0 0x1000>;
+ interrupts = <GIC_SPI 495 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&vdosys1 CLK_VDO1_MDP_RDMA0>;
+ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>;
+ iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA0>;
+ mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x4000 0x1000>;
+ };
+ };
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;