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 - Jitao shi 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,-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 = ; - 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 + - Philipp Zabel + - Jitao Shi + - Xinlei Lee + +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 + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + dsi0: dsi@14014000 { + compatible = "mediatek,mt8183-dsi"; + reg = <0 0x14014000 0 0x1000>; + interrupts = ; + 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 + - Philipp Zabel + +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/-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 + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + rdma@1c104000 { + compatible = "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c104000 0 0x1000>; + interrupts = ; + 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 #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 +#include +#include +#include +#include +#include +#include + +#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 #include #include +#include #include #include @@ -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,30 +181,30 @@ 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, struct mtk_dpi_sync_param *sync, 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 (0xFFF << 16) +#define DPINTF_HFP_MASK (0xFFFF << 16) #define DPI_TGEN_VWIDTH 0x28 #define DPI_TGEN_VPORCH 0x2C #define VSYNC_WIDTH_SHIFT 0 #define VSYNC_WIDTH_MASK (0xFFF << 0) +#define DPINTF_VSYNC_WIDTH_MASK (0xFFFF << 0) #define VSYNC_HALF_LINE_SHIFT 16 #define VSYNC_HALF_LINE_MASK BIT(16) #define VSYNC_BACK_PORCH_SHIFT 0 #define VSYNC_BACK_PORCH_MASK (0xFFF << 0) +#define DPINTF_VSYNC_BACK_PORCH_MASK (0xFFFF << 0) #define VSYNC_FRONT_PORCH_SHIFT 16 #define VSYNC_FRONT_PORCH_MASK (0xFFF << 16) +#define DPINTF_VSYNC_FRONT_PORCH_MASK (0xFFFF << 16) #define DPI_BG_HCNTL 0x30 #define BG_RIGHT (0x1FFF << 0) @@ -217,4 +229,10 @@ #define EDGE_SEL_EN BIT(5) #define H_FRE_2N BIT(25) + +#define DPI_MATRIX_SET 0xB4 +#define INT_MATRIX_SEL_MASK GENMASK(4, 0) +#define MATRIX_SEL_RGB_TO_JPEG 0 +#define MATRIX_SEL_RGB_TO_BT601 2 + #endif /* __MTK_DPI_REGS_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 5d7504a72b11..2d72cc5ddaba 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -40,6 +40,12 @@ #define DITHER_LSB_ERR_SHIFT_G(x) (((x) & 0x7) << 12) #define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4) +#define DISP_REG_DSC_CON 0x0000 +#define DSC_EN BIT(0) +#define DSC_DUAL_INOUT BIT(2) +#define DSC_BYPASS BIT(4) +#define DSC_UFOE_SEL BIT(16) + #define DISP_REG_OD_EN 0x0000 #define DISP_REG_OD_CFG 0x0020 #define OD_RELAYMODE BIT(0) @@ -181,6 +187,36 @@ static void mtk_dither_set(struct device *dev, unsigned int bpc, DISP_DITHERING, cmdq_pkt); } +static void mtk_dsc_config(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + /* dsc bypass mode */ + mtk_ddp_write_mask(cmdq_pkt, DSC_BYPASS, &priv->cmdq_reg, priv->regs, + DISP_REG_DSC_CON, DSC_BYPASS); + mtk_ddp_write_mask(cmdq_pkt, DSC_UFOE_SEL, &priv->cmdq_reg, priv->regs, + DISP_REG_DSC_CON, DSC_UFOE_SEL); + mtk_ddp_write_mask(cmdq_pkt, DSC_DUAL_INOUT, &priv->cmdq_reg, priv->regs, + DISP_REG_DSC_CON, DSC_DUAL_INOUT); +} + +static void mtk_dsc_start(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + /* write with mask to reserve the value set in mtk_dsc_config */ + mtk_ddp_write_mask(NULL, DSC_EN, &priv->cmdq_reg, priv->regs, DISP_REG_DSC_CON, DSC_EN); +} + +static void mtk_dsc_stop(struct device *dev) +{ + struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); + + writel_relaxed(0x0, priv->regs + DISP_REG_DSC_CON); +} + 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) @@ -270,6 +306,14 @@ static const struct mtk_ddp_comp_funcs ddp_dpi = { .stop = mtk_dpi_stop, }; +static const struct mtk_ddp_comp_funcs ddp_dsc = { + .clk_enable = mtk_ddp_clk_enable, + .clk_disable = mtk_ddp_clk_disable, + .config = mtk_dsc_config, + .start = mtk_dsc_start, + .stop = mtk_dsc_stop, +}; + static const struct mtk_ddp_comp_funcs ddp_dsi = { .start = mtk_dsi_ddp_start, .stop = mtk_dsi_ddp_stop, @@ -284,6 +328,14 @@ static const struct mtk_ddp_comp_funcs ddp_gamma = { .stop = mtk_gamma_stop, }; +static const struct mtk_ddp_comp_funcs ddp_merge = { + .clk_enable = mtk_merge_clk_enable, + .clk_disable = mtk_merge_clk_disable, + .start = mtk_merge_start, + .stop = mtk_merge_stop, + .config = mtk_merge_config, +}; + static const struct mtk_ddp_comp_funcs ddp_od = { .clk_enable = mtk_ddp_clk_enable, .clk_disable = mtk_ddp_clk_disable, @@ -343,7 +395,9 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = { [MTK_DISP_CCORR] = "ccorr", [MTK_DISP_COLOR] = "color", [MTK_DISP_DITHER] = "dither", + [MTK_DISP_DSC] = "dsc", [MTK_DISP_GAMMA] = "gamma", + [MTK_DISP_MERGE] = "merge", [MTK_DISP_MUTEX] = "mutex", [MTK_DISP_OD] = "od", [MTK_DISP_OVL] = "ovl", @@ -353,6 +407,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = { [MTK_DISP_RDMA] = "rdma", [MTK_DISP_UFOE] = "ufoe", [MTK_DISP_WDMA] = "wdma", + [MTK_DP_INTF] = "dp-intf", [MTK_DPI] = "dpi", [MTK_DSI] = "dsi", }; @@ -370,14 +425,24 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_CCORR] = { MTK_DISP_CCORR, 0, &ddp_ccorr }, [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_DITHER0] = { MTK_DISP_DITHER, 0, &ddp_dither }, + [DDP_COMPONENT_DP_INTF0] = { MTK_DP_INTF, 0, &ddp_dpi }, + [DDP_COMPONENT_DP_INTF1] = { MTK_DP_INTF, 1, &ddp_dpi }, [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, &ddp_dpi }, [DDP_COMPONENT_DPI1] = { MTK_DPI, 1, &ddp_dpi }, + [DDP_COMPONENT_DSC0] = { MTK_DISP_DSC, 0, &ddp_dsc }, + [DDP_COMPONENT_DSC1] = { MTK_DISP_DSC, 1, &ddp_dsc }, [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_MERGE0] = { MTK_DISP_MERGE, 0, &ddp_merge }, + [DDP_COMPONENT_MERGE1] = { MTK_DISP_MERGE, 1, &ddp_merge }, + [DDP_COMPONENT_MERGE2] = { MTK_DISP_MERGE, 2, &ddp_merge }, + [DDP_COMPONENT_MERGE3] = { MTK_DISP_MERGE, 3, &ddp_merge }, + [DDP_COMPONENT_MERGE4] = { MTK_DISP_MERGE, 4, &ddp_merge }, + [DDP_COMPONENT_MERGE5] = { MTK_DISP_MERGE, 5, &ddp_merge }, [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, &ddp_ovl }, @@ -480,11 +545,13 @@ int mtk_ddp_comp_init(struct device_node *node, struct mtk_ddp_comp *comp, type == MTK_DISP_CCORR || type == MTK_DISP_COLOR || type == MTK_DISP_GAMMA || + type == MTK_DISP_MERGE || type == MTK_DISP_OVL || type == MTK_DISP_OVL_2L || type == MTK_DISP_PWM || type == MTK_DISP_RDMA || type == MTK_DPI || + type == MTK_DP_INTF || type == MTK_DSI) return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 1cbc6332282d..2d0052c23dcb 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -23,7 +23,9 @@ enum mtk_ddp_comp_type { MTK_DISP_CCORR, MTK_DISP_COLOR, MTK_DISP_DITHER, + MTK_DISP_DSC, MTK_DISP_GAMMA, + MTK_DISP_MERGE, MTK_DISP_MUTEX, MTK_DISP_OD, MTK_DISP_OVL, @@ -34,6 +36,7 @@ enum mtk_ddp_comp_type { MTK_DISP_UFOE, MTK_DISP_WDMA, MTK_DPI, + MTK_DP_INTF, MTK_DSI, MTK_DDP_COMP_TYPE_MAX, }; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 6abe6bcacbdc..0e4c77724b05 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -4,6 +4,8 @@ * Author: YT SHEN */ +#include +#include #include #include #include @@ -116,7 +118,7 @@ static enum mtk_ddp_comp_id mt8167_mtk_ddp_main[] = { DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0, DDP_COMPONENT_GAMMA, - DDP_COMPONENT_DITHER, + DDP_COMPONENT_DITHER0, DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI0, }; @@ -148,7 +150,7 @@ static const enum mtk_ddp_comp_id mt8183_mtk_ddp_main[] = { DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0, DDP_COMPONENT_GAMMA, - DDP_COMPONENT_DITHER, + DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0, }; @@ -166,7 +168,7 @@ static const enum mtk_ddp_comp_id mt8186_mtk_ddp_main[] = { DDP_COMPONENT_AAL0, DDP_COMPONENT_GAMMA, DDP_COMPONENT_POSTMASK0, - DDP_COMPONENT_DITHER, + DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0, }; @@ -185,7 +187,7 @@ static const enum mtk_ddp_comp_id mt8192_mtk_ddp_main[] = { DDP_COMPONENT_AAL0, DDP_COMPONENT_GAMMA, DDP_COMPONENT_POSTMASK0, - DDP_COMPONENT_DITHER, + DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0, }; @@ -195,6 +197,19 @@ static const enum mtk_ddp_comp_id mt8192_mtk_ddp_ext[] = { DDP_COMPONENT_DPI0, }; +static const enum mtk_ddp_comp_id mt8195_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_RDMA0, + DDP_COMPONENT_COLOR0, + DDP_COMPONENT_CCORR, + DDP_COMPONENT_AAL0, + DDP_COMPONENT_GAMMA, + DDP_COMPONENT_DITHER0, + DDP_COMPONENT_DSC0, + DDP_COMPONENT_MERGE0, + DDP_COMPONENT_DP_INTF0, +}; + 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), @@ -203,6 +218,13 @@ static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { .shadow_register = true, }; +static const struct mtk_mmsys_match_data mt2701_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt2701_mmsys_driver_data, + }, +}; + static const struct mtk_mmsys_driver_data mt7623_mmsys_driver_data = { .main_path = mt7623_mtk_ddp_main, .main_len = ARRAY_SIZE(mt7623_mtk_ddp_main), @@ -211,6 +233,13 @@ static const struct mtk_mmsys_driver_data mt7623_mmsys_driver_data = { .shadow_register = true, }; +static const struct mtk_mmsys_match_data mt7623_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt7623_mmsys_driver_data, + }, +}; + static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = { .main_path = mt2712_mtk_ddp_main, .main_len = ARRAY_SIZE(mt2712_mtk_ddp_main), @@ -220,11 +249,25 @@ static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = { .third_len = ARRAY_SIZE(mt2712_mtk_ddp_third), }; +static const struct mtk_mmsys_match_data mt2712_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt2712_mmsys_driver_data, + }, +}; + static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = { .main_path = mt8167_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8167_mtk_ddp_main), }; +static const struct mtk_mmsys_match_data mt8167_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt8167_mmsys_driver_data, + }, +}; + static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { .main_path = mt8173_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8173_mtk_ddp_main), @@ -232,6 +275,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_match_data mt8173_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt8173_mmsys_driver_data, + }, +}; + 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), @@ -239,6 +289,13 @@ static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = { .ext_len = ARRAY_SIZE(mt8183_mtk_ddp_ext), }; +static const struct mtk_mmsys_match_data mt8183_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt8183_mmsys_driver_data, + }, +}; + static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { .main_path = mt8186_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8186_mtk_ddp_main), @@ -246,6 +303,13 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { .ext_len = ARRAY_SIZE(mt8186_mtk_ddp_ext), }; +static const struct mtk_mmsys_match_data mt8186_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt8186_mmsys_driver_data, + }, +}; + static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { .main_path = mt8192_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8192_mtk_ddp_main), @@ -253,6 +317,31 @@ static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { .ext_len = ARRAY_SIZE(mt8192_mtk_ddp_ext), }; +static const struct mtk_mmsys_match_data mt8192_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt8192_mmsys_driver_data, + }, +}; + +static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = { + .io_start = 0x1c01a000, + .main_path = mt8195_mtk_ddp_main, + .main_len = ARRAY_SIZE(mt8195_mtk_ddp_main), +}; + +static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = { + .io_start = 0x1c100000, +}; + +static const struct mtk_mmsys_match_data mt8195_mmsys_match_data = { + .num_drv_data = 1, + .drv_data = { + &mt8195_vdosys0_driver_data, + &mt8195_vdosys1_driver_data, + }, +}; + static int mtk_drm_kms_init(struct drm_device *drm) { struct mtk_drm_private *private = drm->dev_private; @@ -470,12 +559,16 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DISP_DITHER }, { .compatible = "mediatek,mt8183-disp-dither", .data = (void *)MTK_DISP_DITHER }, + { .compatible = "mediatek,mt8195-disp-dsc", + .data = (void *)MTK_DISP_DSC }, { .compatible = "mediatek,mt8167-disp-gamma", .data = (void *)MTK_DISP_GAMMA, }, { .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, }, { .compatible = "mediatek,mt8183-disp-gamma", .data = (void *)MTK_DISP_GAMMA, }, + { .compatible = "mediatek,mt8195-disp-merge", + .data = (void *)MTK_DISP_MERGE }, { .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, { .compatible = "mediatek,mt2712-disp-mutex", @@ -490,6 +583,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DISP_MUTEX }, { .compatible = "mediatek,mt8192-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, + { .compatible = "mediatek,mt8195-disp-mutex", + .data = (void *)MTK_DISP_MUTEX }, { .compatible = "mediatek,mt8173-disp-od", .data = (void *)MTK_DISP_OD }, { .compatible = "mediatek,mt2701-disp-ovl", @@ -522,7 +617,7 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DISP_RDMA }, { .compatible = "mediatek,mt8183-disp-rdma", .data = (void *)MTK_DISP_RDMA }, - { .compatible = "mediatek,mt8192-disp-rdma", + { .compatible = "mediatek,mt8195-disp-rdma", .data = (void *)MTK_DISP_RDMA }, { .compatible = "mediatek,mt8173-disp-ufoe", .data = (void *)MTK_DISP_UFOE }, @@ -538,41 +633,68 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DPI }, { .compatible = "mediatek,mt8192-dpi", .data = (void *)MTK_DPI }, + { .compatible = "mediatek,mt8195-dp-intf", + .data = (void *)MTK_DP_INTF }, { .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,mt8186-dsi", + .data = (void *)MTK_DSI }, { } }; static const struct of_device_id mtk_drm_of_ids[] = { { .compatible = "mediatek,mt2701-mmsys", - .data = &mt2701_mmsys_driver_data}, + .data = &mt2701_mmsys_match_data}, { .compatible = "mediatek,mt7623-mmsys", - .data = &mt7623_mmsys_driver_data}, + .data = &mt7623_mmsys_match_data}, { .compatible = "mediatek,mt2712-mmsys", - .data = &mt2712_mmsys_driver_data}, + .data = &mt2712_mmsys_match_data}, { .compatible = "mediatek,mt8167-mmsys", - .data = &mt8167_mmsys_driver_data}, + .data = &mt8167_mmsys_match_data}, { .compatible = "mediatek,mt8173-mmsys", - .data = &mt8173_mmsys_driver_data}, + .data = &mt8173_mmsys_match_data}, { .compatible = "mediatek,mt8183-mmsys", - .data = &mt8183_mmsys_driver_data}, + .data = &mt8183_mmsys_match_data}, { .compatible = "mediatek,mt8186-mmsys", - .data = &mt8186_mmsys_driver_data}, + .data = &mt8186_mmsys_match_data}, { .compatible = "mediatek,mt8192-mmsys", - .data = &mt8192_mmsys_driver_data}, + .data = &mt8192_mmsys_match_data}, + { .compatible = "mediatek,mt8195-mmsys", + .data = &mt8195_mmsys_match_data}, { } }; MODULE_DEVICE_TABLE(of, mtk_drm_of_ids); +static int mtk_drm_find_match_data(struct device *dev, + const struct mtk_mmsys_match_data *match_data) +{ + int i; + struct platform_device *pdev = of_find_device_by_node(dev->parent->of_node); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get parent resource\n"); + return -EINVAL; + } + + for (i = 0; i < match_data->num_drv_data; i++) + if (match_data->drv_data[i]->io_start == res->start) + return i; + + return -EINVAL; +} + static int mtk_drm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *phandle = dev->parent->of_node; const struct of_device_id *of_id; + const struct mtk_mmsys_match_data *match_data; struct mtk_drm_private *private; struct device_node *node; struct component_match *match = NULL; @@ -593,7 +715,19 @@ static int mtk_drm_probe(struct platform_device *pdev) if (!of_id) return -ENODEV; - private->data = of_id->data; + match_data = of_id->data; + if (match_data->num_drv_data > 1) { + /* This SoC has multiple mmsys channels */ + ret = mtk_drm_find_match_data(dev, match_data); + if (ret < 0) { + dev_err(dev, "Couldn't get match driver data\n"); + return ret; + } + private->data = match_data->drv_data[ret]; + } else { + dev_dbg(dev, "Using single mmsys channel\n"); + private->data = match_data->drv_data[0]; + } /* Iterate over sibling DISP function blocks */ for_each_child_of_node(phandle->parent, node) { @@ -628,7 +762,7 @@ static int mtk_drm_probe(struct platform_device *pdev) private->comp_node[comp_id] = of_node_get(node); /* - * Currently only the AAL, CCORR, COLOR, GAMMA, OVL, RDMA, DSI, and DPI + * Currently only the AAL, CCORR, COLOR, GAMMA, MERGE, OVL, RDMA, DSI, and DPI * blocks have separate component platform drivers and initialize their own * DDP component structure. The others are initialized here. */ @@ -636,9 +770,11 @@ static int mtk_drm_probe(struct platform_device *pdev) comp_type == MTK_DISP_CCORR || comp_type == MTK_DISP_COLOR || comp_type == MTK_DISP_GAMMA || + comp_type == MTK_DISP_MERGE || comp_type == MTK_DISP_OVL || comp_type == MTK_DISP_OVL_2L || comp_type == MTK_DISP_RDMA || + comp_type == MTK_DP_INTF || comp_type == MTK_DPI || comp_type == MTK_DSI) { dev_info(dev, "Adding component match for %pOF\n", @@ -693,8 +829,7 @@ static int mtk_drm_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int mtk_drm_sys_suspend(struct device *dev) +static int mtk_drm_sys_prepare(struct device *dev) { struct mtk_drm_private *private = dev_get_drvdata(dev); struct drm_device *drm = private->drm; @@ -705,20 +840,21 @@ static int mtk_drm_sys_suspend(struct device *dev) return ret; } -static int mtk_drm_sys_resume(struct device *dev) +static void mtk_drm_sys_complete(struct device *dev) { struct mtk_drm_private *private = dev_get_drvdata(dev); struct drm_device *drm = private->drm; int ret; ret = drm_mode_config_helper_resume(drm); - - return ret; + if (ret) + dev_err(dev, "Failed to resume\n"); } -#endif -static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend, - mtk_drm_sys_resume); +static const struct dev_pm_ops mtk_drm_pm_ops = { + .prepare = mtk_drm_sys_prepare, + .complete = mtk_drm_sys_complete, +}; static struct platform_driver mtk_drm_platform_driver = { .probe = mtk_drm_probe, @@ -734,11 +870,13 @@ static struct platform_driver * const mtk_drm_drivers[] = { &mtk_disp_ccorr_driver, &mtk_disp_color_driver, &mtk_disp_gamma_driver, + &mtk_disp_merge_driver, &mtk_disp_ovl_driver, &mtk_disp_rdma_driver, &mtk_dpi_driver, &mtk_drm_platform_driver, &mtk_dsi_driver, + &mtk_mdp_rdma_driver, }; static int __init mtk_drm_init(void) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index 3e7d1e6fbe01..7b37b5cf9629 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -21,6 +21,7 @@ struct drm_property; struct regmap; struct mtk_mmsys_driver_data { + const resource_size_t io_start; const enum mtk_ddp_comp_id *main_path; unsigned int main_len; const enum mtk_ddp_comp_id *ext_path; @@ -31,6 +32,11 @@ struct mtk_mmsys_driver_data { bool shadow_register; }; +struct mtk_mmsys_match_data { + unsigned short num_drv_data; + const struct mtk_mmsys_driver_data *drv_data[]; +}; + struct mtk_drm_private { struct drm_device *drm; struct device *dma_dev; @@ -50,9 +56,11 @@ extern struct platform_driver mtk_disp_aal_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_merge_driver; extern struct platform_driver mtk_disp_ovl_driver; extern struct platform_driver mtk_disp_rdma_driver; extern struct platform_driver mtk_dpi_driver; extern struct platform_driver mtk_dsi_driver; +extern struct platform_driver mtk_mdp_rdma_driver; #endif /* MTK_DRM_DRV_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 91f57cbde06b..5c0d9ce69931 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -140,6 +140,7 @@ static void mtk_plane_update_new_state(struct drm_plane_state *new_state, mtk_plane_state->pending.width = drm_rect_width(&new_state->dst); mtk_plane_state->pending.height = drm_rect_height(&new_state->dst); mtk_plane_state->pending.rotation = new_state->rotation; + mtk_plane_state->pending.color_encoding = new_state->color_encoding; } static void mtk_plane_atomic_async_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.h b/drivers/gpu/drm/mediatek/mtk_drm_plane.h index d454bece9535..2d5ec66e3df1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.h @@ -24,6 +24,7 @@ struct mtk_plane_pending_state { bool dirty; bool async_dirty; bool async_config; + enum drm_color_encoding color_encoding; }; struct mtk_plane_state { diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index d9f10a33e6fa..9cc406e1eee1 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -203,6 +203,7 @@ struct mtk_dsi { struct mtk_phy_timing phy_timing; int refcount; bool enabled; + bool lanes_ready; u32 irq_data; wait_queue_head_t irq_wait_queue; const struct mtk_dsi_driver_data *driver_data; @@ -661,18 +662,11 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi) mtk_dsi_reset_engine(dsi); mtk_dsi_phy_timconfig(dsi); - mtk_dsi_rxtx_control(dsi); - usleep_range(30, 100); - mtk_dsi_reset_dphy(dsi); mtk_dsi_ps_control_vact(dsi); mtk_dsi_set_vm_cmd(dsi); mtk_dsi_config_vdo_timing(dsi); mtk_dsi_set_interrupt_enable(dsi); - mtk_dsi_clk_ulp_mode_leave(dsi); - mtk_dsi_lane0_ulp_mode_leave(dsi); - mtk_dsi_clk_hs_mode(dsi, 0); - return 0; err_disable_engine_clk: clk_disable_unprepare(dsi->engine_clk); @@ -691,19 +685,11 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) if (--dsi->refcount != 0) return; - /* - * mtk_dsi_stop() and mtk_dsi_start() is asymmetric, since - * mtk_dsi_stop() should be called after mtk_drm_crtc_atomic_disable(), - * which needs irq for vblank, and mtk_dsi_stop() will disable irq. - * mtk_dsi_start() needs to be called in mtk_output_dsi_enable(), - * after dsi is fully set. - */ - mtk_dsi_stop(dsi); - - mtk_dsi_switch_to_cmd_mode(dsi, VM_DONE_INT_FLAG, 500); mtk_dsi_reset_engine(dsi); mtk_dsi_lane0_ulp_mode_enter(dsi); mtk_dsi_clk_ulp_mode_enter(dsi); + /* set the lane number as 0 to pull down mipi */ + writel(0, dsi->regs + DSI_TXRX_CTRL); mtk_dsi_disable(dsi); @@ -711,21 +697,31 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) clk_disable_unprepare(dsi->digital_clk); phy_power_off(dsi->phy); + + dsi->lanes_ready = false; +} + +static void mtk_dsi_lane_ready(struct mtk_dsi *dsi) +{ + if (!dsi->lanes_ready) { + dsi->lanes_ready = true; + mtk_dsi_rxtx_control(dsi); + usleep_range(30, 100); + mtk_dsi_reset_dphy(dsi); + mtk_dsi_clk_ulp_mode_leave(dsi); + mtk_dsi_lane0_ulp_mode_leave(dsi); + mtk_dsi_clk_hs_mode(dsi, 0); + msleep(20); + /* The reaction time after pulling up the mipi signal for dsi_rx */ + } } static void mtk_output_dsi_enable(struct mtk_dsi *dsi) { - int ret; - if (dsi->enabled) return; - ret = mtk_dsi_poweron(dsi); - if (ret < 0) { - DRM_ERROR("failed to power on dsi\n"); - return; - } - + mtk_dsi_lane_ready(dsi); mtk_dsi_set_mode(dsi); mtk_dsi_clk_hs_mode(dsi, 1); @@ -739,7 +735,16 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi) if (!dsi->enabled) return; - mtk_dsi_poweroff(dsi); + /* + * mtk_dsi_stop() and mtk_dsi_start() is asymmetric, since + * mtk_dsi_stop() should be called after mtk_drm_crtc_atomic_disable(), + * which needs irq for vblank, and mtk_dsi_stop() will disable irq. + * mtk_dsi_start() needs to be called in mtk_output_dsi_enable(), + * after dsi is fully set. + */ + mtk_dsi_stop(dsi); + + mtk_dsi_switch_to_cmd_mode(dsi, VM_DONE_INT_FLAG, 500); dsi->enabled = false; } @@ -763,24 +768,50 @@ static void mtk_dsi_bridge_mode_set(struct drm_bridge *bridge, drm_display_mode_to_videomode(adjusted, &dsi->vm); } -static void mtk_dsi_bridge_disable(struct drm_bridge *bridge) +static void mtk_dsi_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct mtk_dsi *dsi = bridge_to_dsi(bridge); mtk_output_dsi_disable(dsi); } -static void mtk_dsi_bridge_enable(struct drm_bridge *bridge) +static void mtk_dsi_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct mtk_dsi *dsi = bridge_to_dsi(bridge); + if (dsi->refcount == 0) + return; + mtk_output_dsi_enable(dsi); } +static void mtk_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct mtk_dsi *dsi = bridge_to_dsi(bridge); + int ret; + + ret = mtk_dsi_poweron(dsi); + if (ret < 0) + DRM_ERROR("failed to power on dsi\n"); +} + +static void mtk_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct mtk_dsi *dsi = bridge_to_dsi(bridge); + + mtk_dsi_poweroff(dsi); +} + static const struct drm_bridge_funcs mtk_dsi_bridge_funcs = { .attach = mtk_dsi_bridge_attach, - .disable = mtk_dsi_bridge_disable, - .enable = mtk_dsi_bridge_enable, + .atomic_disable = mtk_dsi_bridge_atomic_disable, + .atomic_enable = mtk_dsi_bridge_atomic_enable, + .atomic_pre_enable = mtk_dsi_bridge_atomic_pre_enable, + .atomic_post_disable = mtk_dsi_bridge_atomic_post_disable, .mode_set = mtk_dsi_bridge_mode_set, }; @@ -1000,6 +1031,8 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host, if (MTK_DSI_HOST_IS_READ(msg->type)) irq_flag |= LPRX_RD_RDY_INT_FLAG; + mtk_dsi_lane_ready(dsi); + ret = mtk_dsi_host_send_cmd(dsi, msg, irq_flag); if (ret) goto restore_dsi_mode; @@ -1166,6 +1199,12 @@ static const struct mtk_dsi_driver_data mt8183_dsi_driver_data = { .has_size_ctl = true, }; +static const struct mtk_dsi_driver_data mt8186_dsi_driver_data = { + .reg_cmdq_off = 0xd00, + .has_shadow_ctl = true, + .has_size_ctl = true, +}; + static const struct of_device_id mtk_dsi_of_match[] = { { .compatible = "mediatek,mt2701-dsi", .data = &mt2701_dsi_driver_data }, @@ -1173,6 +1212,8 @@ static const struct of_device_id mtk_dsi_of_match[] = { .data = &mt8173_dsi_driver_data }, { .compatible = "mediatek,mt8183-dsi", .data = &mt8183_dsi_driver_data }, + { .compatible = "mediatek,mt8186-dsi", + .data = &mt8186_dsi_driver_data }, { }, }; MODULE_DEVICE_TABLE(of, mtk_dsi_of_match); diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c new file mode 100644 index 000000000000..eecfa98ff52e --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_disp_drv.h" +#include "mtk_drm_drv.h" +#include "mtk_mdp_rdma.h" + +#define MDP_RDMA_EN 0x000 +#define FLD_ROT_ENABLE BIT(0) +#define MDP_RDMA_RESET 0x008 +#define MDP_RDMA_CON 0x020 +#define FLD_OUTPUT_10B BIT(5) +#define FLD_SIMPLE_MODE BIT(4) +#define MDP_RDMA_GMCIF_CON 0x028 +#define FLD_COMMAND_DIV BIT(0) +#define FLD_EXT_PREULTRA_EN BIT(3) +#define FLD_RD_REQ_TYPE GENMASK(7, 4) +#define VAL_RD_REQ_TYPE_BURST_8_ACCESS 7 +#define FLD_ULTRA_EN GENMASK(13, 12) +#define VAL_ULTRA_EN_ENABLE 1 +#define FLD_PRE_ULTRA_EN GENMASK(17, 16) +#define VAL_PRE_ULTRA_EN_ENABLE 1 +#define FLD_EXT_ULTRA_EN BIT(18) +#define MDP_RDMA_SRC_CON 0x030 +#define FLD_OUTPUT_ARGB BIT(25) +#define FLD_BIT_NUMBER GENMASK(19, 18) +#define FLD_SWAP BIT(14) +#define FLD_UNIFORM_CONFIG BIT(17) +#define RDMA_INPUT_10BIT BIT(18) +#define FLD_SRC_FORMAT GENMASK(3, 0) +#define MDP_RDMA_COMP_CON 0x038 +#define FLD_AFBC_EN BIT(22) +#define FLD_AFBC_YUV_TRANSFORM BIT(21) +#define FLD_UFBDC_EN BIT(12) +#define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE 0x060 +#define FLD_MF_BKGD_WB GENMASK(22, 0) +#define MDP_RDMA_MF_SRC_SIZE 0x070 +#define FLD_MF_SRC_H GENMASK(30, 16) +#define FLD_MF_SRC_W GENMASK(14, 0) +#define MDP_RDMA_MF_CLIP_SIZE 0x078 +#define FLD_MF_CLIP_H GENMASK(30, 16) +#define FLD_MF_CLIP_W GENMASK(14, 0) +#define MDP_RDMA_SRC_OFFSET_0 0x118 +#define FLD_SRC_OFFSET_0 GENMASK(31, 0) +#define MDP_RDMA_TRANSFORM_0 0x200 +#define FLD_INT_MATRIX_SEL GENMASK(27, 23) +#define FLD_TRANS_EN BIT(16) +#define MDP_RDMA_SRC_BASE_0 0xf00 +#define FLD_SRC_BASE_0 GENMASK(31, 0) + +#define RDMA_CSC_FULL709_TO_RGB 5 +#define RDMA_CSC_BT601_TO_RGB 6 + +enum rdma_format { + RDMA_INPUT_FORMAT_RGB565 = 0, + RDMA_INPUT_FORMAT_RGB888 = 1, + RDMA_INPUT_FORMAT_RGBA8888 = 2, + RDMA_INPUT_FORMAT_ARGB8888 = 3, + RDMA_INPUT_FORMAT_UYVY = 4, + RDMA_INPUT_FORMAT_YUY2 = 5, + RDMA_INPUT_FORMAT_Y8 = 7, + RDMA_INPUT_FORMAT_YV12 = 8, + RDMA_INPUT_FORMAT_UYVY_3PL = 9, + RDMA_INPUT_FORMAT_NV12 = 12, + RDMA_INPUT_FORMAT_UYVY_2PL = 13, + RDMA_INPUT_FORMAT_Y410 = 14 +}; + +struct mtk_mdp_rdma { + void __iomem *regs; + struct clk *clk; + struct cmdq_client_reg cmdq_reg; +}; + +static unsigned int rdma_fmt_convert(unsigned int fmt) +{ + switch (fmt) { + default: + case DRM_FORMAT_RGB565: + return RDMA_INPUT_FORMAT_RGB565; + case DRM_FORMAT_BGR565: + return RDMA_INPUT_FORMAT_RGB565 | FLD_SWAP; + case DRM_FORMAT_RGB888: + return RDMA_INPUT_FORMAT_RGB888; + case DRM_FORMAT_BGR888: + return RDMA_INPUT_FORMAT_RGB888 | FLD_SWAP; + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_RGBA8888: + return RDMA_INPUT_FORMAT_ARGB8888; + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_BGRA8888: + return RDMA_INPUT_FORMAT_ARGB8888 | FLD_SWAP; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + return RDMA_INPUT_FORMAT_RGBA8888; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return RDMA_INPUT_FORMAT_RGBA8888 | FLD_SWAP; + case DRM_FORMAT_ABGR2101010: + return RDMA_INPUT_FORMAT_RGBA8888 | FLD_SWAP | RDMA_INPUT_10BIT; + case DRM_FORMAT_ARGB2101010: + return RDMA_INPUT_FORMAT_RGBA8888 | RDMA_INPUT_10BIT; + case DRM_FORMAT_RGBA1010102: + return RDMA_INPUT_FORMAT_ARGB8888 | FLD_SWAP | RDMA_INPUT_10BIT; + case DRM_FORMAT_BGRA1010102: + return RDMA_INPUT_FORMAT_ARGB8888 | RDMA_INPUT_10BIT; + case DRM_FORMAT_UYVY: + return RDMA_INPUT_FORMAT_UYVY; + case DRM_FORMAT_YUYV: + return RDMA_INPUT_FORMAT_YUY2; + } +} + +static unsigned int rdma_color_convert(unsigned int color_encoding) +{ + switch (color_encoding) { + default: + case DRM_COLOR_YCBCR_BT709: + return RDMA_CSC_FULL709_TO_RGB; + case DRM_COLOR_YCBCR_BT601: + return RDMA_CSC_BT601_TO_RGB; + } +} + +static void mtk_mdp_rdma_fifo_config(struct device *dev, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); + + mtk_ddp_write_mask(cmdq_pkt, FLD_EXT_ULTRA_EN | VAL_PRE_ULTRA_EN_ENABLE << 16 | + VAL_ULTRA_EN_ENABLE << 12 | VAL_RD_REQ_TYPE_BURST_8_ACCESS << 4 | + FLD_EXT_PREULTRA_EN | FLD_COMMAND_DIV, &priv->cmdq_reg, + priv->regs, MDP_RDMA_GMCIF_CON, FLD_EXT_ULTRA_EN | + FLD_PRE_ULTRA_EN | FLD_ULTRA_EN | FLD_RD_REQ_TYPE | + FLD_EXT_PREULTRA_EN | FLD_COMMAND_DIV); +} + +void mtk_mdp_rdma_start(struct device *dev, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); + + mtk_ddp_write_mask(cmdq_pkt, FLD_ROT_ENABLE, &priv->cmdq_reg, + priv->regs, MDP_RDMA_EN, FLD_ROT_ENABLE); +} + +void mtk_mdp_rdma_stop(struct device *dev, struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); + + mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, + priv->regs, MDP_RDMA_EN, FLD_ROT_ENABLE); + mtk_ddp_write(cmdq_pkt, 1, &priv->cmdq_reg, priv->regs, MDP_RDMA_RESET); + mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, MDP_RDMA_RESET); +} + +void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg, + struct cmdq_pkt *cmdq_pkt) +{ + struct mtk_mdp_rdma *priv = dev_get_drvdata(dev); + const struct drm_format_info *fmt_info = drm_format_info(cfg->fmt); + bool csc_enable = fmt_info->is_yuv ? true : false; + unsigned int src_pitch_y = cfg->pitch; + unsigned int offset_y = 0; + + mtk_mdp_rdma_fifo_config(dev, cmdq_pkt); + + mtk_ddp_write_mask(cmdq_pkt, FLD_UNIFORM_CONFIG, &priv->cmdq_reg, priv->regs, + MDP_RDMA_SRC_CON, FLD_UNIFORM_CONFIG); + mtk_ddp_write_mask(cmdq_pkt, rdma_fmt_convert(cfg->fmt), &priv->cmdq_reg, priv->regs, + MDP_RDMA_SRC_CON, FLD_SWAP | FLD_SRC_FORMAT | FLD_BIT_NUMBER); + + if (!csc_enable && fmt_info->has_alpha) + mtk_ddp_write_mask(cmdq_pkt, FLD_OUTPUT_ARGB, &priv->cmdq_reg, + priv->regs, MDP_RDMA_SRC_CON, FLD_OUTPUT_ARGB); + else + mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, + MDP_RDMA_SRC_CON, FLD_OUTPUT_ARGB); + + mtk_ddp_write_mask(cmdq_pkt, cfg->addr0, &priv->cmdq_reg, priv->regs, + MDP_RDMA_SRC_BASE_0, FLD_SRC_BASE_0); + + mtk_ddp_write_mask(cmdq_pkt, src_pitch_y, &priv->cmdq_reg, priv->regs, + MDP_RDMA_MF_BKGD_SIZE_IN_BYTE, FLD_MF_BKGD_WB); + + mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, MDP_RDMA_COMP_CON, + FLD_AFBC_YUV_TRANSFORM | FLD_UFBDC_EN | FLD_AFBC_EN); + mtk_ddp_write_mask(cmdq_pkt, FLD_OUTPUT_10B, &priv->cmdq_reg, priv->regs, + MDP_RDMA_CON, FLD_OUTPUT_10B); + mtk_ddp_write_mask(cmdq_pkt, FLD_SIMPLE_MODE, &priv->cmdq_reg, priv->regs, + MDP_RDMA_CON, FLD_SIMPLE_MODE); + if (csc_enable) + mtk_ddp_write_mask(cmdq_pkt, rdma_color_convert(cfg->color_encoding) << 23, + &priv->cmdq_reg, priv->regs, MDP_RDMA_TRANSFORM_0, + FLD_INT_MATRIX_SEL); + mtk_ddp_write_mask(cmdq_pkt, csc_enable << 16, &priv->cmdq_reg, priv->regs, + MDP_RDMA_TRANSFORM_0, FLD_TRANS_EN); + + offset_y = cfg->x_left * fmt_info->cpp[0] + cfg->y_top * src_pitch_y; + + mtk_ddp_write_mask(cmdq_pkt, offset_y, &priv->cmdq_reg, priv->regs, + MDP_RDMA_SRC_OFFSET_0, FLD_SRC_OFFSET_0); + mtk_ddp_write_mask(cmdq_pkt, cfg->width, &priv->cmdq_reg, priv->regs, + MDP_RDMA_MF_SRC_SIZE, FLD_MF_SRC_W); + mtk_ddp_write_mask(cmdq_pkt, cfg->height << 16, &priv->cmdq_reg, priv->regs, + MDP_RDMA_MF_SRC_SIZE, FLD_MF_SRC_H); + mtk_ddp_write_mask(cmdq_pkt, cfg->width, &priv->cmdq_reg, priv->regs, + MDP_RDMA_MF_CLIP_SIZE, FLD_MF_CLIP_W); + mtk_ddp_write_mask(cmdq_pkt, cfg->height << 16, &priv->cmdq_reg, priv->regs, + MDP_RDMA_MF_CLIP_SIZE, FLD_MF_CLIP_H); +} + +int mtk_mdp_rdma_clk_enable(struct device *dev) +{ + struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev); + + clk_prepare_enable(rdma->clk); + return 0; +} + +void mtk_mdp_rdma_clk_disable(struct device *dev) +{ + struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev); + + clk_disable_unprepare(rdma->clk); +} + +static int mtk_mdp_rdma_bind(struct device *dev, struct device *master, + void *data) +{ + return 0; +} + +static void mtk_mdp_rdma_unbind(struct device *dev, struct device *master, + void *data) +{ +} + +static const struct component_ops mtk_mdp_rdma_component_ops = { + .bind = mtk_mdp_rdma_bind, + .unbind = mtk_mdp_rdma_unbind, +}; + +static int mtk_mdp_rdma_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct mtk_mdp_rdma *priv; + int ret = 0; + + 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 rdma\n"); + return PTR_ERR(priv->regs); + } + + 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); + } + +#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 + platform_set_drvdata(pdev, priv); + + pm_runtime_enable(dev); + + ret = component_add(dev, &mtk_mdp_rdma_component_ops); + if (ret != 0) { + pm_runtime_disable(dev); + dev_err(dev, "Failed to add component: %d\n", ret); + } + return ret; +} + +static int mtk_mdp_rdma_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &mtk_mdp_rdma_component_ops); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static const struct of_device_id mtk_mdp_rdma_driver_dt_match[] = { + { .compatible = "mediatek,mt8195-vdo1-rdma", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_mdp_rdma_driver_dt_match); + +struct platform_driver mtk_mdp_rdma_driver = { + .probe = mtk_mdp_rdma_probe, + .remove = mtk_mdp_rdma_remove, + .driver = { + .name = "mediatek-mdp-rdma", + .owner = THIS_MODULE, + .of_match_table = mtk_mdp_rdma_driver_dt_match, + }, +}; diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.h b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.h new file mode 100644 index 000000000000..9943ee3aac31 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MTK_MDP_RDMA_H__ +#define __MTK_MDP_RDMA_H__ + +struct mtk_mdp_rdma_cfg { + unsigned int pitch; + unsigned int addr0; + unsigned int width; + unsigned int height; + unsigned int x_left; + unsigned int y_top; + int fmt; + int color_encoding; +}; + +#endif // __MTK_MDP_RDMA_H__