Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'mediatek-drm-2016-05-09' of git://git.pengutronix.de/git/pza/linux into drm-next

MT8173 DRM support

- device tree binding documentation for all MT8173 display
subsystem components
- basic mediatek-drm driver for MT8173 with two optional,
currently fixed output paths:
- DSI encoder support for DSI and (via bridge) eDP panels
- DPI encoder support for output to HDMI bridge
- necessary clock tree changes for the DPI->HDMI path
- export mtk-smi functions used by mediatek-drm

* tag 'mediatek-drm-2016-05-09' of git://git.pengutronix.de/git/pza/linux:
clk: mediatek: remove hdmitx_dig_cts from TOP clocks
clk: mediatek: Add hdmi_ref HDMI PHY PLL reference clock output
clk: mediatek: make dpi0_sel propagate rate changes
drm/mediatek: Add DPI sub driver
drm/mediatek: Add DSI sub driver
drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.
dt-bindings: drm/mediatek: Add Mediatek display subsystem dts binding
memory: mtk-smi: export mtk_smi_larb_get/put

+6098 -5
+203
Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt
··· 1 + Mediatek display subsystem 2 + ========================== 3 + 4 + The Mediatek display subsystem consists of various DISP function blocks in the 5 + MMSYS register space. The connections between them can be configured by output 6 + and input selectors in the MMSYS_CONFIG register space. Pixel clock and start 7 + of frame signal are distributed to the other function blocks by a DISP_MUTEX 8 + function block. 9 + 10 + All DISP device tree nodes must be siblings to the central MMSYS_CONFIG node. 11 + For a description of the MMSYS_CONFIG binding, see 12 + Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt. 13 + 14 + DISP function blocks 15 + ==================== 16 + 17 + A display stream starts at a source function block that reads pixel data from 18 + memory and ends with a sink function block that drives pixels on a display 19 + interface, or writes pixels back to memory. All DISP function blocks have 20 + their own register space, interrupt, and clock gate. The blocks that can 21 + access memory additionally have to list the IOMMU and local arbiter they are 22 + connected to. 23 + 24 + For a description of the display interface sink function blocks, see 25 + Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt and 26 + Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.txt. 27 + 28 + Required properties (all function blocks): 29 + - compatible: "mediatek,<chip>-disp-<function>", one of 30 + "mediatek,<chip>-disp-ovl" - overlay (4 layers, blending, csc) 31 + "mediatek,<chip>-disp-rdma" - read DMA / line buffer 32 + "mediatek,<chip>-disp-wdma" - write DMA 33 + "mediatek,<chip>-disp-color" - color processor 34 + "mediatek,<chip>-disp-aal" - adaptive ambient light controller 35 + "mediatek,<chip>-disp-gamma" - gamma correction 36 + "mediatek,<chip>-disp-merge" - merge streams from two RDMA sources 37 + "mediatek,<chip>-disp-split" - split stream to two encoders 38 + "mediatek,<chip>-disp-ufoe" - data compression engine 39 + "mediatek,<chip>-dsi" - DSI controller, see mediatek,dsi.txt 40 + "mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt 41 + "mediatek,<chip>-disp-mutex" - display mutex 42 + "mediatek,<chip>-disp-od" - overdrive 43 + - reg: Physical base address and length of the function block register space 44 + - interrupts: The interrupt signal from the function block (required, except for 45 + merge and split function blocks). 46 + - clocks: device clocks 47 + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. 48 + For most function blocks this is just a single clock input. Only the DSI and 49 + DPI controller nodes have multiple clock inputs. These are documented in 50 + mediatek,dsi.txt and mediatek,dpi.txt, respectively. 51 + 52 + Required properties (DMA function blocks): 53 + - compatible: Should be one of 54 + "mediatek,<chip>-disp-ovl" 55 + "mediatek,<chip>-disp-rdma" 56 + "mediatek,<chip>-disp-wdma" 57 + - larb: Should contain a phandle pointing to the local arbiter device as defined 58 + in Documentation/devicetree/bindings/soc/mediatek/mediatek,smi-larb.txt 59 + - iommus: Should point to the respective IOMMU block with master port as 60 + argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt 61 + for details. 62 + 63 + Examples: 64 + 65 + mmsys: clock-controller@14000000 { 66 + compatible = "mediatek,mt8173-mmsys", "syscon"; 67 + reg = <0 0x14000000 0 0x1000>; 68 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 69 + #clock-cells = <1>; 70 + }; 71 + 72 + ovl0: ovl@1400c000 { 73 + compatible = "mediatek,mt8173-disp-ovl"; 74 + reg = <0 0x1400c000 0 0x1000>; 75 + interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_LOW>; 76 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 77 + clocks = <&mmsys CLK_MM_DISP_OVL0>; 78 + iommus = <&iommu M4U_PORT_DISP_OVL0>; 79 + mediatek,larb = <&larb0>; 80 + }; 81 + 82 + ovl1: ovl@1400d000 { 83 + compatible = "mediatek,mt8173-disp-ovl"; 84 + reg = <0 0x1400d000 0 0x1000>; 85 + interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_LOW>; 86 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 87 + clocks = <&mmsys CLK_MM_DISP_OVL1>; 88 + iommus = <&iommu M4U_PORT_DISP_OVL1>; 89 + mediatek,larb = <&larb4>; 90 + }; 91 + 92 + rdma0: rdma@1400e000 { 93 + compatible = "mediatek,mt8173-disp-rdma"; 94 + reg = <0 0x1400e000 0 0x1000>; 95 + interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_LOW>; 96 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 97 + clocks = <&mmsys CLK_MM_DISP_RDMA0>; 98 + iommus = <&iommu M4U_PORT_DISP_RDMA0>; 99 + mediatek,larb = <&larb0>; 100 + }; 101 + 102 + rdma1: rdma@1400f000 { 103 + compatible = "mediatek,mt8173-disp-rdma"; 104 + reg = <0 0x1400f000 0 0x1000>; 105 + interrupts = <GIC_SPI 183 IRQ_TYPE_LEVEL_LOW>; 106 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 107 + clocks = <&mmsys CLK_MM_DISP_RDMA1>; 108 + iommus = <&iommu M4U_PORT_DISP_RDMA1>; 109 + mediatek,larb = <&larb4>; 110 + }; 111 + 112 + rdma2: rdma@14010000 { 113 + compatible = "mediatek,mt8173-disp-rdma"; 114 + reg = <0 0x14010000 0 0x1000>; 115 + interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_LOW>; 116 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 117 + clocks = <&mmsys CLK_MM_DISP_RDMA2>; 118 + iommus = <&iommu M4U_PORT_DISP_RDMA2>; 119 + mediatek,larb = <&larb4>; 120 + }; 121 + 122 + wdma0: wdma@14011000 { 123 + compatible = "mediatek,mt8173-disp-wdma"; 124 + reg = <0 0x14011000 0 0x1000>; 125 + interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_LOW>; 126 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 127 + clocks = <&mmsys CLK_MM_DISP_WDMA0>; 128 + iommus = <&iommu M4U_PORT_DISP_WDMA0>; 129 + mediatek,larb = <&larb0>; 130 + }; 131 + 132 + wdma1: wdma@14012000 { 133 + compatible = "mediatek,mt8173-disp-wdma"; 134 + reg = <0 0x14012000 0 0x1000>; 135 + interrupts = <GIC_SPI 186 IRQ_TYPE_LEVEL_LOW>; 136 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 137 + clocks = <&mmsys CLK_MM_DISP_WDMA1>; 138 + iommus = <&iommu M4U_PORT_DISP_WDMA1>; 139 + mediatek,larb = <&larb4>; 140 + }; 141 + 142 + color0: color@14013000 { 143 + compatible = "mediatek,mt8173-disp-color"; 144 + reg = <0 0x14013000 0 0x1000>; 145 + interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_LOW>; 146 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 147 + clocks = <&mmsys CLK_MM_DISP_COLOR0>; 148 + }; 149 + 150 + color1: color@14014000 { 151 + compatible = "mediatek,mt8173-disp-color"; 152 + reg = <0 0x14014000 0 0x1000>; 153 + interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_LOW>; 154 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 155 + clocks = <&mmsys CLK_MM_DISP_COLOR1>; 156 + }; 157 + 158 + aal@14015000 { 159 + compatible = "mediatek,mt8173-disp-aal"; 160 + reg = <0 0x14015000 0 0x1000>; 161 + interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_LOW>; 162 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 163 + clocks = <&mmsys CLK_MM_DISP_AAL>; 164 + }; 165 + 166 + gamma@14016000 { 167 + compatible = "mediatek,mt8173-disp-gamma"; 168 + reg = <0 0x14016000 0 0x1000>; 169 + interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_LOW>; 170 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 171 + clocks = <&mmsys CLK_MM_DISP_GAMMA>; 172 + }; 173 + 174 + ufoe@1401a000 { 175 + compatible = "mediatek,mt8173-disp-ufoe"; 176 + reg = <0 0x1401a000 0 0x1000>; 177 + interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_LOW>; 178 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 179 + clocks = <&mmsys CLK_MM_DISP_UFOE>; 180 + }; 181 + 182 + dsi0: dsi@1401b000 { 183 + /* See mediatek,dsi.txt for details */ 184 + }; 185 + 186 + dpi0: dpi@1401d000 { 187 + /* See mediatek,dpi.txt for details */ 188 + }; 189 + 190 + mutex: mutex@14020000 { 191 + compatible = "mediatek,mt8173-disp-mutex"; 192 + reg = <0 0x14020000 0 0x1000>; 193 + interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_LOW>; 194 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 195 + clocks = <&mmsys CLK_MM_MUTEX_32K>; 196 + }; 197 + 198 + od@14023000 { 199 + compatible = "mediatek,mt8173-disp-od"; 200 + reg = <0 0x14023000 0 0x1000>; 201 + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; 202 + clocks = <&mmsys CLK_MM_DISP_OD>; 203 + };
+35
Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.txt
··· 1 + Mediatek DPI Device 2 + =================== 3 + 4 + The Mediatek DPI function block is a sink of the display subsystem and 5 + provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a parallel 6 + output bus. 7 + 8 + Required properties: 9 + - compatible: "mediatek,<chip>-dpi" 10 + - reg: Physical base address and length of the controller's registers 11 + - interrupts: The interrupt signal from the function block. 12 + - clocks: device clocks 13 + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. 14 + - clock-names: must contain "pixel", "engine", and "pll" 15 + - port: Output port node with endpoint definitions as described in 16 + Documentation/devicetree/bindings/graph.txt. This port should be connected 17 + to the input port of an attached HDMI or LVDS encoder chip. 18 + 19 + Example: 20 + 21 + dpi0: dpi@1401d000 { 22 + compatible = "mediatek,mt8173-dpi"; 23 + reg = <0 0x1401d000 0 0x1000>; 24 + interrupts = <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>; 25 + clocks = <&mmsys CLK_MM_DPI_PIXEL>, 26 + <&mmsys CLK_MM_DPI_ENGINE>, 27 + <&apmixedsys CLK_APMIXED_TVDPLL>; 28 + clock-names = "pixel", "engine", "pll"; 29 + 30 + port { 31 + dpi0_out: endpoint { 32 + remote-endpoint = <&hdmi0_in>; 33 + }; 34 + }; 35 + };
+60
Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt
··· 1 + Mediatek DSI Device 2 + =================== 3 + 4 + The Mediatek DSI function block is a sink of the display subsystem and can 5 + drive up to 4-lane MIPI DSI output. Two DSIs can be synchronized for dual- 6 + channel output. 7 + 8 + Required properties: 9 + - compatible: "mediatek,<chip>-dsi" 10 + - reg: Physical base address and length of the controller's registers 11 + - interrupts: The interrupt signal from the function block. 12 + - clocks: device clocks 13 + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. 14 + - clock-names: must contain "engine", "digital", and "hs" 15 + - phys: phandle link to the MIPI D-PHY controller. 16 + - phy-names: must contain "dphy" 17 + - port: Output port node with endpoint definitions as described in 18 + Documentation/devicetree/bindings/graph.txt. This port should be connected 19 + to the input port of an attached DSI panel or DSI-to-eDP encoder chip. 20 + 21 + MIPI TX Configuration Module 22 + ============================ 23 + 24 + The MIPI TX configuration module controls the MIPI D-PHY. 25 + 26 + Required properties: 27 + - compatible: "mediatek,<chip>-mipi-tx" 28 + - reg: Physical base address and length of the controller's registers 29 + - clocks: PLL reference clock 30 + - clock-output-names: name of the output clock line to the DSI encoder 31 + - #clock-cells: must be <0>; 32 + - #phy-cells: must be <0>. 33 + 34 + Example: 35 + 36 + mipi_tx0: mipi-dphy@10215000 { 37 + compatible = "mediatek,mt8173-mipi-tx"; 38 + reg = <0 0x10215000 0 0x1000>; 39 + clocks = <&clk26m>; 40 + clock-output-names = "mipi_tx0_pll"; 41 + #clock-cells = <0>; 42 + #phy-cells = <0>; 43 + }; 44 + 45 + dsi0: dsi@1401b000 { 46 + compatible = "mediatek,mt8173-dsi"; 47 + reg = <0 0x1401b000 0 0x1000>; 48 + interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_LOW>; 49 + clocks = <&mmsys MM_DSI0_ENGINE>, <&mmsys MM_DSI0_DIGITAL>, 50 + <&mipi_tx0>; 51 + clock-names = "engine", "digital", "hs"; 52 + phys = <&mipi_tx0>; 53 + phy-names = "dphy"; 54 + 55 + port { 56 + dsi0_out: endpoint { 57 + remote-endpoint = <&panel_in>; 58 + }; 59 + }; 60 + };
+10 -2
drivers/clk/mediatek/clk-mt8173.c
··· 61 61 FACTOR(CLK_TOP_CLKRTC_INT, "clkrtc_int", "clk26m", 1, 793), 62 62 FACTOR(CLK_TOP_FPC, "fpc_ck", "clk26m", 1, 1), 63 63 64 - FACTOR(CLK_TOP_HDMITX_DIG_CTS, "hdmitx_dig_cts", "tvdpll_445p5m", 1, 3), 65 64 FACTOR(CLK_TOP_HDMITXPLL_D2, "hdmitxpll_d2", "hdmitx_dig_cts", 1, 2), 66 65 FACTOR(CLK_TOP_HDMITXPLL_D3, "hdmitxpll_d3", "hdmitx_dig_cts", 1, 3), 67 66 ··· 557 558 MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, 0x0090, 16, 2, 23), 558 559 MUX_GATE(CLK_TOP_VENC_LT_SEL, "venclt_sel", venc_lt_parents, 0x0090, 24, 4, 31), 559 560 /* CLK_CFG_6 */ 560 - MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x00a0, 0, 3, 7), 561 + /* 562 + * The dpi0_sel clock should not propagate rate changes to its parent 563 + * clock so the dpi driver can have full control over PLL and divider. 564 + */ 565 + MUX_GATE_FLAGS(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x00a0, 0, 3, 7, 0), 561 566 MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x00a0, 8, 2, 15), 562 567 MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", cci400_parents, 0x00a0, 16, 3, 23), 563 568 MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", aud_1_parents, 0x00a0, 24, 2, 31), ··· 1093 1090 1094 1091 clk_data->clks[cku->id] = clk; 1095 1092 } 1093 + 1094 + clk = clk_register_divider(NULL, "hdmi_ref", "tvdpll_594m", 0, 1095 + base + 0x40, 16, 3, CLK_DIVIDER_POWER_OF_TWO, 1096 + NULL); 1097 + clk_data->clks[CLK_APMIXED_HDMI_REF] = clk; 1096 1098 1097 1099 r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 1098 1100 if (r)
+13 -2
drivers/clk/mediatek/clk-mtk.h
··· 83 83 signed char num_parents; 84 84 }; 85 85 86 - #define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) { \ 86 + /* 87 + * In case the rate change propagation to parent clocks is undesirable, 88 + * this macro allows to specify the clock flags manually. 89 + */ 90 + #define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, _gate, _flags) { \ 87 91 .id = _id, \ 88 92 .name = _name, \ 89 93 .mux_reg = _reg, \ ··· 98 94 .divider_shift = -1, \ 99 95 .parent_names = _parents, \ 100 96 .num_parents = ARRAY_SIZE(_parents), \ 101 - .flags = CLK_SET_RATE_PARENT, \ 97 + .flags = _flags, \ 102 98 } 99 + 100 + /* 101 + * Unless necessary, all MUX_GATE clocks propagate rate changes to their 102 + * parent clock by default. 103 + */ 104 + #define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) \ 105 + MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, _gate, CLK_SET_RATE_PARENT) 103 106 104 107 #define MUX(_id, _name, _parents, _reg, _shift, _width) { \ 105 108 .id = _id, \
+2
drivers/gpu/drm/Kconfig
··· 288 288 source "drivers/gpu/drm/arc/Kconfig" 289 289 290 290 source "drivers/gpu/drm/hisilicon/Kconfig" 291 + 292 + source "drivers/gpu/drm/mediatek/Kconfig"
+1
drivers/gpu/drm/Makefile
··· 74 74 obj-$(CONFIG_DRM_TEGRA) += tegra/ 75 75 obj-$(CONFIG_DRM_STI) += sti/ 76 76 obj-$(CONFIG_DRM_IMX) += imx/ 77 + obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ 77 78 obj-y += i2c/ 78 79 obj-y += panel/ 79 80 obj-y += bridge/
+16
drivers/gpu/drm/mediatek/Kconfig
··· 1 + config DRM_MEDIATEK 2 + tristate "DRM Support for Mediatek SoCs" 3 + depends on DRM 4 + depends on ARCH_MEDIATEK || (ARM && COMPILE_TEST) 5 + select DRM_GEM_CMA_HELPER 6 + select DRM_KMS_HELPER 7 + select DRM_MIPI_DSI 8 + select DRM_PANEL 9 + select IOMMU_DMA 10 + select MEMORY 11 + select MTK_SMI 12 + help 13 + Choose this option if you have a Mediatek SoCs. 14 + The module will be called mediatek-drm 15 + This driver provides kernel mode setting and 16 + buffer management to userspace.
+14
drivers/gpu/drm/mediatek/Makefile
··· 1 + mediatek-drm-y := mtk_disp_ovl.o \ 2 + mtk_disp_rdma.o \ 3 + mtk_drm_crtc.o \ 4 + mtk_drm_ddp.o \ 5 + mtk_drm_ddp_comp.o \ 6 + mtk_drm_drv.o \ 7 + mtk_drm_fb.o \ 8 + mtk_drm_gem.o \ 9 + mtk_drm_plane.o \ 10 + mtk_dsi.o \ 11 + mtk_mipi_tx.o \ 12 + mtk_dpi.o 13 + 14 + obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
+302
drivers/gpu/drm/mediatek/mtk_disp_ovl.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <drm/drmP.h> 15 + #include <linux/clk.h> 16 + #include <linux/component.h> 17 + #include <linux/of_device.h> 18 + #include <linux/of_irq.h> 19 + #include <linux/platform_device.h> 20 + 21 + #include "mtk_drm_crtc.h" 22 + #include "mtk_drm_ddp_comp.h" 23 + 24 + #define DISP_REG_OVL_INTEN 0x0004 25 + #define OVL_FME_CPL_INT BIT(1) 26 + #define DISP_REG_OVL_INTSTA 0x0008 27 + #define DISP_REG_OVL_EN 0x000c 28 + #define DISP_REG_OVL_RST 0x0014 29 + #define DISP_REG_OVL_ROI_SIZE 0x0020 30 + #define DISP_REG_OVL_ROI_BGCLR 0x0028 31 + #define DISP_REG_OVL_SRC_CON 0x002c 32 + #define DISP_REG_OVL_CON(n) (0x0030 + 0x20 * (n)) 33 + #define DISP_REG_OVL_SRC_SIZE(n) (0x0038 + 0x20 * (n)) 34 + #define DISP_REG_OVL_OFFSET(n) (0x003c + 0x20 * (n)) 35 + #define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n)) 36 + #define DISP_REG_OVL_RDMA_CTRL(n) (0x00c0 + 0x20 * (n)) 37 + #define DISP_REG_OVL_RDMA_GMC(n) (0x00c8 + 0x20 * (n)) 38 + #define DISP_REG_OVL_ADDR(n) (0x0f40 + 0x20 * (n)) 39 + 40 + #define OVL_RDMA_MEM_GMC 0x40402020 41 + 42 + #define OVL_CON_BYTE_SWAP BIT(24) 43 + #define OVL_CON_CLRFMT_RGB565 (0 << 12) 44 + #define OVL_CON_CLRFMT_RGB888 (1 << 12) 45 + #define OVL_CON_CLRFMT_RGBA8888 (2 << 12) 46 + #define OVL_CON_CLRFMT_ARGB8888 (3 << 12) 47 + #define OVL_CON_AEN BIT(8) 48 + #define OVL_CON_ALPHA 0xff 49 + 50 + /** 51 + * struct mtk_disp_ovl - DISP_OVL driver structure 52 + * @ddp_comp - structure containing type enum and hardware resources 53 + * @crtc - associated crtc to report vblank events to 54 + */ 55 + struct mtk_disp_ovl { 56 + struct mtk_ddp_comp ddp_comp; 57 + struct drm_crtc *crtc; 58 + }; 59 + 60 + static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) 61 + { 62 + struct mtk_disp_ovl *priv = dev_id; 63 + struct mtk_ddp_comp *ovl = &priv->ddp_comp; 64 + 65 + /* Clear frame completion interrupt */ 66 + writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA); 67 + 68 + if (!priv->crtc) 69 + return IRQ_NONE; 70 + 71 + mtk_crtc_ddp_irq(priv->crtc, ovl); 72 + 73 + return IRQ_HANDLED; 74 + } 75 + 76 + static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp, 77 + struct drm_crtc *crtc) 78 + { 79 + struct mtk_disp_ovl *priv = container_of(comp, struct mtk_disp_ovl, 80 + ddp_comp); 81 + 82 + priv->crtc = crtc; 83 + writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN); 84 + } 85 + 86 + static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp) 87 + { 88 + struct mtk_disp_ovl *priv = container_of(comp, struct mtk_disp_ovl, 89 + ddp_comp); 90 + 91 + priv->crtc = NULL; 92 + writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN); 93 + } 94 + 95 + static void mtk_ovl_start(struct mtk_ddp_comp *comp) 96 + { 97 + writel_relaxed(0x1, comp->regs + DISP_REG_OVL_EN); 98 + } 99 + 100 + static void mtk_ovl_stop(struct mtk_ddp_comp *comp) 101 + { 102 + writel_relaxed(0x0, comp->regs + DISP_REG_OVL_EN); 103 + } 104 + 105 + static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w, 106 + unsigned int h, unsigned int vrefresh) 107 + { 108 + if (w != 0 && h != 0) 109 + writel_relaxed(h << 16 | w, comp->regs + DISP_REG_OVL_ROI_SIZE); 110 + writel_relaxed(0x0, comp->regs + DISP_REG_OVL_ROI_BGCLR); 111 + 112 + writel(0x1, comp->regs + DISP_REG_OVL_RST); 113 + writel(0x0, comp->regs + DISP_REG_OVL_RST); 114 + } 115 + 116 + static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx) 117 + { 118 + unsigned int reg; 119 + 120 + writel(0x1, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx)); 121 + writel(OVL_RDMA_MEM_GMC, comp->regs + DISP_REG_OVL_RDMA_GMC(idx)); 122 + 123 + reg = readl(comp->regs + DISP_REG_OVL_SRC_CON); 124 + reg = reg | BIT(idx); 125 + writel(reg, comp->regs + DISP_REG_OVL_SRC_CON); 126 + } 127 + 128 + static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx) 129 + { 130 + unsigned int reg; 131 + 132 + reg = readl(comp->regs + DISP_REG_OVL_SRC_CON); 133 + reg = reg & ~BIT(idx); 134 + writel(reg, comp->regs + DISP_REG_OVL_SRC_CON); 135 + 136 + writel(0x0, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx)); 137 + } 138 + 139 + static unsigned int ovl_fmt_convert(unsigned int fmt) 140 + { 141 + switch (fmt) { 142 + default: 143 + case DRM_FORMAT_RGB565: 144 + return OVL_CON_CLRFMT_RGB565; 145 + case DRM_FORMAT_BGR565: 146 + return OVL_CON_CLRFMT_RGB565 | OVL_CON_BYTE_SWAP; 147 + case DRM_FORMAT_RGB888: 148 + return OVL_CON_CLRFMT_RGB888; 149 + case DRM_FORMAT_BGR888: 150 + return OVL_CON_CLRFMT_RGB888 | OVL_CON_BYTE_SWAP; 151 + case DRM_FORMAT_RGBX8888: 152 + case DRM_FORMAT_RGBA8888: 153 + return OVL_CON_CLRFMT_ARGB8888; 154 + case DRM_FORMAT_BGRX8888: 155 + case DRM_FORMAT_BGRA8888: 156 + return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP; 157 + case DRM_FORMAT_XRGB8888: 158 + case DRM_FORMAT_ARGB8888: 159 + return OVL_CON_CLRFMT_RGBA8888; 160 + case DRM_FORMAT_XBGR8888: 161 + case DRM_FORMAT_ABGR8888: 162 + return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP; 163 + } 164 + } 165 + 166 + static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx, 167 + struct mtk_plane_state *state) 168 + { 169 + struct mtk_plane_pending_state *pending = &state->pending; 170 + unsigned int addr = pending->addr; 171 + unsigned int pitch = pending->pitch & 0xffff; 172 + unsigned int fmt = pending->format; 173 + unsigned int offset = (pending->y << 16) | pending->x; 174 + unsigned int src_size = (pending->height << 16) | pending->width; 175 + unsigned int con; 176 + 177 + if (!pending->enable) 178 + mtk_ovl_layer_off(comp, idx); 179 + 180 + con = ovl_fmt_convert(fmt); 181 + if (idx != 0) 182 + con |= OVL_CON_AEN | OVL_CON_ALPHA; 183 + 184 + writel_relaxed(con, comp->regs + DISP_REG_OVL_CON(idx)); 185 + writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx)); 186 + writel_relaxed(src_size, comp->regs + DISP_REG_OVL_SRC_SIZE(idx)); 187 + writel_relaxed(offset, comp->regs + DISP_REG_OVL_OFFSET(idx)); 188 + writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(idx)); 189 + 190 + if (pending->enable) 191 + mtk_ovl_layer_on(comp, idx); 192 + } 193 + 194 + static const struct mtk_ddp_comp_funcs mtk_disp_ovl_funcs = { 195 + .config = mtk_ovl_config, 196 + .start = mtk_ovl_start, 197 + .stop = mtk_ovl_stop, 198 + .enable_vblank = mtk_ovl_enable_vblank, 199 + .disable_vblank = mtk_ovl_disable_vblank, 200 + .layer_on = mtk_ovl_layer_on, 201 + .layer_off = mtk_ovl_layer_off, 202 + .layer_config = mtk_ovl_layer_config, 203 + }; 204 + 205 + static int mtk_disp_ovl_bind(struct device *dev, struct device *master, 206 + void *data) 207 + { 208 + struct mtk_disp_ovl *priv = dev_get_drvdata(dev); 209 + struct drm_device *drm_dev = data; 210 + int ret; 211 + 212 + ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp); 213 + if (ret < 0) { 214 + dev_err(dev, "Failed to register component %s: %d\n", 215 + dev->of_node->full_name, ret); 216 + return ret; 217 + } 218 + 219 + return 0; 220 + } 221 + 222 + static void mtk_disp_ovl_unbind(struct device *dev, struct device *master, 223 + void *data) 224 + { 225 + struct mtk_disp_ovl *priv = dev_get_drvdata(dev); 226 + struct drm_device *drm_dev = data; 227 + 228 + mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp); 229 + } 230 + 231 + static const struct component_ops mtk_disp_ovl_component_ops = { 232 + .bind = mtk_disp_ovl_bind, 233 + .unbind = mtk_disp_ovl_unbind, 234 + }; 235 + 236 + static int mtk_disp_ovl_probe(struct platform_device *pdev) 237 + { 238 + struct device *dev = &pdev->dev; 239 + struct mtk_disp_ovl *priv; 240 + int comp_id; 241 + int irq; 242 + int ret; 243 + 244 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 245 + if (!priv) 246 + return -ENOMEM; 247 + 248 + irq = platform_get_irq(pdev, 0); 249 + if (irq < 0) 250 + return irq; 251 + 252 + ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler, 253 + IRQF_TRIGGER_NONE, dev_name(dev), priv); 254 + if (ret < 0) { 255 + dev_err(dev, "Failed to request irq %d: %d\n", irq, ret); 256 + return ret; 257 + } 258 + 259 + comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_OVL); 260 + if (comp_id < 0) { 261 + dev_err(dev, "Failed to identify by alias: %d\n", comp_id); 262 + return comp_id; 263 + } 264 + 265 + ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, 266 + &mtk_disp_ovl_funcs); 267 + if (ret) { 268 + dev_err(dev, "Failed to initialize component: %d\n", ret); 269 + return ret; 270 + } 271 + 272 + platform_set_drvdata(pdev, priv); 273 + 274 + ret = component_add(dev, &mtk_disp_ovl_component_ops); 275 + if (ret) 276 + dev_err(dev, "Failed to add component: %d\n", ret); 277 + 278 + return ret; 279 + } 280 + 281 + static int mtk_disp_ovl_remove(struct platform_device *pdev) 282 + { 283 + component_del(&pdev->dev, &mtk_disp_ovl_component_ops); 284 + 285 + return 0; 286 + } 287 + 288 + static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = { 289 + { .compatible = "mediatek,mt8173-disp-ovl", }, 290 + {}, 291 + }; 292 + MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match); 293 + 294 + struct platform_driver mtk_disp_ovl_driver = { 295 + .probe = mtk_disp_ovl_probe, 296 + .remove = mtk_disp_ovl_remove, 297 + .driver = { 298 + .name = "mediatek-disp-ovl", 299 + .owner = THIS_MODULE, 300 + .of_match_table = mtk_disp_ovl_driver_dt_match, 301 + }, 302 + };
+240
drivers/gpu/drm/mediatek/mtk_disp_rdma.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <drm/drmP.h> 15 + #include <linux/clk.h> 16 + #include <linux/component.h> 17 + #include <linux/of_device.h> 18 + #include <linux/of_irq.h> 19 + #include <linux/platform_device.h> 20 + 21 + #include "mtk_drm_crtc.h" 22 + #include "mtk_drm_ddp_comp.h" 23 + 24 + #define DISP_REG_RDMA_INT_ENABLE 0x0000 25 + #define DISP_REG_RDMA_INT_STATUS 0x0004 26 + #define RDMA_TARGET_LINE_INT BIT(5) 27 + #define RDMA_FIFO_UNDERFLOW_INT BIT(4) 28 + #define RDMA_EOF_ABNORMAL_INT BIT(3) 29 + #define RDMA_FRAME_END_INT BIT(2) 30 + #define RDMA_FRAME_START_INT BIT(1) 31 + #define RDMA_REG_UPDATE_INT BIT(0) 32 + #define DISP_REG_RDMA_GLOBAL_CON 0x0010 33 + #define RDMA_ENGINE_EN BIT(0) 34 + #define DISP_REG_RDMA_SIZE_CON_0 0x0014 35 + #define DISP_REG_RDMA_SIZE_CON_1 0x0018 36 + #define DISP_REG_RDMA_TARGET_LINE 0x001c 37 + #define DISP_REG_RDMA_FIFO_CON 0x0040 38 + #define RDMA_FIFO_UNDERFLOW_EN BIT(31) 39 + #define RDMA_FIFO_PSEUDO_SIZE(bytes) (((bytes) / 16) << 16) 40 + #define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16) 41 + 42 + /** 43 + * struct mtk_disp_rdma - DISP_RDMA driver structure 44 + * @ddp_comp - structure containing type enum and hardware resources 45 + * @crtc - associated crtc to report irq events to 46 + */ 47 + struct mtk_disp_rdma { 48 + struct mtk_ddp_comp ddp_comp; 49 + struct drm_crtc *crtc; 50 + }; 51 + 52 + static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id) 53 + { 54 + struct mtk_disp_rdma *priv = dev_id; 55 + struct mtk_ddp_comp *rdma = &priv->ddp_comp; 56 + 57 + /* Clear frame completion interrupt */ 58 + writel(0x0, rdma->regs + DISP_REG_RDMA_INT_STATUS); 59 + 60 + if (!priv->crtc) 61 + return IRQ_NONE; 62 + 63 + mtk_crtc_ddp_irq(priv->crtc, rdma); 64 + 65 + return IRQ_HANDLED; 66 + } 67 + 68 + static void rdma_update_bits(struct mtk_ddp_comp *comp, unsigned int reg, 69 + unsigned int mask, unsigned int val) 70 + { 71 + unsigned int tmp = readl(comp->regs + reg); 72 + 73 + tmp = (tmp & ~mask) | (val & mask); 74 + writel(tmp, comp->regs + reg); 75 + } 76 + 77 + static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp, 78 + struct drm_crtc *crtc) 79 + { 80 + struct mtk_disp_rdma *priv = container_of(comp, struct mtk_disp_rdma, 81 + ddp_comp); 82 + 83 + priv->crtc = crtc; 84 + rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 85 + RDMA_FRAME_END_INT); 86 + } 87 + 88 + static void mtk_rdma_disable_vblank(struct mtk_ddp_comp *comp) 89 + { 90 + struct mtk_disp_rdma *priv = container_of(comp, struct mtk_disp_rdma, 91 + ddp_comp); 92 + 93 + priv->crtc = NULL; 94 + rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0); 95 + } 96 + 97 + static void mtk_rdma_start(struct mtk_ddp_comp *comp) 98 + { 99 + rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 100 + RDMA_ENGINE_EN); 101 + } 102 + 103 + static void mtk_rdma_stop(struct mtk_ddp_comp *comp) 104 + { 105 + rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 0); 106 + } 107 + 108 + static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width, 109 + unsigned int height, unsigned int vrefresh) 110 + { 111 + unsigned int threshold; 112 + unsigned int reg; 113 + 114 + rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_0, 0xfff, width); 115 + rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_1, 0xfffff, height); 116 + 117 + /* 118 + * Enable FIFO underflow since DSI and DPI can't be blocked. 119 + * Keep the FIFO pseudo size reset default of 8 KiB. Set the 120 + * output threshold to 6 microseconds with 7/6 overhead to 121 + * account for blanking, and with a pixel depth of 4 bytes: 122 + */ 123 + threshold = width * height * vrefresh * 4 * 7 / 1000000; 124 + reg = RDMA_FIFO_UNDERFLOW_EN | 125 + RDMA_FIFO_PSEUDO_SIZE(SZ_8K) | 126 + RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold); 127 + writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON); 128 + } 129 + 130 + static const struct mtk_ddp_comp_funcs mtk_disp_rdma_funcs = { 131 + .config = mtk_rdma_config, 132 + .start = mtk_rdma_start, 133 + .stop = mtk_rdma_stop, 134 + .enable_vblank = mtk_rdma_enable_vblank, 135 + .disable_vblank = mtk_rdma_disable_vblank, 136 + }; 137 + 138 + static int mtk_disp_rdma_bind(struct device *dev, struct device *master, 139 + void *data) 140 + { 141 + struct mtk_disp_rdma *priv = dev_get_drvdata(dev); 142 + struct drm_device *drm_dev = data; 143 + int ret; 144 + 145 + ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp); 146 + if (ret < 0) { 147 + dev_err(dev, "Failed to register component %s: %d\n", 148 + dev->of_node->full_name, ret); 149 + return ret; 150 + } 151 + 152 + return 0; 153 + 154 + } 155 + 156 + static void mtk_disp_rdma_unbind(struct device *dev, struct device *master, 157 + void *data) 158 + { 159 + struct mtk_disp_rdma *priv = dev_get_drvdata(dev); 160 + struct drm_device *drm_dev = data; 161 + 162 + mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp); 163 + } 164 + 165 + static const struct component_ops mtk_disp_rdma_component_ops = { 166 + .bind = mtk_disp_rdma_bind, 167 + .unbind = mtk_disp_rdma_unbind, 168 + }; 169 + 170 + static int mtk_disp_rdma_probe(struct platform_device *pdev) 171 + { 172 + struct device *dev = &pdev->dev; 173 + struct mtk_disp_rdma *priv; 174 + int comp_id; 175 + int irq; 176 + int ret; 177 + 178 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 179 + if (!priv) 180 + return -ENOMEM; 181 + 182 + irq = platform_get_irq(pdev, 0); 183 + if (irq < 0) 184 + return irq; 185 + 186 + comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_RDMA); 187 + if (comp_id < 0) { 188 + dev_err(dev, "Failed to identify by alias: %d\n", comp_id); 189 + return comp_id; 190 + } 191 + 192 + ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, 193 + &mtk_disp_rdma_funcs); 194 + if (ret) { 195 + dev_err(dev, "Failed to initialize component: %d\n", ret); 196 + return ret; 197 + } 198 + 199 + /* Disable and clear pending interrupts */ 200 + writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_ENABLE); 201 + writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_STATUS); 202 + 203 + ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler, 204 + IRQF_TRIGGER_NONE, dev_name(dev), priv); 205 + if (ret < 0) { 206 + dev_err(dev, "Failed to request irq %d: %d\n", irq, ret); 207 + return ret; 208 + } 209 + 210 + platform_set_drvdata(pdev, priv); 211 + 212 + ret = component_add(dev, &mtk_disp_rdma_component_ops); 213 + if (ret) 214 + dev_err(dev, "Failed to add component: %d\n", ret); 215 + 216 + return ret; 217 + } 218 + 219 + static int mtk_disp_rdma_remove(struct platform_device *pdev) 220 + { 221 + component_del(&pdev->dev, &mtk_disp_rdma_component_ops); 222 + 223 + return 0; 224 + } 225 + 226 + static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = { 227 + { .compatible = "mediatek,mt8173-disp-rdma", }, 228 + {}, 229 + }; 230 + MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match); 231 + 232 + struct platform_driver mtk_disp_rdma_driver = { 233 + .probe = mtk_disp_rdma_probe, 234 + .remove = mtk_disp_rdma_remove, 235 + .driver = { 236 + .name = "mediatek-disp-rdma", 237 + .owner = THIS_MODULE, 238 + .of_match_table = mtk_disp_rdma_driver_dt_match, 239 + }, 240 + };
+769
drivers/gpu/drm/mediatek/mtk_dpi.c
··· 1 + /* 2 + * Copyright (c) 2014 MediaTek Inc. 3 + * Author: Jie Qiu <jie.qiu@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + #include <drm/drmP.h> 15 + #include <drm/drm_crtc.h> 16 + #include <drm/drm_crtc_helper.h> 17 + #include <linux/kernel.h> 18 + #include <linux/component.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/of.h> 21 + #include <linux/of_graph.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/types.h> 24 + #include <linux/clk.h> 25 + 26 + #include "mtk_dpi_regs.h" 27 + #include "mtk_drm_ddp_comp.h" 28 + 29 + enum mtk_dpi_out_bit_num { 30 + MTK_DPI_OUT_BIT_NUM_8BITS, 31 + MTK_DPI_OUT_BIT_NUM_10BITS, 32 + MTK_DPI_OUT_BIT_NUM_12BITS, 33 + MTK_DPI_OUT_BIT_NUM_16BITS 34 + }; 35 + 36 + enum mtk_dpi_out_yc_map { 37 + MTK_DPI_OUT_YC_MAP_RGB, 38 + MTK_DPI_OUT_YC_MAP_CYCY, 39 + MTK_DPI_OUT_YC_MAP_YCYC, 40 + MTK_DPI_OUT_YC_MAP_CY, 41 + MTK_DPI_OUT_YC_MAP_YC 42 + }; 43 + 44 + enum mtk_dpi_out_channel_swap { 45 + MTK_DPI_OUT_CHANNEL_SWAP_RGB, 46 + MTK_DPI_OUT_CHANNEL_SWAP_GBR, 47 + MTK_DPI_OUT_CHANNEL_SWAP_BRG, 48 + MTK_DPI_OUT_CHANNEL_SWAP_RBG, 49 + MTK_DPI_OUT_CHANNEL_SWAP_GRB, 50 + MTK_DPI_OUT_CHANNEL_SWAP_BGR 51 + }; 52 + 53 + enum mtk_dpi_out_color_format { 54 + MTK_DPI_COLOR_FORMAT_RGB, 55 + MTK_DPI_COLOR_FORMAT_RGB_FULL, 56 + MTK_DPI_COLOR_FORMAT_YCBCR_444, 57 + MTK_DPI_COLOR_FORMAT_YCBCR_422, 58 + MTK_DPI_COLOR_FORMAT_XV_YCC, 59 + MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL, 60 + MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL 61 + }; 62 + 63 + struct mtk_dpi { 64 + struct mtk_ddp_comp ddp_comp; 65 + struct drm_encoder encoder; 66 + void __iomem *regs; 67 + struct device *dev; 68 + struct clk *engine_clk; 69 + struct clk *pixel_clk; 70 + struct clk *tvd_clk; 71 + int irq; 72 + struct drm_display_mode mode; 73 + enum mtk_dpi_out_color_format color_format; 74 + enum mtk_dpi_out_yc_map yc_map; 75 + enum mtk_dpi_out_bit_num bit_num; 76 + enum mtk_dpi_out_channel_swap channel_swap; 77 + bool power_sta; 78 + u8 power_ctl; 79 + }; 80 + 81 + static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e) 82 + { 83 + return container_of(e, struct mtk_dpi, encoder); 84 + } 85 + 86 + enum mtk_dpi_polarity { 87 + MTK_DPI_POLARITY_RISING, 88 + MTK_DPI_POLARITY_FALLING, 89 + }; 90 + 91 + enum mtk_dpi_power_ctl { 92 + DPI_POWER_START = BIT(0), 93 + DPI_POWER_ENABLE = BIT(1), 94 + }; 95 + 96 + struct mtk_dpi_polarities { 97 + enum mtk_dpi_polarity de_pol; 98 + enum mtk_dpi_polarity ck_pol; 99 + enum mtk_dpi_polarity hsync_pol; 100 + enum mtk_dpi_polarity vsync_pol; 101 + }; 102 + 103 + struct mtk_dpi_sync_param { 104 + u32 sync_width; 105 + u32 front_porch; 106 + u32 back_porch; 107 + bool shift_half_line; 108 + }; 109 + 110 + struct mtk_dpi_yc_limit { 111 + u16 y_top; 112 + u16 y_bottom; 113 + u16 c_top; 114 + u16 c_bottom; 115 + }; 116 + 117 + static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask) 118 + { 119 + u32 tmp = readl(dpi->regs + offset) & ~mask; 120 + 121 + tmp |= (val & mask); 122 + writel(tmp, dpi->regs + offset); 123 + } 124 + 125 + static void mtk_dpi_sw_reset(struct mtk_dpi *dpi, bool reset) 126 + { 127 + mtk_dpi_mask(dpi, DPI_RET, reset ? RST : 0, RST); 128 + } 129 + 130 + static void mtk_dpi_enable(struct mtk_dpi *dpi) 131 + { 132 + mtk_dpi_mask(dpi, DPI_EN, EN, EN); 133 + } 134 + 135 + static void mtk_dpi_disable(struct mtk_dpi *dpi) 136 + { 137 + mtk_dpi_mask(dpi, DPI_EN, 0, EN); 138 + } 139 + 140 + static void mtk_dpi_config_hsync(struct mtk_dpi *dpi, 141 + struct mtk_dpi_sync_param *sync) 142 + { 143 + mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH, 144 + sync->sync_width << HPW, HPW_MASK); 145 + mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, 146 + sync->back_porch << HBP, HBP_MASK); 147 + mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->front_porch << HFP, 148 + HFP_MASK); 149 + } 150 + 151 + static void mtk_dpi_config_vsync(struct mtk_dpi *dpi, 152 + struct mtk_dpi_sync_param *sync, 153 + u32 width_addr, u32 porch_addr) 154 + { 155 + mtk_dpi_mask(dpi, width_addr, 156 + sync->sync_width << VSYNC_WIDTH_SHIFT, 157 + VSYNC_WIDTH_MASK); 158 + mtk_dpi_mask(dpi, width_addr, 159 + sync->shift_half_line << VSYNC_HALF_LINE_SHIFT, 160 + VSYNC_HALF_LINE_MASK); 161 + mtk_dpi_mask(dpi, porch_addr, 162 + sync->back_porch << VSYNC_BACK_PORCH_SHIFT, 163 + VSYNC_BACK_PORCH_MASK); 164 + mtk_dpi_mask(dpi, porch_addr, 165 + sync->front_porch << VSYNC_FRONT_PORCH_SHIFT, 166 + VSYNC_FRONT_PORCH_MASK); 167 + } 168 + 169 + static void mtk_dpi_config_vsync_lodd(struct mtk_dpi *dpi, 170 + struct mtk_dpi_sync_param *sync) 171 + { 172 + mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH, DPI_TGEN_VPORCH); 173 + } 174 + 175 + static void mtk_dpi_config_vsync_leven(struct mtk_dpi *dpi, 176 + struct mtk_dpi_sync_param *sync) 177 + { 178 + mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_LEVEN, 179 + DPI_TGEN_VPORCH_LEVEN); 180 + } 181 + 182 + static void mtk_dpi_config_vsync_rodd(struct mtk_dpi *dpi, 183 + struct mtk_dpi_sync_param *sync) 184 + { 185 + mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_RODD, 186 + DPI_TGEN_VPORCH_RODD); 187 + } 188 + 189 + static void mtk_dpi_config_vsync_reven(struct mtk_dpi *dpi, 190 + struct mtk_dpi_sync_param *sync) 191 + { 192 + mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_REVEN, 193 + DPI_TGEN_VPORCH_REVEN); 194 + } 195 + 196 + static void mtk_dpi_config_pol(struct mtk_dpi *dpi, 197 + struct mtk_dpi_polarities *dpi_pol) 198 + { 199 + unsigned int pol; 200 + 201 + pol = (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ? 0 : CK_POL) | 202 + (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ? 0 : DE_POL) | 203 + (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) | 204 + (dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VSYNC_POL); 205 + mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol, 206 + CK_POL | DE_POL | HSYNC_POL | VSYNC_POL); 207 + } 208 + 209 + static void mtk_dpi_config_3d(struct mtk_dpi *dpi, bool en_3d) 210 + { 211 + mtk_dpi_mask(dpi, DPI_CON, en_3d ? TDFP_EN : 0, TDFP_EN); 212 + } 213 + 214 + static void mtk_dpi_config_interface(struct mtk_dpi *dpi, bool inter) 215 + { 216 + mtk_dpi_mask(dpi, DPI_CON, inter ? INTL_EN : 0, INTL_EN); 217 + } 218 + 219 + static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height) 220 + { 221 + mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE, HSIZE_MASK); 222 + mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, VSIZE_MASK); 223 + } 224 + 225 + static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi, 226 + struct mtk_dpi_yc_limit *limit) 227 + { 228 + mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_bottom << Y_LIMINT_BOT, 229 + Y_LIMINT_BOT_MASK); 230 + mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_top << Y_LIMINT_TOP, 231 + Y_LIMINT_TOP_MASK); 232 + mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_bottom << C_LIMIT_BOT, 233 + C_LIMIT_BOT_MASK); 234 + mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_top << C_LIMIT_TOP, 235 + C_LIMIT_TOP_MASK); 236 + } 237 + 238 + static void mtk_dpi_config_bit_num(struct mtk_dpi *dpi, 239 + enum mtk_dpi_out_bit_num num) 240 + { 241 + u32 val; 242 + 243 + switch (num) { 244 + case MTK_DPI_OUT_BIT_NUM_8BITS: 245 + val = OUT_BIT_8; 246 + break; 247 + case MTK_DPI_OUT_BIT_NUM_10BITS: 248 + val = OUT_BIT_10; 249 + break; 250 + case MTK_DPI_OUT_BIT_NUM_12BITS: 251 + val = OUT_BIT_12; 252 + break; 253 + case MTK_DPI_OUT_BIT_NUM_16BITS: 254 + val = OUT_BIT_16; 255 + break; 256 + default: 257 + val = OUT_BIT_8; 258 + break; 259 + } 260 + mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << OUT_BIT, 261 + OUT_BIT_MASK); 262 + } 263 + 264 + static void mtk_dpi_config_yc_map(struct mtk_dpi *dpi, 265 + enum mtk_dpi_out_yc_map map) 266 + { 267 + u32 val; 268 + 269 + switch (map) { 270 + case MTK_DPI_OUT_YC_MAP_RGB: 271 + val = YC_MAP_RGB; 272 + break; 273 + case MTK_DPI_OUT_YC_MAP_CYCY: 274 + val = YC_MAP_CYCY; 275 + break; 276 + case MTK_DPI_OUT_YC_MAP_YCYC: 277 + val = YC_MAP_YCYC; 278 + break; 279 + case MTK_DPI_OUT_YC_MAP_CY: 280 + val = YC_MAP_CY; 281 + break; 282 + case MTK_DPI_OUT_YC_MAP_YC: 283 + val = YC_MAP_YC; 284 + break; 285 + default: 286 + val = YC_MAP_RGB; 287 + break; 288 + } 289 + 290 + mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << YC_MAP, YC_MAP_MASK); 291 + } 292 + 293 + static void mtk_dpi_config_channel_swap(struct mtk_dpi *dpi, 294 + enum mtk_dpi_out_channel_swap swap) 295 + { 296 + u32 val; 297 + 298 + switch (swap) { 299 + case MTK_DPI_OUT_CHANNEL_SWAP_RGB: 300 + val = SWAP_RGB; 301 + break; 302 + case MTK_DPI_OUT_CHANNEL_SWAP_GBR: 303 + val = SWAP_GBR; 304 + break; 305 + case MTK_DPI_OUT_CHANNEL_SWAP_BRG: 306 + val = SWAP_BRG; 307 + break; 308 + case MTK_DPI_OUT_CHANNEL_SWAP_RBG: 309 + val = SWAP_RBG; 310 + break; 311 + case MTK_DPI_OUT_CHANNEL_SWAP_GRB: 312 + val = SWAP_GRB; 313 + break; 314 + case MTK_DPI_OUT_CHANNEL_SWAP_BGR: 315 + val = SWAP_BGR; 316 + break; 317 + default: 318 + val = SWAP_RGB; 319 + break; 320 + } 321 + 322 + mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << CH_SWAP, CH_SWAP_MASK); 323 + } 324 + 325 + static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable) 326 + { 327 + mtk_dpi_mask(dpi, DPI_CON, enable ? YUV422_EN : 0, YUV422_EN); 328 + } 329 + 330 + static void mtk_dpi_config_csc_enable(struct mtk_dpi *dpi, bool enable) 331 + { 332 + mtk_dpi_mask(dpi, DPI_CON, enable ? CSC_ENABLE : 0, CSC_ENABLE); 333 + } 334 + 335 + static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable) 336 + { 337 + mtk_dpi_mask(dpi, DPI_CON, enable ? IN_RB_SWAP : 0, IN_RB_SWAP); 338 + } 339 + 340 + static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) 341 + { 342 + mtk_dpi_mask(dpi, DPI_H_FRE_CON, H_FRE_2N, H_FRE_2N); 343 + } 344 + 345 + static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, 346 + enum mtk_dpi_out_color_format format) 347 + { 348 + if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_444) || 349 + (format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) { 350 + mtk_dpi_config_yuv422_enable(dpi, false); 351 + mtk_dpi_config_csc_enable(dpi, true); 352 + mtk_dpi_config_swap_input(dpi, false); 353 + mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR); 354 + } else if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_422) || 355 + (format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) { 356 + mtk_dpi_config_yuv422_enable(dpi, true); 357 + mtk_dpi_config_csc_enable(dpi, true); 358 + mtk_dpi_config_swap_input(dpi, true); 359 + mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB); 360 + } else { 361 + mtk_dpi_config_yuv422_enable(dpi, false); 362 + mtk_dpi_config_csc_enable(dpi, false); 363 + mtk_dpi_config_swap_input(dpi, false); 364 + mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB); 365 + } 366 + } 367 + 368 + static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) 369 + { 370 + dpi->power_ctl &= ~pctl; 371 + 372 + if ((dpi->power_ctl & DPI_POWER_START) || 373 + (dpi->power_ctl & DPI_POWER_ENABLE)) 374 + return; 375 + 376 + if (!dpi->power_sta) 377 + return; 378 + 379 + mtk_dpi_disable(dpi); 380 + clk_disable_unprepare(dpi->pixel_clk); 381 + clk_disable_unprepare(dpi->engine_clk); 382 + dpi->power_sta = false; 383 + } 384 + 385 + static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) 386 + { 387 + int ret; 388 + 389 + dpi->power_ctl |= pctl; 390 + 391 + if (!(dpi->power_ctl & DPI_POWER_START) && 392 + !(dpi->power_ctl & DPI_POWER_ENABLE)) 393 + return 0; 394 + 395 + if (dpi->power_sta) 396 + return 0; 397 + 398 + ret = clk_prepare_enable(dpi->engine_clk); 399 + if (ret) { 400 + dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret); 401 + goto err_eng; 402 + } 403 + 404 + ret = clk_prepare_enable(dpi->pixel_clk); 405 + if (ret) { 406 + dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret); 407 + goto err_pixel; 408 + } 409 + 410 + mtk_dpi_enable(dpi); 411 + dpi->power_sta = true; 412 + return 0; 413 + 414 + err_pixel: 415 + clk_disable_unprepare(dpi->engine_clk); 416 + err_eng: 417 + dpi->power_ctl &= ~pctl; 418 + return ret; 419 + } 420 + 421 + static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, 422 + struct drm_display_mode *mode) 423 + { 424 + struct mtk_dpi_yc_limit limit; 425 + struct mtk_dpi_polarities dpi_pol; 426 + struct mtk_dpi_sync_param hsync; 427 + struct mtk_dpi_sync_param vsync_lodd = { 0 }; 428 + struct mtk_dpi_sync_param vsync_leven = { 0 }; 429 + struct mtk_dpi_sync_param vsync_rodd = { 0 }; 430 + struct mtk_dpi_sync_param vsync_reven = { 0 }; 431 + unsigned long pix_rate; 432 + unsigned long pll_rate; 433 + unsigned int factor; 434 + 435 + if (!dpi) { 436 + dev_err(dpi->dev, "invalid argument\n"); 437 + return -EINVAL; 438 + } 439 + 440 + pix_rate = 1000UL * mode->clock; 441 + if (mode->clock <= 74000) 442 + factor = 8 * 3; 443 + else 444 + factor = 4 * 3; 445 + pll_rate = pix_rate * factor; 446 + 447 + dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n", 448 + pll_rate, pix_rate); 449 + 450 + clk_set_rate(dpi->tvd_clk, pll_rate); 451 + pll_rate = clk_get_rate(dpi->tvd_clk); 452 + 453 + pix_rate = pll_rate / factor; 454 + clk_set_rate(dpi->pixel_clk, pix_rate); 455 + pix_rate = clk_get_rate(dpi->pixel_clk); 456 + 457 + dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n", 458 + pll_rate, pix_rate); 459 + 460 + limit.c_bottom = 0x0010; 461 + limit.c_top = 0x0FE0; 462 + limit.y_bottom = 0x0010; 463 + limit.y_top = 0x0FE0; 464 + 465 + dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING; 466 + dpi_pol.de_pol = MTK_DPI_POLARITY_RISING; 467 + dpi_pol.hsync_pol = mode->flags & DRM_MODE_FLAG_PHSYNC ? 468 + MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING; 469 + dpi_pol.vsync_pol = mode->flags & DRM_MODE_FLAG_PVSYNC ? 470 + MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING; 471 + 472 + hsync.sync_width = mode->hsync_end - mode->hsync_start; 473 + hsync.back_porch = mode->htotal - mode->hsync_end; 474 + hsync.front_porch = mode->hsync_start - mode->hdisplay; 475 + hsync.shift_half_line = false; 476 + 477 + vsync_lodd.sync_width = mode->vsync_end - mode->vsync_start; 478 + vsync_lodd.back_porch = mode->vtotal - mode->vsync_end; 479 + vsync_lodd.front_porch = mode->vsync_start - mode->vdisplay; 480 + vsync_lodd.shift_half_line = false; 481 + 482 + if (mode->flags & DRM_MODE_FLAG_INTERLACE && 483 + mode->flags & DRM_MODE_FLAG_3D_MASK) { 484 + vsync_leven = vsync_lodd; 485 + vsync_rodd = vsync_lodd; 486 + vsync_reven = vsync_lodd; 487 + vsync_leven.shift_half_line = true; 488 + vsync_reven.shift_half_line = true; 489 + } else if (mode->flags & DRM_MODE_FLAG_INTERLACE && 490 + !(mode->flags & DRM_MODE_FLAG_3D_MASK)) { 491 + vsync_leven = vsync_lodd; 492 + vsync_leven.shift_half_line = true; 493 + } else if (!(mode->flags & DRM_MODE_FLAG_INTERLACE) && 494 + mode->flags & DRM_MODE_FLAG_3D_MASK) { 495 + vsync_rodd = vsync_lodd; 496 + } 497 + mtk_dpi_sw_reset(dpi, true); 498 + mtk_dpi_config_pol(dpi, &dpi_pol); 499 + 500 + mtk_dpi_config_hsync(dpi, &hsync); 501 + mtk_dpi_config_vsync_lodd(dpi, &vsync_lodd); 502 + mtk_dpi_config_vsync_rodd(dpi, &vsync_rodd); 503 + mtk_dpi_config_vsync_leven(dpi, &vsync_leven); 504 + mtk_dpi_config_vsync_reven(dpi, &vsync_reven); 505 + 506 + mtk_dpi_config_3d(dpi, !!(mode->flags & DRM_MODE_FLAG_3D_MASK)); 507 + mtk_dpi_config_interface(dpi, !!(mode->flags & 508 + DRM_MODE_FLAG_INTERLACE)); 509 + if (mode->flags & DRM_MODE_FLAG_INTERLACE) 510 + mtk_dpi_config_fb_size(dpi, mode->hdisplay, mode->vdisplay / 2); 511 + else 512 + mtk_dpi_config_fb_size(dpi, mode->hdisplay, mode->vdisplay); 513 + 514 + mtk_dpi_config_channel_limit(dpi, &limit); 515 + mtk_dpi_config_bit_num(dpi, dpi->bit_num); 516 + mtk_dpi_config_channel_swap(dpi, dpi->channel_swap); 517 + mtk_dpi_config_yc_map(dpi, dpi->yc_map); 518 + mtk_dpi_config_color_format(dpi, dpi->color_format); 519 + mtk_dpi_config_2n_h_fre(dpi); 520 + mtk_dpi_sw_reset(dpi, false); 521 + 522 + return 0; 523 + } 524 + 525 + static void mtk_dpi_encoder_destroy(struct drm_encoder *encoder) 526 + { 527 + drm_encoder_cleanup(encoder); 528 + } 529 + 530 + static const struct drm_encoder_funcs mtk_dpi_encoder_funcs = { 531 + .destroy = mtk_dpi_encoder_destroy, 532 + }; 533 + 534 + static bool mtk_dpi_encoder_mode_fixup(struct drm_encoder *encoder, 535 + const struct drm_display_mode *mode, 536 + struct drm_display_mode *adjusted_mode) 537 + { 538 + return true; 539 + } 540 + 541 + static void mtk_dpi_encoder_mode_set(struct drm_encoder *encoder, 542 + struct drm_display_mode *mode, 543 + struct drm_display_mode *adjusted_mode) 544 + { 545 + struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); 546 + 547 + drm_mode_copy(&dpi->mode, adjusted_mode); 548 + } 549 + 550 + static void mtk_dpi_encoder_disable(struct drm_encoder *encoder) 551 + { 552 + struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); 553 + 554 + mtk_dpi_power_off(dpi, DPI_POWER_ENABLE); 555 + } 556 + 557 + static void mtk_dpi_encoder_enable(struct drm_encoder *encoder) 558 + { 559 + struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); 560 + 561 + mtk_dpi_power_on(dpi, DPI_POWER_ENABLE); 562 + mtk_dpi_set_display_mode(dpi, &dpi->mode); 563 + } 564 + 565 + static int mtk_dpi_atomic_check(struct drm_encoder *encoder, 566 + struct drm_crtc_state *crtc_state, 567 + struct drm_connector_state *conn_state) 568 + { 569 + return 0; 570 + } 571 + 572 + static const struct drm_encoder_helper_funcs mtk_dpi_encoder_helper_funcs = { 573 + .mode_fixup = mtk_dpi_encoder_mode_fixup, 574 + .mode_set = mtk_dpi_encoder_mode_set, 575 + .disable = mtk_dpi_encoder_disable, 576 + .enable = mtk_dpi_encoder_enable, 577 + .atomic_check = mtk_dpi_atomic_check, 578 + }; 579 + 580 + static void mtk_dpi_start(struct mtk_ddp_comp *comp) 581 + { 582 + struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); 583 + 584 + mtk_dpi_power_on(dpi, DPI_POWER_START); 585 + } 586 + 587 + static void mtk_dpi_stop(struct mtk_ddp_comp *comp) 588 + { 589 + struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); 590 + 591 + mtk_dpi_power_off(dpi, DPI_POWER_START); 592 + } 593 + 594 + static const struct mtk_ddp_comp_funcs mtk_dpi_funcs = { 595 + .start = mtk_dpi_start, 596 + .stop = mtk_dpi_stop, 597 + }; 598 + 599 + static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) 600 + { 601 + struct mtk_dpi *dpi = dev_get_drvdata(dev); 602 + struct drm_device *drm_dev = data; 603 + int ret; 604 + 605 + ret = mtk_ddp_comp_register(drm_dev, &dpi->ddp_comp); 606 + if (ret < 0) { 607 + dev_err(dev, "Failed to register component %s: %d\n", 608 + dev->of_node->full_name, ret); 609 + return ret; 610 + } 611 + 612 + ret = drm_encoder_init(drm_dev, &dpi->encoder, &mtk_dpi_encoder_funcs, 613 + DRM_MODE_ENCODER_TMDS, NULL); 614 + if (ret) { 615 + dev_err(dev, "Failed to initialize decoder: %d\n", ret); 616 + goto err_unregister; 617 + } 618 + drm_encoder_helper_add(&dpi->encoder, &mtk_dpi_encoder_helper_funcs); 619 + 620 + /* Currently DPI0 is fixed to be driven by OVL1 */ 621 + dpi->encoder.possible_crtcs = BIT(1); 622 + 623 + dpi->encoder.bridge->encoder = &dpi->encoder; 624 + ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge); 625 + if (ret) { 626 + dev_err(dev, "Failed to attach bridge: %d\n", ret); 627 + goto err_cleanup; 628 + } 629 + 630 + dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS; 631 + dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB; 632 + dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB; 633 + dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB; 634 + 635 + return 0; 636 + 637 + err_cleanup: 638 + drm_encoder_cleanup(&dpi->encoder); 639 + err_unregister: 640 + mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp); 641 + return ret; 642 + } 643 + 644 + static void mtk_dpi_unbind(struct device *dev, struct device *master, 645 + void *data) 646 + { 647 + struct mtk_dpi *dpi = dev_get_drvdata(dev); 648 + struct drm_device *drm_dev = data; 649 + 650 + drm_encoder_cleanup(&dpi->encoder); 651 + mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp); 652 + } 653 + 654 + static const struct component_ops mtk_dpi_component_ops = { 655 + .bind = mtk_dpi_bind, 656 + .unbind = mtk_dpi_unbind, 657 + }; 658 + 659 + static int mtk_dpi_probe(struct platform_device *pdev) 660 + { 661 + struct device *dev = &pdev->dev; 662 + struct mtk_dpi *dpi; 663 + struct resource *mem; 664 + struct device_node *ep, *bridge_node = NULL; 665 + int comp_id; 666 + int ret; 667 + 668 + dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); 669 + if (!dpi) 670 + return -ENOMEM; 671 + 672 + dpi->dev = dev; 673 + 674 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 675 + dpi->regs = devm_ioremap_resource(dev, mem); 676 + if (IS_ERR(dpi->regs)) { 677 + ret = PTR_ERR(dpi->regs); 678 + dev_err(dev, "Failed to ioremap mem resource: %d\n", ret); 679 + return ret; 680 + } 681 + 682 + dpi->engine_clk = devm_clk_get(dev, "engine"); 683 + if (IS_ERR(dpi->engine_clk)) { 684 + ret = PTR_ERR(dpi->engine_clk); 685 + dev_err(dev, "Failed to get engine clock: %d\n", ret); 686 + return ret; 687 + } 688 + 689 + dpi->pixel_clk = devm_clk_get(dev, "pixel"); 690 + if (IS_ERR(dpi->pixel_clk)) { 691 + ret = PTR_ERR(dpi->pixel_clk); 692 + dev_err(dev, "Failed to get pixel clock: %d\n", ret); 693 + return ret; 694 + } 695 + 696 + dpi->tvd_clk = devm_clk_get(dev, "pll"); 697 + if (IS_ERR(dpi->tvd_clk)) { 698 + ret = PTR_ERR(dpi->tvd_clk); 699 + dev_err(dev, "Failed to get tvdpll clock: %d\n", ret); 700 + return ret; 701 + } 702 + 703 + dpi->irq = platform_get_irq(pdev, 0); 704 + if (dpi->irq <= 0) { 705 + dev_err(dev, "Failed to get irq: %d\n", dpi->irq); 706 + return -EINVAL; 707 + } 708 + 709 + ep = of_graph_get_next_endpoint(dev->of_node, NULL); 710 + if (ep) { 711 + bridge_node = of_graph_get_remote_port_parent(ep); 712 + of_node_put(ep); 713 + } 714 + if (!bridge_node) { 715 + dev_err(dev, "Failed to find bridge node\n"); 716 + return -ENODEV; 717 + } 718 + 719 + dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name); 720 + 721 + dpi->encoder.bridge = of_drm_find_bridge(bridge_node); 722 + of_node_put(bridge_node); 723 + if (!dpi->encoder.bridge) 724 + return -EPROBE_DEFER; 725 + 726 + comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI); 727 + if (comp_id < 0) { 728 + dev_err(dev, "Failed to identify by alias: %d\n", comp_id); 729 + return comp_id; 730 + } 731 + 732 + ret = mtk_ddp_comp_init(dev, dev->of_node, &dpi->ddp_comp, comp_id, 733 + &mtk_dpi_funcs); 734 + if (ret) { 735 + dev_err(dev, "Failed to initialize component: %d\n", ret); 736 + return ret; 737 + } 738 + 739 + platform_set_drvdata(pdev, dpi); 740 + 741 + ret = component_add(dev, &mtk_dpi_component_ops); 742 + if (ret) { 743 + dev_err(dev, "Failed to add component: %d\n", ret); 744 + return ret; 745 + } 746 + 747 + return 0; 748 + } 749 + 750 + static int mtk_dpi_remove(struct platform_device *pdev) 751 + { 752 + component_del(&pdev->dev, &mtk_dpi_component_ops); 753 + 754 + return 0; 755 + } 756 + 757 + static const struct of_device_id mtk_dpi_of_ids[] = { 758 + { .compatible = "mediatek,mt8173-dpi", }, 759 + {} 760 + }; 761 + 762 + struct platform_driver mtk_dpi_driver = { 763 + .probe = mtk_dpi_probe, 764 + .remove = mtk_dpi_remove, 765 + .driver = { 766 + .name = "mediatek-dpi", 767 + .of_match_table = mtk_dpi_of_ids, 768 + }, 769 + };
+228
drivers/gpu/drm/mediatek/mtk_dpi_regs.h
··· 1 + /* 2 + * Copyright (c) 2014 MediaTek Inc. 3 + * Author: Jie Qiu <jie.qiu@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + #ifndef __MTK_DPI_REGS_H 15 + #define __MTK_DPI_REGS_H 16 + 17 + #define DPI_EN 0x00 18 + #define EN BIT(0) 19 + 20 + #define DPI_RET 0x04 21 + #define RST BIT(0) 22 + 23 + #define DPI_INTEN 0x08 24 + #define INT_VSYNC_EN BIT(0) 25 + #define INT_VDE_EN BIT(1) 26 + #define INT_UNDERFLOW_EN BIT(2) 27 + 28 + #define DPI_INTSTA 0x0C 29 + #define INT_VSYNC_STA BIT(0) 30 + #define INT_VDE_STA BIT(1) 31 + #define INT_UNDERFLOW_STA BIT(2) 32 + 33 + #define DPI_CON 0x10 34 + #define BG_ENABLE BIT(0) 35 + #define IN_RB_SWAP BIT(1) 36 + #define INTL_EN BIT(2) 37 + #define TDFP_EN BIT(3) 38 + #define CLPF_EN BIT(4) 39 + #define YUV422_EN BIT(5) 40 + #define CSC_ENABLE BIT(6) 41 + #define R601_SEL BIT(7) 42 + #define EMBSYNC_EN BIT(8) 43 + #define VS_LODD_EN BIT(16) 44 + #define VS_LEVEN_EN BIT(17) 45 + #define VS_RODD_EN BIT(18) 46 + #define VS_REVEN BIT(19) 47 + #define FAKE_DE_LODD BIT(20) 48 + #define FAKE_DE_LEVEN BIT(21) 49 + #define FAKE_DE_RODD BIT(22) 50 + #define FAKE_DE_REVEN BIT(23) 51 + 52 + #define DPI_OUTPUT_SETTING 0x14 53 + #define CH_SWAP 0 54 + #define CH_SWAP_MASK (0x7 << 0) 55 + #define SWAP_RGB 0x00 56 + #define SWAP_GBR 0x01 57 + #define SWAP_BRG 0x02 58 + #define SWAP_RBG 0x03 59 + #define SWAP_GRB 0x04 60 + #define SWAP_BGR 0x05 61 + #define BIT_SWAP BIT(3) 62 + #define B_MASK BIT(4) 63 + #define G_MASK BIT(5) 64 + #define R_MASK BIT(6) 65 + #define DE_MASK BIT(8) 66 + #define HS_MASK BIT(9) 67 + #define VS_MASK BIT(10) 68 + #define DE_POL BIT(12) 69 + #define HSYNC_POL BIT(13) 70 + #define VSYNC_POL BIT(14) 71 + #define CK_POL BIT(15) 72 + #define OEN_OFF BIT(16) 73 + #define EDGE_SEL BIT(17) 74 + #define OUT_BIT 18 75 + #define OUT_BIT_MASK (0x3 << 18) 76 + #define OUT_BIT_8 0x00 77 + #define OUT_BIT_10 0x01 78 + #define OUT_BIT_12 0x02 79 + #define OUT_BIT_16 0x03 80 + #define YC_MAP 20 81 + #define YC_MAP_MASK (0x7 << 20) 82 + #define YC_MAP_RGB 0x00 83 + #define YC_MAP_CYCY 0x04 84 + #define YC_MAP_YCYC 0x05 85 + #define YC_MAP_CY 0x06 86 + #define YC_MAP_YC 0x07 87 + 88 + #define DPI_SIZE 0x18 89 + #define HSIZE 0 90 + #define HSIZE_MASK (0x1FFF << 0) 91 + #define VSIZE 16 92 + #define VSIZE_MASK (0x1FFF << 16) 93 + 94 + #define DPI_DDR_SETTING 0x1C 95 + #define DDR_EN BIT(0) 96 + #define DDDR_SEL BIT(1) 97 + #define DDR_4PHASE BIT(2) 98 + #define DDR_WIDTH (0x3 << 4) 99 + #define DDR_PAD_MODE (0x1 << 8) 100 + 101 + #define DPI_TGEN_HWIDTH 0x20 102 + #define HPW 0 103 + #define HPW_MASK (0xFFF << 0) 104 + 105 + #define DPI_TGEN_HPORCH 0x24 106 + #define HBP 0 107 + #define HBP_MASK (0xFFF << 0) 108 + #define HFP 16 109 + #define HFP_MASK (0xFFF << 16) 110 + 111 + #define DPI_TGEN_VWIDTH 0x28 112 + #define DPI_TGEN_VPORCH 0x2C 113 + 114 + #define VSYNC_WIDTH_SHIFT 0 115 + #define VSYNC_WIDTH_MASK (0xFFF << 0) 116 + #define VSYNC_HALF_LINE_SHIFT 16 117 + #define VSYNC_HALF_LINE_MASK BIT(16) 118 + #define VSYNC_BACK_PORCH_SHIFT 0 119 + #define VSYNC_BACK_PORCH_MASK (0xFFF << 0) 120 + #define VSYNC_FRONT_PORCH_SHIFT 16 121 + #define VSYNC_FRONT_PORCH_MASK (0xFFF << 16) 122 + 123 + #define DPI_BG_HCNTL 0x30 124 + #define BG_RIGHT (0x1FFF << 0) 125 + #define BG_LEFT (0x1FFF << 16) 126 + 127 + #define DPI_BG_VCNTL 0x34 128 + #define BG_BOT (0x1FFF << 0) 129 + #define BG_TOP (0x1FFF << 16) 130 + 131 + #define DPI_BG_COLOR 0x38 132 + #define BG_B (0xF << 0) 133 + #define BG_G (0xF << 8) 134 + #define BG_R (0xF << 16) 135 + 136 + #define DPI_FIFO_CTL 0x3C 137 + #define FIFO_VALID_SET (0x1F << 0) 138 + #define FIFO_RST_SEL (0x1 << 8) 139 + 140 + #define DPI_STATUS 0x40 141 + #define VCOUNTER (0x1FFF << 0) 142 + #define DPI_BUSY BIT(16) 143 + #define OUTEN BIT(17) 144 + #define FIELD BIT(20) 145 + #define TDLR BIT(21) 146 + 147 + #define DPI_TMODE 0x44 148 + #define DPI_OEN_ON BIT(0) 149 + 150 + #define DPI_CHECKSUM 0x48 151 + #define DPI_CHECKSUM_MASK (0xFFFFFF << 0) 152 + #define DPI_CHECKSUM_READY BIT(30) 153 + #define DPI_CHECKSUM_EN BIT(31) 154 + 155 + #define DPI_DUMMY 0x50 156 + #define DPI_DUMMY_MASK (0xFFFFFFFF << 0) 157 + 158 + #define DPI_TGEN_VWIDTH_LEVEN 0x68 159 + #define DPI_TGEN_VPORCH_LEVEN 0x6C 160 + #define DPI_TGEN_VWIDTH_RODD 0x70 161 + #define DPI_TGEN_VPORCH_RODD 0x74 162 + #define DPI_TGEN_VWIDTH_REVEN 0x78 163 + #define DPI_TGEN_VPORCH_REVEN 0x7C 164 + 165 + #define DPI_ESAV_VTIMING_LODD 0x80 166 + #define ESAV_VOFST_LODD (0xFFF << 0) 167 + #define ESAV_VWID_LODD (0xFFF << 16) 168 + 169 + #define DPI_ESAV_VTIMING_LEVEN 0x84 170 + #define ESAV_VOFST_LEVEN (0xFFF << 0) 171 + #define ESAV_VWID_LEVEN (0xFFF << 16) 172 + 173 + #define DPI_ESAV_VTIMING_RODD 0x88 174 + #define ESAV_VOFST_RODD (0xFFF << 0) 175 + #define ESAV_VWID_RODD (0xFFF << 16) 176 + 177 + #define DPI_ESAV_VTIMING_REVEN 0x8C 178 + #define ESAV_VOFST_REVEN (0xFFF << 0) 179 + #define ESAV_VWID_REVEN (0xFFF << 16) 180 + 181 + #define DPI_ESAV_FTIMING 0x90 182 + #define ESAV_FOFST_ODD (0xFFF << 0) 183 + #define ESAV_FOFST_EVEN (0xFFF << 16) 184 + 185 + #define DPI_CLPF_SETTING 0x94 186 + #define CLPF_TYPE (0x3 << 0) 187 + #define ROUND_EN BIT(4) 188 + 189 + #define DPI_Y_LIMIT 0x98 190 + #define Y_LIMINT_BOT 0 191 + #define Y_LIMINT_BOT_MASK (0xFFF << 0) 192 + #define Y_LIMINT_TOP 16 193 + #define Y_LIMINT_TOP_MASK (0xFFF << 16) 194 + 195 + #define DPI_C_LIMIT 0x9C 196 + #define C_LIMIT_BOT 0 197 + #define C_LIMIT_BOT_MASK (0xFFF << 0) 198 + #define C_LIMIT_TOP 16 199 + #define C_LIMIT_TOP_MASK (0xFFF << 16) 200 + 201 + #define DPI_YUV422_SETTING 0xA0 202 + #define UV_SWAP BIT(0) 203 + #define CR_DELSEL BIT(4) 204 + #define CB_DELSEL BIT(5) 205 + #define Y_DELSEL BIT(6) 206 + #define DE_DELSEL BIT(7) 207 + 208 + #define DPI_EMBSYNC_SETTING 0xA4 209 + #define EMBSYNC_R_CR_EN BIT(0) 210 + #define EMPSYNC_G_Y_EN BIT(1) 211 + #define EMPSYNC_B_CB_EN BIT(2) 212 + #define ESAV_F_INV BIT(4) 213 + #define ESAV_V_INV BIT(5) 214 + #define ESAV_H_INV BIT(6) 215 + #define ESAV_CODE_MAN BIT(8) 216 + #define VS_OUT_SEL (0x7 << 12) 217 + 218 + #define DPI_ESAV_CODE_SET0 0xA8 219 + #define ESAV_CODE0 (0xFFF << 0) 220 + #define ESAV_CODE1 (0xFFF << 16) 221 + 222 + #define DPI_ESAV_CODE_SET1 0xAC 223 + #define ESAV_CODE2 (0xFFF << 0) 224 + #define ESAV_CODE3_MSB BIT(16) 225 + 226 + #define DPI_H_FRE_CON 0xE0 227 + #define H_FRE_2N BIT(25) 228 + #endif /* __MTK_DPI_REGS_H */
+582
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <asm/barrier.h> 15 + #include <drm/drmP.h> 16 + #include <drm/drm_atomic_helper.h> 17 + #include <drm/drm_crtc_helper.h> 18 + #include <drm/drm_plane_helper.h> 19 + #include <linux/clk.h> 20 + #include <linux/pm_runtime.h> 21 + #include <soc/mediatek/smi.h> 22 + 23 + #include "mtk_drm_drv.h" 24 + #include "mtk_drm_crtc.h" 25 + #include "mtk_drm_ddp.h" 26 + #include "mtk_drm_ddp_comp.h" 27 + #include "mtk_drm_gem.h" 28 + #include "mtk_drm_plane.h" 29 + 30 + /** 31 + * struct mtk_drm_crtc - MediaTek specific crtc structure. 32 + * @base: crtc object. 33 + * @enabled: records whether crtc_enable succeeded 34 + * @planes: array of 4 mtk_drm_plane structures, one for each overlay plane 35 + * @pending_planes: whether any plane has pending changes to be applied 36 + * @config_regs: memory mapped mmsys configuration register space 37 + * @mutex: handle to one of the ten disp_mutex streams 38 + * @ddp_comp_nr: number of components in ddp_comp 39 + * @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc 40 + */ 41 + struct mtk_drm_crtc { 42 + struct drm_crtc base; 43 + bool enabled; 44 + 45 + bool pending_needs_vblank; 46 + struct drm_pending_vblank_event *event; 47 + 48 + struct mtk_drm_plane planes[OVL_LAYER_NR]; 49 + bool pending_planes; 50 + 51 + void __iomem *config_regs; 52 + struct mtk_disp_mutex *mutex; 53 + unsigned int ddp_comp_nr; 54 + struct mtk_ddp_comp **ddp_comp; 55 + }; 56 + 57 + struct mtk_crtc_state { 58 + struct drm_crtc_state base; 59 + 60 + bool pending_config; 61 + unsigned int pending_width; 62 + unsigned int pending_height; 63 + unsigned int pending_vrefresh; 64 + }; 65 + 66 + static inline struct mtk_drm_crtc *to_mtk_crtc(struct drm_crtc *c) 67 + { 68 + return container_of(c, struct mtk_drm_crtc, base); 69 + } 70 + 71 + static inline struct mtk_crtc_state *to_mtk_crtc_state(struct drm_crtc_state *s) 72 + { 73 + return container_of(s, struct mtk_crtc_state, base); 74 + } 75 + 76 + static void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) 77 + { 78 + struct drm_crtc *crtc = &mtk_crtc->base; 79 + unsigned long flags; 80 + 81 + spin_lock_irqsave(&crtc->dev->event_lock, flags); 82 + drm_crtc_send_vblank_event(crtc, mtk_crtc->event); 83 + drm_crtc_vblank_put(crtc); 84 + mtk_crtc->event = NULL; 85 + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 86 + } 87 + 88 + static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) 89 + { 90 + drm_crtc_handle_vblank(&mtk_crtc->base); 91 + if (mtk_crtc->pending_needs_vblank) { 92 + mtk_drm_crtc_finish_page_flip(mtk_crtc); 93 + mtk_crtc->pending_needs_vblank = false; 94 + } 95 + } 96 + 97 + static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) 98 + { 99 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 100 + int i; 101 + 102 + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) 103 + clk_unprepare(mtk_crtc->ddp_comp[i]->clk); 104 + 105 + mtk_disp_mutex_put(mtk_crtc->mutex); 106 + 107 + drm_crtc_cleanup(crtc); 108 + } 109 + 110 + static void mtk_drm_crtc_reset(struct drm_crtc *crtc) 111 + { 112 + struct mtk_crtc_state *state; 113 + 114 + if (crtc->state) { 115 + if (crtc->state->mode_blob) 116 + drm_property_unreference_blob(crtc->state->mode_blob); 117 + 118 + state = to_mtk_crtc_state(crtc->state); 119 + memset(state, 0, sizeof(*state)); 120 + } else { 121 + state = kzalloc(sizeof(*state), GFP_KERNEL); 122 + if (!state) 123 + return; 124 + crtc->state = &state->base; 125 + } 126 + 127 + state->base.crtc = crtc; 128 + } 129 + 130 + static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc) 131 + { 132 + struct mtk_crtc_state *state; 133 + 134 + state = kzalloc(sizeof(*state), GFP_KERNEL); 135 + if (!state) 136 + return NULL; 137 + 138 + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); 139 + 140 + WARN_ON(state->base.crtc != crtc); 141 + state->base.crtc = crtc; 142 + 143 + return &state->base; 144 + } 145 + 146 + static void mtk_drm_crtc_destroy_state(struct drm_crtc *crtc, 147 + struct drm_crtc_state *state) 148 + { 149 + __drm_atomic_helper_crtc_destroy_state(crtc, state); 150 + kfree(to_mtk_crtc_state(state)); 151 + } 152 + 153 + static bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc, 154 + const struct drm_display_mode *mode, 155 + struct drm_display_mode *adjusted_mode) 156 + { 157 + /* Nothing to do here, but this callback is mandatory. */ 158 + return true; 159 + } 160 + 161 + static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) 162 + { 163 + struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state); 164 + 165 + state->pending_width = crtc->mode.hdisplay; 166 + state->pending_height = crtc->mode.vdisplay; 167 + state->pending_vrefresh = crtc->mode.vrefresh; 168 + wmb(); /* Make sure the above parameters are set before update */ 169 + state->pending_config = true; 170 + } 171 + 172 + int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe) 173 + { 174 + struct mtk_drm_private *priv = drm->dev_private; 175 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]); 176 + struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0]; 177 + 178 + mtk_ddp_comp_enable_vblank(ovl, &mtk_crtc->base); 179 + 180 + return 0; 181 + } 182 + 183 + void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe) 184 + { 185 + struct mtk_drm_private *priv = drm->dev_private; 186 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(priv->crtc[pipe]); 187 + struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0]; 188 + 189 + mtk_ddp_comp_disable_vblank(ovl); 190 + } 191 + 192 + static int mtk_crtc_ddp_clk_enable(struct mtk_drm_crtc *mtk_crtc) 193 + { 194 + int ret; 195 + int i; 196 + 197 + DRM_DEBUG_DRIVER("%s\n", __func__); 198 + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 199 + ret = clk_enable(mtk_crtc->ddp_comp[i]->clk); 200 + if (ret) { 201 + DRM_ERROR("Failed to enable clock %d: %d\n", i, ret); 202 + goto err; 203 + } 204 + } 205 + 206 + return 0; 207 + err: 208 + while (--i >= 0) 209 + clk_disable(mtk_crtc->ddp_comp[i]->clk); 210 + return ret; 211 + } 212 + 213 + static void mtk_crtc_ddp_clk_disable(struct mtk_drm_crtc *mtk_crtc) 214 + { 215 + int i; 216 + 217 + DRM_DEBUG_DRIVER("%s\n", __func__); 218 + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) 219 + clk_disable(mtk_crtc->ddp_comp[i]->clk); 220 + } 221 + 222 + static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) 223 + { 224 + struct drm_crtc *crtc = &mtk_crtc->base; 225 + unsigned int width, height, vrefresh; 226 + int ret; 227 + int i; 228 + 229 + DRM_DEBUG_DRIVER("%s\n", __func__); 230 + if (WARN_ON(!crtc->state)) 231 + return -EINVAL; 232 + 233 + width = crtc->state->adjusted_mode.hdisplay; 234 + height = crtc->state->adjusted_mode.vdisplay; 235 + vrefresh = crtc->state->adjusted_mode.vrefresh; 236 + 237 + ret = pm_runtime_get_sync(crtc->dev->dev); 238 + if (ret < 0) { 239 + DRM_ERROR("Failed to enable power domain: %d\n", ret); 240 + return ret; 241 + } 242 + 243 + ret = mtk_disp_mutex_prepare(mtk_crtc->mutex); 244 + if (ret < 0) { 245 + DRM_ERROR("Failed to enable mutex clock: %d\n", ret); 246 + goto err_pm_runtime_put; 247 + } 248 + 249 + ret = mtk_crtc_ddp_clk_enable(mtk_crtc); 250 + if (ret < 0) { 251 + DRM_ERROR("Failed to enable component clocks: %d\n", ret); 252 + goto err_mutex_unprepare; 253 + } 254 + 255 + DRM_DEBUG_DRIVER("mediatek_ddp_ddp_path_setup\n"); 256 + for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { 257 + mtk_ddp_add_comp_to_path(mtk_crtc->config_regs, 258 + mtk_crtc->ddp_comp[i]->id, 259 + mtk_crtc->ddp_comp[i + 1]->id); 260 + mtk_disp_mutex_add_comp(mtk_crtc->mutex, 261 + mtk_crtc->ddp_comp[i]->id); 262 + } 263 + mtk_disp_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); 264 + mtk_disp_mutex_enable(mtk_crtc->mutex); 265 + 266 + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 267 + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i]; 268 + 269 + mtk_ddp_comp_config(comp, width, height, vrefresh); 270 + mtk_ddp_comp_start(comp); 271 + } 272 + 273 + /* Initially configure all planes */ 274 + for (i = 0; i < OVL_LAYER_NR; i++) { 275 + struct drm_plane *plane = &mtk_crtc->planes[i].base; 276 + struct mtk_plane_state *plane_state; 277 + 278 + plane_state = to_mtk_plane_state(plane->state); 279 + mtk_ddp_comp_layer_config(mtk_crtc->ddp_comp[0], i, 280 + plane_state); 281 + } 282 + 283 + return 0; 284 + 285 + err_mutex_unprepare: 286 + mtk_disp_mutex_unprepare(mtk_crtc->mutex); 287 + err_pm_runtime_put: 288 + pm_runtime_put(crtc->dev->dev); 289 + return ret; 290 + } 291 + 292 + static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) 293 + { 294 + struct drm_device *drm = mtk_crtc->base.dev; 295 + int i; 296 + 297 + DRM_DEBUG_DRIVER("%s\n", __func__); 298 + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) 299 + mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]); 300 + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) 301 + mtk_disp_mutex_remove_comp(mtk_crtc->mutex, 302 + mtk_crtc->ddp_comp[i]->id); 303 + mtk_disp_mutex_disable(mtk_crtc->mutex); 304 + for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { 305 + mtk_ddp_remove_comp_from_path(mtk_crtc->config_regs, 306 + mtk_crtc->ddp_comp[i]->id, 307 + mtk_crtc->ddp_comp[i + 1]->id); 308 + mtk_disp_mutex_remove_comp(mtk_crtc->mutex, 309 + mtk_crtc->ddp_comp[i]->id); 310 + } 311 + mtk_disp_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); 312 + mtk_crtc_ddp_clk_disable(mtk_crtc); 313 + mtk_disp_mutex_unprepare(mtk_crtc->mutex); 314 + 315 + pm_runtime_put(drm->dev); 316 + } 317 + 318 + static void mtk_drm_crtc_enable(struct drm_crtc *crtc) 319 + { 320 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 321 + struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0]; 322 + int ret; 323 + 324 + DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); 325 + 326 + ret = mtk_smi_larb_get(ovl->larb_dev); 327 + if (ret) { 328 + DRM_ERROR("Failed to get larb: %d\n", ret); 329 + return; 330 + } 331 + 332 + ret = mtk_crtc_ddp_hw_init(mtk_crtc); 333 + if (ret) { 334 + mtk_smi_larb_put(ovl->larb_dev); 335 + return; 336 + } 337 + 338 + drm_crtc_vblank_on(crtc); 339 + mtk_crtc->enabled = true; 340 + } 341 + 342 + static void mtk_drm_crtc_disable(struct drm_crtc *crtc) 343 + { 344 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 345 + struct mtk_ddp_comp *ovl = mtk_crtc->ddp_comp[0]; 346 + int i; 347 + 348 + DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); 349 + if (!mtk_crtc->enabled) 350 + return; 351 + 352 + /* Set all pending plane state to disabled */ 353 + for (i = 0; i < OVL_LAYER_NR; i++) { 354 + struct drm_plane *plane = &mtk_crtc->planes[i].base; 355 + struct mtk_plane_state *plane_state; 356 + 357 + plane_state = to_mtk_plane_state(plane->state); 358 + plane_state->pending.enable = false; 359 + plane_state->pending.config = true; 360 + } 361 + mtk_crtc->pending_planes = true; 362 + 363 + /* Wait for planes to be disabled */ 364 + drm_crtc_wait_one_vblank(crtc); 365 + 366 + drm_crtc_vblank_off(crtc); 367 + mtk_crtc_ddp_hw_fini(mtk_crtc); 368 + mtk_smi_larb_put(ovl->larb_dev); 369 + 370 + mtk_crtc->enabled = false; 371 + } 372 + 373 + static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc, 374 + struct drm_crtc_state *old_crtc_state) 375 + { 376 + struct mtk_crtc_state *state = to_mtk_crtc_state(crtc->state); 377 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 378 + 379 + if (mtk_crtc->event && state->base.event) 380 + DRM_ERROR("new event while there is still a pending event\n"); 381 + 382 + if (state->base.event) { 383 + state->base.event->pipe = drm_crtc_index(crtc); 384 + WARN_ON(drm_crtc_vblank_get(crtc) != 0); 385 + mtk_crtc->event = state->base.event; 386 + state->base.event = NULL; 387 + } 388 + } 389 + 390 + static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc, 391 + struct drm_crtc_state *old_crtc_state) 392 + { 393 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 394 + unsigned int pending_planes = 0; 395 + int i; 396 + 397 + if (mtk_crtc->event) 398 + mtk_crtc->pending_needs_vblank = true; 399 + for (i = 0; i < OVL_LAYER_NR; i++) { 400 + struct drm_plane *plane = &mtk_crtc->planes[i].base; 401 + struct mtk_plane_state *plane_state; 402 + 403 + plane_state = to_mtk_plane_state(plane->state); 404 + if (plane_state->pending.dirty) { 405 + plane_state->pending.config = true; 406 + plane_state->pending.dirty = false; 407 + pending_planes |= BIT(i); 408 + } 409 + } 410 + if (pending_planes) 411 + mtk_crtc->pending_planes = true; 412 + } 413 + 414 + static const struct drm_crtc_funcs mtk_crtc_funcs = { 415 + .set_config = drm_atomic_helper_set_config, 416 + .page_flip = drm_atomic_helper_page_flip, 417 + .destroy = mtk_drm_crtc_destroy, 418 + .reset = mtk_drm_crtc_reset, 419 + .atomic_duplicate_state = mtk_drm_crtc_duplicate_state, 420 + .atomic_destroy_state = mtk_drm_crtc_destroy_state, 421 + }; 422 + 423 + static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = { 424 + .mode_fixup = mtk_drm_crtc_mode_fixup, 425 + .mode_set_nofb = mtk_drm_crtc_mode_set_nofb, 426 + .enable = mtk_drm_crtc_enable, 427 + .disable = mtk_drm_crtc_disable, 428 + .atomic_begin = mtk_drm_crtc_atomic_begin, 429 + .atomic_flush = mtk_drm_crtc_atomic_flush, 430 + }; 431 + 432 + static int mtk_drm_crtc_init(struct drm_device *drm, 433 + struct mtk_drm_crtc *mtk_crtc, 434 + struct drm_plane *primary, 435 + struct drm_plane *cursor, unsigned int pipe) 436 + { 437 + int ret; 438 + 439 + ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor, 440 + &mtk_crtc_funcs, NULL); 441 + if (ret) 442 + goto err_cleanup_crtc; 443 + 444 + drm_crtc_helper_add(&mtk_crtc->base, &mtk_crtc_helper_funcs); 445 + 446 + return 0; 447 + 448 + err_cleanup_crtc: 449 + drm_crtc_cleanup(&mtk_crtc->base); 450 + return ret; 451 + } 452 + 453 + void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl) 454 + { 455 + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); 456 + struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state); 457 + unsigned int i; 458 + 459 + /* 460 + * TODO: instead of updating the registers here, we should prepare 461 + * working registers in atomic_commit and let the hardware command 462 + * queue update module registers on vblank. 463 + */ 464 + if (state->pending_config) { 465 + mtk_ddp_comp_config(ovl, state->pending_width, 466 + state->pending_height, 467 + state->pending_vrefresh); 468 + 469 + state->pending_config = false; 470 + } 471 + 472 + if (mtk_crtc->pending_planes) { 473 + for (i = 0; i < OVL_LAYER_NR; i++) { 474 + struct drm_plane *plane = &mtk_crtc->planes[i].base; 475 + struct mtk_plane_state *plane_state; 476 + 477 + plane_state = to_mtk_plane_state(plane->state); 478 + 479 + if (plane_state->pending.config) { 480 + mtk_ddp_comp_layer_config(ovl, i, plane_state); 481 + plane_state->pending.config = false; 482 + } 483 + } 484 + mtk_crtc->pending_planes = false; 485 + } 486 + 487 + mtk_drm_finish_page_flip(mtk_crtc); 488 + } 489 + 490 + int mtk_drm_crtc_create(struct drm_device *drm_dev, 491 + const enum mtk_ddp_comp_id *path, unsigned int path_len) 492 + { 493 + struct mtk_drm_private *priv = drm_dev->dev_private; 494 + struct device *dev = drm_dev->dev; 495 + struct mtk_drm_crtc *mtk_crtc; 496 + enum drm_plane_type type; 497 + unsigned int zpos; 498 + int pipe = priv->num_pipes; 499 + int ret; 500 + int i; 501 + 502 + for (i = 0; i < path_len; i++) { 503 + enum mtk_ddp_comp_id comp_id = path[i]; 504 + struct device_node *node; 505 + 506 + node = priv->comp_node[comp_id]; 507 + if (!node) { 508 + dev_info(dev, 509 + "Not creating crtc %d because component %d is disabled or missing\n", 510 + pipe, comp_id); 511 + return 0; 512 + } 513 + } 514 + 515 + mtk_crtc = devm_kzalloc(dev, sizeof(*mtk_crtc), GFP_KERNEL); 516 + if (!mtk_crtc) 517 + return -ENOMEM; 518 + 519 + mtk_crtc->config_regs = priv->config_regs; 520 + mtk_crtc->ddp_comp_nr = path_len; 521 + mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr, 522 + sizeof(*mtk_crtc->ddp_comp), 523 + GFP_KERNEL); 524 + 525 + mtk_crtc->mutex = mtk_disp_mutex_get(priv->mutex_dev, pipe); 526 + if (IS_ERR(mtk_crtc->mutex)) { 527 + ret = PTR_ERR(mtk_crtc->mutex); 528 + dev_err(dev, "Failed to get mutex: %d\n", ret); 529 + return ret; 530 + } 531 + 532 + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { 533 + enum mtk_ddp_comp_id comp_id = path[i]; 534 + struct mtk_ddp_comp *comp; 535 + struct device_node *node; 536 + 537 + node = priv->comp_node[comp_id]; 538 + comp = priv->ddp_comp[comp_id]; 539 + if (!comp) { 540 + dev_err(dev, "Component %s not initialized\n", 541 + node->full_name); 542 + ret = -ENODEV; 543 + goto unprepare; 544 + } 545 + 546 + ret = clk_prepare(comp->clk); 547 + if (ret) { 548 + dev_err(dev, 549 + "Failed to prepare clock for component %s: %d\n", 550 + node->full_name, ret); 551 + goto unprepare; 552 + } 553 + 554 + mtk_crtc->ddp_comp[i] = comp; 555 + } 556 + 557 + for (zpos = 0; zpos < OVL_LAYER_NR; zpos++) { 558 + type = (zpos == 0) ? DRM_PLANE_TYPE_PRIMARY : 559 + (zpos == 1) ? DRM_PLANE_TYPE_CURSOR : 560 + DRM_PLANE_TYPE_OVERLAY; 561 + ret = mtk_plane_init(drm_dev, &mtk_crtc->planes[zpos], 562 + BIT(pipe), type, zpos); 563 + if (ret) 564 + goto unprepare; 565 + } 566 + 567 + ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0].base, 568 + &mtk_crtc->planes[1].base, pipe); 569 + if (ret < 0) 570 + goto unprepare; 571 + 572 + priv->crtc[pipe] = &mtk_crtc->base; 573 + priv->num_pipes++; 574 + 575 + return 0; 576 + 577 + unprepare: 578 + while (--i >= 0) 579 + clk_unprepare(mtk_crtc->ddp_comp[i]->clk); 580 + 581 + return ret; 582 + }
+32
drivers/gpu/drm/mediatek/mtk_drm_crtc.h
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef MTK_DRM_CRTC_H 15 + #define MTK_DRM_CRTC_H 16 + 17 + #include <drm/drm_crtc.h> 18 + #include "mtk_drm_ddp_comp.h" 19 + #include "mtk_drm_plane.h" 20 + 21 + #define OVL_LAYER_NR 4 22 + 23 + int mtk_drm_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe); 24 + void mtk_drm_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe); 25 + void mtk_drm_crtc_check_flush(struct drm_crtc *crtc); 26 + void mtk_drm_crtc_commit(struct drm_crtc *crtc); 27 + void mtk_crtc_ddp_irq(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl); 28 + int mtk_drm_crtc_create(struct drm_device *drm_dev, 29 + const enum mtk_ddp_comp_id *path, 30 + unsigned int path_len); 31 + 32 + #endif /* MTK_DRM_CRTC_H */
+353
drivers/gpu/drm/mediatek/mtk_drm_ddp.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <linux/clk.h> 15 + #include <linux/module.h> 16 + #include <linux/of_device.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/regmap.h> 19 + 20 + #include "mtk_drm_ddp.h" 21 + #include "mtk_drm_ddp_comp.h" 22 + 23 + #define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040 24 + #define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044 25 + #define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048 26 + #define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c 27 + #define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 28 + #define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 29 + #define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 30 + #define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac 31 + #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN 0x0c8 32 + #define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 33 + 34 + #define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n)) 35 + #define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) 36 + #define DISP_REG_MUTEX_MOD(n) (0x2c + 0x20 * (n)) 37 + #define DISP_REG_MUTEX_SOF(n) (0x30 + 0x20 * (n)) 38 + 39 + #define MUTEX_MOD_DISP_OVL0 BIT(11) 40 + #define MUTEX_MOD_DISP_OVL1 BIT(12) 41 + #define MUTEX_MOD_DISP_RDMA0 BIT(13) 42 + #define MUTEX_MOD_DISP_RDMA1 BIT(14) 43 + #define MUTEX_MOD_DISP_RDMA2 BIT(15) 44 + #define MUTEX_MOD_DISP_WDMA0 BIT(16) 45 + #define MUTEX_MOD_DISP_WDMA1 BIT(17) 46 + #define MUTEX_MOD_DISP_COLOR0 BIT(18) 47 + #define MUTEX_MOD_DISP_COLOR1 BIT(19) 48 + #define MUTEX_MOD_DISP_AAL BIT(20) 49 + #define MUTEX_MOD_DISP_GAMMA BIT(21) 50 + #define MUTEX_MOD_DISP_UFOE BIT(22) 51 + #define MUTEX_MOD_DISP_PWM0 BIT(23) 52 + #define MUTEX_MOD_DISP_PWM1 BIT(24) 53 + #define MUTEX_MOD_DISP_OD BIT(25) 54 + 55 + #define MUTEX_SOF_SINGLE_MODE 0 56 + #define MUTEX_SOF_DSI0 1 57 + #define MUTEX_SOF_DSI1 2 58 + #define MUTEX_SOF_DPI0 3 59 + 60 + #define OVL0_MOUT_EN_COLOR0 0x1 61 + #define OD_MOUT_EN_RDMA0 0x1 62 + #define UFOE_MOUT_EN_DSI0 0x1 63 + #define COLOR0_SEL_IN_OVL0 0x1 64 + #define OVL1_MOUT_EN_COLOR1 0x1 65 + #define GAMMA_MOUT_EN_RDMA1 0x1 66 + #define RDMA1_MOUT_DPI0 0x2 67 + #define DPI0_SEL_IN_RDMA1 0x1 68 + #define COLOR1_SEL_IN_OVL1 0x1 69 + 70 + struct mtk_disp_mutex { 71 + int id; 72 + bool claimed; 73 + }; 74 + 75 + struct mtk_ddp { 76 + struct device *dev; 77 + struct clk *clk; 78 + void __iomem *regs; 79 + struct mtk_disp_mutex mutex[10]; 80 + }; 81 + 82 + static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = { 83 + [DDP_COMPONENT_AAL] = MUTEX_MOD_DISP_AAL, 84 + [DDP_COMPONENT_COLOR0] = MUTEX_MOD_DISP_COLOR0, 85 + [DDP_COMPONENT_COLOR1] = MUTEX_MOD_DISP_COLOR1, 86 + [DDP_COMPONENT_GAMMA] = MUTEX_MOD_DISP_GAMMA, 87 + [DDP_COMPONENT_OD] = MUTEX_MOD_DISP_OD, 88 + [DDP_COMPONENT_OVL0] = MUTEX_MOD_DISP_OVL0, 89 + [DDP_COMPONENT_OVL1] = MUTEX_MOD_DISP_OVL1, 90 + [DDP_COMPONENT_PWM0] = MUTEX_MOD_DISP_PWM0, 91 + [DDP_COMPONENT_PWM1] = MUTEX_MOD_DISP_PWM1, 92 + [DDP_COMPONENT_RDMA0] = MUTEX_MOD_DISP_RDMA0, 93 + [DDP_COMPONENT_RDMA1] = MUTEX_MOD_DISP_RDMA1, 94 + [DDP_COMPONENT_RDMA2] = MUTEX_MOD_DISP_RDMA2, 95 + [DDP_COMPONENT_UFOE] = MUTEX_MOD_DISP_UFOE, 96 + [DDP_COMPONENT_WDMA0] = MUTEX_MOD_DISP_WDMA0, 97 + [DDP_COMPONENT_WDMA1] = MUTEX_MOD_DISP_WDMA1, 98 + }; 99 + 100 + static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, 101 + enum mtk_ddp_comp_id next, 102 + unsigned int *addr) 103 + { 104 + unsigned int value; 105 + 106 + if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { 107 + *addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN; 108 + value = OVL0_MOUT_EN_COLOR0; 109 + } else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) { 110 + *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; 111 + value = OD_MOUT_EN_RDMA0; 112 + } else if (cur == DDP_COMPONENT_UFOE && next == DDP_COMPONENT_DSI0) { 113 + *addr = DISP_REG_CONFIG_DISP_UFOE_MOUT_EN; 114 + value = UFOE_MOUT_EN_DSI0; 115 + } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { 116 + *addr = DISP_REG_CONFIG_DISP_OVL1_MOUT_EN; 117 + value = OVL1_MOUT_EN_COLOR1; 118 + } else if (cur == DDP_COMPONENT_GAMMA && next == DDP_COMPONENT_RDMA1) { 119 + *addr = DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN; 120 + value = GAMMA_MOUT_EN_RDMA1; 121 + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { 122 + *addr = DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN; 123 + value = RDMA1_MOUT_DPI0; 124 + } else { 125 + value = 0; 126 + } 127 + 128 + return value; 129 + } 130 + 131 + static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, 132 + enum mtk_ddp_comp_id next, 133 + unsigned int *addr) 134 + { 135 + unsigned int value; 136 + 137 + if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) { 138 + *addr = DISP_REG_CONFIG_DISP_COLOR0_SEL_IN; 139 + value = COLOR0_SEL_IN_OVL0; 140 + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { 141 + *addr = DISP_REG_CONFIG_DPI_SEL_IN; 142 + value = DPI0_SEL_IN_RDMA1; 143 + } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { 144 + *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; 145 + value = COLOR1_SEL_IN_OVL1; 146 + } else { 147 + value = 0; 148 + } 149 + 150 + return value; 151 + } 152 + 153 + void mtk_ddp_add_comp_to_path(void __iomem *config_regs, 154 + enum mtk_ddp_comp_id cur, 155 + enum mtk_ddp_comp_id next) 156 + { 157 + unsigned int addr, value, reg; 158 + 159 + value = mtk_ddp_mout_en(cur, next, &addr); 160 + if (value) { 161 + reg = readl_relaxed(config_regs + addr) | value; 162 + writel_relaxed(reg, config_regs + addr); 163 + } 164 + 165 + value = mtk_ddp_sel_in(cur, next, &addr); 166 + if (value) { 167 + reg = readl_relaxed(config_regs + addr) | value; 168 + writel_relaxed(reg, config_regs + addr); 169 + } 170 + } 171 + 172 + void mtk_ddp_remove_comp_from_path(void __iomem *config_regs, 173 + enum mtk_ddp_comp_id cur, 174 + enum mtk_ddp_comp_id next) 175 + { 176 + unsigned int addr, value, reg; 177 + 178 + value = mtk_ddp_mout_en(cur, next, &addr); 179 + if (value) { 180 + reg = readl_relaxed(config_regs + addr) & ~value; 181 + writel_relaxed(reg, config_regs + addr); 182 + } 183 + 184 + value = mtk_ddp_sel_in(cur, next, &addr); 185 + if (value) { 186 + reg = readl_relaxed(config_regs + addr) & ~value; 187 + writel_relaxed(reg, config_regs + addr); 188 + } 189 + } 190 + 191 + struct mtk_disp_mutex *mtk_disp_mutex_get(struct device *dev, unsigned int id) 192 + { 193 + struct mtk_ddp *ddp = dev_get_drvdata(dev); 194 + 195 + if (id >= 10) 196 + return ERR_PTR(-EINVAL); 197 + if (ddp->mutex[id].claimed) 198 + return ERR_PTR(-EBUSY); 199 + 200 + ddp->mutex[id].claimed = true; 201 + 202 + return &ddp->mutex[id]; 203 + } 204 + 205 + void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex) 206 + { 207 + struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 208 + mutex[mutex->id]); 209 + 210 + WARN_ON(&ddp->mutex[mutex->id] != mutex); 211 + 212 + mutex->claimed = false; 213 + } 214 + 215 + int mtk_disp_mutex_prepare(struct mtk_disp_mutex *mutex) 216 + { 217 + struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 218 + mutex[mutex->id]); 219 + return clk_prepare_enable(ddp->clk); 220 + } 221 + 222 + void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex) 223 + { 224 + struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 225 + mutex[mutex->id]); 226 + clk_disable_unprepare(ddp->clk); 227 + } 228 + 229 + void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, 230 + enum mtk_ddp_comp_id id) 231 + { 232 + struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 233 + mutex[mutex->id]); 234 + unsigned int reg; 235 + 236 + WARN_ON(&ddp->mutex[mutex->id] != mutex); 237 + 238 + switch (id) { 239 + case DDP_COMPONENT_DSI0: 240 + reg = MUTEX_SOF_DSI0; 241 + break; 242 + case DDP_COMPONENT_DSI1: 243 + reg = MUTEX_SOF_DSI0; 244 + break; 245 + case DDP_COMPONENT_DPI0: 246 + reg = MUTEX_SOF_DPI0; 247 + break; 248 + default: 249 + reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 250 + reg |= mutex_mod[id]; 251 + writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 252 + return; 253 + } 254 + 255 + writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_SOF(mutex->id)); 256 + } 257 + 258 + void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, 259 + enum mtk_ddp_comp_id id) 260 + { 261 + struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 262 + mutex[mutex->id]); 263 + unsigned int reg; 264 + 265 + WARN_ON(&ddp->mutex[mutex->id] != mutex); 266 + 267 + switch (id) { 268 + case DDP_COMPONENT_DSI0: 269 + case DDP_COMPONENT_DSI1: 270 + case DDP_COMPONENT_DPI0: 271 + writel_relaxed(MUTEX_SOF_SINGLE_MODE, 272 + ddp->regs + DISP_REG_MUTEX_SOF(mutex->id)); 273 + break; 274 + default: 275 + reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 276 + reg &= ~mutex_mod[id]; 277 + writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); 278 + break; 279 + } 280 + } 281 + 282 + void mtk_disp_mutex_enable(struct mtk_disp_mutex *mutex) 283 + { 284 + struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 285 + mutex[mutex->id]); 286 + 287 + WARN_ON(&ddp->mutex[mutex->id] != mutex); 288 + 289 + writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); 290 + } 291 + 292 + void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex) 293 + { 294 + struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, 295 + mutex[mutex->id]); 296 + 297 + WARN_ON(&ddp->mutex[mutex->id] != mutex); 298 + 299 + writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id)); 300 + } 301 + 302 + static int mtk_ddp_probe(struct platform_device *pdev) 303 + { 304 + struct device *dev = &pdev->dev; 305 + struct mtk_ddp *ddp; 306 + struct resource *regs; 307 + int i; 308 + 309 + ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL); 310 + if (!ddp) 311 + return -ENOMEM; 312 + 313 + for (i = 0; i < 10; i++) 314 + ddp->mutex[i].id = i; 315 + 316 + ddp->clk = devm_clk_get(dev, NULL); 317 + if (IS_ERR(ddp->clk)) { 318 + dev_err(dev, "Failed to get clock\n"); 319 + return PTR_ERR(ddp->clk); 320 + } 321 + 322 + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 323 + ddp->regs = devm_ioremap_resource(dev, regs); 324 + if (IS_ERR(ddp->regs)) { 325 + dev_err(dev, "Failed to map mutex registers\n"); 326 + return PTR_ERR(ddp->regs); 327 + } 328 + 329 + platform_set_drvdata(pdev, ddp); 330 + 331 + return 0; 332 + } 333 + 334 + static int mtk_ddp_remove(struct platform_device *pdev) 335 + { 336 + return 0; 337 + } 338 + 339 + static const struct of_device_id ddp_driver_dt_match[] = { 340 + { .compatible = "mediatek,mt8173-disp-mutex" }, 341 + {}, 342 + }; 343 + MODULE_DEVICE_TABLE(of, ddp_driver_dt_match); 344 + 345 + struct platform_driver mtk_ddp_driver = { 346 + .probe = mtk_ddp_probe, 347 + .remove = mtk_ddp_remove, 348 + .driver = { 349 + .name = "mediatek-ddp", 350 + .owner = THIS_MODULE, 351 + .of_match_table = ddp_driver_dt_match, 352 + }, 353 + };
+41
drivers/gpu/drm/mediatek/mtk_drm_ddp.h
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef MTK_DRM_DDP_H 15 + #define MTK_DRM_DDP_H 16 + 17 + #include "mtk_drm_ddp_comp.h" 18 + 19 + struct regmap; 20 + struct device; 21 + struct mtk_disp_mutex; 22 + 23 + void mtk_ddp_add_comp_to_path(void __iomem *config_regs, 24 + enum mtk_ddp_comp_id cur, 25 + enum mtk_ddp_comp_id next); 26 + void mtk_ddp_remove_comp_from_path(void __iomem *config_regs, 27 + enum mtk_ddp_comp_id cur, 28 + enum mtk_ddp_comp_id next); 29 + 30 + struct mtk_disp_mutex *mtk_disp_mutex_get(struct device *dev, unsigned int id); 31 + int mtk_disp_mutex_prepare(struct mtk_disp_mutex *mutex); 32 + void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, 33 + enum mtk_ddp_comp_id id); 34 + void mtk_disp_mutex_enable(struct mtk_disp_mutex *mutex); 35 + void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex); 36 + void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, 37 + enum mtk_ddp_comp_id id); 38 + void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex); 39 + void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex); 40 + 41 + #endif /* MTK_DRM_DDP_H */
+225
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * Authors: 4 + * YT Shen <yt.shen@mediatek.com> 5 + * CK Hu <ck.hu@mediatek.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #include <linux/clk.h> 18 + #include <linux/of.h> 19 + #include <linux/of_address.h> 20 + #include <linux/of_irq.h> 21 + #include <linux/of_platform.h> 22 + #include <linux/platform_device.h> 23 + #include <drm/drmP.h> 24 + #include "mtk_drm_drv.h" 25 + #include "mtk_drm_plane.h" 26 + #include "mtk_drm_ddp_comp.h" 27 + 28 + #define DISP_OD_EN 0x0000 29 + #define DISP_OD_INTEN 0x0008 30 + #define DISP_OD_INTSTA 0x000c 31 + #define DISP_OD_CFG 0x0020 32 + #define DISP_OD_SIZE 0x0030 33 + 34 + #define DISP_REG_UFO_START 0x0000 35 + 36 + #define DISP_COLOR_CFG_MAIN 0x0400 37 + #define DISP_COLOR_START 0x0c00 38 + #define DISP_COLOR_WIDTH 0x0c50 39 + #define DISP_COLOR_HEIGHT 0x0c54 40 + 41 + #define OD_RELAY_MODE BIT(0) 42 + 43 + #define UFO_BYPASS BIT(2) 44 + 45 + #define COLOR_BYPASS_ALL BIT(7) 46 + #define COLOR_SEQ_SEL BIT(13) 47 + 48 + static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w, 49 + unsigned int h, unsigned int vrefresh) 50 + { 51 + writel(w, comp->regs + DISP_COLOR_WIDTH); 52 + writel(h, comp->regs + DISP_COLOR_HEIGHT); 53 + } 54 + 55 + static void mtk_color_start(struct mtk_ddp_comp *comp) 56 + { 57 + writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL, 58 + comp->regs + DISP_COLOR_CFG_MAIN); 59 + writel(0x1, comp->regs + DISP_COLOR_START); 60 + } 61 + 62 + static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w, 63 + unsigned int h, unsigned int vrefresh) 64 + { 65 + writel(w << 16 | h, comp->regs + DISP_OD_SIZE); 66 + } 67 + 68 + static void mtk_od_start(struct mtk_ddp_comp *comp) 69 + { 70 + writel(OD_RELAY_MODE, comp->regs + DISP_OD_CFG); 71 + writel(1, comp->regs + DISP_OD_EN); 72 + } 73 + 74 + static void mtk_ufoe_start(struct mtk_ddp_comp *comp) 75 + { 76 + writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START); 77 + } 78 + 79 + static const struct mtk_ddp_comp_funcs ddp_color = { 80 + .config = mtk_color_config, 81 + .start = mtk_color_start, 82 + }; 83 + 84 + static const struct mtk_ddp_comp_funcs ddp_od = { 85 + .config = mtk_od_config, 86 + .start = mtk_od_start, 87 + }; 88 + 89 + static const struct mtk_ddp_comp_funcs ddp_ufoe = { 90 + .start = mtk_ufoe_start, 91 + }; 92 + 93 + static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = { 94 + [MTK_DISP_OVL] = "ovl", 95 + [MTK_DISP_RDMA] = "rdma", 96 + [MTK_DISP_WDMA] = "wdma", 97 + [MTK_DISP_COLOR] = "color", 98 + [MTK_DISP_AAL] = "aal", 99 + [MTK_DISP_GAMMA] = "gamma", 100 + [MTK_DISP_UFOE] = "ufoe", 101 + [MTK_DSI] = "dsi", 102 + [MTK_DPI] = "dpi", 103 + [MTK_DISP_PWM] = "pwm", 104 + [MTK_DISP_MUTEX] = "mutex", 105 + [MTK_DISP_OD] = "od", 106 + }; 107 + 108 + struct mtk_ddp_comp_match { 109 + enum mtk_ddp_comp_type type; 110 + int alias_id; 111 + const struct mtk_ddp_comp_funcs *funcs; 112 + }; 113 + 114 + static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { 115 + [DDP_COMPONENT_AAL] = { MTK_DISP_AAL, 0, NULL }, 116 + [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color }, 117 + [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color }, 118 + [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, NULL }, 119 + [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, NULL }, 120 + [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, NULL }, 121 + [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, NULL }, 122 + [DDP_COMPONENT_OD] = { MTK_DISP_OD, 0, &ddp_od }, 123 + [DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, NULL }, 124 + [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, NULL }, 125 + [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL }, 126 + [DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, NULL }, 127 + [DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, NULL }, 128 + [DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, NULL }, 129 + [DDP_COMPONENT_UFOE] = { MTK_DISP_UFOE, 0, &ddp_ufoe }, 130 + [DDP_COMPONENT_WDMA0] = { MTK_DISP_WDMA, 0, NULL }, 131 + [DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, NULL }, 132 + }; 133 + 134 + int mtk_ddp_comp_get_id(struct device_node *node, 135 + enum mtk_ddp_comp_type comp_type) 136 + { 137 + int id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]); 138 + int i; 139 + 140 + for (i = 0; i < ARRAY_SIZE(mtk_ddp_matches); i++) { 141 + if (comp_type == mtk_ddp_matches[i].type && 142 + (id < 0 || id == mtk_ddp_matches[i].alias_id)) 143 + return i; 144 + } 145 + 146 + return -EINVAL; 147 + } 148 + 149 + int mtk_ddp_comp_init(struct device *dev, struct device_node *node, 150 + struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id, 151 + const struct mtk_ddp_comp_funcs *funcs) 152 + { 153 + enum mtk_ddp_comp_type type; 154 + struct device_node *larb_node; 155 + struct platform_device *larb_pdev; 156 + 157 + if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX) 158 + return -EINVAL; 159 + 160 + comp->id = comp_id; 161 + comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs; 162 + 163 + if (comp_id == DDP_COMPONENT_DPI0 || 164 + comp_id == DDP_COMPONENT_DSI0 || 165 + comp_id == DDP_COMPONENT_PWM0) { 166 + comp->regs = NULL; 167 + comp->clk = NULL; 168 + comp->irq = 0; 169 + return 0; 170 + } 171 + 172 + comp->regs = of_iomap(node, 0); 173 + comp->irq = of_irq_get(node, 0); 174 + comp->clk = of_clk_get(node, 0); 175 + if (IS_ERR(comp->clk)) 176 + comp->clk = NULL; 177 + 178 + type = mtk_ddp_matches[comp_id].type; 179 + 180 + /* Only DMA capable components need the LARB property */ 181 + comp->larb_dev = NULL; 182 + if (type != MTK_DISP_OVL && 183 + type != MTK_DISP_RDMA && 184 + type != MTK_DISP_WDMA) 185 + return 0; 186 + 187 + larb_node = of_parse_phandle(node, "mediatek,larb", 0); 188 + if (!larb_node) { 189 + dev_err(dev, 190 + "Missing mediadek,larb phandle in %s node\n", 191 + node->full_name); 192 + return -EINVAL; 193 + } 194 + 195 + larb_pdev = of_find_device_by_node(larb_node); 196 + if (!larb_pdev) { 197 + dev_warn(dev, "Waiting for larb device %s\n", 198 + larb_node->full_name); 199 + of_node_put(larb_node); 200 + return -EPROBE_DEFER; 201 + } 202 + of_node_put(larb_node); 203 + 204 + comp->larb_dev = &larb_pdev->dev; 205 + 206 + return 0; 207 + } 208 + 209 + int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp) 210 + { 211 + struct mtk_drm_private *private = drm->dev_private; 212 + 213 + if (private->ddp_comp[comp->id]) 214 + return -EBUSY; 215 + 216 + private->ddp_comp[comp->id] = comp; 217 + return 0; 218 + } 219 + 220 + void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp) 221 + { 222 + struct mtk_drm_private *private = drm->dev_private; 223 + 224 + private->ddp_comp[comp->id] = NULL; 225 + }
+150
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef MTK_DRM_DDP_COMP_H 15 + #define MTK_DRM_DDP_COMP_H 16 + 17 + #include <linux/io.h> 18 + 19 + struct device; 20 + struct device_node; 21 + struct drm_crtc; 22 + struct drm_device; 23 + struct mtk_plane_state; 24 + 25 + enum mtk_ddp_comp_type { 26 + MTK_DISP_OVL, 27 + MTK_DISP_RDMA, 28 + MTK_DISP_WDMA, 29 + MTK_DISP_COLOR, 30 + MTK_DISP_AAL, 31 + MTK_DISP_GAMMA, 32 + MTK_DISP_UFOE, 33 + MTK_DSI, 34 + MTK_DPI, 35 + MTK_DISP_PWM, 36 + MTK_DISP_MUTEX, 37 + MTK_DISP_OD, 38 + MTK_DDP_COMP_TYPE_MAX, 39 + }; 40 + 41 + enum mtk_ddp_comp_id { 42 + DDP_COMPONENT_AAL, 43 + DDP_COMPONENT_COLOR0, 44 + DDP_COMPONENT_COLOR1, 45 + DDP_COMPONENT_DPI0, 46 + DDP_COMPONENT_DSI0, 47 + DDP_COMPONENT_DSI1, 48 + DDP_COMPONENT_GAMMA, 49 + DDP_COMPONENT_OD, 50 + DDP_COMPONENT_OVL0, 51 + DDP_COMPONENT_OVL1, 52 + DDP_COMPONENT_PWM0, 53 + DDP_COMPONENT_PWM1, 54 + DDP_COMPONENT_RDMA0, 55 + DDP_COMPONENT_RDMA1, 56 + DDP_COMPONENT_RDMA2, 57 + DDP_COMPONENT_UFOE, 58 + DDP_COMPONENT_WDMA0, 59 + DDP_COMPONENT_WDMA1, 60 + DDP_COMPONENT_ID_MAX, 61 + }; 62 + 63 + struct mtk_ddp_comp; 64 + 65 + struct mtk_ddp_comp_funcs { 66 + void (*config)(struct mtk_ddp_comp *comp, unsigned int w, 67 + unsigned int h, unsigned int vrefresh); 68 + void (*start)(struct mtk_ddp_comp *comp); 69 + void (*stop)(struct mtk_ddp_comp *comp); 70 + void (*enable_vblank)(struct mtk_ddp_comp *comp, struct drm_crtc *crtc); 71 + void (*disable_vblank)(struct mtk_ddp_comp *comp); 72 + void (*layer_on)(struct mtk_ddp_comp *comp, unsigned int idx); 73 + void (*layer_off)(struct mtk_ddp_comp *comp, unsigned int idx); 74 + void (*layer_config)(struct mtk_ddp_comp *comp, unsigned int idx, 75 + struct mtk_plane_state *state); 76 + }; 77 + 78 + struct mtk_ddp_comp { 79 + struct clk *clk; 80 + void __iomem *regs; 81 + int irq; 82 + struct device *larb_dev; 83 + enum mtk_ddp_comp_id id; 84 + const struct mtk_ddp_comp_funcs *funcs; 85 + }; 86 + 87 + static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp, 88 + unsigned int w, unsigned int h, 89 + unsigned int vrefresh) 90 + { 91 + if (comp->funcs && comp->funcs->config) 92 + comp->funcs->config(comp, w, h, vrefresh); 93 + } 94 + 95 + static inline void mtk_ddp_comp_start(struct mtk_ddp_comp *comp) 96 + { 97 + if (comp->funcs && comp->funcs->start) 98 + comp->funcs->start(comp); 99 + } 100 + 101 + static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp) 102 + { 103 + if (comp->funcs && comp->funcs->stop) 104 + comp->funcs->stop(comp); 105 + } 106 + 107 + static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp, 108 + struct drm_crtc *crtc) 109 + { 110 + if (comp->funcs && comp->funcs->enable_vblank) 111 + comp->funcs->enable_vblank(comp, crtc); 112 + } 113 + 114 + static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp) 115 + { 116 + if (comp->funcs && comp->funcs->disable_vblank) 117 + comp->funcs->disable_vblank(comp); 118 + } 119 + 120 + static inline void mtk_ddp_comp_layer_on(struct mtk_ddp_comp *comp, 121 + unsigned int idx) 122 + { 123 + if (comp->funcs && comp->funcs->layer_on) 124 + comp->funcs->layer_on(comp, idx); 125 + } 126 + 127 + static inline void mtk_ddp_comp_layer_off(struct mtk_ddp_comp *comp, 128 + unsigned int idx) 129 + { 130 + if (comp->funcs && comp->funcs->layer_off) 131 + comp->funcs->layer_off(comp, idx); 132 + } 133 + 134 + static inline void mtk_ddp_comp_layer_config(struct mtk_ddp_comp *comp, 135 + unsigned int idx, 136 + struct mtk_plane_state *state) 137 + { 138 + if (comp->funcs && comp->funcs->layer_config) 139 + comp->funcs->layer_config(comp, idx, state); 140 + } 141 + 142 + int mtk_ddp_comp_get_id(struct device_node *node, 143 + enum mtk_ddp_comp_type comp_type); 144 + int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node, 145 + struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id, 146 + const struct mtk_ddp_comp_funcs *funcs); 147 + int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp); 148 + void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp); 149 + 150 + #endif /* MTK_DRM_DDP_COMP_H */
+567
drivers/gpu/drm/mediatek/mtk_drm_drv.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * Author: YT SHEN <yt.shen@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <drm/drmP.h> 16 + #include <drm/drm_atomic.h> 17 + #include <drm/drm_atomic_helper.h> 18 + #include <drm/drm_crtc_helper.h> 19 + #include <drm/drm_gem.h> 20 + #include <drm/drm_gem_cma_helper.h> 21 + #include <linux/component.h> 22 + #include <linux/iommu.h> 23 + #include <linux/of_address.h> 24 + #include <linux/of_platform.h> 25 + #include <linux/pm_runtime.h> 26 + 27 + #include "mtk_drm_crtc.h" 28 + #include "mtk_drm_ddp.h" 29 + #include "mtk_drm_ddp_comp.h" 30 + #include "mtk_drm_drv.h" 31 + #include "mtk_drm_fb.h" 32 + #include "mtk_drm_gem.h" 33 + 34 + #define DRIVER_NAME "mediatek" 35 + #define DRIVER_DESC "Mediatek SoC DRM" 36 + #define DRIVER_DATE "20150513" 37 + #define DRIVER_MAJOR 1 38 + #define DRIVER_MINOR 0 39 + 40 + static void mtk_atomic_schedule(struct mtk_drm_private *private, 41 + struct drm_atomic_state *state) 42 + { 43 + private->commit.state = state; 44 + schedule_work(&private->commit.work); 45 + } 46 + 47 + static void mtk_atomic_wait_for_fences(struct drm_atomic_state *state) 48 + { 49 + struct drm_plane *plane; 50 + struct drm_plane_state *plane_state; 51 + int i; 52 + 53 + for_each_plane_in_state(state, plane, plane_state, i) 54 + mtk_fb_wait(plane->state->fb); 55 + } 56 + 57 + static void mtk_atomic_complete(struct mtk_drm_private *private, 58 + struct drm_atomic_state *state) 59 + { 60 + struct drm_device *drm = private->drm; 61 + 62 + mtk_atomic_wait_for_fences(state); 63 + 64 + drm_atomic_helper_commit_modeset_disables(drm, state); 65 + drm_atomic_helper_commit_planes(drm, state, false); 66 + drm_atomic_helper_commit_modeset_enables(drm, state); 67 + drm_atomic_helper_wait_for_vblanks(drm, state); 68 + drm_atomic_helper_cleanup_planes(drm, state); 69 + drm_atomic_state_free(state); 70 + } 71 + 72 + static void mtk_atomic_work(struct work_struct *work) 73 + { 74 + struct mtk_drm_private *private = container_of(work, 75 + struct mtk_drm_private, commit.work); 76 + 77 + mtk_atomic_complete(private, private->commit.state); 78 + } 79 + 80 + static int mtk_atomic_commit(struct drm_device *drm, 81 + struct drm_atomic_state *state, 82 + bool async) 83 + { 84 + struct mtk_drm_private *private = drm->dev_private; 85 + int ret; 86 + 87 + ret = drm_atomic_helper_prepare_planes(drm, state); 88 + if (ret) 89 + return ret; 90 + 91 + mutex_lock(&private->commit.lock); 92 + flush_work(&private->commit.work); 93 + 94 + drm_atomic_helper_swap_state(drm, state); 95 + 96 + if (async) 97 + mtk_atomic_schedule(private, state); 98 + else 99 + mtk_atomic_complete(private, state); 100 + 101 + mutex_unlock(&private->commit.lock); 102 + 103 + return 0; 104 + } 105 + 106 + static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = { 107 + .fb_create = mtk_drm_mode_fb_create, 108 + .atomic_check = drm_atomic_helper_check, 109 + .atomic_commit = mtk_atomic_commit, 110 + }; 111 + 112 + static const enum mtk_ddp_comp_id mtk_ddp_main[] = { 113 + DDP_COMPONENT_OVL0, 114 + DDP_COMPONENT_COLOR0, 115 + DDP_COMPONENT_AAL, 116 + DDP_COMPONENT_OD, 117 + DDP_COMPONENT_RDMA0, 118 + DDP_COMPONENT_UFOE, 119 + DDP_COMPONENT_DSI0, 120 + DDP_COMPONENT_PWM0, 121 + }; 122 + 123 + static const enum mtk_ddp_comp_id mtk_ddp_ext[] = { 124 + DDP_COMPONENT_OVL1, 125 + DDP_COMPONENT_COLOR1, 126 + DDP_COMPONENT_GAMMA, 127 + DDP_COMPONENT_RDMA1, 128 + DDP_COMPONENT_DPI0, 129 + }; 130 + 131 + static int mtk_drm_kms_init(struct drm_device *drm) 132 + { 133 + struct mtk_drm_private *private = drm->dev_private; 134 + struct platform_device *pdev; 135 + struct device_node *np; 136 + int ret; 137 + 138 + if (!iommu_present(&platform_bus_type)) 139 + return -EPROBE_DEFER; 140 + 141 + pdev = of_find_device_by_node(private->mutex_node); 142 + if (!pdev) { 143 + dev_err(drm->dev, "Waiting for disp-mutex device %s\n", 144 + private->mutex_node->full_name); 145 + of_node_put(private->mutex_node); 146 + return -EPROBE_DEFER; 147 + } 148 + private->mutex_dev = &pdev->dev; 149 + 150 + drm_mode_config_init(drm); 151 + 152 + drm->mode_config.min_width = 64; 153 + drm->mode_config.min_height = 64; 154 + 155 + /* 156 + * set max width and height as default value(4096x4096). 157 + * this value would be used to check framebuffer size limitation 158 + * at drm_mode_addfb(). 159 + */ 160 + drm->mode_config.max_width = 4096; 161 + drm->mode_config.max_height = 4096; 162 + drm->mode_config.funcs = &mtk_drm_mode_config_funcs; 163 + 164 + ret = component_bind_all(drm->dev, drm); 165 + if (ret) 166 + goto err_config_cleanup; 167 + 168 + /* 169 + * We currently support two fixed data streams, each optional, 170 + * and each statically assigned to a crtc: 171 + * OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 ... 172 + */ 173 + ret = mtk_drm_crtc_create(drm, mtk_ddp_main, ARRAY_SIZE(mtk_ddp_main)); 174 + if (ret < 0) 175 + goto err_component_unbind; 176 + /* ... and OVL1 -> COLOR1 -> GAMMA -> RDMA1 -> DPI0. */ 177 + ret = mtk_drm_crtc_create(drm, mtk_ddp_ext, ARRAY_SIZE(mtk_ddp_ext)); 178 + if (ret < 0) 179 + goto err_component_unbind; 180 + 181 + /* Use OVL device for all DMA memory allocations */ 182 + np = private->comp_node[mtk_ddp_main[0]] ?: 183 + private->comp_node[mtk_ddp_ext[0]]; 184 + pdev = of_find_device_by_node(np); 185 + if (!pdev) { 186 + ret = -ENODEV; 187 + dev_err(drm->dev, "Need at least one OVL device\n"); 188 + goto err_component_unbind; 189 + } 190 + 191 + private->dma_dev = &pdev->dev; 192 + 193 + /* 194 + * We don't use the drm_irq_install() helpers provided by the DRM 195 + * core, so we need to set this manually in order to allow the 196 + * DRM_IOCTL_WAIT_VBLANK to operate correctly. 197 + */ 198 + drm->irq_enabled = true; 199 + ret = drm_vblank_init(drm, MAX_CRTC); 200 + if (ret < 0) 201 + goto err_component_unbind; 202 + 203 + drm_kms_helper_poll_init(drm); 204 + drm_mode_config_reset(drm); 205 + 206 + return 0; 207 + 208 + err_component_unbind: 209 + component_unbind_all(drm->dev, drm); 210 + err_config_cleanup: 211 + drm_mode_config_cleanup(drm); 212 + 213 + return ret; 214 + } 215 + 216 + static void mtk_drm_kms_deinit(struct drm_device *drm) 217 + { 218 + drm_kms_helper_poll_fini(drm); 219 + 220 + drm_vblank_cleanup(drm); 221 + component_unbind_all(drm->dev, drm); 222 + drm_mode_config_cleanup(drm); 223 + } 224 + 225 + static const struct file_operations mtk_drm_fops = { 226 + .owner = THIS_MODULE, 227 + .open = drm_open, 228 + .release = drm_release, 229 + .unlocked_ioctl = drm_ioctl, 230 + .mmap = mtk_drm_gem_mmap, 231 + .poll = drm_poll, 232 + .read = drm_read, 233 + #ifdef CONFIG_COMPAT 234 + .compat_ioctl = drm_compat_ioctl, 235 + #endif 236 + }; 237 + 238 + static struct drm_driver mtk_drm_driver = { 239 + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 240 + DRIVER_ATOMIC, 241 + 242 + .get_vblank_counter = drm_vblank_count, 243 + .enable_vblank = mtk_drm_crtc_enable_vblank, 244 + .disable_vblank = mtk_drm_crtc_disable_vblank, 245 + 246 + .gem_free_object = mtk_drm_gem_free_object, 247 + .gem_vm_ops = &drm_gem_cma_vm_ops, 248 + .dumb_create = mtk_drm_gem_dumb_create, 249 + .dumb_map_offset = mtk_drm_gem_dumb_map_offset, 250 + .dumb_destroy = drm_gem_dumb_destroy, 251 + 252 + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 253 + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 254 + .gem_prime_export = drm_gem_prime_export, 255 + .gem_prime_import = drm_gem_prime_import, 256 + .gem_prime_get_sg_table = mtk_gem_prime_get_sg_table, 257 + .gem_prime_import_sg_table = mtk_gem_prime_import_sg_table, 258 + .gem_prime_mmap = mtk_drm_gem_mmap_buf, 259 + .fops = &mtk_drm_fops, 260 + 261 + .name = DRIVER_NAME, 262 + .desc = DRIVER_DESC, 263 + .date = DRIVER_DATE, 264 + .major = DRIVER_MAJOR, 265 + .minor = DRIVER_MINOR, 266 + }; 267 + 268 + static int compare_of(struct device *dev, void *data) 269 + { 270 + return dev->of_node == data; 271 + } 272 + 273 + static int mtk_drm_bind(struct device *dev) 274 + { 275 + struct mtk_drm_private *private = dev_get_drvdata(dev); 276 + struct drm_device *drm; 277 + int ret; 278 + 279 + drm = drm_dev_alloc(&mtk_drm_driver, dev); 280 + if (!drm) 281 + return -ENOMEM; 282 + 283 + drm_dev_set_unique(drm, dev_name(dev)); 284 + 285 + drm->dev_private = private; 286 + private->drm = drm; 287 + 288 + ret = mtk_drm_kms_init(drm); 289 + if (ret < 0) 290 + goto err_free; 291 + 292 + ret = drm_dev_register(drm, 0); 293 + if (ret < 0) 294 + goto err_deinit; 295 + 296 + ret = drm_connector_register_all(drm); 297 + if (ret < 0) 298 + goto err_unregister; 299 + 300 + return 0; 301 + 302 + err_unregister: 303 + drm_dev_unregister(drm); 304 + err_deinit: 305 + mtk_drm_kms_deinit(drm); 306 + err_free: 307 + drm_dev_unref(drm); 308 + return ret; 309 + } 310 + 311 + static void mtk_drm_unbind(struct device *dev) 312 + { 313 + struct mtk_drm_private *private = dev_get_drvdata(dev); 314 + 315 + drm_put_dev(private->drm); 316 + private->drm = NULL; 317 + } 318 + 319 + static const struct component_master_ops mtk_drm_ops = { 320 + .bind = mtk_drm_bind, 321 + .unbind = mtk_drm_unbind, 322 + }; 323 + 324 + static const struct of_device_id mtk_ddp_comp_dt_ids[] = { 325 + { .compatible = "mediatek,mt8173-disp-ovl", .data = (void *)MTK_DISP_OVL }, 326 + { .compatible = "mediatek,mt8173-disp-rdma", .data = (void *)MTK_DISP_RDMA }, 327 + { .compatible = "mediatek,mt8173-disp-wdma", .data = (void *)MTK_DISP_WDMA }, 328 + { .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR }, 329 + { .compatible = "mediatek,mt8173-disp-aal", .data = (void *)MTK_DISP_AAL}, 330 + { .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, }, 331 + { .compatible = "mediatek,mt8173-disp-ufoe", .data = (void *)MTK_DISP_UFOE }, 332 + { .compatible = "mediatek,mt8173-dsi", .data = (void *)MTK_DSI }, 333 + { .compatible = "mediatek,mt8173-dpi", .data = (void *)MTK_DPI }, 334 + { .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, 335 + { .compatible = "mediatek,mt8173-disp-pwm", .data = (void *)MTK_DISP_PWM }, 336 + { .compatible = "mediatek,mt8173-disp-od", .data = (void *)MTK_DISP_OD }, 337 + { } 338 + }; 339 + 340 + static int mtk_drm_probe(struct platform_device *pdev) 341 + { 342 + struct device *dev = &pdev->dev; 343 + struct mtk_drm_private *private; 344 + struct resource *mem; 345 + struct device_node *node; 346 + struct component_match *match = NULL; 347 + int ret; 348 + int i; 349 + 350 + private = devm_kzalloc(dev, sizeof(*private), GFP_KERNEL); 351 + if (!private) 352 + return -ENOMEM; 353 + 354 + mutex_init(&private->commit.lock); 355 + INIT_WORK(&private->commit.work, mtk_atomic_work); 356 + 357 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 358 + private->config_regs = devm_ioremap_resource(dev, mem); 359 + if (IS_ERR(private->config_regs)) { 360 + ret = PTR_ERR(private->config_regs); 361 + dev_err(dev, "Failed to ioremap mmsys-config resource: %d\n", 362 + ret); 363 + return ret; 364 + } 365 + 366 + /* Iterate over sibling DISP function blocks */ 367 + for_each_child_of_node(dev->of_node->parent, node) { 368 + const struct of_device_id *of_id; 369 + enum mtk_ddp_comp_type comp_type; 370 + int comp_id; 371 + 372 + of_id = of_match_node(mtk_ddp_comp_dt_ids, node); 373 + if (!of_id) 374 + continue; 375 + 376 + if (!of_device_is_available(node)) { 377 + dev_dbg(dev, "Skipping disabled component %s\n", 378 + node->full_name); 379 + continue; 380 + } 381 + 382 + comp_type = (enum mtk_ddp_comp_type)of_id->data; 383 + 384 + if (comp_type == MTK_DISP_MUTEX) { 385 + private->mutex_node = of_node_get(node); 386 + continue; 387 + } 388 + 389 + comp_id = mtk_ddp_comp_get_id(node, comp_type); 390 + if (comp_id < 0) { 391 + dev_warn(dev, "Skipping unknown component %s\n", 392 + node->full_name); 393 + continue; 394 + } 395 + 396 + private->comp_node[comp_id] = of_node_get(node); 397 + 398 + /* 399 + * Currently only the OVL, RDMA, DSI, and DPI blocks have 400 + * separate component platform drivers and initialize their own 401 + * DDP component structure. The others are initialized here. 402 + */ 403 + if (comp_type == MTK_DISP_OVL || 404 + comp_type == MTK_DISP_RDMA || 405 + comp_type == MTK_DSI || 406 + comp_type == MTK_DPI) { 407 + dev_info(dev, "Adding component match for %s\n", 408 + node->full_name); 409 + component_match_add(dev, &match, compare_of, node); 410 + } else { 411 + struct mtk_ddp_comp *comp; 412 + 413 + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); 414 + if (!comp) { 415 + ret = -ENOMEM; 416 + goto err_node; 417 + } 418 + 419 + ret = mtk_ddp_comp_init(dev, node, comp, comp_id, NULL); 420 + if (ret) 421 + goto err_node; 422 + 423 + private->ddp_comp[comp_id] = comp; 424 + } 425 + } 426 + 427 + if (!private->mutex_node) { 428 + dev_err(dev, "Failed to find disp-mutex node\n"); 429 + ret = -ENODEV; 430 + goto err_node; 431 + } 432 + 433 + pm_runtime_enable(dev); 434 + 435 + platform_set_drvdata(pdev, private); 436 + 437 + ret = component_master_add_with_match(dev, &mtk_drm_ops, match); 438 + if (ret) 439 + goto err_pm; 440 + 441 + return 0; 442 + 443 + err_pm: 444 + pm_runtime_disable(dev); 445 + err_node: 446 + of_node_put(private->mutex_node); 447 + for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) 448 + of_node_put(private->comp_node[i]); 449 + return ret; 450 + } 451 + 452 + static int mtk_drm_remove(struct platform_device *pdev) 453 + { 454 + struct mtk_drm_private *private = platform_get_drvdata(pdev); 455 + struct drm_device *drm = private->drm; 456 + int i; 457 + 458 + drm_connector_unregister_all(drm); 459 + drm_dev_unregister(drm); 460 + mtk_drm_kms_deinit(drm); 461 + drm_dev_unref(drm); 462 + 463 + component_master_del(&pdev->dev, &mtk_drm_ops); 464 + pm_runtime_disable(&pdev->dev); 465 + of_node_put(private->mutex_node); 466 + for (i = 0; i < DDP_COMPONENT_ID_MAX; i++) 467 + of_node_put(private->comp_node[i]); 468 + 469 + return 0; 470 + } 471 + 472 + #ifdef CONFIG_PM_SLEEP 473 + static int mtk_drm_sys_suspend(struct device *dev) 474 + { 475 + struct mtk_drm_private *private = dev_get_drvdata(dev); 476 + struct drm_device *drm = private->drm; 477 + 478 + drm_kms_helper_poll_disable(drm); 479 + 480 + private->suspend_state = drm_atomic_helper_suspend(drm); 481 + if (IS_ERR(private->suspend_state)) { 482 + drm_kms_helper_poll_enable(drm); 483 + return PTR_ERR(private->suspend_state); 484 + } 485 + 486 + DRM_DEBUG_DRIVER("mtk_drm_sys_suspend\n"); 487 + return 0; 488 + } 489 + 490 + static int mtk_drm_sys_resume(struct device *dev) 491 + { 492 + struct mtk_drm_private *private = dev_get_drvdata(dev); 493 + struct drm_device *drm = private->drm; 494 + 495 + drm_atomic_helper_resume(drm, private->suspend_state); 496 + drm_kms_helper_poll_enable(drm); 497 + 498 + DRM_DEBUG_DRIVER("mtk_drm_sys_resume\n"); 499 + return 0; 500 + } 501 + #endif 502 + 503 + static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend, 504 + mtk_drm_sys_resume); 505 + 506 + static const struct of_device_id mtk_drm_of_ids[] = { 507 + { .compatible = "mediatek,mt8173-mmsys", }, 508 + { } 509 + }; 510 + 511 + static struct platform_driver mtk_drm_platform_driver = { 512 + .probe = mtk_drm_probe, 513 + .remove = mtk_drm_remove, 514 + .driver = { 515 + .name = "mediatek-drm", 516 + .of_match_table = mtk_drm_of_ids, 517 + .pm = &mtk_drm_pm_ops, 518 + }, 519 + }; 520 + 521 + static struct platform_driver * const mtk_drm_drivers[] = { 522 + &mtk_ddp_driver, 523 + &mtk_disp_ovl_driver, 524 + &mtk_disp_rdma_driver, 525 + &mtk_dpi_driver, 526 + &mtk_drm_platform_driver, 527 + &mtk_dsi_driver, 528 + &mtk_mipi_tx_driver, 529 + }; 530 + 531 + static int __init mtk_drm_init(void) 532 + { 533 + int ret; 534 + int i; 535 + 536 + for (i = 0; i < ARRAY_SIZE(mtk_drm_drivers); i++) { 537 + ret = platform_driver_register(mtk_drm_drivers[i]); 538 + if (ret < 0) { 539 + pr_err("Failed to register %s driver: %d\n", 540 + mtk_drm_drivers[i]->driver.name, ret); 541 + goto err; 542 + } 543 + } 544 + 545 + return 0; 546 + 547 + err: 548 + while (--i >= 0) 549 + platform_driver_unregister(mtk_drm_drivers[i]); 550 + 551 + return ret; 552 + } 553 + 554 + static void __exit mtk_drm_exit(void) 555 + { 556 + int i; 557 + 558 + for (i = ARRAY_SIZE(mtk_drm_drivers) - 1; i >= 0; i--) 559 + platform_driver_unregister(mtk_drm_drivers[i]); 560 + } 561 + 562 + module_init(mtk_drm_init); 563 + module_exit(mtk_drm_exit); 564 + 565 + MODULE_AUTHOR("YT SHEN <yt.shen@mediatek.com>"); 566 + MODULE_DESCRIPTION("Mediatek SoC DRM driver"); 567 + MODULE_LICENSE("GPL v2");
+60
drivers/gpu/drm/mediatek/mtk_drm_drv.h
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef MTK_DRM_DRV_H 15 + #define MTK_DRM_DRV_H 16 + 17 + #include <linux/io.h> 18 + #include "mtk_drm_ddp_comp.h" 19 + 20 + #define MAX_CRTC 2 21 + #define MAX_CONNECTOR 2 22 + 23 + struct device; 24 + struct device_node; 25 + struct drm_crtc; 26 + struct drm_device; 27 + struct drm_fb_helper; 28 + struct drm_property; 29 + struct regmap; 30 + 31 + struct mtk_drm_private { 32 + struct drm_device *drm; 33 + struct device *dma_dev; 34 + 35 + struct drm_crtc *crtc[MAX_CRTC]; 36 + unsigned int num_pipes; 37 + 38 + struct device_node *mutex_node; 39 + struct device *mutex_dev; 40 + void __iomem *config_regs; 41 + struct device_node *comp_node[DDP_COMPONENT_ID_MAX]; 42 + struct mtk_ddp_comp *ddp_comp[DDP_COMPONENT_ID_MAX]; 43 + 44 + struct { 45 + struct drm_atomic_state *state; 46 + struct work_struct work; 47 + struct mutex lock; 48 + } commit; 49 + 50 + struct drm_atomic_state *suspend_state; 51 + }; 52 + 53 + extern struct platform_driver mtk_ddp_driver; 54 + extern struct platform_driver mtk_disp_ovl_driver; 55 + extern struct platform_driver mtk_disp_rdma_driver; 56 + extern struct platform_driver mtk_dpi_driver; 57 + extern struct platform_driver mtk_dsi_driver; 58 + extern struct platform_driver mtk_mipi_tx_driver; 59 + 60 + #endif /* MTK_DRM_DRV_H */
+165
drivers/gpu/drm/mediatek/mtk_drm_fb.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <drm/drmP.h> 15 + #include <drm/drm_crtc_helper.h> 16 + #include <drm/drm_fb_helper.h> 17 + #include <drm/drm_gem.h> 18 + #include <linux/dma-buf.h> 19 + #include <linux/reservation.h> 20 + 21 + #include "mtk_drm_drv.h" 22 + #include "mtk_drm_fb.h" 23 + #include "mtk_drm_gem.h" 24 + 25 + /* 26 + * mtk specific framebuffer structure. 27 + * 28 + * @fb: drm framebuffer object. 29 + * @gem_obj: array of gem objects. 30 + */ 31 + struct mtk_drm_fb { 32 + struct drm_framebuffer base; 33 + /* For now we only support a single plane */ 34 + struct drm_gem_object *gem_obj; 35 + }; 36 + 37 + #define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base) 38 + 39 + struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb) 40 + { 41 + struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); 42 + 43 + return mtk_fb->gem_obj; 44 + } 45 + 46 + static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb, 47 + struct drm_file *file_priv, 48 + unsigned int *handle) 49 + { 50 + struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); 51 + 52 + return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle); 53 + } 54 + 55 + static void mtk_drm_fb_destroy(struct drm_framebuffer *fb) 56 + { 57 + struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); 58 + 59 + drm_framebuffer_cleanup(fb); 60 + 61 + drm_gem_object_unreference_unlocked(mtk_fb->gem_obj); 62 + 63 + kfree(mtk_fb); 64 + } 65 + 66 + static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = { 67 + .create_handle = mtk_drm_fb_create_handle, 68 + .destroy = mtk_drm_fb_destroy, 69 + }; 70 + 71 + static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, 72 + const struct drm_mode_fb_cmd2 *mode, 73 + struct drm_gem_object *obj) 74 + { 75 + struct mtk_drm_fb *mtk_fb; 76 + int ret; 77 + 78 + if (drm_format_num_planes(mode->pixel_format) != 1) 79 + return ERR_PTR(-EINVAL); 80 + 81 + mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL); 82 + if (!mtk_fb) 83 + return ERR_PTR(-ENOMEM); 84 + 85 + drm_helper_mode_fill_fb_struct(&mtk_fb->base, mode); 86 + 87 + mtk_fb->gem_obj = obj; 88 + 89 + ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs); 90 + if (ret) { 91 + DRM_ERROR("failed to initialize framebuffer\n"); 92 + kfree(mtk_fb); 93 + return ERR_PTR(ret); 94 + } 95 + 96 + return mtk_fb; 97 + } 98 + 99 + /* 100 + * Wait for any exclusive fence in fb's gem object's reservation object. 101 + * 102 + * Returns -ERESTARTSYS if interrupted, else 0. 103 + */ 104 + int mtk_fb_wait(struct drm_framebuffer *fb) 105 + { 106 + struct drm_gem_object *gem; 107 + struct reservation_object *resv; 108 + long ret; 109 + 110 + if (!fb) 111 + return 0; 112 + 113 + gem = mtk_fb_get_gem_obj(fb); 114 + if (!gem || !gem->dma_buf || !gem->dma_buf->resv) 115 + return 0; 116 + 117 + resv = gem->dma_buf->resv; 118 + ret = reservation_object_wait_timeout_rcu(resv, false, true, 119 + MAX_SCHEDULE_TIMEOUT); 120 + /* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */ 121 + if (WARN_ON(ret < 0)) 122 + return ret; 123 + 124 + return 0; 125 + } 126 + 127 + struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, 128 + struct drm_file *file, 129 + const struct drm_mode_fb_cmd2 *cmd) 130 + { 131 + struct mtk_drm_fb *mtk_fb; 132 + struct drm_gem_object *gem; 133 + unsigned int width = cmd->width; 134 + unsigned int height = cmd->height; 135 + unsigned int size, bpp; 136 + int ret; 137 + 138 + if (drm_format_num_planes(cmd->pixel_format) != 1) 139 + return ERR_PTR(-EINVAL); 140 + 141 + gem = drm_gem_object_lookup(dev, file, cmd->handles[0]); 142 + if (!gem) 143 + return ERR_PTR(-ENOENT); 144 + 145 + bpp = drm_format_plane_cpp(cmd->pixel_format, 0); 146 + size = (height - 1) * cmd->pitches[0] + width * bpp; 147 + size += cmd->offsets[0]; 148 + 149 + if (gem->size < size) { 150 + ret = -EINVAL; 151 + goto unreference; 152 + } 153 + 154 + mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem); 155 + if (IS_ERR(mtk_fb)) { 156 + ret = PTR_ERR(mtk_fb); 157 + goto unreference; 158 + } 159 + 160 + return &mtk_fb->base; 161 + 162 + unreference: 163 + drm_gem_object_unreference_unlocked(gem); 164 + return ERR_PTR(ret); 165 + }
+23
drivers/gpu/drm/mediatek/mtk_drm_fb.h
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef MTK_DRM_FB_H 15 + #define MTK_DRM_FB_H 16 + 17 + struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb); 18 + int mtk_fb_wait(struct drm_framebuffer *fb); 19 + struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, 20 + struct drm_file *file, 21 + const struct drm_mode_fb_cmd2 *cmd); 22 + 23 + #endif /* MTK_DRM_FB_H */
+269
drivers/gpu/drm/mediatek/mtk_drm_gem.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <drm/drmP.h> 15 + #include <drm/drm_gem.h> 16 + #include <linux/dma-buf.h> 17 + 18 + #include "mtk_drm_drv.h" 19 + #include "mtk_drm_gem.h" 20 + 21 + static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev, 22 + unsigned long size) 23 + { 24 + struct mtk_drm_gem_obj *mtk_gem_obj; 25 + int ret; 26 + 27 + size = round_up(size, PAGE_SIZE); 28 + 29 + mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL); 30 + if (!mtk_gem_obj) 31 + return ERR_PTR(-ENOMEM); 32 + 33 + ret = drm_gem_object_init(dev, &mtk_gem_obj->base, size); 34 + if (ret < 0) { 35 + DRM_ERROR("failed to initialize gem object\n"); 36 + kfree(mtk_gem_obj); 37 + return ERR_PTR(ret); 38 + } 39 + 40 + return mtk_gem_obj; 41 + } 42 + 43 + struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev, 44 + size_t size, bool alloc_kmap) 45 + { 46 + struct mtk_drm_private *priv = dev->dev_private; 47 + struct mtk_drm_gem_obj *mtk_gem; 48 + struct drm_gem_object *obj; 49 + int ret; 50 + 51 + mtk_gem = mtk_drm_gem_init(dev, size); 52 + if (IS_ERR(mtk_gem)) 53 + return ERR_CAST(mtk_gem); 54 + 55 + obj = &mtk_gem->base; 56 + 57 + init_dma_attrs(&mtk_gem->dma_attrs); 58 + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &mtk_gem->dma_attrs); 59 + 60 + if (!alloc_kmap) 61 + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &mtk_gem->dma_attrs); 62 + 63 + mtk_gem->cookie = dma_alloc_attrs(priv->dma_dev, obj->size, 64 + &mtk_gem->dma_addr, GFP_KERNEL, 65 + &mtk_gem->dma_attrs); 66 + if (!mtk_gem->cookie) { 67 + DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size); 68 + ret = -ENOMEM; 69 + goto err_gem_free; 70 + } 71 + 72 + if (alloc_kmap) 73 + mtk_gem->kvaddr = mtk_gem->cookie; 74 + 75 + DRM_DEBUG_DRIVER("cookie = %p dma_addr = %pad size = %zu\n", 76 + mtk_gem->cookie, &mtk_gem->dma_addr, 77 + size); 78 + 79 + return mtk_gem; 80 + 81 + err_gem_free: 82 + drm_gem_object_release(obj); 83 + kfree(mtk_gem); 84 + return ERR_PTR(ret); 85 + } 86 + 87 + void mtk_drm_gem_free_object(struct drm_gem_object *obj) 88 + { 89 + struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); 90 + struct mtk_drm_private *priv = obj->dev->dev_private; 91 + 92 + if (mtk_gem->sg) 93 + drm_prime_gem_destroy(obj, mtk_gem->sg); 94 + else 95 + dma_free_attrs(priv->dma_dev, obj->size, mtk_gem->cookie, 96 + mtk_gem->dma_addr, &mtk_gem->dma_attrs); 97 + 98 + /* release file pointer to gem object. */ 99 + drm_gem_object_release(obj); 100 + 101 + kfree(mtk_gem); 102 + } 103 + 104 + int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, 105 + struct drm_mode_create_dumb *args) 106 + { 107 + struct mtk_drm_gem_obj *mtk_gem; 108 + int ret; 109 + 110 + args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); 111 + args->size = args->pitch * args->height; 112 + 113 + mtk_gem = mtk_drm_gem_create(dev, args->size, false); 114 + if (IS_ERR(mtk_gem)) 115 + return PTR_ERR(mtk_gem); 116 + 117 + /* 118 + * allocate a id of idr table where the obj is registered 119 + * and handle has the id what user can see. 120 + */ 121 + ret = drm_gem_handle_create(file_priv, &mtk_gem->base, &args->handle); 122 + if (ret) 123 + goto err_handle_create; 124 + 125 + /* drop reference from allocate - handle holds it now. */ 126 + drm_gem_object_unreference_unlocked(&mtk_gem->base); 127 + 128 + return 0; 129 + 130 + err_handle_create: 131 + mtk_drm_gem_free_object(&mtk_gem->base); 132 + return ret; 133 + } 134 + 135 + int mtk_drm_gem_dumb_map_offset(struct drm_file *file_priv, 136 + struct drm_device *dev, uint32_t handle, 137 + uint64_t *offset) 138 + { 139 + struct drm_gem_object *obj; 140 + int ret; 141 + 142 + obj = drm_gem_object_lookup(dev, file_priv, handle); 143 + if (!obj) { 144 + DRM_ERROR("failed to lookup gem object.\n"); 145 + return -EINVAL; 146 + } 147 + 148 + ret = drm_gem_create_mmap_offset(obj); 149 + if (ret) 150 + goto out; 151 + 152 + *offset = drm_vma_node_offset_addr(&obj->vma_node); 153 + DRM_DEBUG_KMS("offset = 0x%llx\n", *offset); 154 + 155 + out: 156 + drm_gem_object_unreference_unlocked(obj); 157 + return ret; 158 + } 159 + 160 + static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj, 161 + struct vm_area_struct *vma) 162 + 163 + { 164 + int ret; 165 + struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); 166 + struct mtk_drm_private *priv = obj->dev->dev_private; 167 + 168 + /* 169 + * dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear 170 + * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). 171 + */ 172 + vma->vm_flags &= ~VM_PFNMAP; 173 + vma->vm_pgoff = 0; 174 + 175 + ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie, 176 + mtk_gem->dma_addr, obj->size, &mtk_gem->dma_attrs); 177 + if (ret) 178 + drm_gem_vm_close(vma); 179 + 180 + return ret; 181 + } 182 + 183 + int mtk_drm_gem_mmap_buf(struct drm_gem_object *obj, struct vm_area_struct *vma) 184 + { 185 + int ret; 186 + 187 + ret = drm_gem_mmap_obj(obj, obj->size, vma); 188 + if (ret) 189 + return ret; 190 + 191 + return mtk_drm_gem_object_mmap(obj, vma); 192 + } 193 + 194 + int mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) 195 + { 196 + struct drm_gem_object *obj; 197 + int ret; 198 + 199 + ret = drm_gem_mmap(filp, vma); 200 + if (ret) 201 + return ret; 202 + 203 + obj = vma->vm_private_data; 204 + 205 + return mtk_drm_gem_object_mmap(obj, vma); 206 + } 207 + 208 + /* 209 + * Allocate a sg_table for this GEM object. 210 + * Note: Both the table's contents, and the sg_table itself must be freed by 211 + * the caller. 212 + * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error. 213 + */ 214 + struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj) 215 + { 216 + struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); 217 + struct mtk_drm_private *priv = obj->dev->dev_private; 218 + struct sg_table *sgt; 219 + int ret; 220 + 221 + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); 222 + if (!sgt) 223 + return ERR_PTR(-ENOMEM); 224 + 225 + ret = dma_get_sgtable_attrs(priv->dma_dev, sgt, mtk_gem->cookie, 226 + mtk_gem->dma_addr, obj->size, 227 + &mtk_gem->dma_attrs); 228 + if (ret) { 229 + DRM_ERROR("failed to allocate sgt, %d\n", ret); 230 + kfree(sgt); 231 + return ERR_PTR(ret); 232 + } 233 + 234 + return sgt; 235 + } 236 + 237 + struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, 238 + struct dma_buf_attachment *attach, struct sg_table *sg) 239 + { 240 + struct mtk_drm_gem_obj *mtk_gem; 241 + int ret; 242 + struct scatterlist *s; 243 + unsigned int i; 244 + dma_addr_t expected; 245 + 246 + mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size); 247 + 248 + if (IS_ERR(mtk_gem)) 249 + return ERR_PTR(PTR_ERR(mtk_gem)); 250 + 251 + expected = sg_dma_address(sg->sgl); 252 + for_each_sg(sg->sgl, s, sg->nents, i) { 253 + if (sg_dma_address(s) != expected) { 254 + DRM_ERROR("sg_table is not contiguous"); 255 + ret = -EINVAL; 256 + goto err_gem_free; 257 + } 258 + expected = sg_dma_address(s) + sg_dma_len(s); 259 + } 260 + 261 + mtk_gem->dma_addr = sg_dma_address(sg->sgl); 262 + mtk_gem->sg = sg; 263 + 264 + return &mtk_gem->base; 265 + 266 + err_gem_free: 267 + kfree(mtk_gem); 268 + return ERR_PTR(ret); 269 + }
+59
drivers/gpu/drm/mediatek/mtk_drm_gem.h
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #ifndef _MTK_DRM_GEM_H_ 15 + #define _MTK_DRM_GEM_H_ 16 + 17 + #include <drm/drm_gem.h> 18 + 19 + /* 20 + * mtk drm buffer structure. 21 + * 22 + * @base: a gem object. 23 + * - a new handle to this gem object would be created 24 + * by drm_gem_handle_create(). 25 + * @cookie: the return value of dma_alloc_attrs(), keep it for dma_free_attrs() 26 + * @kvaddr: kernel virtual address of gem buffer. 27 + * @dma_addr: dma address of gem buffer. 28 + * @dma_attrs: dma attributes of gem buffer. 29 + * 30 + * P.S. this object would be transferred to user as kms_bo.handle so 31 + * user can access the buffer through kms_bo.handle. 32 + */ 33 + struct mtk_drm_gem_obj { 34 + struct drm_gem_object base; 35 + void *cookie; 36 + void *kvaddr; 37 + dma_addr_t dma_addr; 38 + struct dma_attrs dma_attrs; 39 + struct sg_table *sg; 40 + }; 41 + 42 + #define to_mtk_gem_obj(x) container_of(x, struct mtk_drm_gem_obj, base) 43 + 44 + void mtk_drm_gem_free_object(struct drm_gem_object *gem); 45 + struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev, size_t size, 46 + bool alloc_kmap); 47 + int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, 48 + struct drm_mode_create_dumb *args); 49 + int mtk_drm_gem_dumb_map_offset(struct drm_file *file_priv, 50 + struct drm_device *dev, uint32_t handle, 51 + uint64_t *offset); 52 + int mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); 53 + int mtk_drm_gem_mmap_buf(struct drm_gem_object *obj, 54 + struct vm_area_struct *vma); 55 + struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj); 56 + struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev, 57 + struct dma_buf_attachment *attach, struct sg_table *sg); 58 + 59 + #endif
+240
drivers/gpu/drm/mediatek/mtk_drm_plane.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * Author: CK Hu <ck.hu@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #include <drm/drmP.h> 16 + #include <drm/drm_atomic.h> 17 + #include <drm/drm_atomic_helper.h> 18 + #include <drm/drm_plane_helper.h> 19 + 20 + #include "mtk_drm_crtc.h" 21 + #include "mtk_drm_ddp_comp.h" 22 + #include "mtk_drm_drv.h" 23 + #include "mtk_drm_fb.h" 24 + #include "mtk_drm_gem.h" 25 + #include "mtk_drm_plane.h" 26 + 27 + static const u32 formats[] = { 28 + DRM_FORMAT_XRGB8888, 29 + DRM_FORMAT_ARGB8888, 30 + DRM_FORMAT_RGB565, 31 + }; 32 + 33 + static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane, bool enable, 34 + dma_addr_t addr, struct drm_rect *dest) 35 + { 36 + struct drm_plane *plane = &mtk_plane->base; 37 + struct mtk_plane_state *state = to_mtk_plane_state(plane->state); 38 + unsigned int pitch, format; 39 + int x, y; 40 + 41 + if (WARN_ON(!plane->state || (enable && !plane->state->fb))) 42 + return; 43 + 44 + if (plane->state->fb) { 45 + pitch = plane->state->fb->pitches[0]; 46 + format = plane->state->fb->pixel_format; 47 + } else { 48 + pitch = 0; 49 + format = DRM_FORMAT_RGBA8888; 50 + } 51 + 52 + x = plane->state->crtc_x; 53 + y = plane->state->crtc_y; 54 + 55 + if (x < 0) { 56 + addr -= x * 4; 57 + x = 0; 58 + } 59 + 60 + if (y < 0) { 61 + addr -= y * pitch; 62 + y = 0; 63 + } 64 + 65 + state->pending.enable = enable; 66 + state->pending.pitch = pitch; 67 + state->pending.format = format; 68 + state->pending.addr = addr; 69 + state->pending.x = x; 70 + state->pending.y = y; 71 + state->pending.width = dest->x2 - dest->x1; 72 + state->pending.height = dest->y2 - dest->y1; 73 + wmb(); /* Make sure the above parameters are set before update */ 74 + state->pending.dirty = true; 75 + } 76 + 77 + static void mtk_plane_reset(struct drm_plane *plane) 78 + { 79 + struct mtk_plane_state *state; 80 + 81 + if (plane->state) { 82 + if (plane->state->fb) 83 + drm_framebuffer_unreference(plane->state->fb); 84 + 85 + state = to_mtk_plane_state(plane->state); 86 + memset(state, 0, sizeof(*state)); 87 + } else { 88 + state = kzalloc(sizeof(*state), GFP_KERNEL); 89 + if (!state) 90 + return; 91 + plane->state = &state->base; 92 + } 93 + 94 + state->base.plane = plane; 95 + state->pending.format = DRM_FORMAT_RGB565; 96 + } 97 + 98 + static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) 99 + { 100 + struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state); 101 + struct mtk_plane_state *state; 102 + 103 + state = kzalloc(sizeof(*state), GFP_KERNEL); 104 + if (!state) 105 + return NULL; 106 + 107 + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); 108 + 109 + WARN_ON(state->base.plane != plane); 110 + 111 + state->pending = old_state->pending; 112 + 113 + return &state->base; 114 + } 115 + 116 + static void mtk_drm_plane_destroy_state(struct drm_plane *plane, 117 + struct drm_plane_state *state) 118 + { 119 + __drm_atomic_helper_plane_destroy_state(plane, state); 120 + kfree(to_mtk_plane_state(state)); 121 + } 122 + 123 + static const struct drm_plane_funcs mtk_plane_funcs = { 124 + .update_plane = drm_atomic_helper_update_plane, 125 + .disable_plane = drm_atomic_helper_disable_plane, 126 + .destroy = drm_plane_cleanup, 127 + .reset = mtk_plane_reset, 128 + .atomic_duplicate_state = mtk_plane_duplicate_state, 129 + .atomic_destroy_state = mtk_drm_plane_destroy_state, 130 + }; 131 + 132 + static int mtk_plane_atomic_check(struct drm_plane *plane, 133 + struct drm_plane_state *state) 134 + { 135 + struct drm_framebuffer *fb = state->fb; 136 + struct drm_crtc_state *crtc_state; 137 + bool visible; 138 + struct drm_rect dest = { 139 + .x1 = state->crtc_x, 140 + .y1 = state->crtc_y, 141 + .x2 = state->crtc_x + state->crtc_w, 142 + .y2 = state->crtc_y + state->crtc_h, 143 + }; 144 + struct drm_rect src = { 145 + /* 16.16 fixed point */ 146 + .x1 = state->src_x, 147 + .y1 = state->src_y, 148 + .x2 = state->src_x + state->src_w, 149 + .y2 = state->src_y + state->src_h, 150 + }; 151 + struct drm_rect clip = { 0, }; 152 + 153 + if (!fb) 154 + return 0; 155 + 156 + if (!mtk_fb_get_gem_obj(fb)) { 157 + DRM_DEBUG_KMS("buffer is null\n"); 158 + return -EFAULT; 159 + } 160 + 161 + if (!state->crtc) 162 + return 0; 163 + 164 + crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); 165 + if (IS_ERR(crtc_state)) 166 + return PTR_ERR(crtc_state); 167 + 168 + clip.x2 = crtc_state->mode.hdisplay; 169 + clip.y2 = crtc_state->mode.vdisplay; 170 + 171 + return drm_plane_helper_check_update(plane, state->crtc, fb, 172 + &src, &dest, &clip, 173 + DRM_PLANE_HELPER_NO_SCALING, 174 + DRM_PLANE_HELPER_NO_SCALING, 175 + true, true, &visible); 176 + } 177 + 178 + static void mtk_plane_atomic_update(struct drm_plane *plane, 179 + struct drm_plane_state *old_state) 180 + { 181 + struct mtk_plane_state *state = to_mtk_plane_state(plane->state); 182 + struct drm_crtc *crtc = state->base.crtc; 183 + struct drm_gem_object *gem; 184 + struct mtk_drm_gem_obj *mtk_gem; 185 + struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane); 186 + struct drm_rect dest = { 187 + .x1 = state->base.crtc_x, 188 + .y1 = state->base.crtc_y, 189 + .x2 = state->base.crtc_x + state->base.crtc_w, 190 + .y2 = state->base.crtc_y + state->base.crtc_h, 191 + }; 192 + struct drm_rect clip = { 0, }; 193 + 194 + if (!crtc) 195 + return; 196 + 197 + clip.x2 = state->base.crtc->state->mode.hdisplay; 198 + clip.y2 = state->base.crtc->state->mode.vdisplay; 199 + drm_rect_intersect(&dest, &clip); 200 + 201 + gem = mtk_fb_get_gem_obj(state->base.fb); 202 + mtk_gem = to_mtk_gem_obj(gem); 203 + mtk_plane_enable(mtk_plane, true, mtk_gem->dma_addr, &dest); 204 + } 205 + 206 + static void mtk_plane_atomic_disable(struct drm_plane *plane, 207 + struct drm_plane_state *old_state) 208 + { 209 + struct mtk_plane_state *state = to_mtk_plane_state(plane->state); 210 + 211 + state->pending.enable = false; 212 + wmb(); /* Make sure the above parameter is set before update */ 213 + state->pending.dirty = true; 214 + } 215 + 216 + static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = { 217 + .atomic_check = mtk_plane_atomic_check, 218 + .atomic_update = mtk_plane_atomic_update, 219 + .atomic_disable = mtk_plane_atomic_disable, 220 + }; 221 + 222 + int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane, 223 + unsigned long possible_crtcs, enum drm_plane_type type, 224 + unsigned int zpos) 225 + { 226 + int err; 227 + 228 + err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs, 229 + &mtk_plane_funcs, formats, 230 + ARRAY_SIZE(formats), type, NULL); 231 + if (err) { 232 + DRM_ERROR("failed to initialize plane\n"); 233 + return err; 234 + } 235 + 236 + drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs); 237 + mtk_plane->idx = zpos; 238 + 239 + return 0; 240 + }
+59
drivers/gpu/drm/mediatek/mtk_drm_plane.h
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * Author: CK Hu <ck.hu@mediatek.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + */ 14 + 15 + #ifndef _MTK_DRM_PLANE_H_ 16 + #define _MTK_DRM_PLANE_H_ 17 + 18 + #include <drm/drm_crtc.h> 19 + #include <linux/types.h> 20 + 21 + struct mtk_drm_plane { 22 + struct drm_plane base; 23 + unsigned int idx; 24 + }; 25 + 26 + struct mtk_plane_pending_state { 27 + bool config; 28 + bool enable; 29 + dma_addr_t addr; 30 + unsigned int pitch; 31 + unsigned int format; 32 + unsigned int x; 33 + unsigned int y; 34 + unsigned int width; 35 + unsigned int height; 36 + bool dirty; 37 + }; 38 + 39 + struct mtk_plane_state { 40 + struct drm_plane_state base; 41 + struct mtk_plane_pending_state pending; 42 + }; 43 + 44 + static inline struct mtk_drm_plane *to_mtk_plane(struct drm_plane *plane) 45 + { 46 + return container_of(plane, struct mtk_drm_plane, base); 47 + } 48 + 49 + static inline struct mtk_plane_state * 50 + to_mtk_plane_state(struct drm_plane_state *state) 51 + { 52 + return container_of(state, struct mtk_plane_state, base); 53 + } 54 + 55 + int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane, 56 + unsigned long possible_crtcs, enum drm_plane_type type, 57 + unsigned int zpos); 58 + 59 + #endif
+913
drivers/gpu/drm/mediatek/mtk_dsi.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <drm/drmP.h> 15 + #include <drm/drm_atomic_helper.h> 16 + #include <drm/drm_crtc_helper.h> 17 + #include <drm/drm_mipi_dsi.h> 18 + #include <drm/drm_panel.h> 19 + #include <linux/clk.h> 20 + #include <linux/component.h> 21 + #include <linux/of.h> 22 + #include <linux/of_platform.h> 23 + #include <linux/of_graph.h> 24 + #include <linux/phy/phy.h> 25 + #include <linux/platform_device.h> 26 + #include <video/videomode.h> 27 + 28 + #include "mtk_drm_ddp_comp.h" 29 + 30 + #define DSI_VIDEO_FIFO_DEPTH (1920 / 4) 31 + #define DSI_HOST_FIFO_DEPTH 64 32 + 33 + #define DSI_START 0x00 34 + 35 + #define DSI_CON_CTRL 0x10 36 + #define DSI_RESET BIT(0) 37 + #define DSI_EN BIT(1) 38 + 39 + #define DSI_MODE_CTRL 0x14 40 + #define MODE (3) 41 + #define CMD_MODE 0 42 + #define SYNC_PULSE_MODE 1 43 + #define SYNC_EVENT_MODE 2 44 + #define BURST_MODE 3 45 + #define FRM_MODE BIT(16) 46 + #define MIX_MODE BIT(17) 47 + 48 + #define DSI_TXRX_CTRL 0x18 49 + #define VC_NUM (2 << 0) 50 + #define LANE_NUM (0xf << 2) 51 + #define DIS_EOT BIT(6) 52 + #define NULL_EN BIT(7) 53 + #define TE_FREERUN BIT(8) 54 + #define EXT_TE_EN BIT(9) 55 + #define EXT_TE_EDGE BIT(10) 56 + #define MAX_RTN_SIZE (0xf << 12) 57 + #define HSTX_CKLP_EN BIT(16) 58 + 59 + #define DSI_PSCTRL 0x1c 60 + #define DSI_PS_WC 0x3fff 61 + #define DSI_PS_SEL (3 << 16) 62 + #define PACKED_PS_16BIT_RGB565 (0 << 16) 63 + #define LOOSELY_PS_18BIT_RGB666 (1 << 16) 64 + #define PACKED_PS_18BIT_RGB666 (2 << 16) 65 + #define PACKED_PS_24BIT_RGB888 (3 << 16) 66 + 67 + #define DSI_VSA_NL 0x20 68 + #define DSI_VBP_NL 0x24 69 + #define DSI_VFP_NL 0x28 70 + #define DSI_VACT_NL 0x2C 71 + #define DSI_HSA_WC 0x50 72 + #define DSI_HBP_WC 0x54 73 + #define DSI_HFP_WC 0x58 74 + 75 + #define DSI_HSTX_CKL_WC 0x64 76 + 77 + #define DSI_PHY_LCCON 0x104 78 + #define LC_HS_TX_EN BIT(0) 79 + #define LC_ULPM_EN BIT(1) 80 + #define LC_WAKEUP_EN BIT(2) 81 + 82 + #define DSI_PHY_LD0CON 0x108 83 + #define LD0_HS_TX_EN BIT(0) 84 + #define LD0_ULPM_EN BIT(1) 85 + #define LD0_WAKEUP_EN BIT(2) 86 + 87 + #define DSI_PHY_TIMECON0 0x110 88 + #define LPX (0xff << 0) 89 + #define HS_PRPR (0xff << 8) 90 + #define HS_ZERO (0xff << 16) 91 + #define HS_TRAIL (0xff << 24) 92 + 93 + #define DSI_PHY_TIMECON1 0x114 94 + #define TA_GO (0xff << 0) 95 + #define TA_SURE (0xff << 8) 96 + #define TA_GET (0xff << 16) 97 + #define DA_HS_EXIT (0xff << 24) 98 + 99 + #define DSI_PHY_TIMECON2 0x118 100 + #define CONT_DET (0xff << 0) 101 + #define CLK_ZERO (0xff << 16) 102 + #define CLK_TRAIL (0xff << 24) 103 + 104 + #define DSI_PHY_TIMECON3 0x11c 105 + #define CLK_HS_PRPR (0xff << 0) 106 + #define CLK_HS_POST (0xff << 8) 107 + #define CLK_HS_EXIT (0xff << 16) 108 + 109 + #define NS_TO_CYCLE(n, c) ((n) / (c) + (((n) % (c)) ? 1 : 0)) 110 + 111 + struct phy; 112 + 113 + struct mtk_dsi { 114 + struct mtk_ddp_comp ddp_comp; 115 + struct device *dev; 116 + struct mipi_dsi_host host; 117 + struct drm_encoder encoder; 118 + struct drm_connector conn; 119 + struct drm_panel *panel; 120 + struct drm_bridge *bridge; 121 + struct phy *phy; 122 + 123 + void __iomem *regs; 124 + 125 + struct clk *engine_clk; 126 + struct clk *digital_clk; 127 + struct clk *hs_clk; 128 + 129 + u32 data_rate; 130 + 131 + unsigned long mode_flags; 132 + enum mipi_dsi_pixel_format format; 133 + unsigned int lanes; 134 + struct videomode vm; 135 + int refcount; 136 + bool enabled; 137 + }; 138 + 139 + static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e) 140 + { 141 + return container_of(e, struct mtk_dsi, encoder); 142 + } 143 + 144 + static inline struct mtk_dsi *connector_to_dsi(struct drm_connector *c) 145 + { 146 + return container_of(c, struct mtk_dsi, conn); 147 + } 148 + 149 + static inline struct mtk_dsi *host_to_dsi(struct mipi_dsi_host *h) 150 + { 151 + return container_of(h, struct mtk_dsi, host); 152 + } 153 + 154 + static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, u32 mask, u32 data) 155 + { 156 + u32 temp = readl(dsi->regs + offset); 157 + 158 + writel((temp & ~mask) | (data & mask), dsi->regs + offset); 159 + } 160 + 161 + static void dsi_phy_timconfig(struct mtk_dsi *dsi) 162 + { 163 + u32 timcon0, timcon1, timcon2, timcon3; 164 + unsigned int ui, cycle_time; 165 + unsigned int lpx; 166 + 167 + ui = 1000 / dsi->data_rate + 0x01; 168 + cycle_time = 8000 / dsi->data_rate + 0x01; 169 + lpx = 5; 170 + 171 + timcon0 = (8 << 24) | (0xa << 16) | (0x6 << 8) | lpx; 172 + timcon1 = (7 << 24) | (5 * lpx << 16) | ((3 * lpx) / 2) << 8 | 173 + (4 * lpx); 174 + timcon2 = ((NS_TO_CYCLE(0x64, cycle_time) + 0xa) << 24) | 175 + (NS_TO_CYCLE(0x150, cycle_time) << 16); 176 + timcon3 = (2 * lpx) << 16 | NS_TO_CYCLE(80 + 52 * ui, cycle_time) << 8 | 177 + NS_TO_CYCLE(0x40, cycle_time); 178 + 179 + writel(timcon0, dsi->regs + DSI_PHY_TIMECON0); 180 + writel(timcon1, dsi->regs + DSI_PHY_TIMECON1); 181 + writel(timcon2, dsi->regs + DSI_PHY_TIMECON2); 182 + writel(timcon3, dsi->regs + DSI_PHY_TIMECON3); 183 + } 184 + 185 + static void mtk_dsi_enable(struct mtk_dsi *dsi) 186 + { 187 + mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, DSI_EN); 188 + } 189 + 190 + static void mtk_dsi_disable(struct mtk_dsi *dsi) 191 + { 192 + mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_EN, 0); 193 + } 194 + 195 + static void mtk_dsi_reset(struct mtk_dsi *dsi) 196 + { 197 + mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, DSI_RESET); 198 + mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0); 199 + } 200 + 201 + static int mtk_dsi_poweron(struct mtk_dsi *dsi) 202 + { 203 + struct device *dev = dsi->dev; 204 + int ret; 205 + 206 + if (++dsi->refcount != 1) 207 + return 0; 208 + 209 + /** 210 + * data_rate = (pixel_clock / 1000) * pixel_dipth * mipi_ratio; 211 + * pixel_clock unit is Khz, data_rata unit is MHz, so need divide 1000. 212 + * mipi_ratio is mipi clk coefficient for balance the pixel clk in mipi. 213 + * we set mipi_ratio is 1.05. 214 + */ 215 + dsi->data_rate = dsi->vm.pixelclock * 3 * 21 / (1 * 1000 * 10); 216 + 217 + ret = clk_set_rate(dsi->hs_clk, dsi->data_rate * 1000000); 218 + if (ret < 0) { 219 + dev_err(dev, "Failed to set data rate: %d\n", ret); 220 + goto err_refcount; 221 + } 222 + 223 + phy_power_on(dsi->phy); 224 + 225 + ret = clk_prepare_enable(dsi->engine_clk); 226 + if (ret < 0) { 227 + dev_err(dev, "Failed to enable engine clock: %d\n", ret); 228 + goto err_phy_power_off; 229 + } 230 + 231 + ret = clk_prepare_enable(dsi->digital_clk); 232 + if (ret < 0) { 233 + dev_err(dev, "Failed to enable digital clock: %d\n", ret); 234 + goto err_disable_engine_clk; 235 + } 236 + 237 + mtk_dsi_enable(dsi); 238 + mtk_dsi_reset(dsi); 239 + dsi_phy_timconfig(dsi); 240 + 241 + return 0; 242 + 243 + err_disable_engine_clk: 244 + clk_disable_unprepare(dsi->engine_clk); 245 + err_phy_power_off: 246 + phy_power_off(dsi->phy); 247 + err_refcount: 248 + dsi->refcount--; 249 + return ret; 250 + } 251 + 252 + static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi) 253 + { 254 + mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0); 255 + mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0); 256 + } 257 + 258 + static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi) 259 + { 260 + mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_ULPM_EN, 0); 261 + mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, LC_WAKEUP_EN); 262 + mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_WAKEUP_EN, 0); 263 + } 264 + 265 + static void dsi_lane0_ulp_mode_enter(struct mtk_dsi *dsi) 266 + { 267 + mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_HS_TX_EN, 0); 268 + mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0); 269 + } 270 + 271 + static void dsi_lane0_ulp_mode_leave(struct mtk_dsi *dsi) 272 + { 273 + mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_ULPM_EN, 0); 274 + mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, LD0_WAKEUP_EN); 275 + mtk_dsi_mask(dsi, DSI_PHY_LD0CON, LD0_WAKEUP_EN, 0); 276 + } 277 + 278 + static bool dsi_clk_hs_state(struct mtk_dsi *dsi) 279 + { 280 + u32 tmp_reg1; 281 + 282 + tmp_reg1 = readl(dsi->regs + DSI_PHY_LCCON); 283 + return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false; 284 + } 285 + 286 + static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter) 287 + { 288 + if (enter && !dsi_clk_hs_state(dsi)) 289 + mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, LC_HS_TX_EN); 290 + else if (!enter && dsi_clk_hs_state(dsi)) 291 + mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0); 292 + } 293 + 294 + static void dsi_set_mode(struct mtk_dsi *dsi) 295 + { 296 + u32 vid_mode = CMD_MODE; 297 + 298 + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { 299 + vid_mode = SYNC_PULSE_MODE; 300 + 301 + if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) && 302 + !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) 303 + vid_mode = BURST_MODE; 304 + } 305 + 306 + writel(vid_mode, dsi->regs + DSI_MODE_CTRL); 307 + } 308 + 309 + static void dsi_ps_control_vact(struct mtk_dsi *dsi) 310 + { 311 + struct videomode *vm = &dsi->vm; 312 + u32 dsi_buf_bpp, ps_wc; 313 + u32 ps_bpp_mode; 314 + 315 + if (dsi->format == MIPI_DSI_FMT_RGB565) 316 + dsi_buf_bpp = 2; 317 + else 318 + dsi_buf_bpp = 3; 319 + 320 + ps_wc = vm->hactive * dsi_buf_bpp; 321 + ps_bpp_mode = ps_wc; 322 + 323 + switch (dsi->format) { 324 + case MIPI_DSI_FMT_RGB888: 325 + ps_bpp_mode |= PACKED_PS_24BIT_RGB888; 326 + break; 327 + case MIPI_DSI_FMT_RGB666: 328 + ps_bpp_mode |= PACKED_PS_18BIT_RGB666; 329 + break; 330 + case MIPI_DSI_FMT_RGB666_PACKED: 331 + ps_bpp_mode |= LOOSELY_PS_18BIT_RGB666; 332 + break; 333 + case MIPI_DSI_FMT_RGB565: 334 + ps_bpp_mode |= PACKED_PS_16BIT_RGB565; 335 + break; 336 + } 337 + 338 + writel(vm->vactive, dsi->regs + DSI_VACT_NL); 339 + writel(ps_bpp_mode, dsi->regs + DSI_PSCTRL); 340 + writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC); 341 + } 342 + 343 + static void dsi_rxtx_control(struct mtk_dsi *dsi) 344 + { 345 + u32 tmp_reg; 346 + 347 + switch (dsi->lanes) { 348 + case 1: 349 + tmp_reg = 1 << 2; 350 + break; 351 + case 2: 352 + tmp_reg = 3 << 2; 353 + break; 354 + case 3: 355 + tmp_reg = 7 << 2; 356 + break; 357 + case 4: 358 + tmp_reg = 0xf << 2; 359 + break; 360 + default: 361 + tmp_reg = 0xf << 2; 362 + break; 363 + } 364 + 365 + writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL); 366 + } 367 + 368 + static void dsi_ps_control(struct mtk_dsi *dsi) 369 + { 370 + unsigned int dsi_tmp_buf_bpp; 371 + u32 tmp_reg; 372 + 373 + switch (dsi->format) { 374 + case MIPI_DSI_FMT_RGB888: 375 + tmp_reg = PACKED_PS_24BIT_RGB888; 376 + dsi_tmp_buf_bpp = 3; 377 + break; 378 + case MIPI_DSI_FMT_RGB666: 379 + tmp_reg = LOOSELY_PS_18BIT_RGB666; 380 + dsi_tmp_buf_bpp = 3; 381 + break; 382 + case MIPI_DSI_FMT_RGB666_PACKED: 383 + tmp_reg = PACKED_PS_18BIT_RGB666; 384 + dsi_tmp_buf_bpp = 3; 385 + break; 386 + case MIPI_DSI_FMT_RGB565: 387 + tmp_reg = PACKED_PS_16BIT_RGB565; 388 + dsi_tmp_buf_bpp = 2; 389 + break; 390 + default: 391 + tmp_reg = PACKED_PS_24BIT_RGB888; 392 + dsi_tmp_buf_bpp = 3; 393 + break; 394 + } 395 + 396 + tmp_reg += dsi->vm.hactive * dsi_tmp_buf_bpp & DSI_PS_WC; 397 + writel(tmp_reg, dsi->regs + DSI_PSCTRL); 398 + } 399 + 400 + static void dsi_config_vdo_timing(struct mtk_dsi *dsi) 401 + { 402 + unsigned int horizontal_sync_active_byte; 403 + unsigned int horizontal_backporch_byte; 404 + unsigned int horizontal_frontporch_byte; 405 + unsigned int dsi_tmp_buf_bpp; 406 + 407 + struct videomode *vm = &dsi->vm; 408 + 409 + if (dsi->format == MIPI_DSI_FMT_RGB565) 410 + dsi_tmp_buf_bpp = 2; 411 + else 412 + dsi_tmp_buf_bpp = 3; 413 + 414 + writel(vm->vsync_len, dsi->regs + DSI_VSA_NL); 415 + writel(vm->vback_porch, dsi->regs + DSI_VBP_NL); 416 + writel(vm->vfront_porch, dsi->regs + DSI_VFP_NL); 417 + writel(vm->vactive, dsi->regs + DSI_VACT_NL); 418 + 419 + horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10); 420 + 421 + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) 422 + horizontal_backporch_byte = 423 + (vm->hback_porch * dsi_tmp_buf_bpp - 10); 424 + else 425 + horizontal_backporch_byte = ((vm->hback_porch + vm->hsync_len) * 426 + dsi_tmp_buf_bpp - 10); 427 + 428 + horizontal_frontporch_byte = (vm->hfront_porch * dsi_tmp_buf_bpp - 12); 429 + 430 + writel(horizontal_sync_active_byte, dsi->regs + DSI_HSA_WC); 431 + writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC); 432 + writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC); 433 + 434 + dsi_ps_control(dsi); 435 + } 436 + 437 + static void mtk_dsi_start(struct mtk_dsi *dsi) 438 + { 439 + writel(0, dsi->regs + DSI_START); 440 + writel(1, dsi->regs + DSI_START); 441 + } 442 + 443 + static void mtk_dsi_poweroff(struct mtk_dsi *dsi) 444 + { 445 + if (WARN_ON(dsi->refcount == 0)) 446 + return; 447 + 448 + if (--dsi->refcount != 0) 449 + return; 450 + 451 + dsi_lane0_ulp_mode_enter(dsi); 452 + dsi_clk_ulp_mode_enter(dsi); 453 + 454 + mtk_dsi_disable(dsi); 455 + 456 + clk_disable_unprepare(dsi->engine_clk); 457 + clk_disable_unprepare(dsi->digital_clk); 458 + 459 + phy_power_off(dsi->phy); 460 + } 461 + 462 + static void mtk_output_dsi_enable(struct mtk_dsi *dsi) 463 + { 464 + int ret; 465 + 466 + if (dsi->enabled) 467 + return; 468 + 469 + if (dsi->panel) { 470 + if (drm_panel_prepare(dsi->panel)) { 471 + DRM_ERROR("failed to setup the panel\n"); 472 + return; 473 + } 474 + } 475 + 476 + ret = mtk_dsi_poweron(dsi); 477 + if (ret < 0) { 478 + DRM_ERROR("failed to power on dsi\n"); 479 + return; 480 + } 481 + 482 + dsi_rxtx_control(dsi); 483 + 484 + dsi_clk_ulp_mode_leave(dsi); 485 + dsi_lane0_ulp_mode_leave(dsi); 486 + dsi_clk_hs_mode(dsi, 0); 487 + dsi_set_mode(dsi); 488 + 489 + dsi_ps_control_vact(dsi); 490 + dsi_config_vdo_timing(dsi); 491 + 492 + dsi_set_mode(dsi); 493 + dsi_clk_hs_mode(dsi, 1); 494 + 495 + mtk_dsi_start(dsi); 496 + 497 + dsi->enabled = true; 498 + } 499 + 500 + static void mtk_output_dsi_disable(struct mtk_dsi *dsi) 501 + { 502 + if (!dsi->enabled) 503 + return; 504 + 505 + if (dsi->panel) { 506 + if (drm_panel_disable(dsi->panel)) { 507 + DRM_ERROR("failed to disable the panel\n"); 508 + return; 509 + } 510 + } 511 + 512 + mtk_dsi_poweroff(dsi); 513 + 514 + dsi->enabled = false; 515 + } 516 + 517 + static void mtk_dsi_encoder_destroy(struct drm_encoder *encoder) 518 + { 519 + drm_encoder_cleanup(encoder); 520 + } 521 + 522 + static const struct drm_encoder_funcs mtk_dsi_encoder_funcs = { 523 + .destroy = mtk_dsi_encoder_destroy, 524 + }; 525 + 526 + static bool mtk_dsi_encoder_mode_fixup(struct drm_encoder *encoder, 527 + const struct drm_display_mode *mode, 528 + struct drm_display_mode *adjusted_mode) 529 + { 530 + return true; 531 + } 532 + 533 + static void mtk_dsi_encoder_mode_set(struct drm_encoder *encoder, 534 + struct drm_display_mode *mode, 535 + struct drm_display_mode *adjusted) 536 + { 537 + struct mtk_dsi *dsi = encoder_to_dsi(encoder); 538 + 539 + dsi->vm.pixelclock = adjusted->clock; 540 + dsi->vm.hactive = adjusted->hdisplay; 541 + dsi->vm.hback_porch = adjusted->htotal - adjusted->hsync_end; 542 + dsi->vm.hfront_porch = adjusted->hsync_start - adjusted->hdisplay; 543 + dsi->vm.hsync_len = adjusted->hsync_end - adjusted->hsync_start; 544 + 545 + dsi->vm.vactive = adjusted->vdisplay; 546 + dsi->vm.vback_porch = adjusted->vtotal - adjusted->vsync_end; 547 + dsi->vm.vfront_porch = adjusted->vsync_start - adjusted->vdisplay; 548 + dsi->vm.vsync_len = adjusted->vsync_end - adjusted->vsync_start; 549 + } 550 + 551 + static void mtk_dsi_encoder_disable(struct drm_encoder *encoder) 552 + { 553 + struct mtk_dsi *dsi = encoder_to_dsi(encoder); 554 + 555 + mtk_output_dsi_disable(dsi); 556 + } 557 + 558 + static void mtk_dsi_encoder_enable(struct drm_encoder *encoder) 559 + { 560 + struct mtk_dsi *dsi = encoder_to_dsi(encoder); 561 + 562 + mtk_output_dsi_enable(dsi); 563 + } 564 + 565 + static enum drm_connector_status mtk_dsi_connector_detect( 566 + struct drm_connector *connector, bool force) 567 + { 568 + return connector_status_connected; 569 + } 570 + 571 + static int mtk_dsi_connector_get_modes(struct drm_connector *connector) 572 + { 573 + struct mtk_dsi *dsi = connector_to_dsi(connector); 574 + 575 + return drm_panel_get_modes(dsi->panel); 576 + } 577 + 578 + static struct drm_encoder *mtk_dsi_connector_best_encoder( 579 + struct drm_connector *connector) 580 + { 581 + struct mtk_dsi *dsi = connector_to_dsi(connector); 582 + 583 + return &dsi->encoder; 584 + } 585 + 586 + static const struct drm_encoder_helper_funcs mtk_dsi_encoder_helper_funcs = { 587 + .mode_fixup = mtk_dsi_encoder_mode_fixup, 588 + .mode_set = mtk_dsi_encoder_mode_set, 589 + .disable = mtk_dsi_encoder_disable, 590 + .enable = mtk_dsi_encoder_enable, 591 + }; 592 + 593 + static const struct drm_connector_funcs mtk_dsi_connector_funcs = { 594 + .dpms = drm_atomic_helper_connector_dpms, 595 + .detect = mtk_dsi_connector_detect, 596 + .fill_modes = drm_helper_probe_single_connector_modes, 597 + .destroy = drm_connector_cleanup, 598 + .reset = drm_atomic_helper_connector_reset, 599 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 600 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 601 + }; 602 + 603 + static const struct drm_connector_helper_funcs 604 + mtk_dsi_connector_helper_funcs = { 605 + .get_modes = mtk_dsi_connector_get_modes, 606 + .best_encoder = mtk_dsi_connector_best_encoder, 607 + }; 608 + 609 + static int mtk_drm_attach_bridge(struct drm_bridge *bridge, 610 + struct drm_encoder *encoder) 611 + { 612 + int ret; 613 + 614 + if (!bridge) 615 + return -ENOENT; 616 + 617 + encoder->bridge = bridge; 618 + bridge->encoder = encoder; 619 + ret = drm_bridge_attach(encoder->dev, bridge); 620 + if (ret) { 621 + DRM_ERROR("Failed to attach bridge to drm\n"); 622 + encoder->bridge = NULL; 623 + bridge->encoder = NULL; 624 + } 625 + 626 + return ret; 627 + } 628 + 629 + static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi) 630 + { 631 + int ret; 632 + 633 + ret = drm_connector_init(drm, &dsi->conn, &mtk_dsi_connector_funcs, 634 + DRM_MODE_CONNECTOR_DSI); 635 + if (ret) { 636 + DRM_ERROR("Failed to connector init to drm\n"); 637 + return ret; 638 + } 639 + 640 + drm_connector_helper_add(&dsi->conn, &mtk_dsi_connector_helper_funcs); 641 + 642 + dsi->conn.dpms = DRM_MODE_DPMS_OFF; 643 + drm_mode_connector_attach_encoder(&dsi->conn, &dsi->encoder); 644 + 645 + if (dsi->panel) { 646 + ret = drm_panel_attach(dsi->panel, &dsi->conn); 647 + if (ret) { 648 + DRM_ERROR("Failed to attach panel to drm\n"); 649 + goto err_connector_cleanup; 650 + } 651 + } 652 + 653 + return 0; 654 + 655 + err_connector_cleanup: 656 + drm_connector_cleanup(&dsi->conn); 657 + return ret; 658 + } 659 + 660 + static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi) 661 + { 662 + int ret; 663 + 664 + ret = drm_encoder_init(drm, &dsi->encoder, &mtk_dsi_encoder_funcs, 665 + DRM_MODE_ENCODER_DSI, NULL); 666 + if (ret) { 667 + DRM_ERROR("Failed to encoder init to drm\n"); 668 + return ret; 669 + } 670 + drm_encoder_helper_add(&dsi->encoder, &mtk_dsi_encoder_helper_funcs); 671 + 672 + /* 673 + * Currently display data paths are statically assigned to a crtc each. 674 + * crtc 0 is OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0 675 + */ 676 + dsi->encoder.possible_crtcs = 1; 677 + 678 + /* If there's a bridge, attach to it and let it create the connector */ 679 + ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder); 680 + if (ret) { 681 + /* Otherwise create our own connector and attach to a panel */ 682 + ret = mtk_dsi_create_connector(drm, dsi); 683 + if (ret) 684 + goto err_encoder_cleanup; 685 + } 686 + 687 + return 0; 688 + 689 + err_encoder_cleanup: 690 + drm_encoder_cleanup(&dsi->encoder); 691 + return ret; 692 + } 693 + 694 + static void mtk_dsi_destroy_conn_enc(struct mtk_dsi *dsi) 695 + { 696 + drm_encoder_cleanup(&dsi->encoder); 697 + /* Skip connector cleanup if creation was delegated to the bridge */ 698 + if (dsi->conn.dev) { 699 + drm_connector_unregister(&dsi->conn); 700 + drm_connector_cleanup(&dsi->conn); 701 + } 702 + } 703 + 704 + static void mtk_dsi_ddp_start(struct mtk_ddp_comp *comp) 705 + { 706 + struct mtk_dsi *dsi = container_of(comp, struct mtk_dsi, ddp_comp); 707 + 708 + mtk_dsi_poweron(dsi); 709 + } 710 + 711 + static void mtk_dsi_ddp_stop(struct mtk_ddp_comp *comp) 712 + { 713 + struct mtk_dsi *dsi = container_of(comp, struct mtk_dsi, ddp_comp); 714 + 715 + mtk_dsi_poweroff(dsi); 716 + } 717 + 718 + static const struct mtk_ddp_comp_funcs mtk_dsi_funcs = { 719 + .start = mtk_dsi_ddp_start, 720 + .stop = mtk_dsi_ddp_stop, 721 + }; 722 + 723 + static int mtk_dsi_host_attach(struct mipi_dsi_host *host, 724 + struct mipi_dsi_device *device) 725 + { 726 + struct mtk_dsi *dsi = host_to_dsi(host); 727 + 728 + dsi->lanes = device->lanes; 729 + dsi->format = device->format; 730 + dsi->mode_flags = device->mode_flags; 731 + 732 + if (dsi->conn.dev) 733 + drm_helper_hpd_irq_event(dsi->conn.dev); 734 + 735 + return 0; 736 + } 737 + 738 + static int mtk_dsi_host_detach(struct mipi_dsi_host *host, 739 + struct mipi_dsi_device *device) 740 + { 741 + struct mtk_dsi *dsi = host_to_dsi(host); 742 + 743 + if (dsi->conn.dev) 744 + drm_helper_hpd_irq_event(dsi->conn.dev); 745 + 746 + return 0; 747 + } 748 + 749 + static const struct mipi_dsi_host_ops mtk_dsi_ops = { 750 + .attach = mtk_dsi_host_attach, 751 + .detach = mtk_dsi_host_detach, 752 + }; 753 + 754 + static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) 755 + { 756 + int ret; 757 + struct drm_device *drm = data; 758 + struct mtk_dsi *dsi = dev_get_drvdata(dev); 759 + 760 + ret = mtk_ddp_comp_register(drm, &dsi->ddp_comp); 761 + if (ret < 0) { 762 + dev_err(dev, "Failed to register component %s: %d\n", 763 + dev->of_node->full_name, ret); 764 + return ret; 765 + } 766 + 767 + ret = mipi_dsi_host_register(&dsi->host); 768 + if (ret < 0) { 769 + dev_err(dev, "failed to register DSI host: %d\n", ret); 770 + goto err_ddp_comp_unregister; 771 + } 772 + 773 + ret = mtk_dsi_create_conn_enc(drm, dsi); 774 + if (ret) { 775 + DRM_ERROR("Encoder create failed with %d\n", ret); 776 + goto err_unregister; 777 + } 778 + 779 + return 0; 780 + 781 + err_unregister: 782 + mipi_dsi_host_unregister(&dsi->host); 783 + err_ddp_comp_unregister: 784 + mtk_ddp_comp_unregister(drm, &dsi->ddp_comp); 785 + return ret; 786 + } 787 + 788 + static void mtk_dsi_unbind(struct device *dev, struct device *master, 789 + void *data) 790 + { 791 + struct drm_device *drm = data; 792 + struct mtk_dsi *dsi = dev_get_drvdata(dev); 793 + 794 + mtk_dsi_destroy_conn_enc(dsi); 795 + mipi_dsi_host_unregister(&dsi->host); 796 + mtk_ddp_comp_unregister(drm, &dsi->ddp_comp); 797 + } 798 + 799 + static const struct component_ops mtk_dsi_component_ops = { 800 + .bind = mtk_dsi_bind, 801 + .unbind = mtk_dsi_unbind, 802 + }; 803 + 804 + static int mtk_dsi_probe(struct platform_device *pdev) 805 + { 806 + struct mtk_dsi *dsi; 807 + struct device *dev = &pdev->dev; 808 + struct device_node *remote_node, *endpoint; 809 + struct resource *regs; 810 + int comp_id; 811 + int ret; 812 + 813 + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); 814 + if (!dsi) 815 + return -ENOMEM; 816 + 817 + dsi->host.ops = &mtk_dsi_ops; 818 + dsi->host.dev = dev; 819 + 820 + endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); 821 + if (endpoint) { 822 + remote_node = of_graph_get_remote_port_parent(endpoint); 823 + if (!remote_node) { 824 + dev_err(dev, "No panel connected\n"); 825 + return -ENODEV; 826 + } 827 + 828 + dsi->bridge = of_drm_find_bridge(remote_node); 829 + dsi->panel = of_drm_find_panel(remote_node); 830 + of_node_put(remote_node); 831 + if (!dsi->bridge && !dsi->panel) { 832 + dev_info(dev, "Waiting for bridge or panel driver\n"); 833 + return -EPROBE_DEFER; 834 + } 835 + } 836 + 837 + dsi->engine_clk = devm_clk_get(dev, "engine"); 838 + if (IS_ERR(dsi->engine_clk)) { 839 + ret = PTR_ERR(dsi->engine_clk); 840 + dev_err(dev, "Failed to get engine clock: %d\n", ret); 841 + return ret; 842 + } 843 + 844 + dsi->digital_clk = devm_clk_get(dev, "digital"); 845 + if (IS_ERR(dsi->digital_clk)) { 846 + ret = PTR_ERR(dsi->digital_clk); 847 + dev_err(dev, "Failed to get digital clock: %d\n", ret); 848 + return ret; 849 + } 850 + 851 + dsi->hs_clk = devm_clk_get(dev, "hs"); 852 + if (IS_ERR(dsi->hs_clk)) { 853 + ret = PTR_ERR(dsi->hs_clk); 854 + dev_err(dev, "Failed to get hs clock: %d\n", ret); 855 + return ret; 856 + } 857 + 858 + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 859 + dsi->regs = devm_ioremap_resource(dev, regs); 860 + if (IS_ERR(dsi->regs)) { 861 + ret = PTR_ERR(dsi->regs); 862 + dev_err(dev, "Failed to ioremap memory: %d\n", ret); 863 + return ret; 864 + } 865 + 866 + dsi->phy = devm_phy_get(dev, "dphy"); 867 + if (IS_ERR(dsi->phy)) { 868 + ret = PTR_ERR(dsi->phy); 869 + dev_err(dev, "Failed to get MIPI-DPHY: %d\n", ret); 870 + return ret; 871 + } 872 + 873 + comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DSI); 874 + if (comp_id < 0) { 875 + dev_err(dev, "Failed to identify by alias: %d\n", comp_id); 876 + return comp_id; 877 + } 878 + 879 + ret = mtk_ddp_comp_init(dev, dev->of_node, &dsi->ddp_comp, comp_id, 880 + &mtk_dsi_funcs); 881 + if (ret) { 882 + dev_err(dev, "Failed to initialize component: %d\n", ret); 883 + return ret; 884 + } 885 + 886 + platform_set_drvdata(pdev, dsi); 887 + 888 + return component_add(&pdev->dev, &mtk_dsi_component_ops); 889 + } 890 + 891 + static int mtk_dsi_remove(struct platform_device *pdev) 892 + { 893 + struct mtk_dsi *dsi = platform_get_drvdata(pdev); 894 + 895 + mtk_output_dsi_disable(dsi); 896 + component_del(&pdev->dev, &mtk_dsi_component_ops); 897 + 898 + return 0; 899 + } 900 + 901 + static const struct of_device_id mtk_dsi_of_match[] = { 902 + { .compatible = "mediatek,mt8173-dsi" }, 903 + { }, 904 + }; 905 + 906 + struct platform_driver mtk_dsi_driver = { 907 + .probe = mtk_dsi_probe, 908 + .remove = mtk_dsi_remove, 909 + .driver = { 910 + .name = "mtk-dsi", 911 + .of_match_table = mtk_dsi_of_match, 912 + }, 913 + };
+463
drivers/gpu/drm/mediatek/mtk_mipi_tx.c
··· 1 + /* 2 + * Copyright (c) 2015 MediaTek Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include <linux/clk.h> 15 + #include <linux/clk-provider.h> 16 + #include <linux/delay.h> 17 + #include <linux/io.h> 18 + #include <linux/module.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/phy/phy.h> 21 + 22 + #define MIPITX_DSI_CON 0x00 23 + #define RG_DSI_LDOCORE_EN BIT(0) 24 + #define RG_DSI_CKG_LDOOUT_EN BIT(1) 25 + #define RG_DSI_BCLK_SEL (3 << 2) 26 + #define RG_DSI_LD_IDX_SEL (7 << 4) 27 + #define RG_DSI_PHYCLK_SEL (2 << 8) 28 + #define RG_DSI_DSICLK_FREQ_SEL BIT(10) 29 + #define RG_DSI_LPTX_CLMP_EN BIT(11) 30 + 31 + #define MIPITX_DSI_CLOCK_LANE 0x04 32 + #define MIPITX_DSI_DATA_LANE0 0x08 33 + #define MIPITX_DSI_DATA_LANE1 0x0c 34 + #define MIPITX_DSI_DATA_LANE2 0x10 35 + #define MIPITX_DSI_DATA_LANE3 0x14 36 + #define RG_DSI_LNTx_LDOOUT_EN BIT(0) 37 + #define RG_DSI_LNTx_CKLANE_EN BIT(1) 38 + #define RG_DSI_LNTx_LPTX_IPLUS1 BIT(2) 39 + #define RG_DSI_LNTx_LPTX_IPLUS2 BIT(3) 40 + #define RG_DSI_LNTx_LPTX_IMINUS BIT(4) 41 + #define RG_DSI_LNTx_LPCD_IPLUS BIT(5) 42 + #define RG_DSI_LNTx_LPCD_IMINUS BIT(6) 43 + #define RG_DSI_LNTx_RT_CODE (0xf << 8) 44 + 45 + #define MIPITX_DSI_TOP_CON 0x40 46 + #define RG_DSI_LNT_INTR_EN BIT(0) 47 + #define RG_DSI_LNT_HS_BIAS_EN BIT(1) 48 + #define RG_DSI_LNT_IMP_CAL_EN BIT(2) 49 + #define RG_DSI_LNT_TESTMODE_EN BIT(3) 50 + #define RG_DSI_LNT_IMP_CAL_CODE (0xf << 4) 51 + #define RG_DSI_LNT_AIO_SEL (7 << 8) 52 + #define RG_DSI_PAD_TIE_LOW_EN BIT(11) 53 + #define RG_DSI_DEBUG_INPUT_EN BIT(12) 54 + #define RG_DSI_PRESERVE (7 << 13) 55 + 56 + #define MIPITX_DSI_BG_CON 0x44 57 + #define RG_DSI_BG_CORE_EN BIT(0) 58 + #define RG_DSI_BG_CKEN BIT(1) 59 + #define RG_DSI_BG_DIV (0x3 << 2) 60 + #define RG_DSI_BG_FAST_CHARGE BIT(4) 61 + #define RG_DSI_VOUT_MSK (0x3ffff << 5) 62 + #define RG_DSI_V12_SEL (7 << 5) 63 + #define RG_DSI_V10_SEL (7 << 8) 64 + #define RG_DSI_V072_SEL (7 << 11) 65 + #define RG_DSI_V04_SEL (7 << 14) 66 + #define RG_DSI_V032_SEL (7 << 17) 67 + #define RG_DSI_V02_SEL (7 << 20) 68 + #define RG_DSI_BG_R1_TRIM (0xf << 24) 69 + #define RG_DSI_BG_R2_TRIM (0xf << 28) 70 + 71 + #define MIPITX_DSI_PLL_CON0 0x50 72 + #define RG_DSI_MPPLL_PLL_EN BIT(0) 73 + #define RG_DSI_MPPLL_DIV_MSK (0x1ff << 1) 74 + #define RG_DSI_MPPLL_PREDIV (3 << 1) 75 + #define RG_DSI_MPPLL_TXDIV0 (3 << 3) 76 + #define RG_DSI_MPPLL_TXDIV1 (3 << 5) 77 + #define RG_DSI_MPPLL_POSDIV (7 << 7) 78 + #define RG_DSI_MPPLL_MONVC_EN BIT(10) 79 + #define RG_DSI_MPPLL_MONREF_EN BIT(11) 80 + #define RG_DSI_MPPLL_VOD_EN BIT(12) 81 + 82 + #define MIPITX_DSI_PLL_CON1 0x54 83 + #define RG_DSI_MPPLL_SDM_FRA_EN BIT(0) 84 + #define RG_DSI_MPPLL_SDM_SSC_PH_INIT BIT(1) 85 + #define RG_DSI_MPPLL_SDM_SSC_EN BIT(2) 86 + #define RG_DSI_MPPLL_SDM_SSC_PRD (0xffff << 16) 87 + 88 + #define MIPITX_DSI_PLL_CON2 0x58 89 + 90 + #define MIPITX_DSI_PLL_PWR 0x68 91 + #define RG_DSI_MPPLL_SDM_PWR_ON BIT(0) 92 + #define RG_DSI_MPPLL_SDM_ISO_EN BIT(1) 93 + #define RG_DSI_MPPLL_SDM_PWR_ACK BIT(8) 94 + 95 + #define MIPITX_DSI_SW_CTRL 0x80 96 + #define SW_CTRL_EN BIT(0) 97 + 98 + #define MIPITX_DSI_SW_CTRL_CON0 0x84 99 + #define SW_LNTC_LPTX_PRE_OE BIT(0) 100 + #define SW_LNTC_LPTX_OE BIT(1) 101 + #define SW_LNTC_LPTX_P BIT(2) 102 + #define SW_LNTC_LPTX_N BIT(3) 103 + #define SW_LNTC_HSTX_PRE_OE BIT(4) 104 + #define SW_LNTC_HSTX_OE BIT(5) 105 + #define SW_LNTC_HSTX_ZEROCLK BIT(6) 106 + #define SW_LNT0_LPTX_PRE_OE BIT(7) 107 + #define SW_LNT0_LPTX_OE BIT(8) 108 + #define SW_LNT0_LPTX_P BIT(9) 109 + #define SW_LNT0_LPTX_N BIT(10) 110 + #define SW_LNT0_HSTX_PRE_OE BIT(11) 111 + #define SW_LNT0_HSTX_OE BIT(12) 112 + #define SW_LNT0_LPRX_EN BIT(13) 113 + #define SW_LNT1_LPTX_PRE_OE BIT(14) 114 + #define SW_LNT1_LPTX_OE BIT(15) 115 + #define SW_LNT1_LPTX_P BIT(16) 116 + #define SW_LNT1_LPTX_N BIT(17) 117 + #define SW_LNT1_HSTX_PRE_OE BIT(18) 118 + #define SW_LNT1_HSTX_OE BIT(19) 119 + #define SW_LNT2_LPTX_PRE_OE BIT(20) 120 + #define SW_LNT2_LPTX_OE BIT(21) 121 + #define SW_LNT2_LPTX_P BIT(22) 122 + #define SW_LNT2_LPTX_N BIT(23) 123 + #define SW_LNT2_HSTX_PRE_OE BIT(24) 124 + #define SW_LNT2_HSTX_OE BIT(25) 125 + 126 + struct mtk_mipi_tx { 127 + struct device *dev; 128 + void __iomem *regs; 129 + unsigned int data_rate; 130 + struct clk_hw pll_hw; 131 + struct clk *pll; 132 + }; 133 + 134 + static inline struct mtk_mipi_tx *mtk_mipi_tx_from_clk_hw(struct clk_hw *hw) 135 + { 136 + return container_of(hw, struct mtk_mipi_tx, pll_hw); 137 + } 138 + 139 + static void mtk_mipi_tx_clear_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, 140 + u32 bits) 141 + { 142 + u32 temp = readl(mipi_tx->regs + offset); 143 + 144 + writel(temp & ~bits, mipi_tx->regs + offset); 145 + } 146 + 147 + static void mtk_mipi_tx_set_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, 148 + u32 bits) 149 + { 150 + u32 temp = readl(mipi_tx->regs + offset); 151 + 152 + writel(temp | bits, mipi_tx->regs + offset); 153 + } 154 + 155 + static void mtk_mipi_tx_update_bits(struct mtk_mipi_tx *mipi_tx, u32 offset, 156 + u32 mask, u32 data) 157 + { 158 + u32 temp = readl(mipi_tx->regs + offset); 159 + 160 + writel((temp & ~mask) | (data & mask), mipi_tx->regs + offset); 161 + } 162 + 163 + static int mtk_mipi_tx_pll_prepare(struct clk_hw *hw) 164 + { 165 + struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); 166 + unsigned int txdiv, txdiv0, txdiv1; 167 + u64 pcw; 168 + 169 + dev_dbg(mipi_tx->dev, "prepare: %u Hz\n", mipi_tx->data_rate); 170 + 171 + if (mipi_tx->data_rate >= 500000000) { 172 + txdiv = 1; 173 + txdiv0 = 0; 174 + txdiv1 = 0; 175 + } else if (mipi_tx->data_rate >= 250000000) { 176 + txdiv = 2; 177 + txdiv0 = 1; 178 + txdiv1 = 0; 179 + } else if (mipi_tx->data_rate >= 125000000) { 180 + txdiv = 4; 181 + txdiv0 = 2; 182 + txdiv1 = 0; 183 + } else if (mipi_tx->data_rate > 62000000) { 184 + txdiv = 8; 185 + txdiv0 = 2; 186 + txdiv1 = 1; 187 + } else if (mipi_tx->data_rate >= 50000000) { 188 + txdiv = 16; 189 + txdiv0 = 2; 190 + txdiv1 = 2; 191 + } else { 192 + return -EINVAL; 193 + } 194 + 195 + mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_BG_CON, 196 + RG_DSI_VOUT_MSK | 197 + RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN, 198 + (4 << 20) | (4 << 17) | (4 << 14) | 199 + (4 << 11) | (4 << 8) | (4 << 5) | 200 + RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN); 201 + 202 + usleep_range(30, 100); 203 + 204 + mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_TOP_CON, 205 + RG_DSI_LNT_IMP_CAL_CODE | RG_DSI_LNT_HS_BIAS_EN, 206 + (8 << 4) | RG_DSI_LNT_HS_BIAS_EN); 207 + 208 + mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_CON, 209 + RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN); 210 + 211 + mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR, 212 + RG_DSI_MPPLL_SDM_PWR_ON | 213 + RG_DSI_MPPLL_SDM_ISO_EN, 214 + RG_DSI_MPPLL_SDM_PWR_ON); 215 + 216 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0, 217 + RG_DSI_MPPLL_PLL_EN); 218 + 219 + mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_CON0, 220 + RG_DSI_MPPLL_TXDIV0 | RG_DSI_MPPLL_TXDIV1 | 221 + RG_DSI_MPPLL_PREDIV, 222 + (txdiv0 << 3) | (txdiv1 << 5)); 223 + 224 + /* 225 + * PLL PCW config 226 + * PCW bit 24~30 = integer part of pcw 227 + * PCW bit 0~23 = fractional part of pcw 228 + * pcw = data_Rate*4*txdiv/(Ref_clk*2); 229 + * Post DIV =4, so need data_Rate*4 230 + * Ref_clk is 26MHz 231 + */ 232 + pcw = div_u64(((u64)mipi_tx->data_rate * 2 * txdiv) << 24, 233 + 26000000); 234 + writel(pcw, mipi_tx->regs + MIPITX_DSI_PLL_CON2); 235 + 236 + mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON1, 237 + RG_DSI_MPPLL_SDM_FRA_EN); 238 + 239 + mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_PLL_CON0, RG_DSI_MPPLL_PLL_EN); 240 + 241 + usleep_range(20, 100); 242 + 243 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON1, 244 + RG_DSI_MPPLL_SDM_SSC_EN); 245 + 246 + return 0; 247 + } 248 + 249 + static void mtk_mipi_tx_pll_unprepare(struct clk_hw *hw) 250 + { 251 + struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); 252 + 253 + dev_dbg(mipi_tx->dev, "unprepare\n"); 254 + 255 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0, 256 + RG_DSI_MPPLL_PLL_EN); 257 + 258 + mtk_mipi_tx_update_bits(mipi_tx, MIPITX_DSI_PLL_PWR, 259 + RG_DSI_MPPLL_SDM_ISO_EN | 260 + RG_DSI_MPPLL_SDM_PWR_ON, 261 + RG_DSI_MPPLL_SDM_ISO_EN); 262 + 263 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_TOP_CON, 264 + RG_DSI_LNT_HS_BIAS_EN); 265 + 266 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_CON, 267 + RG_DSI_CKG_LDOOUT_EN | RG_DSI_LDOCORE_EN); 268 + 269 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_BG_CON, 270 + RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN); 271 + 272 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_PLL_CON0, 273 + RG_DSI_MPPLL_DIV_MSK); 274 + } 275 + 276 + static long mtk_mipi_tx_pll_round_rate(struct clk_hw *hw, unsigned long rate, 277 + unsigned long *prate) 278 + { 279 + return clamp_val(rate, 50000000, 1250000000); 280 + } 281 + 282 + static int mtk_mipi_tx_pll_set_rate(struct clk_hw *hw, unsigned long rate, 283 + unsigned long parent_rate) 284 + { 285 + struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); 286 + 287 + dev_dbg(mipi_tx->dev, "set rate: %lu Hz\n", rate); 288 + 289 + mipi_tx->data_rate = rate; 290 + 291 + return 0; 292 + } 293 + 294 + static unsigned long mtk_mipi_tx_pll_recalc_rate(struct clk_hw *hw, 295 + unsigned long parent_rate) 296 + { 297 + struct mtk_mipi_tx *mipi_tx = mtk_mipi_tx_from_clk_hw(hw); 298 + 299 + return mipi_tx->data_rate; 300 + } 301 + 302 + static const struct clk_ops mtk_mipi_tx_pll_ops = { 303 + .prepare = mtk_mipi_tx_pll_prepare, 304 + .unprepare = mtk_mipi_tx_pll_unprepare, 305 + .round_rate = mtk_mipi_tx_pll_round_rate, 306 + .set_rate = mtk_mipi_tx_pll_set_rate, 307 + .recalc_rate = mtk_mipi_tx_pll_recalc_rate, 308 + }; 309 + 310 + static int mtk_mipi_tx_power_on_signal(struct phy *phy) 311 + { 312 + struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); 313 + unsigned int reg; 314 + 315 + for (reg = MIPITX_DSI_CLOCK_LANE; 316 + reg <= MIPITX_DSI_DATA_LANE3; reg += 4) 317 + mtk_mipi_tx_set_bits(mipi_tx, reg, RG_DSI_LNTx_LDOOUT_EN); 318 + 319 + mtk_mipi_tx_clear_bits(mipi_tx, MIPITX_DSI_TOP_CON, 320 + RG_DSI_PAD_TIE_LOW_EN); 321 + 322 + return 0; 323 + } 324 + 325 + static int mtk_mipi_tx_power_on(struct phy *phy) 326 + { 327 + struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); 328 + int ret; 329 + 330 + /* Power up core and enable PLL */ 331 + ret = clk_prepare_enable(mipi_tx->pll); 332 + if (ret < 0) 333 + return ret; 334 + 335 + /* Enable DSI Lane LDO outputs, disable pad tie low */ 336 + mtk_mipi_tx_power_on_signal(phy); 337 + 338 + return 0; 339 + } 340 + 341 + static void mtk_mipi_tx_power_off_signal(struct phy *phy) 342 + { 343 + struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); 344 + unsigned int reg; 345 + 346 + mtk_mipi_tx_set_bits(mipi_tx, MIPITX_DSI_TOP_CON, 347 + RG_DSI_PAD_TIE_LOW_EN); 348 + 349 + for (reg = MIPITX_DSI_CLOCK_LANE; 350 + reg <= MIPITX_DSI_DATA_LANE3; reg += 4) 351 + mtk_mipi_tx_clear_bits(mipi_tx, reg, RG_DSI_LNTx_LDOOUT_EN); 352 + } 353 + 354 + static int mtk_mipi_tx_power_off(struct phy *phy) 355 + { 356 + struct mtk_mipi_tx *mipi_tx = phy_get_drvdata(phy); 357 + 358 + /* Enable pad tie low, disable DSI Lane LDO outputs */ 359 + mtk_mipi_tx_power_off_signal(phy); 360 + 361 + /* Disable PLL and power down core */ 362 + clk_disable_unprepare(mipi_tx->pll); 363 + 364 + return 0; 365 + } 366 + 367 + static const struct phy_ops mtk_mipi_tx_ops = { 368 + .power_on = mtk_mipi_tx_power_on, 369 + .power_off = mtk_mipi_tx_power_off, 370 + .owner = THIS_MODULE, 371 + }; 372 + 373 + static int mtk_mipi_tx_probe(struct platform_device *pdev) 374 + { 375 + struct device *dev = &pdev->dev; 376 + struct mtk_mipi_tx *mipi_tx; 377 + struct resource *mem; 378 + struct clk *ref_clk; 379 + const char *ref_clk_name; 380 + struct clk_init_data clk_init = { 381 + .ops = &mtk_mipi_tx_pll_ops, 382 + .num_parents = 1, 383 + .parent_names = (const char * const *)&ref_clk_name, 384 + .flags = CLK_SET_RATE_GATE, 385 + }; 386 + struct phy *phy; 387 + struct phy_provider *phy_provider; 388 + int ret; 389 + 390 + mipi_tx = devm_kzalloc(dev, sizeof(*mipi_tx), GFP_KERNEL); 391 + if (!mipi_tx) 392 + return -ENOMEM; 393 + 394 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 395 + mipi_tx->regs = devm_ioremap_resource(dev, mem); 396 + if (IS_ERR(mipi_tx->regs)) { 397 + ret = PTR_ERR(mipi_tx->regs); 398 + dev_err(dev, "Failed to get memory resource: %d\n", ret); 399 + return ret; 400 + } 401 + 402 + ref_clk = devm_clk_get(dev, NULL); 403 + if (IS_ERR(ref_clk)) { 404 + ret = PTR_ERR(ref_clk); 405 + dev_err(dev, "Failed to get reference clock: %d\n", ret); 406 + return ret; 407 + } 408 + ref_clk_name = __clk_get_name(ref_clk); 409 + 410 + ret = of_property_read_string(dev->of_node, "clock-output-names", 411 + &clk_init.name); 412 + if (ret < 0) { 413 + dev_err(dev, "Failed to read clock-output-names: %d\n", ret); 414 + return ret; 415 + } 416 + 417 + mipi_tx->pll_hw.init = &clk_init; 418 + mipi_tx->pll = devm_clk_register(dev, &mipi_tx->pll_hw); 419 + if (IS_ERR(mipi_tx->pll)) { 420 + ret = PTR_ERR(mipi_tx->pll); 421 + dev_err(dev, "Failed to register PLL: %d\n", ret); 422 + return ret; 423 + } 424 + 425 + phy = devm_phy_create(dev, NULL, &mtk_mipi_tx_ops); 426 + if (IS_ERR(phy)) { 427 + ret = PTR_ERR(phy); 428 + dev_err(dev, "Failed to create MIPI D-PHY: %d\n", ret); 429 + return ret; 430 + } 431 + phy_set_drvdata(phy, mipi_tx); 432 + 433 + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 434 + if (IS_ERR(phy)) { 435 + ret = PTR_ERR(phy_provider); 436 + return ret; 437 + } 438 + 439 + mipi_tx->dev = dev; 440 + 441 + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, 442 + mipi_tx->pll); 443 + } 444 + 445 + static int mtk_mipi_tx_remove(struct platform_device *pdev) 446 + { 447 + of_clk_del_provider(pdev->dev.of_node); 448 + return 0; 449 + } 450 + 451 + static const struct of_device_id mtk_mipi_tx_match[] = { 452 + { .compatible = "mediatek,mt8173-mipi-tx", }, 453 + {}, 454 + }; 455 + 456 + struct platform_driver mtk_mipi_tx_driver = { 457 + .probe = mtk_mipi_tx_probe, 458 + .remove = mtk_mipi_tx_remove, 459 + .driver = { 460 + .name = "mediatek-mipi-tx", 461 + .of_match_table = mtk_mipi_tx_match, 462 + }, 463 + };
+2
drivers/memory/mtk-smi.c
··· 91 91 92 92 return 0; 93 93 } 94 + EXPORT_SYMBOL_GPL(mtk_smi_larb_get); 94 95 95 96 void mtk_smi_larb_put(struct device *larbdev) 96 97 { ··· 107 106 mtk_smi_disable(&larb->smi); 108 107 mtk_smi_disable(common); 109 108 } 109 + EXPORT_SYMBOL_GPL(mtk_smi_larb_put); 110 110 111 111 static int 112 112 mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
+2 -1
include/dt-bindings/clock/mt8173-clk.h
··· 176 176 #define CLK_APMIXED_LVDSPLL 13 177 177 #define CLK_APMIXED_MSDCPLL2 14 178 178 #define CLK_APMIXED_REF2USB_TX 15 179 - #define CLK_APMIXED_NR_CLK 16 179 + #define CLK_APMIXED_HDMI_REF 16 180 + #define CLK_APMIXED_NR_CLK 17 180 181 181 182 /* INFRA_SYS */ 182 183