aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2018-01-22 04:25:22 -0500
committerMaxime Ripard <maxime.ripard@free-electrons.com>2018-01-22 09:15:38 -0500
commitdd0421f47505bbbe30a4ce37b51a5c127b8754dc (patch)
treec098cb1c3d5d6458548832c42c8c5150d958b414
parent6b8562c86e249b6d46d3c1f02afe570368b01e67 (diff)
drm/sun4i: Add a driver for the display frontend
The display frontend is an hardware block that can be used to implement some more advanced features like hardware scaling or colorspace conversions. It can also be used to implement the output format of the VPU. Let's create a minimal driver for it that will only enable the hardware scaling features. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Link: https://patchwork.freedesktop.org/patch/msgid/029cdc3478bf89d422f5e8d9e600baf5e48ce4db.1516613040.git-series.maxime.ripard@free-electrons.com
-rw-r--r--drivers/gpu/drm/sun4i/Makefile3
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c27
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.h1
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_frontend.c389
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_frontend.h99
5 files changed, 514 insertions, 5 deletions
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 2b37a6abbb1d..582607c0c488 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -1,5 +1,6 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2sun4i-backend-y += sun4i_backend.o sun4i_layer.o 2sun4i-backend-y += sun4i_backend.o sun4i_layer.o
3sun4i-frontend-y += sun4i_frontend.o
3 4
4sun4i-drm-y += sun4i_drv.o 5sun4i-drm-y += sun4i_drv.o
5sun4i-drm-y += sun4i_framebuffer.o 6sun4i-drm-y += sun4i_framebuffer.o
@@ -24,6 +25,6 @@ obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
24obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o 25obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
25obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o 26obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
26 27
27obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o 28obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o
28obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o 29obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
29obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o 30obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 4570da0227b4..3957c2ff6870 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -23,6 +23,7 @@
23#include <drm/drm_of.h> 23#include <drm/drm_of.h>
24 24
25#include "sun4i_drv.h" 25#include "sun4i_drv.h"
26#include "sun4i_frontend.h"
26#include "sun4i_framebuffer.h" 27#include "sun4i_framebuffer.h"
27#include "sun4i_tcon.h" 28#include "sun4i_tcon.h"
28 29
@@ -91,6 +92,7 @@ static int sun4i_drv_bind(struct device *dev)
91 goto free_drm; 92 goto free_drm;
92 } 93 }
93 drm->dev_private = drv; 94 drm->dev_private = drv;
95 INIT_LIST_HEAD(&drv->frontend_list);
94 INIT_LIST_HEAD(&drv->engine_list); 96 INIT_LIST_HEAD(&drv->engine_list);
95 INIT_LIST_HEAD(&drv->tcon_list); 97 INIT_LIST_HEAD(&drv->tcon_list);
96 98
@@ -177,6 +179,14 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node)
177 of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend"); 179 of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend");
178} 180}
179 181
182static bool sun4i_drv_node_is_supported_frontend(struct device_node *node)
183{
184 if (IS_ENABLED(CONFIG_DRM_SUN4I_BACKEND))
185 return !!of_match_node(sun4i_frontend_of_table, node);
186
187 return false;
188}
189
180static bool sun4i_drv_node_is_tcon(struct device_node *node) 190static bool sun4i_drv_node_is_tcon(struct device_node *node)
181{ 191{
182 return !!of_match_node(sun4i_tcon_of_table, node); 192 return !!of_match_node(sun4i_tcon_of_table, node);
@@ -225,9 +235,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
225 int count = 0; 235 int count = 0;
226 236
227 /* 237 /*
228 * We don't support the frontend for now, so we will never 238 * The frontend has been disabled in some of our old device
229 * have a device bound. Just skip over it, but we still want 239 * trees. If we find a node that is the frontend and is
230 * the rest our pipeline to be added. 240 * disabled, we should just follow through and parse its
241 * child, but without adding it to the component list.
242 * Otherwise, we obviously want to add it to the list.
231 */ 243 */
232 if (!sun4i_drv_node_is_frontend(node) && 244 if (!sun4i_drv_node_is_frontend(node) &&
233 !of_device_is_available(node)) 245 !of_device_is_available(node))
@@ -240,7 +252,14 @@ static int sun4i_drv_add_endpoints(struct device *dev,
240 if (sun4i_drv_node_is_connector(node)) 252 if (sun4i_drv_node_is_connector(node))
241 return 0; 253 return 0;
242 254
243 if (!sun4i_drv_node_is_frontend(node)) { 255 /*
256 * If the device is either just a regular device, or an
257 * enabled frontend supported by the driver, we add it to our
258 * component list.
259 */
260 if (!sun4i_drv_node_is_frontend(node) ||
261 (sun4i_drv_node_is_supported_frontend(node) &&
262 of_device_is_available(node))) {
244 /* Add current component */ 263 /* Add current component */
245 DRM_DEBUG_DRIVER("Adding component %pOF\n", node); 264 DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
246 drm_of_component_match_add(dev, match, compare_of, node); 265 drm_of_component_match_add(dev, match, compare_of, node);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index 2825f140da54..5750b8ce8b31 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -19,6 +19,7 @@
19 19
20struct sun4i_drv { 20struct sun4i_drv {
21 struct list_head engine_list; 21 struct list_head engine_list;
22 struct list_head frontend_list;
22 struct list_head tcon_list; 23 struct list_head tcon_list;
23}; 24};
24 25
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
new file mode 100644
index 000000000000..ddf6cfa6dd23
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -0,0 +1,389 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2017 Free Electrons
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 */
6#include <drm/drmP.h>
7#include <drm/drm_gem_cma_helper.h>
8#include <drm/drm_fb_cma_helper.h>
9
10#include <linux/clk.h>
11#include <linux/component.h>
12#include <linux/module.h>
13#include <linux/platform_device.h>
14#include <linux/pm_runtime.h>
15#include <linux/regmap.h>
16#include <linux/reset.h>
17
18#include "sun4i_drv.h"
19#include "sun4i_frontend.h"
20
21static const u32 sun4i_frontend_vert_coef[32] = {
22 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
23 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
24 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
25 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
26 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
27 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
28 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
29 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
30};
31
32static const u32 sun4i_frontend_horz_coef[64] = {
33 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
34 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
35 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
36 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
37 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
38 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
39 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
40 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
41 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
42 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
43 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
44 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
45 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
46 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
47 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
48 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
49};
50
51static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
52{
53 int i;
54
55 for (i = 0; i < 32; i++) {
56 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
57 sun4i_frontend_horz_coef[2 * i]);
58 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
59 sun4i_frontend_horz_coef[2 * i]);
60 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
61 sun4i_frontend_horz_coef[2 * i + 1]);
62 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
63 sun4i_frontend_horz_coef[2 * i + 1]);
64 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
65 sun4i_frontend_vert_coef[i]);
66 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
67 sun4i_frontend_vert_coef[i]);
68 }
69
70 regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
71 SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL,
72 SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL);
73}
74
75int sun4i_frontend_init(struct sun4i_frontend *frontend)
76{
77 return pm_runtime_get_sync(frontend->dev);
78}
79EXPORT_SYMBOL(sun4i_frontend_init);
80
81void sun4i_frontend_exit(struct sun4i_frontend *frontend)
82{
83 pm_runtime_put(frontend->dev);
84}
85EXPORT_SYMBOL(sun4i_frontend_exit);
86
87void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
88 struct drm_plane *plane)
89{
90 struct drm_plane_state *state = plane->state;
91 struct drm_framebuffer *fb = state->fb;
92 dma_addr_t paddr;
93
94 /* Set the line width */
95 DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
96 regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
97 fb->pitches[0]);
98
99 /* Set the physical address of the buffer in memory */
100 paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
101 paddr -= PHYS_OFFSET;
102 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
103 regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
104}
105EXPORT_SYMBOL(sun4i_frontend_update_buffer);
106
107static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
108{
109 switch (fmt) {
110 case DRM_FORMAT_ARGB8888:
111 *val = 5;
112 return 0;
113
114 default:
115 return -EINVAL;
116 }
117}
118
119static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
120{
121 switch (fmt) {
122 case DRM_FORMAT_XRGB8888:
123 case DRM_FORMAT_ARGB8888:
124 *val = 2;
125 return 0;
126
127 default:
128 return -EINVAL;
129 }
130}
131
132int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
133 struct drm_plane *plane, uint32_t out_fmt)
134{
135 struct drm_plane_state *state = plane->state;
136 struct drm_framebuffer *fb = state->fb;
137 u32 out_fmt_val;
138 u32 in_fmt_val;
139 int ret;
140
141 ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
142 &in_fmt_val);
143 if (ret) {
144 DRM_DEBUG_DRIVER("Invalid input format\n");
145 return ret;
146 }
147
148 ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
149 if (ret) {
150 DRM_DEBUG_DRIVER("Invalid output format\n");
151 return ret;
152 }
153
154 /*
155 * I have no idea what this does exactly, but it seems to be
156 * related to the scaler FIR filter phase parameters.
157 */
158 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
159 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
160 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
161 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
162 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
163 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
164
165 regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
166 SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) |
167 SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(in_fmt_val) |
168 SUN4I_FRONTEND_INPUT_FMT_PS(1));
169
170 /*
171 * TODO: It look like the A31 and A80 at least will need the
172 * bit 7 (ALPHA_EN) enabled when using a format with alpha (so
173 * ARGB8888).
174 */
175 regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
176 SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(out_fmt_val));
177
178 return 0;
179}
180EXPORT_SYMBOL(sun4i_frontend_update_formats);
181
182void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
183 struct drm_plane *plane)
184{
185 struct drm_plane_state *state = plane->state;
186
187 /* Set height and width */
188 DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
189 state->crtc_w, state->crtc_h);
190 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
191 SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
192 state->src_w >> 16));
193 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
194 SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
195 state->src_w >> 16));
196
197 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
198 SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
199 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
200 SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
201
202 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
203 state->src_w / state->crtc_w);
204 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
205 state->src_w / state->crtc_w);
206
207 regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
208 state->src_h / state->crtc_h);
209 regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
210 state->src_h / state->crtc_h);
211
212 regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
213 SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
214 SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
215}
216EXPORT_SYMBOL(sun4i_frontend_update_coord);
217
218int sun4i_frontend_enable(struct sun4i_frontend *frontend)
219{
220 regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
221 SUN4I_FRONTEND_FRM_CTRL_FRM_START,
222 SUN4I_FRONTEND_FRM_CTRL_FRM_START);
223
224 return 0;
225}
226EXPORT_SYMBOL(sun4i_frontend_enable);
227
228static struct regmap_config sun4i_frontend_regmap_config = {
229 .reg_bits = 32,
230 .val_bits = 32,
231 .reg_stride = 4,
232 .max_register = 0x0a14,
233};
234
235static int sun4i_frontend_bind(struct device *dev, struct device *master,
236 void *data)
237{
238 struct platform_device *pdev = to_platform_device(dev);
239 struct sun4i_frontend *frontend;
240 struct drm_device *drm = data;
241 struct sun4i_drv *drv = drm->dev_private;
242 struct resource *res;
243 void __iomem *regs;
244
245 frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
246 if (!frontend)
247 return -ENOMEM;
248
249 dev_set_drvdata(dev, frontend);
250 frontend->dev = dev;
251 frontend->node = dev->of_node;
252
253 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
254 regs = devm_ioremap_resource(dev, res);
255 if (IS_ERR(regs))
256 return PTR_ERR(regs);
257
258 frontend->regs = devm_regmap_init_mmio(dev, regs,
259 &sun4i_frontend_regmap_config);
260 if (IS_ERR(frontend->regs)) {
261 dev_err(dev, "Couldn't create the frontend regmap\n");
262 return PTR_ERR(frontend->regs);
263 }
264
265 frontend->reset = devm_reset_control_get(dev, NULL);
266 if (IS_ERR(frontend->reset)) {
267 dev_err(dev, "Couldn't get our reset line\n");
268 return PTR_ERR(frontend->reset);
269 }
270
271 frontend->bus_clk = devm_clk_get(dev, "ahb");
272 if (IS_ERR(frontend->bus_clk)) {
273 dev_err(dev, "Couldn't get our bus clock\n");
274 return PTR_ERR(frontend->bus_clk);
275 }
276
277 frontend->mod_clk = devm_clk_get(dev, "mod");
278 if (IS_ERR(frontend->mod_clk)) {
279 dev_err(dev, "Couldn't get our mod clock\n");
280 return PTR_ERR(frontend->mod_clk);
281 }
282
283 frontend->ram_clk = devm_clk_get(dev, "ram");
284 if (IS_ERR(frontend->ram_clk)) {
285 dev_err(dev, "Couldn't get our ram clock\n");
286 return PTR_ERR(frontend->ram_clk);
287 }
288
289 list_add_tail(&frontend->list, &drv->frontend_list);
290 pm_runtime_enable(dev);
291
292 return 0;
293}
294
295static void sun4i_frontend_unbind(struct device *dev, struct device *master,
296 void *data)
297{
298 struct sun4i_frontend *frontend = dev_get_drvdata(dev);
299
300 list_del(&frontend->list);
301 pm_runtime_force_suspend(dev);
302}
303
304static const struct component_ops sun4i_frontend_ops = {
305 .bind = sun4i_frontend_bind,
306 .unbind = sun4i_frontend_unbind,
307};
308
309static int sun4i_frontend_probe(struct platform_device *pdev)
310{
311 return component_add(&pdev->dev, &sun4i_frontend_ops);
312}
313
314static int sun4i_frontend_remove(struct platform_device *pdev)
315{
316 component_del(&pdev->dev, &sun4i_frontend_ops);
317
318 return 0;
319}
320
321static int sun4i_frontend_runtime_resume(struct device *dev)
322{
323 struct sun4i_frontend *frontend = dev_get_drvdata(dev);
324 int ret;
325
326 clk_set_rate(frontend->mod_clk, 300000000);
327
328 clk_prepare_enable(frontend->bus_clk);
329 clk_prepare_enable(frontend->mod_clk);
330 clk_prepare_enable(frontend->ram_clk);
331
332 ret = reset_control_reset(frontend->reset);
333 if (ret) {
334 dev_err(dev, "Couldn't reset our device\n");
335 return ret;
336 }
337
338 regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
339 SUN4I_FRONTEND_EN_EN,
340 SUN4I_FRONTEND_EN_EN);
341
342 regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
343 SUN4I_FRONTEND_BYPASS_CSC_EN,
344 SUN4I_FRONTEND_BYPASS_CSC_EN);
345
346 sun4i_frontend_scaler_init(frontend);
347
348 return 0;
349}
350
351static int sun4i_frontend_runtime_suspend(struct device *dev)
352{
353 struct sun4i_frontend *frontend = dev_get_drvdata(dev);
354
355 clk_disable_unprepare(frontend->ram_clk);
356 clk_disable_unprepare(frontend->mod_clk);
357 clk_disable_unprepare(frontend->bus_clk);
358
359 reset_control_assert(frontend->reset);
360
361 return 0;
362}
363
364static const struct dev_pm_ops sun4i_frontend_pm_ops = {
365 .runtime_resume = sun4i_frontend_runtime_resume,
366 .runtime_suspend = sun4i_frontend_runtime_suspend,
367};
368
369const struct of_device_id sun4i_frontend_of_table[] = {
370 { .compatible = "allwinner,sun8i-a33-display-frontend" },
371 { }
372};
373EXPORT_SYMBOL(sun4i_frontend_of_table);
374MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
375
376static struct platform_driver sun4i_frontend_driver = {
377 .probe = sun4i_frontend_probe,
378 .remove = sun4i_frontend_remove,
379 .driver = {
380 .name = "sun4i-frontend",
381 .of_match_table = sun4i_frontend_of_table,
382 .pm = &sun4i_frontend_pm_ops,
383 },
384};
385module_platform_driver(sun4i_frontend_driver);
386
387MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
388MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
389MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
new file mode 100644
index 000000000000..02661ce81f3e
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
@@ -0,0 +1,99 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2017 Free Electrons
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 */
6
7#ifndef _SUN4I_FRONTEND_H_
8#define _SUN4I_FRONTEND_H_
9
10#include <linux/list.h>
11
12#define SUN4I_FRONTEND_EN_REG 0x000
13#define SUN4I_FRONTEND_EN_EN BIT(0)
14
15#define SUN4I_FRONTEND_FRM_CTRL_REG 0x004
16#define SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL BIT(23)
17#define SUN4I_FRONTEND_FRM_CTRL_FRM_START BIT(16)
18#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY BIT(1)
19#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY BIT(0)
20
21#define SUN4I_FRONTEND_BYPASS_REG 0x008
22#define SUN4I_FRONTEND_BYPASS_CSC_EN BIT(1)
23
24#define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020
25
26#define SUN4I_FRONTEND_LINESTRD0_REG 0x040
27
28#define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c
29#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod) ((mod) << 8)
30#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt) ((fmt) << 4)
31#define SUN4I_FRONTEND_INPUT_FMT_PS(ps) (ps)
32
33#define SUN4I_FRONTEND_OUTPUT_FMT_REG 0x05c
34#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt) (fmt)
35
36#define SUN4I_FRONTEND_CH0_INSIZE_REG 0x100
37#define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
38
39#define SUN4I_FRONTEND_CH0_OUTSIZE_REG 0x104
40#define SUN4I_FRONTEND_OUTSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
41
42#define SUN4I_FRONTEND_CH0_HORZFACT_REG 0x108
43#define SUN4I_FRONTEND_HORZFACT(i, f) (((i) << 16) | (f))
44
45#define SUN4I_FRONTEND_CH0_VERTFACT_REG 0x10c
46#define SUN4I_FRONTEND_VERTFACT(i, f) (((i) << 16) | (f))
47
48#define SUN4I_FRONTEND_CH0_HORZPHASE_REG 0x110
49#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG 0x114
50#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG 0x118
51
52#define SUN4I_FRONTEND_CH1_INSIZE_REG 0x200
53#define SUN4I_FRONTEND_CH1_OUTSIZE_REG 0x204
54#define SUN4I_FRONTEND_CH1_HORZFACT_REG 0x208
55#define SUN4I_FRONTEND_CH1_VERTFACT_REG 0x20c
56
57#define SUN4I_FRONTEND_CH1_HORZPHASE_REG 0x210
58#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG 0x214
59#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG 0x218
60
61#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i) (0x400 + i * 4)
62#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i) (0x480 + i * 4)
63#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i) (0x500 + i * 4)
64#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i) (0x600 + i * 4)
65#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i) (0x680 + i * 4)
66#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i) (0x700 + i * 4)
67
68struct clk;
69struct device_node;
70struct drm_plane;
71struct regmap;
72struct reset_control;
73
74struct sun4i_frontend {
75 struct list_head list;
76 struct device *dev;
77 struct device_node *node;
78
79 struct clk *bus_clk;
80 struct clk *mod_clk;
81 struct clk *ram_clk;
82 struct regmap *regs;
83 struct reset_control *reset;
84};
85
86extern const struct of_device_id sun4i_frontend_of_table[];
87
88int sun4i_frontend_init(struct sun4i_frontend *frontend);
89void sun4i_frontend_exit(struct sun4i_frontend *frontend);
90int sun4i_frontend_enable(struct sun4i_frontend *frontend);
91
92void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
93 struct drm_plane *plane);
94void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
95 struct drm_plane *plane);
96int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
97 struct drm_plane *plane, uint32_t out_fmt);
98
99#endif /* _SUN4I_FRONTEND_H_ */