1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2017 Free Electrons
4*4882a593Smuzhiyun * Maxime Ripard <maxime.ripard@free-electrons.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/clk.h>
8*4882a593Smuzhiyun #include <linux/component.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/of_device.h>
11*4882a593Smuzhiyun #include <linux/platform_device.h>
12*4882a593Smuzhiyun #include <linux/pm_runtime.h>
13*4882a593Smuzhiyun #include <linux/regmap.h>
14*4882a593Smuzhiyun #include <linux/reset.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <drm/drm_device.h>
17*4882a593Smuzhiyun #include <drm/drm_fb_cma_helper.h>
18*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
19*4882a593Smuzhiyun #include <drm/drm_framebuffer.h>
20*4882a593Smuzhiyun #include <drm/drm_gem_cma_helper.h>
21*4882a593Smuzhiyun #include <drm/drm_plane.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "sun4i_drv.h"
24*4882a593Smuzhiyun #include "sun4i_frontend.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun static const u32 sun4i_frontend_vert_coef[32] = {
27*4882a593Smuzhiyun 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
28*4882a593Smuzhiyun 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
29*4882a593Smuzhiyun 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
30*4882a593Smuzhiyun 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
31*4882a593Smuzhiyun 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
32*4882a593Smuzhiyun 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
33*4882a593Smuzhiyun 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
34*4882a593Smuzhiyun 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static const u32 sun4i_frontend_horz_coef[64] = {
38*4882a593Smuzhiyun 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
39*4882a593Smuzhiyun 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
40*4882a593Smuzhiyun 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
41*4882a593Smuzhiyun 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
42*4882a593Smuzhiyun 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
43*4882a593Smuzhiyun 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
44*4882a593Smuzhiyun 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
45*4882a593Smuzhiyun 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
46*4882a593Smuzhiyun 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
47*4882a593Smuzhiyun 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
48*4882a593Smuzhiyun 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
49*4882a593Smuzhiyun 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
50*4882a593Smuzhiyun 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
51*4882a593Smuzhiyun 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
52*4882a593Smuzhiyun 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
53*4882a593Smuzhiyun 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /*
57*4882a593Smuzhiyun * These coefficients are taken from the A33 BSP from Allwinner.
58*4882a593Smuzhiyun *
59*4882a593Smuzhiyun * The first three values of each row are coded as 13-bit signed fixed-point
60*4882a593Smuzhiyun * numbers, with 10 bits for the fractional part. The fourth value is a
61*4882a593Smuzhiyun * constant coded as a 14-bit signed fixed-point number with 4 bits for the
62*4882a593Smuzhiyun * fractional part.
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * The values in table order give the following colorspace translation:
65*4882a593Smuzhiyun * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
66*4882a593Smuzhiyun * R = 1.164 * Y + 1.596 * V - 222
67*4882a593Smuzhiyun * B = 1.164 * Y + 2.018 * U + 276
68*4882a593Smuzhiyun *
69*4882a593Smuzhiyun * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255],
70*4882a593Smuzhiyun * following the BT601 spec.
71*4882a593Smuzhiyun */
72*4882a593Smuzhiyun const u32 sunxi_bt601_yuv2rgb_coef[12] = {
73*4882a593Smuzhiyun 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
74*4882a593Smuzhiyun 0x000004a7, 0x00000000, 0x00000662, 0x00003211,
75*4882a593Smuzhiyun 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun EXPORT_SYMBOL(sunxi_bt601_yuv2rgb_coef);
78*4882a593Smuzhiyun
sun4i_frontend_scaler_init(struct sun4i_frontend * frontend)79*4882a593Smuzhiyun static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun int i;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (frontend->data->has_coef_access_ctrl)
84*4882a593Smuzhiyun regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
85*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL,
86*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_COEF_ACCESS_CTRL);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun for (i = 0; i < 32; i++) {
89*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
90*4882a593Smuzhiyun sun4i_frontend_horz_coef[2 * i]);
91*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
92*4882a593Smuzhiyun sun4i_frontend_horz_coef[2 * i]);
93*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
94*4882a593Smuzhiyun sun4i_frontend_horz_coef[2 * i + 1]);
95*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
96*4882a593Smuzhiyun sun4i_frontend_horz_coef[2 * i + 1]);
97*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
98*4882a593Smuzhiyun sun4i_frontend_vert_coef[i]);
99*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
100*4882a593Smuzhiyun sun4i_frontend_vert_coef[i]);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (frontend->data->has_coef_rdy)
104*4882a593Smuzhiyun regmap_write_bits(frontend->regs,
105*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_REG,
106*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_COEF_RDY,
107*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_COEF_RDY);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
sun4i_frontend_init(struct sun4i_frontend * frontend)110*4882a593Smuzhiyun int sun4i_frontend_init(struct sun4i_frontend *frontend)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun return pm_runtime_get_sync(frontend->dev);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_init);
115*4882a593Smuzhiyun
sun4i_frontend_exit(struct sun4i_frontend * frontend)116*4882a593Smuzhiyun void sun4i_frontend_exit(struct sun4i_frontend *frontend)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun pm_runtime_put(frontend->dev);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_exit);
121*4882a593Smuzhiyun
sun4i_frontend_format_chroma_requires_swap(uint32_t fmt)122*4882a593Smuzhiyun static bool sun4i_frontend_format_chroma_requires_swap(uint32_t fmt)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun switch (fmt) {
125*4882a593Smuzhiyun case DRM_FORMAT_YVU411:
126*4882a593Smuzhiyun case DRM_FORMAT_YVU420:
127*4882a593Smuzhiyun case DRM_FORMAT_YVU422:
128*4882a593Smuzhiyun case DRM_FORMAT_YVU444:
129*4882a593Smuzhiyun return true;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun default:
132*4882a593Smuzhiyun return false;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
sun4i_frontend_format_supports_tiling(uint32_t fmt)136*4882a593Smuzhiyun static bool sun4i_frontend_format_supports_tiling(uint32_t fmt)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun switch (fmt) {
139*4882a593Smuzhiyun case DRM_FORMAT_NV12:
140*4882a593Smuzhiyun case DRM_FORMAT_NV16:
141*4882a593Smuzhiyun case DRM_FORMAT_NV21:
142*4882a593Smuzhiyun case DRM_FORMAT_NV61:
143*4882a593Smuzhiyun case DRM_FORMAT_YUV411:
144*4882a593Smuzhiyun case DRM_FORMAT_YUV420:
145*4882a593Smuzhiyun case DRM_FORMAT_YUV422:
146*4882a593Smuzhiyun case DRM_FORMAT_YVU420:
147*4882a593Smuzhiyun case DRM_FORMAT_YVU422:
148*4882a593Smuzhiyun case DRM_FORMAT_YVU411:
149*4882a593Smuzhiyun return true;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun default:
152*4882a593Smuzhiyun return false;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
sun4i_frontend_update_buffer(struct sun4i_frontend * frontend,struct drm_plane * plane)156*4882a593Smuzhiyun void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
157*4882a593Smuzhiyun struct drm_plane *plane)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun struct drm_plane_state *state = plane->state;
160*4882a593Smuzhiyun struct drm_framebuffer *fb = state->fb;
161*4882a593Smuzhiyun unsigned int strides[3] = {};
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun dma_addr_t paddr;
164*4882a593Smuzhiyun bool swap;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (fb->modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) {
167*4882a593Smuzhiyun unsigned int width = state->src_w >> 16;
168*4882a593Smuzhiyun unsigned int offset;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun strides[0] = SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[0]);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun * The X1 offset is the offset to the bottom-right point in the
174*4882a593Smuzhiyun * end tile, which is the final pixel (at offset width - 1)
175*4882a593Smuzhiyun * within the end tile (with a 32-byte mask).
176*4882a593Smuzhiyun */
177*4882a593Smuzhiyun offset = (width - 1) & (32 - 1);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF0_REG,
180*4882a593Smuzhiyun SUN4I_FRONTEND_TB_OFF_X1(offset));
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (fb->format->num_planes > 1) {
183*4882a593Smuzhiyun strides[1] =
184*4882a593Smuzhiyun SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[1]);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF1_REG,
187*4882a593Smuzhiyun SUN4I_FRONTEND_TB_OFF_X1(offset));
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun if (fb->format->num_planes > 2) {
191*4882a593Smuzhiyun strides[2] =
192*4882a593Smuzhiyun SUN4I_FRONTEND_LINESTRD_TILED(fb->pitches[2]);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_TB_OFF2_REG,
195*4882a593Smuzhiyun SUN4I_FRONTEND_TB_OFF_X1(offset));
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun } else {
198*4882a593Smuzhiyun strides[0] = fb->pitches[0];
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun if (fb->format->num_planes > 1)
201*4882a593Smuzhiyun strides[1] = fb->pitches[1];
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (fb->format->num_planes > 2)
204*4882a593Smuzhiyun strides[2] = fb->pitches[2];
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* Set the line width */
208*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
209*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
210*4882a593Smuzhiyun strides[0]);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (fb->format->num_planes > 1)
213*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD1_REG,
214*4882a593Smuzhiyun strides[1]);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun if (fb->format->num_planes > 2)
217*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD2_REG,
218*4882a593Smuzhiyun strides[2]);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /* Some planar formats require chroma channel swapping by hand. */
221*4882a593Smuzhiyun swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* Set the physical address of the buffer in memory */
224*4882a593Smuzhiyun paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
225*4882a593Smuzhiyun paddr -= PHYS_OFFSET;
226*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &paddr);
227*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun if (fb->format->num_planes > 1) {
230*4882a593Smuzhiyun paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1);
231*4882a593Smuzhiyun paddr -= PHYS_OFFSET;
232*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr);
233*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG,
234*4882a593Smuzhiyun paddr);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (fb->format->num_planes > 2) {
238*4882a593Smuzhiyun paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2);
239*4882a593Smuzhiyun paddr -= PHYS_OFFSET;
240*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr);
241*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG,
242*4882a593Smuzhiyun paddr);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_update_buffer);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun static int
sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info * format,u32 * val)248*4882a593Smuzhiyun sun4i_frontend_drm_format_to_input_fmt(const struct drm_format_info *format,
249*4882a593Smuzhiyun u32 *val)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun if (!format->is_yuv)
252*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_RGB;
253*4882a593Smuzhiyun else if (drm_format_info_is_yuv_sampling_411(format))
254*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV411;
255*4882a593Smuzhiyun else if (drm_format_info_is_yuv_sampling_420(format))
256*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV420;
257*4882a593Smuzhiyun else if (drm_format_info_is_yuv_sampling_422(format))
258*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV422;
259*4882a593Smuzhiyun else if (drm_format_info_is_yuv_sampling_444(format))
260*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_FMT_YUV444;
261*4882a593Smuzhiyun else
262*4882a593Smuzhiyun return -EINVAL;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun static int
sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info * format,uint64_t modifier,u32 * val)268*4882a593Smuzhiyun sun4i_frontend_drm_format_to_input_mode(const struct drm_format_info *format,
269*4882a593Smuzhiyun uint64_t modifier, u32 *val)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun bool tiled = (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun switch (format->num_planes) {
274*4882a593Smuzhiyun case 1:
275*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PACKED;
276*4882a593Smuzhiyun return 0;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun case 2:
279*4882a593Smuzhiyun *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_SEMIPLANAR
280*4882a593Smuzhiyun : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_SEMIPLANAR;
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun case 3:
284*4882a593Smuzhiyun *val = tiled ? SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_MB32_PLANAR
285*4882a593Smuzhiyun : SUN4I_FRONTEND_INPUT_FMT_DATA_MOD_PLANAR;
286*4882a593Smuzhiyun return 0;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun default:
289*4882a593Smuzhiyun return -EINVAL;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun static int
sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info * format,u32 * val)294*4882a593Smuzhiyun sun4i_frontend_drm_format_to_input_sequence(const struct drm_format_info *format,
295*4882a593Smuzhiyun u32 *val)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun /* Planar formats have an explicit input sequence. */
298*4882a593Smuzhiyun if (drm_format_info_is_yuv_planar(format)) {
299*4882a593Smuzhiyun *val = 0;
300*4882a593Smuzhiyun return 0;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun switch (format->format) {
304*4882a593Smuzhiyun case DRM_FORMAT_BGRX8888:
305*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_BGRX;
306*4882a593Smuzhiyun return 0;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun case DRM_FORMAT_NV12:
309*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
310*4882a593Smuzhiyun return 0;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun case DRM_FORMAT_NV16:
313*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UV;
314*4882a593Smuzhiyun return 0;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun case DRM_FORMAT_NV21:
317*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
318*4882a593Smuzhiyun return 0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun case DRM_FORMAT_NV61:
321*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VU;
322*4882a593Smuzhiyun return 0;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun case DRM_FORMAT_UYVY:
325*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_UYVY;
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun case DRM_FORMAT_VYUY:
329*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_VYUY;
330*4882a593Smuzhiyun return 0;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun case DRM_FORMAT_XRGB8888:
333*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_XRGB;
334*4882a593Smuzhiyun return 0;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun case DRM_FORMAT_YUYV:
337*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YUYV;
338*4882a593Smuzhiyun return 0;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun case DRM_FORMAT_YVYU:
341*4882a593Smuzhiyun *val = SUN4I_FRONTEND_INPUT_FMT_DATA_PS_YVYU;
342*4882a593Smuzhiyun return 0;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun default:
345*4882a593Smuzhiyun return -EINVAL;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt,u32 * val)349*4882a593Smuzhiyun static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun switch (fmt) {
352*4882a593Smuzhiyun case DRM_FORMAT_BGRX8888:
353*4882a593Smuzhiyun *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_BGRX8888;
354*4882a593Smuzhiyun return 0;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun case DRM_FORMAT_XRGB8888:
357*4882a593Smuzhiyun *val = SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT_XRGB8888;
358*4882a593Smuzhiyun return 0;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun default:
361*4882a593Smuzhiyun return -EINVAL;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun static const uint32_t sun4i_frontend_formats[] = {
366*4882a593Smuzhiyun DRM_FORMAT_BGRX8888,
367*4882a593Smuzhiyun DRM_FORMAT_NV12,
368*4882a593Smuzhiyun DRM_FORMAT_NV16,
369*4882a593Smuzhiyun DRM_FORMAT_NV21,
370*4882a593Smuzhiyun DRM_FORMAT_NV61,
371*4882a593Smuzhiyun DRM_FORMAT_UYVY,
372*4882a593Smuzhiyun DRM_FORMAT_VYUY,
373*4882a593Smuzhiyun DRM_FORMAT_XRGB8888,
374*4882a593Smuzhiyun DRM_FORMAT_YUV411,
375*4882a593Smuzhiyun DRM_FORMAT_YUV420,
376*4882a593Smuzhiyun DRM_FORMAT_YUV422,
377*4882a593Smuzhiyun DRM_FORMAT_YUV444,
378*4882a593Smuzhiyun DRM_FORMAT_YUYV,
379*4882a593Smuzhiyun DRM_FORMAT_YVU411,
380*4882a593Smuzhiyun DRM_FORMAT_YVU420,
381*4882a593Smuzhiyun DRM_FORMAT_YVU422,
382*4882a593Smuzhiyun DRM_FORMAT_YVU444,
383*4882a593Smuzhiyun DRM_FORMAT_YVYU,
384*4882a593Smuzhiyun };
385*4882a593Smuzhiyun
sun4i_frontend_format_is_supported(uint32_t fmt,uint64_t modifier)386*4882a593Smuzhiyun bool sun4i_frontend_format_is_supported(uint32_t fmt, uint64_t modifier)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun unsigned int i;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (modifier == DRM_FORMAT_MOD_ALLWINNER_TILED)
391*4882a593Smuzhiyun return sun4i_frontend_format_supports_tiling(fmt);
392*4882a593Smuzhiyun else if (modifier != DRM_FORMAT_MOD_LINEAR)
393*4882a593Smuzhiyun return false;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(sun4i_frontend_formats); i++)
396*4882a593Smuzhiyun if (sun4i_frontend_formats[i] == fmt)
397*4882a593Smuzhiyun return true;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun return false;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_format_is_supported);
402*4882a593Smuzhiyun
sun4i_frontend_update_formats(struct sun4i_frontend * frontend,struct drm_plane * plane,uint32_t out_fmt)403*4882a593Smuzhiyun int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
404*4882a593Smuzhiyun struct drm_plane *plane, uint32_t out_fmt)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun struct drm_plane_state *state = plane->state;
407*4882a593Smuzhiyun struct drm_framebuffer *fb = state->fb;
408*4882a593Smuzhiyun const struct drm_format_info *format = fb->format;
409*4882a593Smuzhiyun uint64_t modifier = fb->modifier;
410*4882a593Smuzhiyun unsigned int ch1_phase_idx;
411*4882a593Smuzhiyun u32 out_fmt_val;
412*4882a593Smuzhiyun u32 in_fmt_val, in_mod_val, in_ps_val;
413*4882a593Smuzhiyun unsigned int i;
414*4882a593Smuzhiyun u32 bypass;
415*4882a593Smuzhiyun int ret;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun ret = sun4i_frontend_drm_format_to_input_fmt(format, &in_fmt_val);
418*4882a593Smuzhiyun if (ret) {
419*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Invalid input format\n");
420*4882a593Smuzhiyun return ret;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun ret = sun4i_frontend_drm_format_to_input_mode(format, modifier,
424*4882a593Smuzhiyun &in_mod_val);
425*4882a593Smuzhiyun if (ret) {
426*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Invalid input mode\n");
427*4882a593Smuzhiyun return ret;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun ret = sun4i_frontend_drm_format_to_input_sequence(format, &in_ps_val);
431*4882a593Smuzhiyun if (ret) {
432*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Invalid pixel sequence\n");
433*4882a593Smuzhiyun return ret;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
437*4882a593Smuzhiyun if (ret) {
438*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Invalid output format\n");
439*4882a593Smuzhiyun return ret;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /*
443*4882a593Smuzhiyun * I have no idea what this does exactly, but it seems to be
444*4882a593Smuzhiyun * related to the scaler FIR filter phase parameters.
445*4882a593Smuzhiyun */
446*4882a593Smuzhiyun ch1_phase_idx = (format->num_planes > 1) ? 1 : 0;
447*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG,
448*4882a593Smuzhiyun frontend->data->ch_phase[0]);
449*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG,
450*4882a593Smuzhiyun frontend->data->ch_phase[ch1_phase_idx]);
451*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG,
452*4882a593Smuzhiyun frontend->data->ch_phase[0]);
453*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG,
454*4882a593Smuzhiyun frontend->data->ch_phase[ch1_phase_idx]);
455*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG,
456*4882a593Smuzhiyun frontend->data->ch_phase[0]);
457*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG,
458*4882a593Smuzhiyun frontend->data->ch_phase[ch1_phase_idx]);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun /*
461*4882a593Smuzhiyun * Checking the input format is sufficient since we currently only
462*4882a593Smuzhiyun * support RGB output formats to the backend. If YUV output formats
463*4882a593Smuzhiyun * ever get supported, an YUV input and output would require bypassing
464*4882a593Smuzhiyun * the CSC engine too.
465*4882a593Smuzhiyun */
466*4882a593Smuzhiyun if (format->is_yuv) {
467*4882a593Smuzhiyun /* Setup the CSC engine for YUV to RGB conversion. */
468*4882a593Smuzhiyun bypass = 0;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
471*4882a593Smuzhiyun regmap_write(frontend->regs,
472*4882a593Smuzhiyun SUN4I_FRONTEND_CSC_COEF_REG(i),
473*4882a593Smuzhiyun sunxi_bt601_yuv2rgb_coef[i]);
474*4882a593Smuzhiyun } else {
475*4882a593Smuzhiyun bypass = SUN4I_FRONTEND_BYPASS_CSC_EN;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
479*4882a593Smuzhiyun SUN4I_FRONTEND_BYPASS_CSC_EN, bypass);
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
482*4882a593Smuzhiyun in_mod_val | in_fmt_val | in_ps_val);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun /*
485*4882a593Smuzhiyun * TODO: It look like the A31 and A80 at least will need the
486*4882a593Smuzhiyun * bit 7 (ALPHA_EN) enabled when using a format with alpha (so
487*4882a593Smuzhiyun * ARGB8888).
488*4882a593Smuzhiyun */
489*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
490*4882a593Smuzhiyun out_fmt_val);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_update_formats);
495*4882a593Smuzhiyun
sun4i_frontend_update_coord(struct sun4i_frontend * frontend,struct drm_plane * plane)496*4882a593Smuzhiyun void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
497*4882a593Smuzhiyun struct drm_plane *plane)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun struct drm_plane_state *state = plane->state;
500*4882a593Smuzhiyun struct drm_framebuffer *fb = state->fb;
501*4882a593Smuzhiyun uint32_t luma_width, luma_height;
502*4882a593Smuzhiyun uint32_t chroma_width, chroma_height;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun /* Set height and width */
505*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
506*4882a593Smuzhiyun state->crtc_w, state->crtc_h);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun luma_width = state->src_w >> 16;
509*4882a593Smuzhiyun luma_height = state->src_h >> 16;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun chroma_width = DIV_ROUND_UP(luma_width, fb->format->hsub);
512*4882a593Smuzhiyun chroma_height = DIV_ROUND_UP(luma_height, fb->format->vsub);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
515*4882a593Smuzhiyun SUN4I_FRONTEND_INSIZE(luma_height, luma_width));
516*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
517*4882a593Smuzhiyun SUN4I_FRONTEND_INSIZE(chroma_height, chroma_width));
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
520*4882a593Smuzhiyun SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
521*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
522*4882a593Smuzhiyun SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
525*4882a593Smuzhiyun (luma_width << 16) / state->crtc_w);
526*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
527*4882a593Smuzhiyun (chroma_width << 16) / state->crtc_w);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
530*4882a593Smuzhiyun (luma_height << 16) / state->crtc_h);
531*4882a593Smuzhiyun regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
532*4882a593Smuzhiyun (chroma_height << 16) / state->crtc_h);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
535*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
536*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_update_coord);
539*4882a593Smuzhiyun
sun4i_frontend_enable(struct sun4i_frontend * frontend)540*4882a593Smuzhiyun int sun4i_frontend_enable(struct sun4i_frontend *frontend)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
543*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_FRM_START,
544*4882a593Smuzhiyun SUN4I_FRONTEND_FRM_CTRL_FRM_START);
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun return 0;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_enable);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun static const struct regmap_config sun4i_frontend_regmap_config = {
551*4882a593Smuzhiyun .reg_bits = 32,
552*4882a593Smuzhiyun .val_bits = 32,
553*4882a593Smuzhiyun .reg_stride = 4,
554*4882a593Smuzhiyun .max_register = 0x0a14,
555*4882a593Smuzhiyun };
556*4882a593Smuzhiyun
sun4i_frontend_bind(struct device * dev,struct device * master,void * data)557*4882a593Smuzhiyun static int sun4i_frontend_bind(struct device *dev, struct device *master,
558*4882a593Smuzhiyun void *data)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun struct platform_device *pdev = to_platform_device(dev);
561*4882a593Smuzhiyun struct sun4i_frontend *frontend;
562*4882a593Smuzhiyun struct drm_device *drm = data;
563*4882a593Smuzhiyun struct sun4i_drv *drv = drm->dev_private;
564*4882a593Smuzhiyun struct resource *res;
565*4882a593Smuzhiyun void __iomem *regs;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
568*4882a593Smuzhiyun if (!frontend)
569*4882a593Smuzhiyun return -ENOMEM;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun dev_set_drvdata(dev, frontend);
572*4882a593Smuzhiyun frontend->dev = dev;
573*4882a593Smuzhiyun frontend->node = dev->of_node;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun frontend->data = of_device_get_match_data(dev);
576*4882a593Smuzhiyun if (!frontend->data)
577*4882a593Smuzhiyun return -ENODEV;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
580*4882a593Smuzhiyun regs = devm_ioremap_resource(dev, res);
581*4882a593Smuzhiyun if (IS_ERR(regs))
582*4882a593Smuzhiyun return PTR_ERR(regs);
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun frontend->regs = devm_regmap_init_mmio(dev, regs,
585*4882a593Smuzhiyun &sun4i_frontend_regmap_config);
586*4882a593Smuzhiyun if (IS_ERR(frontend->regs)) {
587*4882a593Smuzhiyun dev_err(dev, "Couldn't create the frontend regmap\n");
588*4882a593Smuzhiyun return PTR_ERR(frontend->regs);
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun frontend->reset = devm_reset_control_get(dev, NULL);
592*4882a593Smuzhiyun if (IS_ERR(frontend->reset)) {
593*4882a593Smuzhiyun dev_err(dev, "Couldn't get our reset line\n");
594*4882a593Smuzhiyun return PTR_ERR(frontend->reset);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun frontend->bus_clk = devm_clk_get(dev, "ahb");
598*4882a593Smuzhiyun if (IS_ERR(frontend->bus_clk)) {
599*4882a593Smuzhiyun dev_err(dev, "Couldn't get our bus clock\n");
600*4882a593Smuzhiyun return PTR_ERR(frontend->bus_clk);
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun frontend->mod_clk = devm_clk_get(dev, "mod");
604*4882a593Smuzhiyun if (IS_ERR(frontend->mod_clk)) {
605*4882a593Smuzhiyun dev_err(dev, "Couldn't get our mod clock\n");
606*4882a593Smuzhiyun return PTR_ERR(frontend->mod_clk);
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun frontend->ram_clk = devm_clk_get(dev, "ram");
610*4882a593Smuzhiyun if (IS_ERR(frontend->ram_clk)) {
611*4882a593Smuzhiyun dev_err(dev, "Couldn't get our ram clock\n");
612*4882a593Smuzhiyun return PTR_ERR(frontend->ram_clk);
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun list_add_tail(&frontend->list, &drv->frontend_list);
616*4882a593Smuzhiyun pm_runtime_enable(dev);
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun return 0;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
sun4i_frontend_unbind(struct device * dev,struct device * master,void * data)621*4882a593Smuzhiyun static void sun4i_frontend_unbind(struct device *dev, struct device *master,
622*4882a593Smuzhiyun void *data)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun struct sun4i_frontend *frontend = dev_get_drvdata(dev);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun list_del(&frontend->list);
627*4882a593Smuzhiyun pm_runtime_force_suspend(dev);
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun static const struct component_ops sun4i_frontend_ops = {
631*4882a593Smuzhiyun .bind = sun4i_frontend_bind,
632*4882a593Smuzhiyun .unbind = sun4i_frontend_unbind,
633*4882a593Smuzhiyun };
634*4882a593Smuzhiyun
sun4i_frontend_probe(struct platform_device * pdev)635*4882a593Smuzhiyun static int sun4i_frontend_probe(struct platform_device *pdev)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun return component_add(&pdev->dev, &sun4i_frontend_ops);
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
sun4i_frontend_remove(struct platform_device * pdev)640*4882a593Smuzhiyun static int sun4i_frontend_remove(struct platform_device *pdev)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun component_del(&pdev->dev, &sun4i_frontend_ops);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun return 0;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
sun4i_frontend_runtime_resume(struct device * dev)647*4882a593Smuzhiyun static int sun4i_frontend_runtime_resume(struct device *dev)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun struct sun4i_frontend *frontend = dev_get_drvdata(dev);
650*4882a593Smuzhiyun int ret;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun clk_set_rate(frontend->mod_clk, 300000000);
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun clk_prepare_enable(frontend->bus_clk);
655*4882a593Smuzhiyun clk_prepare_enable(frontend->mod_clk);
656*4882a593Smuzhiyun clk_prepare_enable(frontend->ram_clk);
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun ret = reset_control_reset(frontend->reset);
659*4882a593Smuzhiyun if (ret) {
660*4882a593Smuzhiyun dev_err(dev, "Couldn't reset our device\n");
661*4882a593Smuzhiyun return ret;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
665*4882a593Smuzhiyun SUN4I_FRONTEND_EN_EN,
666*4882a593Smuzhiyun SUN4I_FRONTEND_EN_EN);
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun sun4i_frontend_scaler_init(frontend);
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun return 0;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun
sun4i_frontend_runtime_suspend(struct device * dev)673*4882a593Smuzhiyun static int sun4i_frontend_runtime_suspend(struct device *dev)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun struct sun4i_frontend *frontend = dev_get_drvdata(dev);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun clk_disable_unprepare(frontend->ram_clk);
678*4882a593Smuzhiyun clk_disable_unprepare(frontend->mod_clk);
679*4882a593Smuzhiyun clk_disable_unprepare(frontend->bus_clk);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun reset_control_assert(frontend->reset);
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun return 0;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun static const struct dev_pm_ops sun4i_frontend_pm_ops = {
687*4882a593Smuzhiyun .runtime_resume = sun4i_frontend_runtime_resume,
688*4882a593Smuzhiyun .runtime_suspend = sun4i_frontend_runtime_suspend,
689*4882a593Smuzhiyun };
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun static const struct sun4i_frontend_data sun4i_a10_frontend = {
692*4882a593Smuzhiyun .ch_phase = { 0x000, 0xfc000 },
693*4882a593Smuzhiyun .has_coef_rdy = true,
694*4882a593Smuzhiyun };
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun static const struct sun4i_frontend_data sun8i_a33_frontend = {
697*4882a593Smuzhiyun .ch_phase = { 0x400, 0xfc400 },
698*4882a593Smuzhiyun .has_coef_access_ctrl = true,
699*4882a593Smuzhiyun };
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun const struct of_device_id sun4i_frontend_of_table[] = {
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun .compatible = "allwinner,sun4i-a10-display-frontend",
704*4882a593Smuzhiyun .data = &sun4i_a10_frontend
705*4882a593Smuzhiyun },
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun .compatible = "allwinner,sun7i-a20-display-frontend",
708*4882a593Smuzhiyun .data = &sun4i_a10_frontend
709*4882a593Smuzhiyun },
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun .compatible = "allwinner,sun8i-a23-display-frontend",
712*4882a593Smuzhiyun .data = &sun8i_a33_frontend
713*4882a593Smuzhiyun },
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun .compatible = "allwinner,sun8i-a33-display-frontend",
716*4882a593Smuzhiyun .data = &sun8i_a33_frontend
717*4882a593Smuzhiyun },
718*4882a593Smuzhiyun { }
719*4882a593Smuzhiyun };
720*4882a593Smuzhiyun EXPORT_SYMBOL(sun4i_frontend_of_table);
721*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun static struct platform_driver sun4i_frontend_driver = {
724*4882a593Smuzhiyun .probe = sun4i_frontend_probe,
725*4882a593Smuzhiyun .remove = sun4i_frontend_remove,
726*4882a593Smuzhiyun .driver = {
727*4882a593Smuzhiyun .name = "sun4i-frontend",
728*4882a593Smuzhiyun .of_match_table = sun4i_frontend_of_table,
729*4882a593Smuzhiyun .pm = &sun4i_frontend_pm_ops,
730*4882a593Smuzhiyun },
731*4882a593Smuzhiyun };
732*4882a593Smuzhiyun module_platform_driver(sun4i_frontend_driver);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
735*4882a593Smuzhiyun MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
736*4882a593Smuzhiyun MODULE_LICENSE("GPL");
737