aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-05-04 05:53:15 -0400
committerDave Airlie <airlied@redhat.com>2016-05-04 05:53:15 -0400
commit4946dd2e14d252cd04e188ed6a4b794541d1c3ce (patch)
treef60cae0676808538becd116090ab6f5f19520edf
parent090e1a7f5ce139ab4246fcaafaac0415008b7dfa (diff)
parentc84ffde963e227bf68efb12315bd39c75e00ff05 (diff)
Merge tag 'drm-hisilicon-next-2016-04-29' of github.com:xin3liang/linux into drm-next
drm-hisilicon-next for 4.7 Add new hisilicon kirin drm driver: - Add maintainer for hisilicon DRM driver - Add support for external bridge - Add designware dsi host driver - Add designware dsi encoder driver - Add cma fbdev and hotplug - Add vblank driver for ADE - Add plane driver for ADE - Add crtc driver for ADE - Add hisilicon kirin drm master driver - Add device tree binding for hi6220 display subsystem * tag 'drm-hisilicon-next-2016-04-29' of github.com:xin3liang/linux: MAINTAINERS: Add maintainer for hisilicon DRM driver drm/hisilicon: Add support for external bridge drm/hisilicon: Add designware dsi host driver drm/hisilicon: Add designware dsi encoder driver drm/hisilicon: Add cma fbdev and hotplug drm/hisilicon: Add vblank driver for ADE drm/hisilicon: Add plane driver for ADE drm/hisilicon: Add crtc driver for ADE drm/hisilicon: Add hisilicon kirin drm master driver drm/hisilicon: Add device tree binding for hi6220 display subsystem
-rw-r--r--Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt72
-rw-r--r--Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt64
-rw-r--r--MAINTAINERS10
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/hisilicon/Kconfig5
-rw-r--r--drivers/gpu/drm/hisilicon/Makefile5
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/Kconfig18
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/Makefile6
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c857
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h103
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h230
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c1057
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c367
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h31
15 files changed, 2828 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt b/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt
new file mode 100644
index 000000000000..d270bfe4e4e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt
@@ -0,0 +1,72 @@
1Device-Tree bindings for DesignWare DSI Host Controller v1.20a driver
2
3A DSI Host Controller resides in the middle of display controller and external
4HDMI converter or panel.
5
6Required properties:
7- compatible: value should be "hisilicon,hi6220-dsi".
8- reg: physical base address and length of dsi controller's registers.
9- clocks: contains APB clock phandle + clock-specifier pair.
10- clock-names: should be "pclk".
11- ports: contains DSI controller input and output sub port.
12 The input port connects to ADE output port with the reg value "0".
13 The output port with the reg value "1", it could connect to panel or
14 any other bridge endpoints.
15 See Documentation/devicetree/bindings/graph.txt for more device graph info.
16
17A example of HiKey board hi6220 SoC and board specific DT entry:
18Example:
19
20SoC specific:
21 dsi: dsi@f4107800 {
22 compatible = "hisilicon,hi6220-dsi";
23 reg = <0x0 0xf4107800 0x0 0x100>;
24 clocks = <&media_ctrl HI6220_DSI_PCLK>;
25 clock-names = "pclk";
26 status = "disabled";
27
28 ports {
29 #address-cells = <1>;
30 #size-cells = <0>;
31
32 /* 0 for input port */
33 port@0 {
34 reg = <0>;
35 dsi_in: endpoint {
36 remote-endpoint = <&ade_out>;
37 };
38 };
39 };
40 };
41
42
43Board specific:
44 &dsi {
45 status = "ok";
46
47 ports {
48 /* 1 for output port */
49 port@1 {
50 reg = <1>;
51
52 dsi_out0: endpoint@0 {
53 remote-endpoint = <&adv7533_in>;
54 };
55 };
56 };
57 };
58
59 &i2c2 {
60 ...
61
62 adv7533: adv7533@39 {
63 ...
64
65 port {
66 adv7533_in: endpoint {
67 remote-endpoint = <&dsi_out0>;
68 };
69 };
70 };
71 };
72
diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
new file mode 100644
index 000000000000..38dc9d60eef8
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
@@ -0,0 +1,64 @@
1Device-Tree bindings for hisilicon ADE display controller driver
2
3ADE (Advanced Display Engine) is the display controller which grab image
4data from memory, do composition, do post image processing, generate RGB
5timing stream and transfer to DSI.
6
7Required properties:
8- compatible: value should be "hisilicon,hi6220-ade".
9- reg: physical base address and length of the ADE controller's registers.
10- hisilicon,noc-syscon: ADE NOC QoS syscon.
11- resets: The ADE reset controller node.
12- interrupt: the ldi vblank interrupt number used.
13- clocks: a list of phandle + clock-specifier pairs, one for each entry
14 in clock-names.
15- clock-names: should contain:
16 "clk_ade_core" for the ADE core clock.
17 "clk_codec_jpeg" for the media NOC QoS clock, which use the same clock with
18 jpeg codec.
19 "clk_ade_pix" for the ADE pixel clok.
20- assigned-clocks: Should contain "clk_ade_core" and "clk_codec_jpeg" clocks'
21 phandle + clock-specifier pairs.
22- assigned-clock-rates: clock rates, one for each entry in assigned-clocks.
23 The rate of "clk_ade_core" could be "360000000" or "180000000";
24 The rate of "clk_codec_jpeg" could be or less than "1440000000".
25 These rate values could be configured according to performance and power
26 consumption.
27- port: the output port. This contains one endpoint subnode, with its
28 remote-endpoint set to the phandle of the connected DSI input endpoint.
29 See Documentation/devicetree/bindings/graph.txt for more device graph info.
30
31Optional properties:
32- dma-coherent: Present if dma operations are coherent.
33
34
35A example of HiKey board hi6220 SoC specific DT entry:
36Example:
37
38 ade: ade@f4100000 {
39 compatible = "hisilicon,hi6220-ade";
40 reg = <0x0 0xf4100000 0x0 0x7800>;
41 reg-names = "ade_base";
42 hisilicon,noc-syscon = <&medianoc_ade>;
43 resets = <&media_ctrl MEDIA_ADE>;
44 interrupts = <0 115 4>; /* ldi interrupt */
45
46 clocks = <&media_ctrl HI6220_ADE_CORE>,
47 <&media_ctrl HI6220_CODEC_JPEG>,
48 <&media_ctrl HI6220_ADE_PIX_SRC>;
49 /*clock name*/
50 clock-names = "clk_ade_core",
51 "clk_codec_jpeg",
52 "clk_ade_pix";
53
54 assigned-clocks = <&media_ctrl HI6220_ADE_CORE>,
55 <&media_ctrl HI6220_CODEC_JPEG>;
56 assigned-clock-rates = <360000000>, <288000000>;
57 dma-coherent;
58
59 port {
60 ade_out: endpoint {
61 remote-endpoint = <&dsi_in>;
62 };
63 };
64 };
diff --git a/MAINTAINERS b/MAINTAINERS
index d1d6498af02f..f262128644e6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3853,6 +3853,16 @@ T: git git://github.com/patjak/drm-gma500
3853S: Maintained 3853S: Maintained
3854F: drivers/gpu/drm/gma500/ 3854F: drivers/gpu/drm/gma500/
3855 3855
3856DRM DRIVERS FOR HISILICON
3857M: Xinliang Liu <z.liuxinliang@hisilicon.com>
3858R: Xinwei Kong <kong.kongxinwei@hisilicon.com>
3859R: Chen Feng <puck.chen@hisilicon.com>
3860L: dri-devel@lists.freedesktop.org
3861T: git git://github.com/xin3liang/linux.git
3862S: Maintained
3863F: drivers/gpu/drm/hisilicon/
3864F: Documentation/devicetree/bindings/display/hisilicon/
3865
3856DRM DRIVERS FOR NVIDIA TEGRA 3866DRM DRIVERS FOR NVIDIA TEGRA
3857M: Thierry Reding <thierry.reding@gmail.com> 3867M: Thierry Reding <thierry.reding@gmail.com>
3858M: Terje Bergström <tbergstrom@nvidia.com> 3868M: Terje Bergström <tbergstrom@nvidia.com>
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index cd515029bb49..87f9ab68e8d1 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -285,3 +285,5 @@ source "drivers/gpu/drm/vc4/Kconfig"
285source "drivers/gpu/drm/etnaviv/Kconfig" 285source "drivers/gpu/drm/etnaviv/Kconfig"
286 286
287source "drivers/gpu/drm/arc/Kconfig" 287source "drivers/gpu/drm/arc/Kconfig"
288
289source "drivers/gpu/drm/hisilicon/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1a26b4eb1ce0..43c2abf425ee 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -80,3 +80,4 @@ obj-y += bridge/
80obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ 80obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
81obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ 81obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
82obj-$(CONFIG_DRM_ARCPGU)+= arc/ 82obj-$(CONFIG_DRM_ARCPGU)+= arc/
83obj-y += hisilicon/
diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
new file mode 100644
index 000000000000..558c61b1b8e8
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -0,0 +1,5 @@
1#
2# hisilicon drm device configuration.
3# Please keep this list sorted alphabetically
4
5source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
new file mode 100644
index 000000000000..e3f6d493c996
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for hisilicon drm drivers.
3# Please keep this list sorted alphabetically
4
5obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig
new file mode 100644
index 000000000000..ea0df6115f7e
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig
@@ -0,0 +1,18 @@
1config DRM_HISI_KIRIN
2 tristate "DRM Support for Hisilicon Kirin series SoCs Platform"
3 depends on DRM && OF && ARM64
4 select DRM_KMS_HELPER
5 select DRM_GEM_CMA_HELPER
6 select DRM_KMS_CMA_HELPER
7 help
8 Choose this option if you have a hisilicon Kirin chipsets(hi6220).
9 If M is selected the module will be called kirin-drm.
10
11config HISI_KIRIN_DW_DSI
12 tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI"
13 depends on DRM_HISI_KIRIN
14 select DRM_MIPI_DSI
15 help
16 This selects support for HiSilicon Kirin SoC specific extensions for
17 the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on
18 hi6220 based SoC, you should selet this option.
diff --git a/drivers/gpu/drm/hisilicon/kirin/Makefile b/drivers/gpu/drm/hisilicon/kirin/Makefile
new file mode 100644
index 000000000000..cdf61589485c
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/Makefile
@@ -0,0 +1,6 @@
1kirin-drm-y := kirin_drm_drv.o \
2 kirin_drm_ade.o
3
4obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o
5
6obj-$(CONFIG_HISI_KIRIN_DW_DSI) += dw_drm_dsi.o
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
new file mode 100644
index 000000000000..bfbc2159250d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -0,0 +1,857 @@
1/*
2 * DesignWare MIPI DSI Host Controller v1.02 driver
3 *
4 * Copyright (c) 2016 Linaro Limited.
5 * Copyright (c) 2014-2016 Hisilicon Limited.
6 *
7 * Author:
8 * Xinliang Liu <z.liuxinliang@hisilicon.com>
9 * Xinliang Liu <xinliang.liu@linaro.org>
10 * Xinwei Kong <kong.kongxinwei@hisilicon.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 */
17
18#include <linux/clk.h>
19#include <linux/component.h>
20#include <linux/of_graph.h>
21
22#include <drm/drm_of.h>
23#include <drm/drm_crtc_helper.h>
24#include <drm/drm_mipi_dsi.h>
25#include <drm/drm_encoder_slave.h>
26#include <drm/drm_atomic_helper.h>
27
28#include "dw_dsi_reg.h"
29
30#define MAX_TX_ESC_CLK 10
31#define ROUND(x, y) ((x) / (y) + \
32 ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
33#define PHY_REF_CLK_RATE 19200000
34#define PHY_REF_CLK_PERIOD_PS (1000000000 / (PHY_REF_CLK_RATE / 1000))
35
36#define encoder_to_dsi(encoder) \
37 container_of(encoder, struct dw_dsi, encoder)
38#define host_to_dsi(host) \
39 container_of(host, struct dw_dsi, host)
40
41struct mipi_phy_params {
42 u32 clk_t_lpx;
43 u32 clk_t_hs_prepare;
44 u32 clk_t_hs_zero;
45 u32 clk_t_hs_trial;
46 u32 clk_t_wakeup;
47 u32 data_t_lpx;
48 u32 data_t_hs_prepare;
49 u32 data_t_hs_zero;
50 u32 data_t_hs_trial;
51 u32 data_t_ta_go;
52 u32 data_t_ta_get;
53 u32 data_t_wakeup;
54 u32 hstx_ckg_sel;
55 u32 pll_fbd_div5f;
56 u32 pll_fbd_div1f;
57 u32 pll_fbd_2p;
58 u32 pll_enbwt;
59 u32 pll_fbd_p;
60 u32 pll_fbd_s;
61 u32 pll_pre_div1p;
62 u32 pll_pre_p;
63 u32 pll_vco_750M;
64 u32 pll_lpf_rs;
65 u32 pll_lpf_cs;
66 u32 clklp2hs_time;
67 u32 clkhs2lp_time;
68 u32 lp2hs_time;
69 u32 hs2lp_time;
70 u32 clk_to_data_delay;
71 u32 data_to_clk_delay;
72 u32 lane_byte_clk_kHz;
73 u32 clk_division;
74};
75
76struct dsi_hw_ctx {
77 void __iomem *base;
78 struct clk *pclk;
79};
80
81struct dw_dsi {
82 struct drm_encoder encoder;
83 struct drm_bridge *bridge;
84 struct mipi_dsi_host host;
85 struct drm_display_mode cur_mode;
86 struct dsi_hw_ctx *ctx;
87 struct mipi_phy_params phy;
88
89 u32 lanes;
90 enum mipi_dsi_pixel_format format;
91 unsigned long mode_flags;
92 bool enable;
93};
94
95struct dsi_data {
96 struct dw_dsi dsi;
97 struct dsi_hw_ctx ctx;
98};
99
100struct dsi_phy_range {
101 u32 min_range_kHz;
102 u32 max_range_kHz;
103 u32 pll_vco_750M;
104 u32 hstx_ckg_sel;
105};
106
107static const struct dsi_phy_range dphy_range_info[] = {
108 { 46875, 62500, 1, 7 },
109 { 62500, 93750, 0, 7 },
110 { 93750, 125000, 1, 6 },
111 { 125000, 187500, 0, 6 },
112 { 187500, 250000, 1, 5 },
113 { 250000, 375000, 0, 5 },
114 { 375000, 500000, 1, 4 },
115 { 500000, 750000, 0, 4 },
116 { 750000, 1000000, 1, 0 },
117 { 1000000, 1500000, 0, 0 }
118};
119
120static u32 dsi_calc_phy_rate(u32 req_kHz, struct mipi_phy_params *phy)
121{
122 u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS;
123 u32 tmp_kHz = req_kHz;
124 u32 i = 0;
125 u32 q_pll = 1;
126 u32 m_pll = 0;
127 u32 n_pll = 0;
128 u32 r_pll = 1;
129 u32 m_n = 0;
130 u32 m_n_int = 0;
131 u32 f_kHz = 0;
132 u64 temp;
133
134 /*
135 * Find a rate >= req_kHz.
136 */
137 do {
138 f_kHz = tmp_kHz;
139
140 for (i = 0; i < ARRAY_SIZE(dphy_range_info); i++)
141 if (f_kHz >= dphy_range_info[i].min_range_kHz &&
142 f_kHz <= dphy_range_info[i].max_range_kHz)
143 break;
144
145 if (i == ARRAY_SIZE(dphy_range_info)) {
146 DRM_ERROR("%dkHz out of range\n", f_kHz);
147 return 0;
148 }
149
150 phy->pll_vco_750M = dphy_range_info[i].pll_vco_750M;
151 phy->hstx_ckg_sel = dphy_range_info[i].hstx_ckg_sel;
152
153 if (phy->hstx_ckg_sel <= 7 &&
154 phy->hstx_ckg_sel >= 4)
155 q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
156
157 temp = f_kHz * (u64)q_pll * (u64)ref_clk_ps;
158 m_n_int = temp / (u64)1000000000;
159 m_n = (temp % (u64)1000000000) / (u64)100000000;
160
161 if (m_n_int % 2 == 0) {
162 if (m_n * 6 >= 50) {
163 n_pll = 2;
164 m_pll = (m_n_int + 1) * n_pll;
165 } else if (m_n * 6 >= 30) {
166 n_pll = 3;
167 m_pll = m_n_int * n_pll + 2;
168 } else {
169 n_pll = 1;
170 m_pll = m_n_int * n_pll;
171 }
172 } else {
173 if (m_n * 6 >= 50) {
174 n_pll = 1;
175 m_pll = (m_n_int + 1) * n_pll;
176 } else if (m_n * 6 >= 30) {
177 n_pll = 1;
178 m_pll = (m_n_int + 1) * n_pll;
179 } else if (m_n * 6 >= 10) {
180 n_pll = 3;
181 m_pll = m_n_int * n_pll + 1;
182 } else {
183 n_pll = 2;
184 m_pll = m_n_int * n_pll;
185 }
186 }
187
188 if (n_pll == 1) {
189 phy->pll_fbd_p = 0;
190 phy->pll_pre_div1p = 1;
191 } else {
192 phy->pll_fbd_p = n_pll;
193 phy->pll_pre_div1p = 0;
194 }
195
196 if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
197 r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
198
199 if (m_pll == 2) {
200 phy->pll_pre_p = 0;
201 phy->pll_fbd_s = 0;
202 phy->pll_fbd_div1f = 0;
203 phy->pll_fbd_div5f = 1;
204 } else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
205 phy->pll_pre_p = m_pll / (2 * r_pll);
206 phy->pll_fbd_s = 0;
207 phy->pll_fbd_div1f = 1;
208 phy->pll_fbd_div5f = 0;
209 } else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
210 if (((m_pll / (2 * r_pll)) % 2) == 0) {
211 phy->pll_pre_p =
212 (m_pll / (2 * r_pll)) / 2 - 1;
213 phy->pll_fbd_s =
214 (m_pll / (2 * r_pll)) % 2 + 2;
215 } else {
216 phy->pll_pre_p =
217 (m_pll / (2 * r_pll)) / 2;
218 phy->pll_fbd_s =
219 (m_pll / (2 * r_pll)) % 2;
220 }
221 phy->pll_fbd_div1f = 0;
222 phy->pll_fbd_div5f = 0;
223 } else {
224 phy->pll_pre_p = 0;
225 phy->pll_fbd_s = 0;
226 phy->pll_fbd_div1f = 0;
227 phy->pll_fbd_div5f = 1;
228 }
229
230 f_kHz = (u64)1000000000 * (u64)m_pll /
231 ((u64)ref_clk_ps * (u64)n_pll * (u64)q_pll);
232
233 if (f_kHz >= req_kHz)
234 break;
235
236 tmp_kHz += 10;
237
238 } while (true);
239
240 return f_kHz;
241}
242
243static void dsi_get_phy_params(u32 phy_req_kHz,
244 struct mipi_phy_params *phy)
245{
246 u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS;
247 u32 phy_rate_kHz;
248 u32 ui;
249
250 memset(phy, 0, sizeof(*phy));
251
252 phy_rate_kHz = dsi_calc_phy_rate(phy_req_kHz, phy);
253 if (!phy_rate_kHz)
254 return;
255
256 ui = 1000000 / phy_rate_kHz;
257
258 phy->clk_t_lpx = ROUND(50, 8 * ui);
259 phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
260
261 phy->clk_t_hs_zero = ROUND(262, 8 * ui);
262 phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
263 phy->clk_t_wakeup = ROUND(1000000, (ref_clk_ps / 1000) - 1);
264 if (phy->clk_t_wakeup > 0xff)
265 phy->clk_t_wakeup = 0xff;
266 phy->data_t_wakeup = phy->clk_t_wakeup;
267 phy->data_t_lpx = phy->clk_t_lpx;
268 phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
269 phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
270 phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
271 phy->data_t_ta_go = 3;
272 phy->data_t_ta_get = 4;
273
274 phy->pll_enbwt = 1;
275 phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
276 phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
277 phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
278 phy->hs2lp_time = phy->clkhs2lp_time;
279 phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
280 phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
281 phy->clkhs2lp_time;
282
283 phy->lane_byte_clk_kHz = phy_rate_kHz / 8;
284 phy->clk_division =
285 DIV_ROUND_UP(phy->lane_byte_clk_kHz, MAX_TX_ESC_CLK);
286}
287
288static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
289{
290 u32 val;
291
292 /*
293 * TODO: only support RGB888 now, to support more
294 */
295 switch (format) {
296 case MIPI_DSI_FMT_RGB888:
297 val = DSI_24BITS_1;
298 break;
299 default:
300 val = DSI_24BITS_1;
301 break;
302 }
303
304 return val;
305}
306
307/*
308 * dsi phy reg write function
309 */
310static void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
311{
312 u32 reg_write = 0x10000 + reg;
313
314 /*
315 * latch reg first
316 */
317 writel(reg_write, base + PHY_TST_CTRL1);
318 writel(0x02, base + PHY_TST_CTRL0);
319 writel(0x00, base + PHY_TST_CTRL0);
320
321 /*
322 * then latch value
323 */
324 writel(val, base + PHY_TST_CTRL1);
325 writel(0x02, base + PHY_TST_CTRL0);
326 writel(0x00, base + PHY_TST_CTRL0);
327}
328
329static void dsi_set_phy_timer(void __iomem *base,
330 struct mipi_phy_params *phy,
331 u32 lanes)
332{
333 u32 val;
334
335 /*
336 * Set lane value and phy stop wait time.
337 */
338 val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
339 writel(val, base + PHY_IF_CFG);
340
341 /*
342 * Set phy clk division.
343 */
344 val = readl(base + CLKMGR_CFG) | phy->clk_division;
345 writel(val, base + CLKMGR_CFG);
346
347 /*
348 * Set lp and hs switching params.
349 */
350 dw_update_bits(base + PHY_TMR_CFG, 24, MASK(8), phy->hs2lp_time);
351 dw_update_bits(base + PHY_TMR_CFG, 16, MASK(8), phy->lp2hs_time);
352 dw_update_bits(base + PHY_TMR_LPCLK_CFG, 16, MASK(10),
353 phy->clkhs2lp_time);
354 dw_update_bits(base + PHY_TMR_LPCLK_CFG, 0, MASK(10),
355 phy->clklp2hs_time);
356 dw_update_bits(base + CLK_DATA_TMR_CFG, 8, MASK(8),
357 phy->data_to_clk_delay);
358 dw_update_bits(base + CLK_DATA_TMR_CFG, 0, MASK(8),
359 phy->clk_to_data_delay);
360}
361
362static void dsi_set_mipi_phy(void __iomem *base,
363 struct mipi_phy_params *phy,
364 u32 lanes)
365{
366 u32 delay_count;
367 u32 val;
368 u32 i;
369
370 /* phy timer setting */
371 dsi_set_phy_timer(base, phy, lanes);
372
373 /*
374 * Reset to clean up phy tst params.
375 */
376 writel(0, base + PHY_RSTZ);
377 writel(0, base + PHY_TST_CTRL0);
378 writel(1, base + PHY_TST_CTRL0);
379 writel(0, base + PHY_TST_CTRL0);
380
381 /*
382 * Clock lane timing control setting: TLPX, THS-PREPARE,
383 * THS-ZERO, THS-TRAIL, TWAKEUP.
384 */
385 dsi_phy_tst_set(base, CLK_TLPX, phy->clk_t_lpx);
386 dsi_phy_tst_set(base, CLK_THS_PREPARE, phy->clk_t_hs_prepare);
387 dsi_phy_tst_set(base, CLK_THS_ZERO, phy->clk_t_hs_zero);
388 dsi_phy_tst_set(base, CLK_THS_TRAIL, phy->clk_t_hs_trial);
389 dsi_phy_tst_set(base, CLK_TWAKEUP, phy->clk_t_wakeup);
390
391 /*
392 * Data lane timing control setting: TLPX, THS-PREPARE,
393 * THS-ZERO, THS-TRAIL, TTA-GO, TTA-GET, TWAKEUP.
394 */
395 for (i = 0; i < lanes; i++) {
396 dsi_phy_tst_set(base, DATA_TLPX(i), phy->data_t_lpx);
397 dsi_phy_tst_set(base, DATA_THS_PREPARE(i),
398 phy->data_t_hs_prepare);
399 dsi_phy_tst_set(base, DATA_THS_ZERO(i), phy->data_t_hs_zero);
400 dsi_phy_tst_set(base, DATA_THS_TRAIL(i), phy->data_t_hs_trial);
401 dsi_phy_tst_set(base, DATA_TTA_GO(i), phy->data_t_ta_go);
402 dsi_phy_tst_set(base, DATA_TTA_GET(i), phy->data_t_ta_get);
403 dsi_phy_tst_set(base, DATA_TWAKEUP(i), phy->data_t_wakeup);
404 }
405
406 /*
407 * physical configuration: I, pll I, pll II, pll III,
408 * pll IV, pll V.
409 */
410 dsi_phy_tst_set(base, PHY_CFG_I, phy->hstx_ckg_sel);
411 val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
412 (phy->pll_fbd_2p << 1) + phy->pll_enbwt;
413 dsi_phy_tst_set(base, PHY_CFG_PLL_I, val);
414 dsi_phy_tst_set(base, PHY_CFG_PLL_II, phy->pll_fbd_p);
415 dsi_phy_tst_set(base, PHY_CFG_PLL_III, phy->pll_fbd_s);
416 val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
417 dsi_phy_tst_set(base, PHY_CFG_PLL_IV, val);
418 val = (5 << 5) + (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
419 phy->pll_lpf_cs;
420 dsi_phy_tst_set(base, PHY_CFG_PLL_V, val);
421
422 writel(PHY_ENABLECLK, base + PHY_RSTZ);
423 udelay(1);
424 writel(PHY_ENABLECLK | PHY_UNSHUTDOWNZ, base + PHY_RSTZ);
425 udelay(1);
426 writel(PHY_ENABLECLK | PHY_UNRSTZ | PHY_UNSHUTDOWNZ, base + PHY_RSTZ);
427 usleep_range(1000, 1500);
428
429 /*
430 * wait for phy's clock ready
431 */
432 delay_count = 100;
433 while (delay_count--) {
434 val = readl(base + PHY_STATUS);
435 if ((BIT(0) | BIT(2)) & val)
436 break;
437
438 udelay(1);
439 }
440
441 if (!delay_count)
442 DRM_INFO("phylock and phystopstateclklane is not ready.\n");
443}
444
445static void dsi_set_mode_timing(void __iomem *base,
446 u32 lane_byte_clk_kHz,
447 struct drm_display_mode *mode,
448 enum mipi_dsi_pixel_format format)
449{
450 u32 hfp, hbp, hsw, vfp, vbp, vsw;
451 u32 hline_time;
452 u32 hsa_time;
453 u32 hbp_time;
454 u32 pixel_clk_kHz;
455 int htot, vtot;
456 u32 val;
457 u64 tmp;
458
459 val = dsi_get_dpi_color_coding(format);
460 writel(val, base + DPI_COLOR_CODING);
461
462 val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
463 val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
464 writel(val, base + DPI_CFG_POL);
465
466 /*
467 * The DSI IP accepts vertical timing using lines as normal,
468 * but horizontal timing is a mixture of pixel-clocks for the
469 * active region and byte-lane clocks for the blanking-related
470 * timings. hfp is specified as the total hline_time in byte-
471 * lane clocks minus hsa, hbp and active.
472 */
473 pixel_clk_kHz = mode->clock;
474 htot = mode->htotal;
475 vtot = mode->vtotal;
476 hfp = mode->hsync_start - mode->hdisplay;
477 hbp = mode->htotal - mode->hsync_end;
478 hsw = mode->hsync_end - mode->hsync_start;
479 vfp = mode->vsync_start - mode->vdisplay;
480 vbp = mode->vtotal - mode->vsync_end;
481 vsw = mode->vsync_end - mode->vsync_start;
482 if (vsw > 15) {
483 DRM_DEBUG_DRIVER("vsw exceeded 15\n");
484 vsw = 15;
485 }
486
487 hsa_time = (hsw * lane_byte_clk_kHz) / pixel_clk_kHz;
488 hbp_time = (hbp * lane_byte_clk_kHz) / pixel_clk_kHz;
489 tmp = (u64)htot * (u64)lane_byte_clk_kHz;
490 hline_time = DIV_ROUND_UP(tmp, pixel_clk_kHz);
491
492 /* all specified in byte-lane clocks */
493 writel(hsa_time, base + VID_HSA_TIME);
494 writel(hbp_time, base + VID_HBP_TIME);
495 writel(hline_time, base + VID_HLINE_TIME);
496
497 writel(vsw, base + VID_VSA_LINES);
498 writel(vbp, base + VID_VBP_LINES);
499 writel(vfp, base + VID_VFP_LINES);
500 writel(mode->vdisplay, base + VID_VACTIVE_LINES);
501 writel(mode->hdisplay, base + VID_PKT_SIZE);
502
503 DRM_DEBUG_DRIVER("htot=%d, hfp=%d, hbp=%d, hsw=%d\n",
504 htot, hfp, hbp, hsw);
505 DRM_DEBUG_DRIVER("vtol=%d, vfp=%d, vbp=%d, vsw=%d\n",
506 vtot, vfp, vbp, vsw);
507 DRM_DEBUG_DRIVER("hsa_time=%d, hbp_time=%d, hline_time=%d\n",
508 hsa_time, hbp_time, hline_time);
509}
510
511static void dsi_set_video_mode(void __iomem *base, unsigned long flags)
512{
513 u32 val;
514 u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
515 MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
516 u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
517 MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
518 u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
519
520 /*
521 * choose video mode type
522 */
523 if ((flags & mode_mask) == non_burst_sync_pulse)
524 val = DSI_NON_BURST_SYNC_PULSES;
525 else if ((flags & mode_mask) == non_burst_sync_event)
526 val = DSI_NON_BURST_SYNC_EVENTS;
527 else
528 val = DSI_BURST_SYNC_PULSES_1;
529 writel(val, base + VID_MODE_CFG);
530
531 writel(PHY_TXREQUESTCLKHS, base + LPCLK_CTRL);
532 writel(DSI_VIDEO_MODE, base + MODE_CFG);
533}
534
535static void dsi_mipi_init(struct dw_dsi *dsi)
536{
537 struct dsi_hw_ctx *ctx = dsi->ctx;
538 struct mipi_phy_params *phy = &dsi->phy;
539 struct drm_display_mode *mode = &dsi->cur_mode;
540 u32 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
541 void __iomem *base = ctx->base;
542 u32 dphy_req_kHz;
543
544 /*
545 * count phy params
546 */
547 dphy_req_kHz = mode->clock * bpp / dsi->lanes;
548 dsi_get_phy_params(dphy_req_kHz, phy);
549
550 /* reset Core */
551 writel(RESET, base + PWR_UP);
552
553 /* set dsi phy params */
554 dsi_set_mipi_phy(base, phy, dsi->lanes);
555
556 /* set dsi mode timing */
557 dsi_set_mode_timing(base, phy->lane_byte_clk_kHz, mode, dsi->format);
558
559 /* set dsi video mode */
560 dsi_set_video_mode(base, dsi->mode_flags);
561
562 /* dsi wake up */
563 writel(POWERUP, base + PWR_UP);
564
565 DRM_DEBUG_DRIVER("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
566 dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
567}
568
569static void dsi_encoder_disable(struct drm_encoder *encoder)
570{
571 struct dw_dsi *dsi = encoder_to_dsi(encoder);
572 struct dsi_hw_ctx *ctx = dsi->ctx;
573 void __iomem *base = ctx->base;
574
575 if (!dsi->enable)
576 return;
577
578 writel(0, base + PWR_UP);
579 writel(0, base + LPCLK_CTRL);
580 writel(0, base + PHY_RSTZ);
581 clk_disable_unprepare(ctx->pclk);
582
583 dsi->enable = false;
584}
585
586static void dsi_encoder_enable(struct drm_encoder *encoder)
587{
588 struct dw_dsi *dsi = encoder_to_dsi(encoder);
589 struct dsi_hw_ctx *ctx = dsi->ctx;
590 int ret;
591
592 if (dsi->enable)
593 return;
594
595 ret = clk_prepare_enable(ctx->pclk);
596 if (ret) {
597 DRM_ERROR("fail to enable pclk: %d\n", ret);
598 return;
599 }
600
601 dsi_mipi_init(dsi);
602
603 dsi->enable = true;
604}
605
606static void dsi_encoder_mode_set(struct drm_encoder *encoder,
607 struct drm_display_mode *mode,
608 struct drm_display_mode *adj_mode)
609{
610 struct dw_dsi *dsi = encoder_to_dsi(encoder);
611
612 drm_mode_copy(&dsi->cur_mode, adj_mode);
613}
614
615static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
616 struct drm_crtc_state *crtc_state,
617 struct drm_connector_state *conn_state)
618{
619 /* do nothing */
620 return 0;
621}
622
623static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = {
624 .atomic_check = dsi_encoder_atomic_check,
625 .mode_set = dsi_encoder_mode_set,
626 .enable = dsi_encoder_enable,
627 .disable = dsi_encoder_disable
628};
629
630static const struct drm_encoder_funcs dw_encoder_funcs = {
631 .destroy = drm_encoder_cleanup,
632};
633
634static int dw_drm_encoder_init(struct device *dev,
635 struct drm_device *drm_dev,
636 struct drm_encoder *encoder)
637{
638 int ret;
639 u32 crtc_mask = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
640
641 if (!crtc_mask) {
642 DRM_ERROR("failed to find crtc mask\n");
643 return -EINVAL;
644 }
645
646 encoder->possible_crtcs = crtc_mask;
647 ret = drm_encoder_init(drm_dev, encoder, &dw_encoder_funcs,
648 DRM_MODE_ENCODER_DSI, NULL);
649 if (ret) {
650 DRM_ERROR("failed to init dsi encoder\n");
651 return ret;
652 }
653
654 drm_encoder_helper_add(encoder, &dw_encoder_helper_funcs);
655
656 return 0;
657}
658
659static int dsi_host_attach(struct mipi_dsi_host *host,
660 struct mipi_dsi_device *mdsi)
661{
662 struct dw_dsi *dsi = host_to_dsi(host);
663
664 if (mdsi->lanes < 1 || mdsi->lanes > 4) {
665 DRM_ERROR("dsi device params invalid\n");
666 return -EINVAL;
667 }
668
669 dsi->lanes = mdsi->lanes;
670 dsi->format = mdsi->format;
671 dsi->mode_flags = mdsi->mode_flags;
672
673 return 0;
674}
675
676static int dsi_host_detach(struct mipi_dsi_host *host,
677 struct mipi_dsi_device *mdsi)
678{
679 /* do nothing */
680 return 0;
681}
682
683static const struct mipi_dsi_host_ops dsi_host_ops = {
684 .attach = dsi_host_attach,
685 .detach = dsi_host_detach,
686};
687
688static int dsi_host_init(struct device *dev, struct dw_dsi *dsi)
689{
690 struct mipi_dsi_host *host = &dsi->host;
691 int ret;
692
693 host->dev = dev;
694 host->ops = &dsi_host_ops;
695 ret = mipi_dsi_host_register(host);
696 if (ret) {
697 DRM_ERROR("failed to register dsi host\n");
698 return ret;
699 }
700
701 return 0;
702}
703
704static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
705{
706 struct drm_encoder *encoder = &dsi->encoder;
707 struct drm_bridge *bridge = dsi->bridge;
708 int ret;
709
710 /* associate the bridge to dsi encoder */
711 encoder->bridge = bridge;
712 bridge->encoder = encoder;
713
714 ret = drm_bridge_attach(dev, bridge);
715 if (ret) {
716 DRM_ERROR("failed to attach external bridge\n");
717 return ret;
718 }
719
720 return 0;
721}
722
723static int dsi_bind(struct device *dev, struct device *master, void *data)
724{
725 struct dsi_data *ddata = dev_get_drvdata(dev);
726 struct dw_dsi *dsi = &ddata->dsi;
727 struct drm_device *drm_dev = data;
728 int ret;
729
730 ret = dw_drm_encoder_init(dev, drm_dev, &dsi->encoder);
731 if (ret)
732 return ret;
733
734 ret = dsi_host_init(dev, dsi);
735 if (ret)
736 return ret;
737
738 ret = dsi_bridge_init(drm_dev, dsi);
739 if (ret)
740 return ret;
741
742 return 0;
743}
744
745static void dsi_unbind(struct device *dev, struct device *master, void *data)
746{
747 /* do nothing */
748}
749
750static const struct component_ops dsi_ops = {
751 .bind = dsi_bind,
752 .unbind = dsi_unbind,
753};
754
755static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi)
756{
757 struct dsi_hw_ctx *ctx = dsi->ctx;
758 struct device_node *np = pdev->dev.of_node;
759 struct device_node *endpoint, *bridge_node;
760 struct drm_bridge *bridge;
761 struct resource *res;
762
763 /*
764 * Get the endpoint node. In our case, dsi has one output port1
765 * to which the external HDMI bridge is connected.
766 */
767 endpoint = of_graph_get_endpoint_by_regs(np, 1, -1);
768 if (!endpoint) {
769 DRM_ERROR("no valid endpoint node\n");
770 return -ENODEV;
771 }
772 of_node_put(endpoint);
773
774 bridge_node = of_graph_get_remote_port_parent(endpoint);
775 if (!bridge_node) {
776 DRM_ERROR("no valid bridge node\n");
777 return -ENODEV;
778 }
779 of_node_put(bridge_node);
780
781 bridge = of_drm_find_bridge(bridge_node);
782 if (!bridge) {
783 DRM_INFO("wait for external HDMI bridge driver.\n");
784 return -EPROBE_DEFER;
785 }
786 dsi->bridge = bridge;
787
788 ctx->pclk = devm_clk_get(&pdev->dev, "pclk");
789 if (IS_ERR(ctx->pclk)) {
790 DRM_ERROR("failed to get pclk clock\n");
791 return PTR_ERR(ctx->pclk);
792 }
793
794 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
795 ctx->base = devm_ioremap_resource(&pdev->dev, res);
796 if (IS_ERR(ctx->base)) {
797 DRM_ERROR("failed to remap dsi io region\n");
798 return PTR_ERR(ctx->base);
799 }
800
801 return 0;
802}
803
804static int dsi_probe(struct platform_device *pdev)
805{
806 struct dsi_data *data;
807 struct dw_dsi *dsi;
808 struct dsi_hw_ctx *ctx;
809 int ret;
810
811 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
812 if (!data) {
813 DRM_ERROR("failed to allocate dsi data.\n");
814 return -ENOMEM;
815 }
816 dsi = &data->dsi;
817 ctx = &data->ctx;
818 dsi->ctx = ctx;
819
820 ret = dsi_parse_dt(pdev, dsi);
821 if (ret)
822 return ret;
823
824 platform_set_drvdata(pdev, data);
825
826 return component_add(&pdev->dev, &dsi_ops);
827}
828
829static int dsi_remove(struct platform_device *pdev)
830{
831 component_del(&pdev->dev, &dsi_ops);
832
833 return 0;
834}
835
836static const struct of_device_id dsi_of_match[] = {
837 {.compatible = "hisilicon,hi6220-dsi"},
838 { }
839};
840MODULE_DEVICE_TABLE(of, dsi_of_match);
841
842static struct platform_driver dsi_driver = {
843 .probe = dsi_probe,
844 .remove = dsi_remove,
845 .driver = {
846 .name = "dw-dsi",
847 .of_match_table = dsi_of_match,
848 },
849};
850
851module_platform_driver(dsi_driver);
852
853MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
854MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
855MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
856MODULE_DESCRIPTION("DesignWare MIPI DSI Host Controller v1.02 driver");
857MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
new file mode 100644
index 000000000000..18808fc9f362
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
@@ -0,0 +1,103 @@
1/*
2 * Copyright (c) 2016 Linaro Limited.
3 * Copyright (c) 2014-2016 Hisilicon Limited.
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 */
10
11#ifndef __DW_DSI_REG_H__
12#define __DW_DSI_REG_H__
13
14#define MASK(x) (BIT(x) - 1)
15
16/*
17 * regs
18 */
19#define PWR_UP 0x04 /* Core power-up */
20#define RESET 0
21#define POWERUP BIT(0)
22#define PHY_IF_CFG 0xA4 /* D-PHY interface configuration */
23#define CLKMGR_CFG 0x08 /* the internal clock dividers */
24#define PHY_RSTZ 0xA0 /* D-PHY reset control */
25#define PHY_ENABLECLK BIT(2)
26#define PHY_UNRSTZ BIT(1)
27#define PHY_UNSHUTDOWNZ BIT(0)
28#define PHY_TST_CTRL0 0xB4 /* D-PHY test interface control 0 */
29#define PHY_TST_CTRL1 0xB8 /* D-PHY test interface control 1 */
30#define CLK_TLPX 0x10
31#define CLK_THS_PREPARE 0x11
32#define CLK_THS_ZERO 0x12
33#define CLK_THS_TRAIL 0x13
34#define CLK_TWAKEUP 0x14
35#define DATA_TLPX(x) (0x20 + ((x) << 4))
36#define DATA_THS_PREPARE(x) (0x21 + ((x) << 4))
37#define DATA_THS_ZERO(x) (0x22 + ((x) << 4))
38#define DATA_THS_TRAIL(x) (0x23 + ((x) << 4))
39#define DATA_TTA_GO(x) (0x24 + ((x) << 4))
40#define DATA_TTA_GET(x) (0x25 + ((x) << 4))
41#define DATA_TWAKEUP(x) (0x26 + ((x) << 4))
42#define PHY_CFG_I 0x60
43#define PHY_CFG_PLL_I 0x63
44#define PHY_CFG_PLL_II 0x64
45#define PHY_CFG_PLL_III 0x65
46#define PHY_CFG_PLL_IV 0x66
47#define PHY_CFG_PLL_V 0x67
48#define DPI_COLOR_CODING 0x10 /* DPI color coding */
49#define DPI_CFG_POL 0x14 /* DPI polarity configuration */
50#define VID_HSA_TIME 0x48 /* Horizontal Sync Active time */
51#define VID_HBP_TIME 0x4C /* Horizontal Back Porch time */
52#define VID_HLINE_TIME 0x50 /* Line time */
53#define VID_VSA_LINES 0x54 /* Vertical Sync Active period */
54#define VID_VBP_LINES 0x58 /* Vertical Back Porch period */
55#define VID_VFP_LINES 0x5C /* Vertical Front Porch period */
56#define VID_VACTIVE_LINES 0x60 /* Vertical resolution */
57#define VID_PKT_SIZE 0x3C /* Video packet size */
58#define VID_MODE_CFG 0x38 /* Video mode configuration */
59#define PHY_TMR_CFG 0x9C /* Data lanes timing configuration */
60#define BTA_TO_CNT 0x8C /* Response timeout definition */
61#define PHY_TMR_LPCLK_CFG 0x98 /* clock lane timing configuration */
62#define CLK_DATA_TMR_CFG 0xCC
63#define LPCLK_CTRL 0x94 /* Low-power in clock lane */
64#define PHY_TXREQUESTCLKHS BIT(0)
65#define MODE_CFG 0x34 /* Video or Command mode selection */
66#define PHY_STATUS 0xB0 /* D-PHY PPI status interface */
67
68#define PHY_STOP_WAIT_TIME 0x30
69
70/*
71 * regs relevant enum
72 */
73enum dpi_color_coding {
74 DSI_24BITS_1 = 5,
75};
76
77enum dsi_video_mode_type {
78 DSI_NON_BURST_SYNC_PULSES = 0,
79 DSI_NON_BURST_SYNC_EVENTS,
80 DSI_BURST_SYNC_PULSES_1,
81 DSI_BURST_SYNC_PULSES_2
82};
83
84enum dsi_work_mode {
85 DSI_VIDEO_MODE = 0,
86 DSI_COMMAND_MODE
87};
88
89/*
90 * Register Write/Read Helper functions
91 */
92static inline void dw_update_bits(void __iomem *addr, u32 bit_start,
93 u32 mask, u32 val)
94{
95 u32 tmp, orig;
96
97 orig = readl(addr);
98 tmp = orig & ~(mask << bit_start);
99 tmp |= (val & mask) << bit_start;
100 writel(tmp, addr);
101}
102
103#endif /* __DW_DRM_DSI_H__ */
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
new file mode 100644
index 000000000000..4cf281b7ed63
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
@@ -0,0 +1,230 @@
1/*
2 * Copyright (c) 2016 Linaro Limited.
3 * Copyright (c) 2014-2016 Hisilicon Limited.
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 */
10
11#ifndef __KIRIN_ADE_REG_H__
12#define __KIRIN_ADE_REG_H__
13
14/*
15 * ADE Registers
16 */
17#define MASK(x) (BIT(x) - 1)
18
19#define ADE_CTRL 0x0004
20#define FRM_END_START_OFST 0
21#define FRM_END_START_MASK MASK(2)
22#define AUTO_CLK_GATE_EN_OFST 0
23#define AUTO_CLK_GATE_EN BIT(0)
24#define ADE_DISP_SRC_CFG 0x0018
25#define ADE_CTRL1 0x008C
26#define ADE_EN 0x0100
27#define ADE_DISABLE 0
28#define ADE_ENABLE 1
29/* reset and reload regs */
30#define ADE_SOFT_RST_SEL(x) (0x0078 + (x) * 0x4)
31#define ADE_RELOAD_DIS(x) (0x00AC + (x) * 0x4)
32#define RDMA_OFST 0
33#define CLIP_OFST 15
34#define SCL_OFST 21
35#define CTRAN_OFST 24
36#define OVLY_OFST 37 /* 32+5 */
37/* channel regs */
38#define RD_CH_CTRL(x) (0x1004 + (x) * 0x80)
39#define RD_CH_ADDR(x) (0x1008 + (x) * 0x80)
40#define RD_CH_SIZE(x) (0x100C + (x) * 0x80)
41#define RD_CH_STRIDE(x) (0x1010 + (x) * 0x80)
42#define RD_CH_SPACE(x) (0x1014 + (x) * 0x80)
43#define RD_CH_EN(x) (0x1020 + (x) * 0x80)
44/* overlay regs */
45#define ADE_OVLY1_TRANS_CFG 0x002C
46#define ADE_OVLY_CTL 0x0098
47#define ADE_OVLY_CH_XY0(x) (0x2004 + (x) * 4)
48#define ADE_OVLY_CH_XY1(x) (0x2024 + (x) * 4)
49#define ADE_OVLY_CH_CTL(x) (0x204C + (x) * 4)
50#define ADE_OVLY_OUTPUT_SIZE(x) (0x2070 + (x) * 8)
51#define OUTPUT_XSIZE_OFST 16
52#define ADE_OVLYX_CTL(x) (0x209C + (x) * 4)
53#define CH_OVLY_SEL_OFST(x) ((x) * 4)
54#define CH_OVLY_SEL_MASK MASK(2)
55#define CH_OVLY_SEL_VAL(x) ((x) + 1)
56#define CH_ALP_MODE_OFST 0
57#define CH_ALP_SEL_OFST 2
58#define CH_UNDER_ALP_SEL_OFST 4
59#define CH_EN_OFST 6
60#define CH_ALP_GBL_OFST 15
61#define CH_SEL_OFST 28
62/* ctran regs */
63#define ADE_CTRAN_DIS(x) (0x5004 + (x) * 0x100)
64#define CTRAN_BYPASS_ON 1
65#define CTRAN_BYPASS_OFF 0
66#define ADE_CTRAN_IMAGE_SIZE(x) (0x503C + (x) * 0x100)
67/* clip regs */
68#define ADE_CLIP_DISABLE(x) (0x6800 + (x) * 0x100)
69#define ADE_CLIP_SIZE0(x) (0x6804 + (x) * 0x100)
70#define ADE_CLIP_SIZE1(x) (0x6808 + (x) * 0x100)
71
72/*
73 * LDI Registers
74 */
75#define LDI_HRZ_CTRL0 0x7400
76#define HBP_OFST 20
77#define LDI_HRZ_CTRL1 0x7404
78#define LDI_VRT_CTRL0 0x7408
79#define VBP_OFST 20
80#define LDI_VRT_CTRL1 0x740C
81#define LDI_PLR_CTRL 0x7410
82#define FLAG_NVSYNC BIT(0)
83#define FLAG_NHSYNC BIT(1)
84#define FLAG_NPIXCLK BIT(2)
85#define FLAG_NDE BIT(3)
86#define LDI_DSP_SIZE 0x7414
87#define VSIZE_OFST 20
88#define LDI_INT_EN 0x741C
89#define FRAME_END_INT_EN_OFST 1
90#define LDI_CTRL 0x7420
91#define BPP_OFST 3
92#define DATA_GATE_EN BIT(2)
93#define LDI_EN BIT(0)
94#define LDI_MSK_INT 0x7428
95#define LDI_INT_CLR 0x742C
96#define LDI_WORK_MODE 0x7430
97#define LDI_HDMI_DSI_GT 0x7434
98
99/*
100 * ADE media bus service regs
101 */
102#define ADE0_QOSGENERATOR_MODE 0x010C
103#define QOSGENERATOR_MODE_MASK MASK(2)
104#define ADE0_QOSGENERATOR_EXTCONTROL 0x0118
105#define SOCKET_QOS_EN BIT(0)
106#define ADE1_QOSGENERATOR_MODE 0x020C
107#define ADE1_QOSGENERATOR_EXTCONTROL 0x0218
108
109/*
110 * ADE regs relevant enums
111 */
112enum frame_end_start {
113 /* regs take effect in every vsync */
114 REG_EFFECTIVE_IN_VSYNC = 0,
115 /* regs take effect in fist ade en and every frame end */
116 REG_EFFECTIVE_IN_ADEEN_FRMEND,
117 /* regs take effect in ade en immediately */
118 REG_EFFECTIVE_IN_ADEEN,
119 /* regs take effect in first vsync and every frame end */
120 REG_EFFECTIVE_IN_VSYNC_FRMEND
121};
122
123enum ade_fb_format {
124 ADE_RGB_565 = 0,
125 ADE_BGR_565,
126 ADE_XRGB_8888,
127 ADE_XBGR_8888,
128 ADE_ARGB_8888,
129 ADE_ABGR_8888,
130 ADE_RGBA_8888,
131 ADE_BGRA_8888,
132 ADE_RGB_888,
133 ADE_BGR_888 = 9,
134 ADE_FORMAT_UNSUPPORT = 800
135};
136
137enum ade_channel {
138 ADE_CH1 = 0, /* channel 1 for primary plane */
139 ADE_CH_NUM
140};
141
142enum ade_scale {
143 ADE_SCL1 = 0,
144 ADE_SCL2,
145 ADE_SCL3,
146 ADE_SCL_NUM
147};
148
149enum ade_ctran {
150 ADE_CTRAN1 = 0,
151 ADE_CTRAN2,
152 ADE_CTRAN3,
153 ADE_CTRAN4,
154 ADE_CTRAN5,
155 ADE_CTRAN6,
156 ADE_CTRAN_NUM
157};
158
159enum ade_overlay {
160 ADE_OVLY1 = 0,
161 ADE_OVLY2,
162 ADE_OVLY3,
163 ADE_OVLY_NUM
164};
165
166enum ade_alpha_mode {
167 ADE_ALP_GLOBAL = 0,
168 ADE_ALP_PIXEL,
169 ADE_ALP_PIXEL_AND_GLB
170};
171
172enum ade_alpha_blending_mode {
173 ADE_ALP_MUL_COEFF_0 = 0, /* alpha */
174 ADE_ALP_MUL_COEFF_1, /* 1-alpha */
175 ADE_ALP_MUL_COEFF_2, /* 0 */
176 ADE_ALP_MUL_COEFF_3 /* 1 */
177};
178
179/*
180 * LDI regs relevant enums
181 */
182enum dsi_pclk_en {
183 DSI_PCLK_ON = 0,
184 DSI_PCLK_OFF
185};
186
187enum ldi_output_format {
188 LDI_OUT_RGB_565 = 0,
189 LDI_OUT_RGB_666,
190 LDI_OUT_RGB_888
191};
192
193enum ldi_work_mode {
194 TEST_MODE = 0,
195 NORMAL_MODE
196};
197
198enum ldi_input_source {
199 DISP_SRC_NONE = 0,
200 DISP_SRC_OVLY2,
201 DISP_SRC_DISP,
202 DISP_SRC_ROT,
203 DISP_SRC_SCL2
204};
205
206/*
207 * ADE media bus service relevant enums
208 */
209enum qos_generator_mode {
210 FIXED_MODE = 0,
211 LIMITER_MODE,
212 BYPASS_MODE,
213 REGULATOR_MODE
214};
215
216/*
217 * Register Write/Read Helper functions
218 */
219static inline void ade_update_bits(void __iomem *addr, u32 bit_start,
220 u32 mask, u32 val)
221{
222 u32 tmp, orig;
223
224 orig = readl(addr);
225 tmp = orig & ~(mask << bit_start);
226 tmp |= (val & mask) << bit_start;
227 writel(tmp, addr);
228}
229
230#endif
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
new file mode 100644
index 000000000000..fba6372d060e
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -0,0 +1,1057 @@
1/*
2 * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
3 *
4 * Copyright (c) 2016 Linaro Limited.
5 * Copyright (c) 2014-2016 Hisilicon Limited.
6 *
7 * Author:
8 * Xinliang Liu <z.liuxinliang@hisilicon.com>
9 * Xinliang Liu <xinliang.liu@linaro.org>
10 * Xinwei Kong <kong.kongxinwei@hisilicon.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 */
17
18#include <linux/bitops.h>
19#include <linux/clk.h>
20#include <video/display_timing.h>
21#include <linux/mfd/syscon.h>
22#include <linux/regmap.h>
23#include <linux/reset.h>
24
25#include <drm/drmP.h>
26#include <drm/drm_crtc.h>
27#include <drm/drm_crtc_helper.h>
28#include <drm/drm_atomic.h>
29#include <drm/drm_atomic_helper.h>
30#include <drm/drm_plane_helper.h>
31#include <drm/drm_gem_cma_helper.h>
32#include <drm/drm_fb_cma_helper.h>
33
34#include "kirin_drm_drv.h"
35#include "kirin_ade_reg.h"
36
37#define PRIMARY_CH ADE_CH1 /* primary plane */
38#define OUT_OVLY ADE_OVLY2 /* output overlay compositor */
39#define ADE_DEBUG 1
40
41#define to_ade_crtc(crtc) \
42 container_of(crtc, struct ade_crtc, base)
43
44#define to_ade_plane(plane) \
45 container_of(plane, struct ade_plane, base)
46
47struct ade_hw_ctx {
48 void __iomem *base;
49 struct regmap *noc_regmap;
50 struct clk *ade_core_clk;
51 struct clk *media_noc_clk;
52 struct clk *ade_pix_clk;
53 struct reset_control *reset;
54 bool power_on;
55 int irq;
56};
57
58struct ade_crtc {
59 struct drm_crtc base;
60 struct ade_hw_ctx *ctx;
61 bool enable;
62 u32 out_format;
63};
64
65struct ade_plane {
66 struct drm_plane base;
67 void *ctx;
68 u8 ch; /* channel */
69};
70
71struct ade_data {
72 struct ade_crtc acrtc;
73 struct ade_plane aplane[ADE_CH_NUM];
74 struct ade_hw_ctx ctx;
75};
76
77/* ade-format info: */
78struct ade_format {
79 u32 pixel_format;
80 enum ade_fb_format ade_format;
81};
82
83static const struct ade_format ade_formats[] = {
84 /* 16bpp RGB: */
85 { DRM_FORMAT_RGB565, ADE_RGB_565 },
86 { DRM_FORMAT_BGR565, ADE_BGR_565 },
87 /* 24bpp RGB: */
88 { DRM_FORMAT_RGB888, ADE_RGB_888 },
89 { DRM_FORMAT_BGR888, ADE_BGR_888 },
90 /* 32bpp [A]RGB: */
91 { DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
92 { DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
93 { DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
94 { DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
95 { DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
96 { DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
97};
98
99static const u32 channel_formats1[] = {
100 /* channel 1,2,3,4 */
101 DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
102 DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
103 DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
104 DRM_FORMAT_ABGR8888
105};
106
107u32 ade_get_channel_formats(u8 ch, const u32 **formats)
108{
109 switch (ch) {
110 case ADE_CH1:
111 *formats = channel_formats1;
112 return ARRAY_SIZE(channel_formats1);
113 default:
114 DRM_ERROR("no this channel %d\n", ch);
115 *formats = NULL;
116 return 0;
117 }
118}
119
120/* convert from fourcc format to ade format */
121static u32 ade_get_format(u32 pixel_format)
122{
123 int i;
124
125 for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
126 if (ade_formats[i].pixel_format == pixel_format)
127 return ade_formats[i].ade_format;
128
129 /* not found */
130 DRM_ERROR("Not found pixel format!!fourcc_format= %d\n",
131 pixel_format);
132 return ADE_FORMAT_UNSUPPORT;
133}
134
135static void ade_update_reload_bit(void __iomem *base, u32 bit_num, u32 val)
136{
137 u32 bit_ofst, reg_num;
138
139 bit_ofst = bit_num % 32;
140 reg_num = bit_num / 32;
141
142 ade_update_bits(base + ADE_RELOAD_DIS(reg_num), bit_ofst,
143 MASK(1), !!val);
144}
145
146static u32 ade_read_reload_bit(void __iomem *base, u32 bit_num)
147{
148 u32 tmp, bit_ofst, reg_num;
149
150 bit_ofst = bit_num % 32;
151 reg_num = bit_num / 32;
152
153 tmp = readl(base + ADE_RELOAD_DIS(reg_num));
154 return !!(BIT(bit_ofst) & tmp);
155}
156
157static void ade_init(struct ade_hw_ctx *ctx)
158{
159 void __iomem *base = ctx->base;
160
161 /* enable clk gate */
162 ade_update_bits(base + ADE_CTRL1, AUTO_CLK_GATE_EN_OFST,
163 AUTO_CLK_GATE_EN, ADE_ENABLE);
164 /* clear overlay */
165 writel(0, base + ADE_OVLY1_TRANS_CFG);
166 writel(0, base + ADE_OVLY_CTL);
167 writel(0, base + ADE_OVLYX_CTL(OUT_OVLY));
168 /* clear reset and reload regs */
169 writel(MASK(32), base + ADE_SOFT_RST_SEL(0));
170 writel(MASK(32), base + ADE_SOFT_RST_SEL(1));
171 writel(MASK(32), base + ADE_RELOAD_DIS(0));
172 writel(MASK(32), base + ADE_RELOAD_DIS(1));
173 /*
174 * for video mode, all the ade registers should
175 * become effective at frame end.
176 */
177 ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
178 FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
179}
180
181static void ade_set_pix_clk(struct ade_hw_ctx *ctx,
182 struct drm_display_mode *mode,
183 struct drm_display_mode *adj_mode)
184{
185 u32 clk_Hz = mode->clock * 1000;
186 int ret;
187
188 /*
189 * Success should be guaranteed in mode_valid call back,
190 * so failure shouldn't happen here
191 */
192 ret = clk_set_rate(ctx->ade_pix_clk, clk_Hz);
193 if (ret)
194 DRM_ERROR("failed to set pixel clk %dHz (%d)\n", clk_Hz, ret);
195 adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
196}
197
198static void ade_ldi_set_mode(struct ade_crtc *acrtc,
199 struct drm_display_mode *mode,
200 struct drm_display_mode *adj_mode)
201{
202 struct ade_hw_ctx *ctx = acrtc->ctx;
203 void __iomem *base = ctx->base;
204 u32 width = mode->hdisplay;
205 u32 height = mode->vdisplay;
206 u32 hfp, hbp, hsw, vfp, vbp, vsw;
207 u32 plr_flags;
208
209 plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? FLAG_NVSYNC : 0;
210 plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? FLAG_NHSYNC : 0;
211 hfp = mode->hsync_start - mode->hdisplay;
212 hbp = mode->htotal - mode->hsync_end;
213 hsw = mode->hsync_end - mode->hsync_start;
214 vfp = mode->vsync_start - mode->vdisplay;
215 vbp = mode->vtotal - mode->vsync_end;
216 vsw = mode->vsync_end - mode->vsync_start;
217 if (vsw > 15) {
218 DRM_DEBUG_DRIVER("vsw exceeded 15\n");
219 vsw = 15;
220 }
221
222 writel((hbp << HBP_OFST) | hfp, base + LDI_HRZ_CTRL0);
223 /* the configured value is actual value - 1 */
224 writel(hsw - 1, base + LDI_HRZ_CTRL1);
225 writel((vbp << VBP_OFST) | vfp, base + LDI_VRT_CTRL0);
226 /* the configured value is actual value - 1 */
227 writel(vsw - 1, base + LDI_VRT_CTRL1);
228 /* the configured value is actual value - 1 */
229 writel(((height - 1) << VSIZE_OFST) | (width - 1),
230 base + LDI_DSP_SIZE);
231 writel(plr_flags, base + LDI_PLR_CTRL);
232
233 /* set overlay compositor output size */
234 writel(((width - 1) << OUTPUT_XSIZE_OFST) | (height - 1),
235 base + ADE_OVLY_OUTPUT_SIZE(OUT_OVLY));
236
237 /* ctran6 setting */
238 writel(CTRAN_BYPASS_ON, base + ADE_CTRAN_DIS(ADE_CTRAN6));
239 /* the configured value is actual value - 1 */
240 writel(width * height - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
241 ade_update_reload_bit(base, CTRAN_OFST + ADE_CTRAN6, 0);
242
243 ade_set_pix_clk(ctx, mode, adj_mode);
244
245 DRM_DEBUG_DRIVER("set mode: %dx%d\n", width, height);
246}
247
248static int ade_power_up(struct ade_hw_ctx *ctx)
249{
250 int ret;
251
252 ret = clk_prepare_enable(ctx->media_noc_clk);
253 if (ret) {
254 DRM_ERROR("failed to enable media_noc_clk (%d)\n", ret);
255 return ret;
256 }
257
258 ret = reset_control_deassert(ctx->reset);
259 if (ret) {
260 DRM_ERROR("failed to deassert reset\n");
261 return ret;
262 }
263
264 ret = clk_prepare_enable(ctx->ade_core_clk);
265 if (ret) {
266 DRM_ERROR("failed to enable ade_core_clk (%d)\n", ret);
267 return ret;
268 }
269
270 ade_init(ctx);
271 ctx->power_on = true;
272 return 0;
273}
274
275static void ade_power_down(struct ade_hw_ctx *ctx)
276{
277 void __iomem *base = ctx->base;
278
279 writel(ADE_DISABLE, base + LDI_CTRL);
280 /* dsi pixel off */
281 writel(DSI_PCLK_OFF, base + LDI_HDMI_DSI_GT);
282
283 clk_disable_unprepare(ctx->ade_core_clk);
284 reset_control_assert(ctx->reset);
285 clk_disable_unprepare(ctx->media_noc_clk);
286 ctx->power_on = false;
287}
288
289static void ade_set_medianoc_qos(struct ade_crtc *acrtc)
290{
291 struct ade_hw_ctx *ctx = acrtc->ctx;
292 struct regmap *map = ctx->noc_regmap;
293
294 regmap_update_bits(map, ADE0_QOSGENERATOR_MODE,
295 QOSGENERATOR_MODE_MASK, BYPASS_MODE);
296 regmap_update_bits(map, ADE0_QOSGENERATOR_EXTCONTROL,
297 SOCKET_QOS_EN, SOCKET_QOS_EN);
298
299 regmap_update_bits(map, ADE1_QOSGENERATOR_MODE,
300 QOSGENERATOR_MODE_MASK, BYPASS_MODE);
301 regmap_update_bits(map, ADE1_QOSGENERATOR_EXTCONTROL,
302 SOCKET_QOS_EN, SOCKET_QOS_EN);
303}
304
305static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
306{
307 struct kirin_drm_private *priv = dev->dev_private;
308 struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
309 struct ade_hw_ctx *ctx = acrtc->ctx;
310 void __iomem *base = ctx->base;
311
312 if (!ctx->power_on)
313 (void)ade_power_up(ctx);
314
315 ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
316 MASK(1), 1);
317
318 return 0;
319}
320
321static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
322{
323 struct kirin_drm_private *priv = dev->dev_private;
324 struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
325 struct ade_hw_ctx *ctx = acrtc->ctx;
326 void __iomem *base = ctx->base;
327
328 if (!ctx->power_on) {
329 DRM_ERROR("power is down! vblank disable fail\n");
330 return;
331 }
332
333 ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
334 MASK(1), 0);
335}
336
337static irqreturn_t ade_irq_handler(int irq, void *data)
338{
339 struct ade_crtc *acrtc = data;
340 struct ade_hw_ctx *ctx = acrtc->ctx;
341 struct drm_crtc *crtc = &acrtc->base;
342 void __iomem *base = ctx->base;
343 u32 status;
344
345 status = readl(base + LDI_MSK_INT);
346 DRM_DEBUG_VBL("LDI IRQ: status=0x%X\n", status);
347
348 /* vblank irq */
349 if (status & BIT(FRAME_END_INT_EN_OFST)) {
350 ade_update_bits(base + LDI_INT_CLR, FRAME_END_INT_EN_OFST,
351 MASK(1), 1);
352 drm_crtc_handle_vblank(crtc);
353 }
354
355 return IRQ_HANDLED;
356}
357
358static void ade_display_enable(struct ade_crtc *acrtc)
359{
360 struct ade_hw_ctx *ctx = acrtc->ctx;
361 void __iomem *base = ctx->base;
362 u32 out_fmt = acrtc->out_format;
363
364 /* enable output overlay compositor */
365 writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY));
366 ade_update_reload_bit(base, OVLY_OFST + OUT_OVLY, 0);
367
368 /* display source setting */
369 writel(DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
370
371 /* enable ade */
372 writel(ADE_ENABLE, base + ADE_EN);
373 /* enable ldi */
374 writel(NORMAL_MODE, base + LDI_WORK_MODE);
375 writel((out_fmt << BPP_OFST) | DATA_GATE_EN | LDI_EN,
376 base + LDI_CTRL);
377 /* dsi pixel on */
378 writel(DSI_PCLK_ON, base + LDI_HDMI_DSI_GT);
379}
380
381#if ADE_DEBUG
382static void ade_rdma_dump_regs(void __iomem *base, u32 ch)
383{
384 u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
385 u32 val;
386
387 reg_ctrl = RD_CH_CTRL(ch);
388 reg_addr = RD_CH_ADDR(ch);
389 reg_size = RD_CH_SIZE(ch);
390 reg_stride = RD_CH_STRIDE(ch);
391 reg_space = RD_CH_SPACE(ch);
392 reg_en = RD_CH_EN(ch);
393
394 val = ade_read_reload_bit(base, RDMA_OFST + ch);
395 DRM_DEBUG_DRIVER("[rdma%d]: reload(%d)\n", ch + 1, val);
396 val = readl(base + reg_ctrl);
397 DRM_DEBUG_DRIVER("[rdma%d]: reg_ctrl(0x%08x)\n", ch + 1, val);
398 val = readl(base + reg_addr);
399 DRM_DEBUG_DRIVER("[rdma%d]: reg_addr(0x%08x)\n", ch + 1, val);
400 val = readl(base + reg_size);
401 DRM_DEBUG_DRIVER("[rdma%d]: reg_size(0x%08x)\n", ch + 1, val);
402 val = readl(base + reg_stride);
403 DRM_DEBUG_DRIVER("[rdma%d]: reg_stride(0x%08x)\n", ch + 1, val);
404 val = readl(base + reg_space);
405 DRM_DEBUG_DRIVER("[rdma%d]: reg_space(0x%08x)\n", ch + 1, val);
406 val = readl(base + reg_en);
407 DRM_DEBUG_DRIVER("[rdma%d]: reg_en(0x%08x)\n", ch + 1, val);
408}
409
410static void ade_clip_dump_regs(void __iomem *base, u32 ch)
411{
412 u32 val;
413
414 val = ade_read_reload_bit(base, CLIP_OFST + ch);
415 DRM_DEBUG_DRIVER("[clip%d]: reload(%d)\n", ch + 1, val);
416 val = readl(base + ADE_CLIP_DISABLE(ch));
417 DRM_DEBUG_DRIVER("[clip%d]: reg_clip_disable(0x%08x)\n", ch + 1, val);
418 val = readl(base + ADE_CLIP_SIZE0(ch));
419 DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size0(0x%08x)\n", ch + 1, val);
420 val = readl(base + ADE_CLIP_SIZE1(ch));
421 DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size1(0x%08x)\n", ch + 1, val);
422}
423
424static void ade_compositor_routing_dump_regs(void __iomem *base, u32 ch)
425{
426 u8 ovly_ch = 0; /* TODO: Only primary plane now */
427 u32 val;
428
429 val = readl(base + ADE_OVLY_CH_XY0(ovly_ch));
430 DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy0(0x%08x)\n", ovly_ch, val);
431 val = readl(base + ADE_OVLY_CH_XY1(ovly_ch));
432 DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy1(0x%08x)\n", ovly_ch, val);
433 val = readl(base + ADE_OVLY_CH_CTL(ovly_ch));
434 DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_ctl(0x%08x)\n", ovly_ch, val);
435}
436
437static void ade_dump_overlay_compositor_regs(void __iomem *base, u32 comp)
438{
439 u32 val;
440
441 val = ade_read_reload_bit(base, OVLY_OFST + comp);
442 DRM_DEBUG_DRIVER("[overlay%d]: reload(%d)\n", comp + 1, val);
443 writel(ADE_ENABLE, base + ADE_OVLYX_CTL(comp));
444 DRM_DEBUG_DRIVER("[overlay%d]: reg_ctl(0x%08x)\n", comp + 1, val);
445 val = readl(base + ADE_OVLY_CTL);
446 DRM_DEBUG_DRIVER("ovly_ctl(0x%08x)\n", val);
447}
448
449static void ade_dump_regs(void __iomem *base)
450{
451 u32 i;
452
453 /* dump channel regs */
454 for (i = 0; i < ADE_CH_NUM; i++) {
455 /* dump rdma regs */
456 ade_rdma_dump_regs(base, i);
457
458 /* dump clip regs */
459 ade_clip_dump_regs(base, i);
460
461 /* dump compositor routing regs */
462 ade_compositor_routing_dump_regs(base, i);
463 }
464
465 /* dump overlay compositor regs */
466 ade_dump_overlay_compositor_regs(base, OUT_OVLY);
467}
468#else
469static void ade_dump_regs(void __iomem *base) { }
470#endif
471
472static void ade_crtc_enable(struct drm_crtc *crtc)
473{
474 struct ade_crtc *acrtc = to_ade_crtc(crtc);
475 struct ade_hw_ctx *ctx = acrtc->ctx;
476 int ret;
477
478 if (acrtc->enable)
479 return;
480
481 if (!ctx->power_on) {
482 ret = ade_power_up(ctx);
483 if (ret)
484 return;
485 }
486
487 ade_set_medianoc_qos(acrtc);
488 ade_display_enable(acrtc);
489 ade_dump_regs(ctx->base);
490 acrtc->enable = true;
491}
492
493static void ade_crtc_disable(struct drm_crtc *crtc)
494{
495 struct ade_crtc *acrtc = to_ade_crtc(crtc);
496 struct ade_hw_ctx *ctx = acrtc->ctx;
497
498 if (!acrtc->enable)
499 return;
500
501 ade_power_down(ctx);
502 acrtc->enable = false;
503}
504
505static int ade_crtc_atomic_check(struct drm_crtc *crtc,
506 struct drm_crtc_state *state)
507{
508 /* do nothing */
509 return 0;
510}
511
512static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
513{
514 struct ade_crtc *acrtc = to_ade_crtc(crtc);
515 struct ade_hw_ctx *ctx = acrtc->ctx;
516 struct drm_display_mode *mode = &crtc->state->mode;
517 struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
518
519 if (!ctx->power_on)
520 (void)ade_power_up(ctx);
521 ade_ldi_set_mode(acrtc, mode, adj_mode);
522}
523
524static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
525 struct drm_crtc_state *old_state)
526{
527 struct ade_crtc *acrtc = to_ade_crtc(crtc);
528 struct ade_hw_ctx *ctx = acrtc->ctx;
529
530 if (!ctx->power_on)
531 (void)ade_power_up(ctx);
532}
533
534static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
535 struct drm_crtc_state *old_state)
536
537{
538 struct ade_crtc *acrtc = to_ade_crtc(crtc);
539 struct ade_hw_ctx *ctx = acrtc->ctx;
540 void __iomem *base = ctx->base;
541
542 /* only crtc is enabled regs take effect */
543 if (acrtc->enable) {
544 ade_dump_regs(base);
545 /* flush ade registers */
546 writel(ADE_ENABLE, base + ADE_EN);
547 }
548}
549
550static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
551 .enable = ade_crtc_enable,
552 .disable = ade_crtc_disable,
553 .atomic_check = ade_crtc_atomic_check,
554 .mode_set_nofb = ade_crtc_mode_set_nofb,
555 .atomic_begin = ade_crtc_atomic_begin,
556 .atomic_flush = ade_crtc_atomic_flush,
557};
558
559static const struct drm_crtc_funcs ade_crtc_funcs = {
560 .destroy = drm_crtc_cleanup,
561 .set_config = drm_atomic_helper_set_config,
562 .page_flip = drm_atomic_helper_page_flip,
563 .reset = drm_atomic_helper_crtc_reset,
564 .set_property = drm_atomic_helper_crtc_set_property,
565 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
566 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
567};
568
569static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
570 struct drm_plane *plane)
571{
572 struct kirin_drm_private *priv = dev->dev_private;
573 struct device_node *port;
574 int ret;
575
576 /* set crtc port so that
577 * drm_of_find_possible_crtcs call works
578 */
579 port = of_get_child_by_name(dev->dev->of_node, "port");
580 if (!port) {
581 DRM_ERROR("no port node found in %s\n",
582 dev->dev->of_node->full_name);
583 return -EINVAL;
584 }
585 of_node_put(port);
586 crtc->port = port;
587
588 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
589 &ade_crtc_funcs, NULL);
590 if (ret) {
591 DRM_ERROR("failed to init crtc.\n");
592 return ret;
593 }
594
595 drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
596 priv->crtc[drm_crtc_index(crtc)] = crtc;
597
598 return 0;
599}
600
601static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb,
602 u32 ch, u32 y, u32 in_h, u32 fmt)
603{
604 struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
605 u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
606 u32 stride = fb->pitches[0];
607 u32 addr = (u32)obj->paddr + y * stride;
608
609 DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n",
610 ch + 1, y, in_h, stride, (u32)obj->paddr);
611 DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
612 addr, fb->width, fb->height, fmt,
613 drm_get_format_name(fb->pixel_format));
614
615 /* get reg offset */
616 reg_ctrl = RD_CH_CTRL(ch);
617 reg_addr = RD_CH_ADDR(ch);
618 reg_size = RD_CH_SIZE(ch);
619 reg_stride = RD_CH_STRIDE(ch);
620 reg_space = RD_CH_SPACE(ch);
621 reg_en = RD_CH_EN(ch);
622
623 /*
624 * TODO: set rotation
625 */
626 writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
627 writel(addr, base + reg_addr);
628 writel((in_h << 16) | stride, base + reg_size);
629 writel(stride, base + reg_stride);
630 writel(in_h * stride, base + reg_space);
631 writel(ADE_ENABLE, base + reg_en);
632 ade_update_reload_bit(base, RDMA_OFST + ch, 0);
633}
634
635static void ade_rdma_disable(void __iomem *base, u32 ch)
636{
637 u32 reg_en;
638
639 /* get reg offset */
640 reg_en = RD_CH_EN(ch);
641 writel(0, base + reg_en);
642 ade_update_reload_bit(base, RDMA_OFST + ch, 1);
643}
644
645static void ade_clip_set(void __iomem *base, u32 ch, u32 fb_w, u32 x,
646 u32 in_w, u32 in_h)
647{
648 u32 disable_val;
649 u32 clip_left;
650 u32 clip_right;
651
652 /*
653 * clip width, no need to clip height
654 */
655 if (fb_w == in_w) { /* bypass */
656 disable_val = 1;
657 clip_left = 0;
658 clip_right = 0;
659 } else {
660 disable_val = 0;
661 clip_left = x;
662 clip_right = fb_w - (x + in_w) - 1;
663 }
664
665 DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
666 ch + 1, clip_left, clip_right);
667
668 writel(disable_val, base + ADE_CLIP_DISABLE(ch));
669 writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
670 writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
671 ade_update_reload_bit(base, CLIP_OFST + ch, 0);
672}
673
674static void ade_clip_disable(void __iomem *base, u32 ch)
675{
676 writel(1, base + ADE_CLIP_DISABLE(ch));
677 ade_update_reload_bit(base, CLIP_OFST + ch, 1);
678}
679
680static bool has_Alpha_channel(int format)
681{
682 switch (format) {
683 case ADE_ARGB_8888:
684 case ADE_ABGR_8888:
685 case ADE_RGBA_8888:
686 case ADE_BGRA_8888:
687 return true;
688 default:
689 return false;
690 }
691}
692
693static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
694 u8 *alp_sel, u8 *under_alp_sel)
695{
696 bool has_alpha = has_Alpha_channel(fmt);
697
698 /*
699 * get alp_mode
700 */
701 if (has_alpha && glb_alpha < 255)
702 *alp_mode = ADE_ALP_PIXEL_AND_GLB;
703 else if (has_alpha)
704 *alp_mode = ADE_ALP_PIXEL;
705 else
706 *alp_mode = ADE_ALP_GLOBAL;
707
708 /*
709 * get alp sel
710 */
711 *alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
712 *under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
713}
714
715static void ade_compositor_routing_set(void __iomem *base, u8 ch,
716 u32 x0, u32 y0,
717 u32 in_w, u32 in_h, u32 fmt)
718{
719 u8 ovly_ch = 0; /* TODO: This is the zpos, only one plane now */
720 u8 glb_alpha = 255;
721 u32 x1 = x0 + in_w - 1;
722 u32 y1 = y0 + in_h - 1;
723 u32 val;
724 u8 alp_sel;
725 u8 under_alp_sel;
726 u8 alp_mode;
727
728 ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
729 &under_alp_sel);
730
731 /* overlay routing setting
732 */
733 writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
734 writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
735 val = (ch + 1) << CH_SEL_OFST | BIT(CH_EN_OFST) |
736 alp_sel << CH_ALP_SEL_OFST |
737 under_alp_sel << CH_UNDER_ALP_SEL_OFST |
738 glb_alpha << CH_ALP_GBL_OFST |
739 alp_mode << CH_ALP_MODE_OFST;
740 writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
741 /* connect this plane/channel to overlay2 compositor */
742 ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
743 CH_OVLY_SEL_MASK, CH_OVLY_SEL_VAL(OUT_OVLY));
744}
745
746static void ade_compositor_routing_disable(void __iomem *base, u32 ch)
747{
748 u8 ovly_ch = 0; /* TODO: Only primary plane now */
749
750 /* disable this plane/channel */
751 ade_update_bits(base + ADE_OVLY_CH_CTL(ovly_ch), CH_EN_OFST,
752 MASK(1), 0);
753 /* dis-connect this plane/channel of overlay2 compositor */
754 ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
755 CH_OVLY_SEL_MASK, 0);
756}
757
758/*
759 * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor
760 */
761static void ade_update_channel(struct ade_plane *aplane,
762 struct drm_framebuffer *fb, int crtc_x,
763 int crtc_y, unsigned int crtc_w,
764 unsigned int crtc_h, u32 src_x,
765 u32 src_y, u32 src_w, u32 src_h)
766{
767 struct ade_hw_ctx *ctx = aplane->ctx;
768 void __iomem *base = ctx->base;
769 u32 fmt = ade_get_format(fb->pixel_format);
770 u32 ch = aplane->ch;
771 u32 in_w;
772 u32 in_h;
773
774 DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
775 ch + 1, src_x, src_y, src_w, src_h,
776 crtc_x, crtc_y, crtc_w, crtc_h);
777
778 /* 1) DMA setting */
779 in_w = src_w;
780 in_h = src_h;
781 ade_rdma_set(base, fb, ch, src_y, in_h, fmt);
782
783 /* 2) clip setting */
784 ade_clip_set(base, ch, fb->width, src_x, in_w, in_h);
785
786 /* 3) TODO: scale setting for overlay planes */
787
788 /* 4) TODO: ctran/csc setting for overlay planes */
789
790 /* 5) compositor routing setting */
791 ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt);
792}
793
794static void ade_disable_channel(struct ade_plane *aplane)
795{
796 struct ade_hw_ctx *ctx = aplane->ctx;
797 void __iomem *base = ctx->base;
798 u32 ch = aplane->ch;
799
800 DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
801
802 /* disable read DMA */
803 ade_rdma_disable(base, ch);
804
805 /* disable clip */
806 ade_clip_disable(base, ch);
807
808 /* disable compositor routing */
809 ade_compositor_routing_disable(base, ch);
810}
811
812static int ade_plane_prepare_fb(struct drm_plane *plane,
813 const struct drm_plane_state *new_state)
814{
815 /* do nothing */
816 return 0;
817}
818
819static void ade_plane_cleanup_fb(struct drm_plane *plane,
820 const struct drm_plane_state *old_state)
821{
822 /* do nothing */
823}
824
825static int ade_plane_atomic_check(struct drm_plane *plane,
826 struct drm_plane_state *state)
827{
828 struct drm_framebuffer *fb = state->fb;
829 struct drm_crtc *crtc = state->crtc;
830 struct drm_crtc_state *crtc_state;
831 u32 src_x = state->src_x >> 16;
832 u32 src_y = state->src_y >> 16;
833 u32 src_w = state->src_w >> 16;
834 u32 src_h = state->src_h >> 16;
835 int crtc_x = state->crtc_x;
836 int crtc_y = state->crtc_y;
837 u32 crtc_w = state->crtc_w;
838 u32 crtc_h = state->crtc_h;
839 u32 fmt;
840
841 if (!crtc || !fb)
842 return 0;
843
844 fmt = ade_get_format(fb->pixel_format);
845 if (fmt == ADE_FORMAT_UNSUPPORT)
846 return -EINVAL;
847
848 crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
849 if (IS_ERR(crtc_state))
850 return PTR_ERR(crtc_state);
851
852 if (src_w != crtc_w || src_h != crtc_h) {
853 DRM_ERROR("Scale not support!!!\n");
854 return -EINVAL;
855 }
856
857 if (src_x + src_w > fb->width ||
858 src_y + src_h > fb->height)
859 return -EINVAL;
860
861 if (crtc_x < 0 || crtc_y < 0)
862 return -EINVAL;
863
864 if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
865 crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
866 return -EINVAL;
867
868 return 0;
869}
870
871static void ade_plane_atomic_update(struct drm_plane *plane,
872 struct drm_plane_state *old_state)
873{
874 struct drm_plane_state *state = plane->state;
875 struct ade_plane *aplane = to_ade_plane(plane);
876
877 ade_update_channel(aplane, state->fb, state->crtc_x, state->crtc_y,
878 state->crtc_w, state->crtc_h,
879 state->src_x >> 16, state->src_y >> 16,
880 state->src_w >> 16, state->src_h >> 16);
881}
882
883static void ade_plane_atomic_disable(struct drm_plane *plane,
884 struct drm_plane_state *old_state)
885{
886 struct ade_plane *aplane = to_ade_plane(plane);
887
888 ade_disable_channel(aplane);
889}
890
891static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
892 .prepare_fb = ade_plane_prepare_fb,
893 .cleanup_fb = ade_plane_cleanup_fb,
894 .atomic_check = ade_plane_atomic_check,
895 .atomic_update = ade_plane_atomic_update,
896 .atomic_disable = ade_plane_atomic_disable,
897};
898
899static struct drm_plane_funcs ade_plane_funcs = {
900 .update_plane = drm_atomic_helper_update_plane,
901 .disable_plane = drm_atomic_helper_disable_plane,
902 .set_property = drm_atomic_helper_plane_set_property,
903 .destroy = drm_plane_cleanup,
904 .reset = drm_atomic_helper_plane_reset,
905 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
906 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
907};
908
909static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
910 enum drm_plane_type type)
911{
912 const u32 *fmts;
913 u32 fmts_cnt;
914 int ret = 0;
915
916 /* get properties */
917 fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts);
918 if (ret)
919 return ret;
920
921 ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
922 fmts, fmts_cnt, type, NULL);
923 if (ret) {
924 DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
925 return ret;
926 }
927
928 drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs);
929
930 return 0;
931}
932
933static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
934{
935 struct resource *res;
936 struct device *dev = &pdev->dev;
937 struct device_node *np = pdev->dev.of_node;
938
939 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
940 ctx->base = devm_ioremap_resource(dev, res);
941 if (IS_ERR(ctx->base)) {
942 DRM_ERROR("failed to remap ade io base\n");
943 return PTR_ERR(ctx->base);
944 }
945
946 ctx->reset = devm_reset_control_get(dev, NULL);
947 if (IS_ERR(ctx->reset))
948 return PTR_ERR(ctx->reset);
949
950 ctx->noc_regmap =
951 syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon");
952 if (IS_ERR(ctx->noc_regmap)) {
953 DRM_ERROR("failed to get noc regmap\n");
954 return PTR_ERR(ctx->noc_regmap);
955 }
956
957 ctx->irq = platform_get_irq(pdev, 0);
958 if (ctx->irq < 0) {
959 DRM_ERROR("failed to get irq\n");
960 return -ENODEV;
961 }
962
963 ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core");
964 if (!ctx->ade_core_clk) {
965 DRM_ERROR("failed to parse clk ADE_CORE\n");
966 return -ENODEV;
967 }
968
969 ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg");
970 if (!ctx->media_noc_clk) {
971 DRM_ERROR("failed to parse clk CODEC_JPEG\n");
972 return -ENODEV;
973 }
974
975 ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix");
976 if (!ctx->ade_pix_clk) {
977 DRM_ERROR("failed to parse clk ADE_PIX\n");
978 return -ENODEV;
979 }
980
981 return 0;
982}
983
984static int ade_drm_init(struct drm_device *dev)
985{
986 struct platform_device *pdev = dev->platformdev;
987 struct ade_data *ade;
988 struct ade_hw_ctx *ctx;
989 struct ade_crtc *acrtc;
990 struct ade_plane *aplane;
991 enum drm_plane_type type;
992 int ret;
993 int i;
994
995 ade = devm_kzalloc(dev->dev, sizeof(*ade), GFP_KERNEL);
996 if (!ade) {
997 DRM_ERROR("failed to alloc ade_data\n");
998 return -ENOMEM;
999 }
1000 platform_set_drvdata(pdev, ade);
1001
1002 ctx = &ade->ctx;
1003 acrtc = &ade->acrtc;
1004 acrtc->ctx = ctx;
1005 acrtc->out_format = LDI_OUT_RGB_888;
1006
1007 ret = ade_dts_parse(pdev, ctx);
1008 if (ret)
1009 return ret;
1010
1011 /*
1012 * plane init
1013 * TODO: Now only support primary plane, overlay planes
1014 * need to do.
1015 */
1016 for (i = 0; i < ADE_CH_NUM; i++) {
1017 aplane = &ade->aplane[i];
1018 aplane->ch = i;
1019 aplane->ctx = ctx;
1020 type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
1021 DRM_PLANE_TYPE_OVERLAY;
1022
1023 ret = ade_plane_init(dev, aplane, type);
1024 if (ret)
1025 return ret;
1026 }
1027
1028 /* crtc init */
1029 ret = ade_crtc_init(dev, &acrtc->base, &ade->aplane[PRIMARY_CH].base);
1030 if (ret)
1031 return ret;
1032
1033 /* vblank irq init */
1034 ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler,
1035 IRQF_SHARED, dev->driver->name, acrtc);
1036 if (ret)
1037 return ret;
1038 dev->driver->get_vblank_counter = drm_vblank_no_hw_counter;
1039 dev->driver->enable_vblank = ade_enable_vblank;
1040 dev->driver->disable_vblank = ade_disable_vblank;
1041
1042 return 0;
1043}
1044
1045static void ade_drm_cleanup(struct drm_device *dev)
1046{
1047 struct platform_device *pdev = dev->platformdev;
1048 struct ade_data *ade = platform_get_drvdata(pdev);
1049 struct drm_crtc *crtc = &ade->acrtc.base;
1050
1051 drm_crtc_cleanup(crtc);
1052}
1053
1054const struct kirin_dc_ops ade_dc_ops = {
1055 .init = ade_drm_init,
1056 .cleanup = ade_drm_cleanup
1057};
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
new file mode 100644
index 000000000000..e102c9e1e7b2
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -0,0 +1,367 @@
1/*
2 * Hisilicon Kirin SoCs drm master driver
3 *
4 * Copyright (c) 2016 Linaro Limited.
5 * Copyright (c) 2014-2016 Hisilicon Limited.
6 *
7 * Author:
8 * Xinliang Liu <z.liuxinliang@hisilicon.com>
9 * Xinliang Liu <xinliang.liu@linaro.org>
10 * Xinwei Kong <kong.kongxinwei@hisilicon.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 */
17
18#include <linux/of_platform.h>
19#include <linux/component.h>
20#include <linux/of_graph.h>
21
22#include <drm/drmP.h>
23#include <drm/drm_gem_cma_helper.h>
24#include <drm/drm_fb_cma_helper.h>
25#include <drm/drm_atomic_helper.h>
26#include <drm/drm_crtc_helper.h>
27
28#include "kirin_drm_drv.h"
29
30static struct kirin_dc_ops *dc_ops;
31
32static int kirin_drm_kms_cleanup(struct drm_device *dev)
33{
34 struct kirin_drm_private *priv = dev->dev_private;
35
36#ifdef CONFIG_DRM_FBDEV_EMULATION
37 if (priv->fbdev) {
38 drm_fbdev_cma_fini(priv->fbdev);
39 priv->fbdev = NULL;
40 }
41#endif
42 drm_kms_helper_poll_fini(dev);
43 drm_vblank_cleanup(dev);
44 dc_ops->cleanup(dev);
45 drm_mode_config_cleanup(dev);
46 devm_kfree(dev->dev, priv);
47 dev->dev_private = NULL;
48
49 return 0;
50}
51
52#ifdef CONFIG_DRM_FBDEV_EMULATION
53static void kirin_fbdev_output_poll_changed(struct drm_device *dev)
54{
55 struct kirin_drm_private *priv = dev->dev_private;
56
57 if (priv->fbdev) {
58 drm_fbdev_cma_hotplug_event(priv->fbdev);
59 } else {
60 priv->fbdev = drm_fbdev_cma_init(dev, 32,
61 dev->mode_config.num_crtc,
62 dev->mode_config.num_connector);
63 if (IS_ERR(priv->fbdev))
64 priv->fbdev = NULL;
65 }
66}
67#endif
68
69static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = {
70 .fb_create = drm_fb_cma_create,
71#ifdef CONFIG_DRM_FBDEV_EMULATION
72 .output_poll_changed = kirin_fbdev_output_poll_changed,
73#endif
74 .atomic_check = drm_atomic_helper_check,
75 .atomic_commit = drm_atomic_helper_commit,
76};
77
78static void kirin_drm_mode_config_init(struct drm_device *dev)
79{
80 dev->mode_config.min_width = 0;
81 dev->mode_config.min_height = 0;
82
83 dev->mode_config.max_width = 2048;
84 dev->mode_config.max_height = 2048;
85
86 dev->mode_config.funcs = &kirin_drm_mode_config_funcs;
87}
88
89static int kirin_drm_kms_init(struct drm_device *dev)
90{
91 struct kirin_drm_private *priv;
92 int ret;
93
94 priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
95 if (!priv)
96 return -ENOMEM;
97
98 dev->dev_private = priv;
99 dev_set_drvdata(dev->dev, dev);
100
101 /* dev->mode_config initialization */
102 drm_mode_config_init(dev);
103 kirin_drm_mode_config_init(dev);
104
105 /* display controller init */
106 ret = dc_ops->init(dev);
107 if (ret)
108 goto err_mode_config_cleanup;
109
110 /* bind and init sub drivers */
111 ret = component_bind_all(dev->dev, dev);
112 if (ret) {
113 DRM_ERROR("failed to bind all component.\n");
114 goto err_dc_cleanup;
115 }
116
117 /* vblank init */
118 ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
119 if (ret) {
120 DRM_ERROR("failed to initialize vblank.\n");
121 goto err_unbind_all;
122 }
123 /* with irq_enabled = true, we can use the vblank feature. */
124 dev->irq_enabled = true;
125
126 /* reset all the states of crtc/plane/encoder/connector */
127 drm_mode_config_reset(dev);
128
129 /* init kms poll for handling hpd */
130 drm_kms_helper_poll_init(dev);
131
132 /* force detection after connectors init */
133 (void)drm_helper_hpd_irq_event(dev);
134
135 return 0;
136
137err_unbind_all:
138 component_unbind_all(dev->dev, dev);
139err_dc_cleanup:
140 dc_ops->cleanup(dev);
141err_mode_config_cleanup:
142 drm_mode_config_cleanup(dev);
143 devm_kfree(dev->dev, priv);
144 dev->dev_private = NULL;
145
146 return ret;
147}
148
149static const struct file_operations kirin_drm_fops = {
150 .owner = THIS_MODULE,
151 .open = drm_open,
152 .release = drm_release,
153 .unlocked_ioctl = drm_ioctl,
154#ifdef CONFIG_COMPAT
155 .compat_ioctl = drm_compat_ioctl,
156#endif
157 .poll = drm_poll,
158 .read = drm_read,
159 .llseek = no_llseek,
160 .mmap = drm_gem_cma_mmap,
161};
162
163static int kirin_gem_cma_dumb_create(struct drm_file *file,
164 struct drm_device *dev,
165 struct drm_mode_create_dumb *args)
166{
167 return drm_gem_cma_dumb_create_internal(file, dev, args);
168}
169
170static struct drm_driver kirin_drm_driver = {
171 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
172 DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
173 .fops = &kirin_drm_fops,
174 .set_busid = drm_platform_set_busid,
175
176 .gem_free_object = drm_gem_cma_free_object,
177 .gem_vm_ops = &drm_gem_cma_vm_ops,
178 .dumb_create = kirin_gem_cma_dumb_create,
179 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
180 .dumb_destroy = drm_gem_dumb_destroy,
181
182 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
183 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
184 .gem_prime_export = drm_gem_prime_export,
185 .gem_prime_import = drm_gem_prime_import,
186 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
187 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
188 .gem_prime_vmap = drm_gem_cma_prime_vmap,
189 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
190 .gem_prime_mmap = drm_gem_cma_prime_mmap,
191
192 .name = "kirin",
193 .desc = "Hisilicon Kirin SoCs' DRM Driver",
194 .date = "20150718",
195 .major = 1,
196 .minor = 0,
197};
198
199static int compare_of(struct device *dev, void *data)
200{
201 return dev->of_node == data;
202}
203
204static int kirin_drm_connectors_register(struct drm_device *dev)
205{
206 struct drm_connector *connector;
207 struct drm_connector *failed_connector;
208 int ret;
209
210 mutex_lock(&dev->mode_config.mutex);
211 drm_for_each_connector(connector, dev) {
212 ret = drm_connector_register(connector);
213 if (ret) {
214 failed_connector = connector;
215 goto err;
216 }
217 }
218 mutex_unlock(&dev->mode_config.mutex);
219
220 return 0;
221
222err:
223 drm_for_each_connector(connector, dev) {
224 if (failed_connector == connector)
225 break;
226 drm_connector_unregister(connector);
227 }
228 mutex_unlock(&dev->mode_config.mutex);
229
230 return ret;
231}
232
233static int kirin_drm_bind(struct device *dev)
234{
235 struct drm_driver *driver = &kirin_drm_driver;
236 struct drm_device *drm_dev;
237 int ret;
238
239 drm_dev = drm_dev_alloc(driver, dev);
240 if (!drm_dev)
241 return -ENOMEM;
242
243 drm_dev->platformdev = to_platform_device(dev);
244
245 ret = kirin_drm_kms_init(drm_dev);
246 if (ret)
247 goto err_drm_dev_unref;
248
249 ret = drm_dev_register(drm_dev, 0);
250 if (ret)
251 goto err_kms_cleanup;
252
253 /* connectors should be registered after drm device register */
254 ret = kirin_drm_connectors_register(drm_dev);
255 if (ret)
256 goto err_drm_dev_unregister;
257
258 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
259 driver->name, driver->major, driver->minor, driver->patchlevel,
260 driver->date, drm_dev->primary->index);
261
262 return 0;
263
264err_drm_dev_unregister:
265 drm_dev_unregister(drm_dev);
266err_kms_cleanup:
267 kirin_drm_kms_cleanup(drm_dev);
268err_drm_dev_unref:
269 drm_dev_unref(drm_dev);
270
271 return ret;
272}
273
274static void kirin_drm_unbind(struct device *dev)
275{
276 drm_put_dev(dev_get_drvdata(dev));
277}
278
279static const struct component_master_ops kirin_drm_ops = {
280 .bind = kirin_drm_bind,
281 .unbind = kirin_drm_unbind,
282};
283
284static struct device_node *kirin_get_remote_node(struct device_node *np)
285{
286 struct device_node *endpoint, *remote;
287
288 /* get the first endpoint, in our case only one remote node
289 * is connected to display controller.
290 */
291 endpoint = of_graph_get_next_endpoint(np, NULL);
292 if (!endpoint) {
293 DRM_ERROR("no valid endpoint node\n");
294 return ERR_PTR(-ENODEV);
295 }
296 of_node_put(endpoint);
297
298 remote = of_graph_get_remote_port_parent(endpoint);
299 if (!remote) {
300 DRM_ERROR("no valid remote node\n");
301 return ERR_PTR(-ENODEV);
302 }
303 of_node_put(remote);
304
305 if (!of_device_is_available(remote)) {
306 DRM_ERROR("not available for remote node\n");
307 return ERR_PTR(-ENODEV);
308 }
309
310 return remote;
311}
312
313static int kirin_drm_platform_probe(struct platform_device *pdev)
314{
315 struct device *dev = &pdev->dev;
316 struct device_node *np = dev->of_node;
317 struct component_match *match = NULL;
318 struct device_node *remote;
319
320 dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
321 if (!dc_ops) {
322 DRM_ERROR("failed to get dt id data\n");
323 return -EINVAL;
324 }
325
326 remote = kirin_get_remote_node(np);
327 if (IS_ERR(remote))
328 return PTR_ERR(remote);
329
330 component_match_add(dev, &match, compare_of, remote);
331
332 return component_master_add_with_match(dev, &kirin_drm_ops, match);
333
334 return 0;
335}
336
337static int kirin_drm_platform_remove(struct platform_device *pdev)
338{
339 component_master_del(&pdev->dev, &kirin_drm_ops);
340 dc_ops = NULL;
341 return 0;
342}
343
344static const struct of_device_id kirin_drm_dt_ids[] = {
345 { .compatible = "hisilicon,hi6220-ade",
346 .data = &ade_dc_ops,
347 },
348 { /* end node */ },
349};
350MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);
351
352static struct platform_driver kirin_drm_platform_driver = {
353 .probe = kirin_drm_platform_probe,
354 .remove = kirin_drm_platform_remove,
355 .driver = {
356 .name = "kirin-drm",
357 .of_match_table = kirin_drm_dt_ids,
358 },
359};
360
361module_platform_driver(kirin_drm_platform_driver);
362
363MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
364MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
365MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
366MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver");
367MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
new file mode 100644
index 000000000000..1a07caf8e7f4
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
@@ -0,0 +1,31 @@
1/*
2 * Copyright (c) 2016 Linaro Limited.
3 * Copyright (c) 2014-2016 Hisilicon Limited.
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 */
10
11#ifndef __KIRIN_DRM_DRV_H__
12#define __KIRIN_DRM_DRV_H__
13
14#define MAX_CRTC 2
15
16/* display controller init/cleanup ops */
17struct kirin_dc_ops {
18 int (*init)(struct drm_device *dev);
19 void (*cleanup)(struct drm_device *dev);
20};
21
22struct kirin_drm_private {
23 struct drm_crtc *crtc[MAX_CRTC];
24#ifdef CONFIG_DRM_FBDEV_EMULATION
25 struct drm_fbdev_cma *fbdev;
26#endif
27};
28
29extern const struct kirin_dc_ops ade_dc_ops;
30
31#endif /* __KIRIN_DRM_DRV_H__ */