aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-09-10 05:43:29 -0400
committerDave Airlie <airlied@redhat.com>2014-09-10 05:43:29 -0400
commitfdcaa1dbb7c6ed419b10fb8cdb5001ab0a00538f (patch)
treeb1e27087862402b573bb90567e27e4a739b82310
parentbb6d822ec546603bca01f7ba17c52f0f4f80e329 (diff)
parent3feb049f378da6aa1209e05ef5c656a1f26a9183 (diff)
Merge tag 'ipu-3.18' of git://git.pengutronix.de/git/pza/linux into drm-next
IPUv3 preparations for capture support * tag 'ipu-3.18' of git://git.pengutronix.de/git/pza/linux: (26 commits) gpu: ipu-v3: Add ipu_dump() gpu: ipu-cpmem: Add ipu_cpmem_dump() gpu: ipu-v3: Add more planar formats support gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image() gpu: ipu-cpmem: Add ipu_cpmem_set_rotation() gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id() gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode() gpu: ipu-v3: Add ipu_idmac_lock_enable() gpu: ipu-v3: Add ipu_idmac_enable_watermark() gpu: ipu-v3: Add ipu_stride_to_bytes() gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer() gpu: ipu-v3: Add ipu_idmac_clear_buffer() gpu: ipu-v3: Add ipu_idmac_buffer_is_ready() gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h gpu: ipu-v3: Add helper function checking if pixfmt is planar gpu: ipu-v3: Add rotation mode conversion utilities gpu: ipu-v3: Add ipu_mbus_code_to_colorspace() gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark() gpu: ipu-v3: smfc: Convert to per-channel gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c ...
-rw-r--r--drivers/gpu/ipu-v3/Makefile3
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c916
-rw-r--r--drivers/gpu/ipu-v3/ipu-cpmem.c764
-rw-r--r--drivers/gpu/ipu-v3/ipu-csi.c741
-rw-r--r--drivers/gpu/ipu-v3/ipu-ic.c778
-rw-r--r--drivers/gpu/ipu-v3/ipu-prv.h44
-rw-r--r--drivers/gpu/ipu-v3/ipu-smfc.c156
-rw-r--r--drivers/staging/imx-drm/ipuv3-plane.c16
-rw-r--r--include/video/imx-ipu-v3.h326
9 files changed, 3072 insertions, 672 deletions
diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile
index 1887972b4ac2..107ec236a4a6 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/ipu-v3/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o 1obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
2 2
3imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o ipu-smfc.o 3imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
4 ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 04e7b2eafbdd..df65d2bca522 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -44,17 +44,6 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
44 writel(value, ipu->cm_reg + offset); 44 writel(value, ipu->cm_reg + offset);
45} 45}
46 46
47static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
48{
49 return readl(ipu->idmac_reg + offset);
50}
51
52static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
53 unsigned offset)
54{
55 writel(value, ipu->idmac_reg + offset);
56}
57
58void ipu_srm_dp_sync_update(struct ipu_soc *ipu) 47void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
59{ 48{
60 u32 val; 49 u32 val;
@@ -65,457 +54,184 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
65} 54}
66EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); 55EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
67 56
68struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel) 57enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
69{
70 struct ipu_soc *ipu = channel->ipu;
71
72 return ipu->cpmem_base + channel->num;
73}
74EXPORT_SYMBOL_GPL(ipu_get_cpmem);
75
76void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel)
77{
78 struct ipu_soc *ipu = channel->ipu;
79 struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel);
80 u32 val;
81
82 if (ipu->ipu_type == IPUV3EX)
83 ipu_ch_param_write_field(p, IPU_FIELD_ID, 1);
84
85 val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num));
86 val |= 1 << (channel->num % 32);
87 ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num));
88};
89EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
90
91void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v)
92{
93 u32 bit = (wbs >> 8) % 160;
94 u32 size = wbs & 0xff;
95 u32 word = (wbs >> 8) / 160;
96 u32 i = bit / 32;
97 u32 ofs = bit % 32;
98 u32 mask = (1 << size) - 1;
99 u32 val;
100
101 pr_debug("%s %d %d %d\n", __func__, word, bit , size);
102
103 val = readl(&base->word[word].data[i]);
104 val &= ~(mask << ofs);
105 val |= v << ofs;
106 writel(val, &base->word[word].data[i]);
107
108 if ((bit + size - 1) / 32 > i) {
109 val = readl(&base->word[word].data[i + 1]);
110 val &= ~(mask >> (ofs ? (32 - ofs) : 0));
111 val |= v >> (ofs ? (32 - ofs) : 0);
112 writel(val, &base->word[word].data[i + 1]);
113 }
114}
115EXPORT_SYMBOL_GPL(ipu_ch_param_write_field);
116
117u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs)
118{
119 u32 bit = (wbs >> 8) % 160;
120 u32 size = wbs & 0xff;
121 u32 word = (wbs >> 8) / 160;
122 u32 i = bit / 32;
123 u32 ofs = bit % 32;
124 u32 mask = (1 << size) - 1;
125 u32 val = 0;
126
127 pr_debug("%s %d %d %d\n", __func__, word, bit , size);
128
129 val = (readl(&base->word[word].data[i]) >> ofs) & mask;
130
131 if ((bit + size - 1) / 32 > i) {
132 u32 tmp;
133 tmp = readl(&base->word[word].data[i + 1]);
134 tmp &= mask >> (ofs ? (32 - ofs) : 0);
135 val |= tmp << (ofs ? (32 - ofs) : 0);
136 }
137
138 return val;
139}
140EXPORT_SYMBOL_GPL(ipu_ch_param_read_field);
141
142int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p,
143 const struct ipu_rgb *rgb)
144{
145 int bpp = 0, npb = 0, ro, go, bo, to;
146
147 ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
148 go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
149 bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
150 to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
151
152 ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1);
153 ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro);
154 ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1);
155 ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go);
156 ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1);
157 ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo);
158
159 if (rgb->transp.length) {
160 ipu_ch_param_write_field(p, IPU_FIELD_WID3,
161 rgb->transp.length - 1);
162 ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to);
163 } else {
164 ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7);
165 ipu_ch_param_write_field(p, IPU_FIELD_OFS3,
166 rgb->bits_per_pixel);
167 }
168
169 switch (rgb->bits_per_pixel) {
170 case 32:
171 bpp = 0;
172 npb = 15;
173 break;
174 case 24:
175 bpp = 1;
176 npb = 19;
177 break;
178 case 16:
179 bpp = 3;
180 npb = 31;
181 break;
182 case 8:
183 bpp = 5;
184 npb = 63;
185 break;
186 default:
187 return -EINVAL;
188 }
189 ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
190 ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
191 ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */
192
193 return 0;
194}
195EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
196
197int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
198 int width)
199{ 58{
200 int bpp = 0, npb = 0; 59 switch (drm_fourcc) {
201 60 case DRM_FORMAT_RGB565:
202 switch (width) { 61 case DRM_FORMAT_BGR565:
203 case 32: 62 case DRM_FORMAT_RGB888:
204 bpp = 0; 63 case DRM_FORMAT_BGR888:
205 npb = 15; 64 case DRM_FORMAT_XRGB8888:
206 break; 65 case DRM_FORMAT_XBGR8888:
207 case 24: 66 case DRM_FORMAT_RGBX8888:
208 bpp = 1; 67 case DRM_FORMAT_BGRX8888:
209 npb = 19; 68 case DRM_FORMAT_ARGB8888:
210 break; 69 case DRM_FORMAT_ABGR8888:
211 case 16: 70 case DRM_FORMAT_RGBA8888:
212 bpp = 3; 71 case DRM_FORMAT_BGRA8888:
213 npb = 31; 72 return IPUV3_COLORSPACE_RGB;
214 break; 73 case DRM_FORMAT_YUYV:
215 case 8: 74 case DRM_FORMAT_UYVY:
216 bpp = 5; 75 case DRM_FORMAT_YUV420:
217 npb = 63; 76 case DRM_FORMAT_YVU420:
218 break; 77 case DRM_FORMAT_YUV422:
78 case DRM_FORMAT_YVU422:
79 case DRM_FORMAT_NV12:
80 case DRM_FORMAT_NV21:
81 case DRM_FORMAT_NV16:
82 case DRM_FORMAT_NV61:
83 return IPUV3_COLORSPACE_YUV;
219 default: 84 default:
220 return -EINVAL; 85 return IPUV3_COLORSPACE_UNKNOWN;
221 } 86 }
222
223 ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
224 ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
225 ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */
226
227 return 0;
228} 87}
229EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); 88EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
230 89
231void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, 90enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
232 u32 pixel_format)
233{ 91{
234 switch (pixel_format) { 92 switch (pixelformat) {
93 case V4L2_PIX_FMT_YUV420:
94 case V4L2_PIX_FMT_YVU420:
95 case V4L2_PIX_FMT_YUV422P:
235 case V4L2_PIX_FMT_UYVY: 96 case V4L2_PIX_FMT_UYVY:
236 ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */
237 ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0xA); /* pix format */
238 ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */
239 break;
240 case V4L2_PIX_FMT_YUYV: 97 case V4L2_PIX_FMT_YUYV:
241 ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */ 98 case V4L2_PIX_FMT_NV12:
242 ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0x8); /* pix format */ 99 case V4L2_PIX_FMT_NV21:
243 ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */ 100 case V4L2_PIX_FMT_NV16:
244 break; 101 case V4L2_PIX_FMT_NV61:
102 return IPUV3_COLORSPACE_YUV;
103 case V4L2_PIX_FMT_RGB32:
104 case V4L2_PIX_FMT_BGR32:
105 case V4L2_PIX_FMT_RGB24:
106 case V4L2_PIX_FMT_BGR24:
107 case V4L2_PIX_FMT_RGB565:
108 return IPUV3_COLORSPACE_RGB;
109 default:
110 return IPUV3_COLORSPACE_UNKNOWN;
245 } 111 }
246} 112}
247EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); 113EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
248 114
249void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, 115bool ipu_pixelformat_is_planar(u32 pixelformat)
250 u32 pixel_format, int stride, int u_offset, int v_offset)
251{ 116{
252 switch (pixel_format) { 117 switch (pixelformat) {
253 case V4L2_PIX_FMT_YUV420: 118 case V4L2_PIX_FMT_YUV420:
254 ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
255 ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8);
256 ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8);
257 break;
258 case V4L2_PIX_FMT_YVU420: 119 case V4L2_PIX_FMT_YVU420:
259 ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1); 120 case V4L2_PIX_FMT_YUV422P:
260 ipu_ch_param_write_field(p, IPU_FIELD_UBO, v_offset / 8); 121 case V4L2_PIX_FMT_NV12:
261 ipu_ch_param_write_field(p, IPU_FIELD_VBO, u_offset / 8); 122 case V4L2_PIX_FMT_NV21:
262 break; 123 case V4L2_PIX_FMT_NV16:
124 case V4L2_PIX_FMT_NV61:
125 return true;
263 } 126 }
264}
265EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
266
267void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
268 int stride, int height)
269{
270 int u_offset, v_offset;
271 int uv_stride = 0;
272 127
273 switch (pixel_format) { 128 return false;
274 case V4L2_PIX_FMT_YUV420:
275 case V4L2_PIX_FMT_YVU420:
276 uv_stride = stride / 2;
277 u_offset = stride * height;
278 v_offset = u_offset + (uv_stride * height / 2);
279 ipu_cpmem_set_yuv_planar_full(p, pixel_format, stride,
280 u_offset, v_offset);
281 break;
282 }
283} 129}
284EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); 130EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
285
286static const struct ipu_rgb def_rgb_32 = {
287 .red = { .offset = 16, .length = 8, },
288 .green = { .offset = 8, .length = 8, },
289 .blue = { .offset = 0, .length = 8, },
290 .transp = { .offset = 24, .length = 8, },
291 .bits_per_pixel = 32,
292};
293
294static const struct ipu_rgb def_bgr_32 = {
295 .red = { .offset = 0, .length = 8, },
296 .green = { .offset = 8, .length = 8, },
297 .blue = { .offset = 16, .length = 8, },
298 .transp = { .offset = 24, .length = 8, },
299 .bits_per_pixel = 32,
300};
301
302static const struct ipu_rgb def_rgb_24 = {
303 .red = { .offset = 16, .length = 8, },
304 .green = { .offset = 8, .length = 8, },
305 .blue = { .offset = 0, .length = 8, },
306 .transp = { .offset = 0, .length = 0, },
307 .bits_per_pixel = 24,
308};
309
310static const struct ipu_rgb def_bgr_24 = {
311 .red = { .offset = 0, .length = 8, },
312 .green = { .offset = 8, .length = 8, },
313 .blue = { .offset = 16, .length = 8, },
314 .transp = { .offset = 0, .length = 0, },
315 .bits_per_pixel = 24,
316};
317
318static const struct ipu_rgb def_rgb_16 = {
319 .red = { .offset = 11, .length = 5, },
320 .green = { .offset = 5, .length = 6, },
321 .blue = { .offset = 0, .length = 5, },
322 .transp = { .offset = 0, .length = 0, },
323 .bits_per_pixel = 16,
324};
325 131
326static const struct ipu_rgb def_bgr_16 = { 132enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
327 .red = { .offset = 0, .length = 5, },
328 .green = { .offset = 5, .length = 6, },
329 .blue = { .offset = 11, .length = 5, },
330 .transp = { .offset = 0, .length = 0, },
331 .bits_per_pixel = 16,
332};
333
334#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
335#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
336 (pix->width * (y) / 4) + (x) / 2)
337#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
338 (pix->width * pix->height / 4) + \
339 (pix->width * (y) / 4) + (x) / 2)
340
341int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc)
342{ 133{
343 switch (drm_fourcc) { 134 switch (mbus_code & 0xf000) {
344 case DRM_FORMAT_YUV420: 135 case 0x1000:
345 case DRM_FORMAT_YVU420: 136 return IPUV3_COLORSPACE_RGB;
346 /* pix format */ 137 case 0x2000:
347 ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2); 138 return IPUV3_COLORSPACE_YUV;
348 /* burst size */
349 ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63);
350 break;
351 case DRM_FORMAT_UYVY:
352 /* bits/pixel */
353 ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
354 /* pix format */
355 ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA);
356 /* burst size */
357 ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
358 break;
359 case DRM_FORMAT_YUYV:
360 /* bits/pixel */
361 ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
362 /* pix format */
363 ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8);
364 /* burst size */
365 ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
366 break;
367 case DRM_FORMAT_ABGR8888:
368 case DRM_FORMAT_XBGR8888:
369 ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
370 break;
371 case DRM_FORMAT_ARGB8888:
372 case DRM_FORMAT_XRGB8888:
373 ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
374 break;
375 case DRM_FORMAT_BGR888:
376 ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
377 break;
378 case DRM_FORMAT_RGB888:
379 ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24);
380 break;
381 case DRM_FORMAT_RGB565:
382 ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
383 break;
384 case DRM_FORMAT_BGR565:
385 ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16);
386 break;
387 default: 139 default:
388 return -EINVAL; 140 return IPUV3_COLORSPACE_UNKNOWN;
389 } 141 }
390
391 return 0;
392} 142}
393EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); 143EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
394 144
395/* 145int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
396 * The V4L2 spec defines packed RGB formats in memory byte order, which from
397 * point of view of the IPU corresponds to little-endian words with the first
398 * component in the least significant bits.
399 * The DRM pixel formats and IPU internal representation are ordered the other
400 * way around, with the first named component ordered at the most significant
401 * bits. Further, V4L2 formats are not well defined:
402 * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
403 * We choose the interpretation which matches GStreamer behavior.
404 */
405static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
406{ 146{
407 switch (pixelformat) { 147 switch (pixelformat) {
408 case V4L2_PIX_FMT_RGB565: 148 case V4L2_PIX_FMT_YUV420:
149 case V4L2_PIX_FMT_YVU420:
150 case V4L2_PIX_FMT_YUV422P:
151 case V4L2_PIX_FMT_NV12:
152 case V4L2_PIX_FMT_NV21:
153 case V4L2_PIX_FMT_NV16:
154 case V4L2_PIX_FMT_NV61:
409 /* 155 /*
410 * Here we choose the 'corrected' interpretation of RGBP, a 156 * for the planar YUV formats, the stride passed to
411 * little-endian 16-bit word with the red component at the most 157 * cpmem must be the stride in bytes of the Y plane.
412 * significant bits: 158 * And all the planar YUV formats have an 8-bit
413 * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B 159 * Y component.
414 */ 160 */
415 return DRM_FORMAT_RGB565; 161 return (8 * pixel_stride) >> 3;
162 case V4L2_PIX_FMT_RGB565:
163 case V4L2_PIX_FMT_YUYV:
164 case V4L2_PIX_FMT_UYVY:
165 return (16 * pixel_stride) >> 3;
416 case V4L2_PIX_FMT_BGR24: 166 case V4L2_PIX_FMT_BGR24:
417 /* B G R <=> [24:0] R:G:B */
418 return DRM_FORMAT_RGB888;
419 case V4L2_PIX_FMT_RGB24: 167 case V4L2_PIX_FMT_RGB24:
420 /* R G B <=> [24:0] B:G:R */ 168 return (24 * pixel_stride) >> 3;
421 return DRM_FORMAT_BGR888;
422 case V4L2_PIX_FMT_BGR32: 169 case V4L2_PIX_FMT_BGR32:
423 /* B G R A <=> [32:0] A:B:G:R */
424 return DRM_FORMAT_XRGB8888;
425 case V4L2_PIX_FMT_RGB32: 170 case V4L2_PIX_FMT_RGB32:
426 /* R G B A <=> [32:0] A:B:G:R */ 171 return (32 * pixel_stride) >> 3;
427 return DRM_FORMAT_XBGR8888; 172 default:
428 case V4L2_PIX_FMT_UYVY: 173 break;
429 return DRM_FORMAT_UYVY;
430 case V4L2_PIX_FMT_YUYV:
431 return DRM_FORMAT_YUYV;
432 case V4L2_PIX_FMT_YUV420:
433 return DRM_FORMAT_YUV420;
434 case V4L2_PIX_FMT_YVU420:
435 return DRM_FORMAT_YVU420;
436 } 174 }
437 175
438 return -EINVAL; 176 return -EINVAL;
439} 177}
178EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
440 179
441enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) 180int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
181 bool hflip, bool vflip)
442{ 182{
443 switch (drm_fourcc) { 183 u32 r90, vf, hf;
444 case DRM_FORMAT_RGB565: 184
445 case DRM_FORMAT_BGR565: 185 switch (degrees) {
446 case DRM_FORMAT_RGB888: 186 case 0:
447 case DRM_FORMAT_BGR888: 187 vf = hf = r90 = 0;
448 case DRM_FORMAT_XRGB8888: 188 break;
449 case DRM_FORMAT_XBGR8888: 189 case 90:
450 case DRM_FORMAT_RGBX8888: 190 vf = hf = 0;
451 case DRM_FORMAT_BGRX8888: 191 r90 = 1;
452 case DRM_FORMAT_ARGB8888: 192 break;
453 case DRM_FORMAT_ABGR8888: 193 case 180:
454 case DRM_FORMAT_RGBA8888: 194 vf = hf = 1;
455 case DRM_FORMAT_BGRA8888: 195 r90 = 0;
456 return IPUV3_COLORSPACE_RGB; 196 break;
457 case DRM_FORMAT_YUYV: 197 case 270:
458 case DRM_FORMAT_UYVY: 198 vf = hf = r90 = 1;
459 case DRM_FORMAT_YUV420: 199 break;
460 case DRM_FORMAT_YVU420:
461 return IPUV3_COLORSPACE_YUV;
462 default: 200 default:
463 return IPUV3_COLORSPACE_UNKNOWN; 201 return -EINVAL;
464 } 202 }
465}
466EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
467 203
468int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, 204 hf ^= (u32)hflip;
469 struct ipu_image *image) 205 vf ^= (u32)vflip;
470{
471 struct v4l2_pix_format *pix = &image->pix;
472 int y_offset, u_offset, v_offset;
473 206
474 pr_debug("%s: resolution: %dx%d stride: %d\n", 207 *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
475 __func__, pix->width, pix->height, 208 return 0;
476 pix->bytesperline); 209}
210EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
477 211
478 ipu_cpmem_set_resolution(cpmem, image->rect.width, 212int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
479 image->rect.height); 213 bool hflip, bool vflip)
480 ipu_cpmem_set_stride(cpmem, pix->bytesperline); 214{
215 u32 r90, vf, hf;
481 216
482 ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); 217 r90 = ((u32)mode >> 2) & 0x1;
218 hf = ((u32)mode >> 1) & 0x1;
219 vf = ((u32)mode >> 0) & 0x1;
220 hf ^= (u32)hflip;
221 vf ^= (u32)vflip;
483 222
484 switch (pix->pixelformat) { 223 switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
485 case V4L2_PIX_FMT_YUV420: 224 case IPU_ROTATE_NONE:
486 case V4L2_PIX_FMT_YVU420: 225 *degrees = 0;
487 y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
488 u_offset = U_OFFSET(pix, image->rect.left,
489 image->rect.top) - y_offset;
490 v_offset = V_OFFSET(pix, image->rect.left,
491 image->rect.top) - y_offset;
492
493 ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat,
494 pix->bytesperline, u_offset, v_offset);
495 ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset);
496 break; 226 break;
497 case V4L2_PIX_FMT_UYVY: 227 case IPU_ROTATE_90_RIGHT:
498 case V4L2_PIX_FMT_YUYV: 228 *degrees = 90;
499 ipu_cpmem_set_buffer(cpmem, 0, image->phys +
500 image->rect.left * 2 +
501 image->rect.top * image->pix.bytesperline);
502 break; 229 break;
503 case V4L2_PIX_FMT_RGB32: 230 case IPU_ROTATE_180:
504 case V4L2_PIX_FMT_BGR32: 231 *degrees = 180;
505 ipu_cpmem_set_buffer(cpmem, 0, image->phys +
506 image->rect.left * 4 +
507 image->rect.top * image->pix.bytesperline);
508 break; 232 break;
509 case V4L2_PIX_FMT_RGB565: 233 case IPU_ROTATE_90_LEFT:
510 ipu_cpmem_set_buffer(cpmem, 0, image->phys + 234 *degrees = 270;
511 image->rect.left * 2 +
512 image->rect.top * image->pix.bytesperline);
513 break;
514 case V4L2_PIX_FMT_RGB24:
515 case V4L2_PIX_FMT_BGR24:
516 ipu_cpmem_set_buffer(cpmem, 0, image->phys +
517 image->rect.left * 3 +
518 image->rect.top * image->pix.bytesperline);
519 break; 235 break;
520 default: 236 default:
521 return -EINVAL; 237 return -EINVAL;
@@ -523,27 +239,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
523 239
524 return 0; 240 return 0;
525} 241}
526EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); 242EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
527
528enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
529{
530 switch (pixelformat) {
531 case V4L2_PIX_FMT_YUV420:
532 case V4L2_PIX_FMT_YVU420:
533 case V4L2_PIX_FMT_UYVY:
534 case V4L2_PIX_FMT_YUYV:
535 return IPUV3_COLORSPACE_YUV;
536 case V4L2_PIX_FMT_RGB32:
537 case V4L2_PIX_FMT_BGR32:
538 case V4L2_PIX_FMT_RGB24:
539 case V4L2_PIX_FMT_BGR24:
540 case V4L2_PIX_FMT_RGB565:
541 return IPUV3_COLORSPACE_RGB;
542 default:
543 return IPUV3_COLORSPACE_UNKNOWN;
544 }
545}
546EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
547 243
548struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) 244struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
549{ 245{
@@ -587,7 +283,26 @@ void ipu_idmac_put(struct ipuv3_channel *channel)
587} 283}
588EXPORT_SYMBOL_GPL(ipu_idmac_put); 284EXPORT_SYMBOL_GPL(ipu_idmac_put);
589 285
590#define idma_mask(ch) (1 << (ch & 0x1f)) 286#define idma_mask(ch) (1 << ((ch) & 0x1f))
287
288/*
289 * This is an undocumented feature, a write one to a channel bit in
290 * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
291 * internal current buffer pointer so that transfers start from buffer
292 * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
293 * only says these are read-only registers). This operation is required
294 * for channel linking to work correctly, for instance video capture
295 * pipelines that carry out image rotations will fail after the first
296 * streaming unless this function is called for each channel before
297 * re-enabling the channels.
298 */
299static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
300{
301 struct ipu_soc *ipu = channel->ipu;
302 unsigned int chno = channel->num;
303
304 ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
305}
591 306
592void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, 307void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
593 bool doublebuffer) 308 bool doublebuffer)
@@ -605,10 +320,81 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
605 reg &= ~idma_mask(channel->num); 320 reg &= ~idma_mask(channel->num);
606 ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num)); 321 ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
607 322
323 __ipu_idmac_reset_current_buffer(channel);
324
608 spin_unlock_irqrestore(&ipu->lock, flags); 325 spin_unlock_irqrestore(&ipu->lock, flags);
609} 326}
610EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer); 327EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
611 328
329static const struct {
330 int chnum;
331 u32 reg;
332 int shift;
333} idmac_lock_en_info[] = {
334 { .chnum = 5, .reg = IDMAC_CH_LOCK_EN_1, .shift = 0, },
335 { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift = 2, },
336 { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift = 4, },
337 { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift = 6, },
338 { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift = 8, },
339 { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
340 { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
341 { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
342 { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
343 { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
344 { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
345 { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift = 0, },
346 { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift = 2, },
347 { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift = 4, },
348 { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift = 6, },
349 { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift = 8, },
350 { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
351};
352
353int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
354{
355 struct ipu_soc *ipu = channel->ipu;
356 unsigned long flags;
357 u32 bursts, regval;
358 int i;
359
360 switch (num_bursts) {
361 case 0:
362 case 1:
363 bursts = 0x00; /* locking disabled */
364 break;
365 case 2:
366 bursts = 0x01;
367 break;
368 case 4:
369 bursts = 0x02;
370 break;
371 case 8:
372 bursts = 0x03;
373 break;
374 default:
375 return -EINVAL;
376 }
377
378 for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
379 if (channel->num == idmac_lock_en_info[i].chnum)
380 break;
381 }
382 if (i >= ARRAY_SIZE(idmac_lock_en_info))
383 return -EINVAL;
384
385 spin_lock_irqsave(&ipu->lock, flags);
386
387 regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
388 regval &= ~(0x03 << idmac_lock_en_info[i].shift);
389 regval |= (bursts << idmac_lock_en_info[i].shift);
390 ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
391
392 spin_unlock_irqrestore(&ipu->lock, flags);
393
394 return 0;
395}
396EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
397
612int ipu_module_enable(struct ipu_soc *ipu, u32 mask) 398int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
613{ 399{
614 unsigned long lock_flags; 400 unsigned long lock_flags;
@@ -661,30 +447,6 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
661} 447}
662EXPORT_SYMBOL_GPL(ipu_module_disable); 448EXPORT_SYMBOL_GPL(ipu_module_disable);
663 449
664int ipu_csi_enable(struct ipu_soc *ipu, int csi)
665{
666 return ipu_module_enable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
667}
668EXPORT_SYMBOL_GPL(ipu_csi_enable);
669
670int ipu_csi_disable(struct ipu_soc *ipu, int csi)
671{
672 return ipu_module_disable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
673}
674EXPORT_SYMBOL_GPL(ipu_csi_disable);
675
676int ipu_smfc_enable(struct ipu_soc *ipu)
677{
678 return ipu_module_enable(ipu, IPU_CONF_SMFC_EN);
679}
680EXPORT_SYMBOL_GPL(ipu_smfc_enable);
681
682int ipu_smfc_disable(struct ipu_soc *ipu)
683{
684 return ipu_module_disable(ipu, IPU_CONF_SMFC_EN);
685}
686EXPORT_SYMBOL_GPL(ipu_smfc_disable);
687
688int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel) 450int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
689{ 451{
690 struct ipu_soc *ipu = channel->ipu; 452 struct ipu_soc *ipu = channel->ipu;
@@ -694,6 +456,30 @@ int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
694} 456}
695EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer); 457EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
696 458
459bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
460{
461 struct ipu_soc *ipu = channel->ipu;
462 unsigned long flags;
463 u32 reg = 0;
464
465 spin_lock_irqsave(&ipu->lock, flags);
466 switch (buf_num) {
467 case 0:
468 reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
469 break;
470 case 1:
471 reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
472 break;
473 case 2:
474 reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
475 break;
476 }
477 spin_unlock_irqrestore(&ipu->lock, flags);
478
479 return ((reg & idma_mask(channel->num)) != 0);
480}
481EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
482
697void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num) 483void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
698{ 484{
699 struct ipu_soc *ipu = channel->ipu; 485 struct ipu_soc *ipu = channel->ipu;
@@ -712,6 +498,34 @@ void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
712} 498}
713EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer); 499EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
714 500
501void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
502{
503 struct ipu_soc *ipu = channel->ipu;
504 unsigned int chno = channel->num;
505 unsigned long flags;
506
507 spin_lock_irqsave(&ipu->lock, flags);
508
509 ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
510 switch (buf_num) {
511 case 0:
512 ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
513 break;
514 case 1:
515 ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
516 break;
517 case 2:
518 ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
519 break;
520 default:
521 break;
522 }
523 ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
524
525 spin_unlock_irqrestore(&ipu->lock, flags);
526}
527EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
528
715int ipu_idmac_enable_channel(struct ipuv3_channel *channel) 529int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
716{ 530{
717 struct ipu_soc *ipu = channel->ipu; 531 struct ipu_soc *ipu = channel->ipu;
@@ -782,6 +596,8 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
782 val &= ~idma_mask(channel->num); 596 val &= ~idma_mask(channel->num);
783 ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); 597 ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
784 598
599 __ipu_idmac_reset_current_buffer(channel);
600
785 /* Set channel buffers NOT to be ready */ 601 /* Set channel buffers NOT to be ready */
786 ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */ 602 ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
787 603
@@ -810,6 +626,31 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
810} 626}
811EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel); 627EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
812 628
629/*
630 * The imx6 rev. D TRM says that enabling the WM feature will increase
631 * a channel's priority. Refer to Table 36-8 Calculated priority value.
632 * The sub-module that is the sink or source for the channel must enable
633 * watermark signal for this to take effect (SMFC_WM for instance).
634 */
635void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
636{
637 struct ipu_soc *ipu = channel->ipu;
638 unsigned long flags;
639 u32 val;
640
641 spin_lock_irqsave(&ipu->lock, flags);
642
643 val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
644 if (enable)
645 val |= 1 << (channel->num % 32);
646 else
647 val &= ~(1 << (channel->num % 32));
648 ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
649
650 spin_unlock_irqrestore(&ipu->lock, flags);
651}
652EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
653
813static int ipu_memory_reset(struct ipu_soc *ipu) 654static int ipu_memory_reset(struct ipu_soc *ipu)
814{ 655{
815 unsigned long timeout; 656 unsigned long timeout;
@@ -826,12 +667,66 @@ static int ipu_memory_reset(struct ipu_soc *ipu)
826 return 0; 667 return 0;
827} 668}
828 669
670/*
671 * Set the source mux for the given CSI. Selects either parallel or
672 * MIPI CSI2 sources.
673 */
674void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
675{
676 unsigned long flags;
677 u32 val, mask;
678
679 mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
680 IPU_CONF_CSI0_DATA_SOURCE;
681
682 spin_lock_irqsave(&ipu->lock, flags);
683
684 val = ipu_cm_read(ipu, IPU_CONF);
685 if (mipi_csi2)
686 val |= mask;
687 else
688 val &= ~mask;
689 ipu_cm_write(ipu, val, IPU_CONF);
690
691 spin_unlock_irqrestore(&ipu->lock, flags);
692}
693EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux);
694
695/*
696 * Set the source mux for the IC. Selects either CSI[01] or the VDI.
697 */
698void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
699{
700 unsigned long flags;
701 u32 val;
702
703 spin_lock_irqsave(&ipu->lock, flags);
704
705 val = ipu_cm_read(ipu, IPU_CONF);
706 if (vdi) {
707 val |= IPU_CONF_IC_INPUT;
708 } else {
709 val &= ~IPU_CONF_IC_INPUT;
710 if (csi_id == 1)
711 val |= IPU_CONF_CSI_SEL;
712 else
713 val &= ~IPU_CONF_CSI_SEL;
714 }
715 ipu_cm_write(ipu, val, IPU_CONF);
716
717 spin_unlock_irqrestore(&ipu->lock, flags);
718}
719EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux);
720
829struct ipu_devtype { 721struct ipu_devtype {
830 const char *name; 722 const char *name;
831 unsigned long cm_ofs; 723 unsigned long cm_ofs;
832 unsigned long cpmem_ofs; 724 unsigned long cpmem_ofs;
833 unsigned long srm_ofs; 725 unsigned long srm_ofs;
834 unsigned long tpm_ofs; 726 unsigned long tpm_ofs;
727 unsigned long csi0_ofs;
728 unsigned long csi1_ofs;
729 unsigned long ic_ofs;
835 unsigned long disp0_ofs; 730 unsigned long disp0_ofs;
836 unsigned long disp1_ofs; 731 unsigned long disp1_ofs;
837 unsigned long dc_tmpl_ofs; 732 unsigned long dc_tmpl_ofs;
@@ -845,6 +740,9 @@ static struct ipu_devtype ipu_type_imx51 = {
845 .cpmem_ofs = 0x1f000000, 740 .cpmem_ofs = 0x1f000000,
846 .srm_ofs = 0x1f040000, 741 .srm_ofs = 0x1f040000,
847 .tpm_ofs = 0x1f060000, 742 .tpm_ofs = 0x1f060000,
743 .csi0_ofs = 0x1f030000,
744 .csi1_ofs = 0x1f038000,
745 .ic_ofs = 0x1f020000,
848 .disp0_ofs = 0x1e040000, 746 .disp0_ofs = 0x1e040000,
849 .disp1_ofs = 0x1e048000, 747 .disp1_ofs = 0x1e048000,
850 .dc_tmpl_ofs = 0x1f080000, 748 .dc_tmpl_ofs = 0x1f080000,
@@ -858,6 +756,9 @@ static struct ipu_devtype ipu_type_imx53 = {
858 .cpmem_ofs = 0x07000000, 756 .cpmem_ofs = 0x07000000,
859 .srm_ofs = 0x07040000, 757 .srm_ofs = 0x07040000,
860 .tpm_ofs = 0x07060000, 758 .tpm_ofs = 0x07060000,
759 .csi0_ofs = 0x07030000,
760 .csi1_ofs = 0x07038000,
761 .ic_ofs = 0x07020000,
861 .disp0_ofs = 0x06040000, 762 .disp0_ofs = 0x06040000,
862 .disp1_ofs = 0x06048000, 763 .disp1_ofs = 0x06048000,
863 .dc_tmpl_ofs = 0x07080000, 764 .dc_tmpl_ofs = 0x07080000,
@@ -871,6 +772,9 @@ static struct ipu_devtype ipu_type_imx6q = {
871 .cpmem_ofs = 0x00300000, 772 .cpmem_ofs = 0x00300000,
872 .srm_ofs = 0x00340000, 773 .srm_ofs = 0x00340000,
873 .tpm_ofs = 0x00360000, 774 .tpm_ofs = 0x00360000,
775 .csi0_ofs = 0x00230000,
776 .csi1_ofs = 0x00238000,
777 .ic_ofs = 0x00220000,
874 .disp0_ofs = 0x00240000, 778 .disp0_ofs = 0x00240000,
875 .disp1_ofs = 0x00248000, 779 .disp1_ofs = 0x00248000,
876 .dc_tmpl_ofs = 0x00380000, 780 .dc_tmpl_ofs = 0x00380000,
@@ -895,8 +799,36 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
895 struct device *dev = &pdev->dev; 799 struct device *dev = &pdev->dev;
896 const struct ipu_devtype *devtype = ipu->devtype; 800 const struct ipu_devtype *devtype = ipu->devtype;
897 801
802 ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
803 if (ret) {
804 unit = "cpmem";
805 goto err_cpmem;
806 }
807
808 ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
809 IPU_CONF_CSI0_EN, ipu_clk);
810 if (ret) {
811 unit = "csi0";
812 goto err_csi_0;
813 }
814
815 ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
816 IPU_CONF_CSI1_EN, ipu_clk);
817 if (ret) {
818 unit = "csi1";
819 goto err_csi_1;
820 }
821
822 ret = ipu_ic_init(ipu, dev,
823 ipu_base + devtype->ic_ofs,
824 ipu_base + devtype->tpm_ofs);
825 if (ret) {
826 unit = "ic";
827 goto err_ic;
828 }
829
898 ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, 830 ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
899 IPU_CONF_DI0_EN, ipu_clk); 831 IPU_CONF_DI0_EN, ipu_clk);
900 if (ret) { 832 if (ret) {
901 unit = "di0"; 833 unit = "di0";
902 goto err_di_0; 834 goto err_di_0;
@@ -949,6 +881,14 @@ err_dc:
949err_di_1: 881err_di_1:
950 ipu_di_exit(ipu, 0); 882 ipu_di_exit(ipu, 0);
951err_di_0: 883err_di_0:
884 ipu_ic_exit(ipu);
885err_ic:
886 ipu_csi_exit(ipu, 1);
887err_csi_1:
888 ipu_csi_exit(ipu, 0);
889err_csi_0:
890 ipu_cpmem_exit(ipu);
891err_cpmem:
952 dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); 892 dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
953 return ret; 893 return ret;
954} 894}
@@ -1025,6 +965,10 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
1025 ipu_dc_exit(ipu); 965 ipu_dc_exit(ipu);
1026 ipu_di_exit(ipu, 1); 966 ipu_di_exit(ipu, 1);
1027 ipu_di_exit(ipu, 0); 967 ipu_di_exit(ipu, 0);
968 ipu_ic_exit(ipu);
969 ipu_csi_exit(ipu, 1);
970 ipu_csi_exit(ipu, 0);
971 ipu_cpmem_exit(ipu);
1028} 972}
1029 973
1030static int platform_remove_devices_fn(struct device *dev, void *unused) 974static int platform_remove_devices_fn(struct device *dev, void *unused)
@@ -1201,6 +1145,44 @@ static void ipu_irq_exit(struct ipu_soc *ipu)
1201 irq_domain_remove(ipu->domain); 1145 irq_domain_remove(ipu->domain);
1202} 1146}
1203 1147
1148void ipu_dump(struct ipu_soc *ipu)
1149{
1150 int i;
1151
1152 dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
1153 ipu_cm_read(ipu, IPU_CONF));
1154 dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
1155 ipu_idmac_read(ipu, IDMAC_CONF));
1156 dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
1157 ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
1158 dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
1159 ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
1160 dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
1161 ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
1162 dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
1163 ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
1164 dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
1165 ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
1166 dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
1167 ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
1168 dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
1169 ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
1170 dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
1171 ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
1172 dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
1173 ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
1174 dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
1175 ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
1176 dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
1177 ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
1178 dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
1179 ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
1180 for (i = 0; i < 15; i++)
1181 dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
1182 ipu_cm_read(ipu, IPU_INT_CTRL(i)));
1183}
1184EXPORT_SYMBOL_GPL(ipu_dump);
1185
1204static int ipu_probe(struct platform_device *pdev) 1186static int ipu_probe(struct platform_device *pdev)
1205{ 1187{
1206 const struct of_device_id *of_id = 1188 const struct of_device_id *of_id =
@@ -1243,6 +1225,12 @@ static int ipu_probe(struct platform_device *pdev)
1243 ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS); 1225 ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
1244 dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n", 1226 dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n",
1245 ipu_base + devtype->cpmem_ofs); 1227 ipu_base + devtype->cpmem_ofs);
1228 dev_dbg(&pdev->dev, "csi0: 0x%08lx\n",
1229 ipu_base + devtype->csi0_ofs);
1230 dev_dbg(&pdev->dev, "csi1: 0x%08lx\n",
1231 ipu_base + devtype->csi1_ofs);
1232 dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
1233 ipu_base + devtype->ic_ofs);
1246 dev_dbg(&pdev->dev, "disp0: 0x%08lx\n", 1234 dev_dbg(&pdev->dev, "disp0: 0x%08lx\n",
1247 ipu_base + devtype->disp0_ofs); 1235 ipu_base + devtype->disp0_ofs);
1248 dev_dbg(&pdev->dev, "disp1: 0x%08lx\n", 1236 dev_dbg(&pdev->dev, "disp1: 0x%08lx\n",
@@ -1265,10 +1253,8 @@ static int ipu_probe(struct platform_device *pdev)
1265 ipu->idmac_reg = devm_ioremap(&pdev->dev, 1253 ipu->idmac_reg = devm_ioremap(&pdev->dev,
1266 ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, 1254 ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
1267 PAGE_SIZE); 1255 PAGE_SIZE);
1268 ipu->cpmem_base = devm_ioremap(&pdev->dev,
1269 ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
1270 1256
1271 if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) 1257 if (!ipu->cm_reg || !ipu->idmac_reg)
1272 return -ENOMEM; 1258 return -ENOMEM;
1273 1259
1274 ipu->clk = devm_clk_get(&pdev->dev, "bus"); 1260 ipu->clk = devm_clk_get(&pdev->dev, "bus");
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
new file mode 100644
index 000000000000..3bf05bc4ab67
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -0,0 +1,764 @@
1/*
2 * Copyright (C) 2012 Mentor Graphics Inc.
3 * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12#include <linux/types.h>
13#include <linux/bitrev.h>
14#include <linux/io.h>
15#include <drm/drm_fourcc.h>
16#include "ipu-prv.h"
17
18struct ipu_cpmem_word {
19 u32 data[5];
20 u32 res[3];
21};
22
23struct ipu_ch_param {
24 struct ipu_cpmem_word word[2];
25};
26
27struct ipu_cpmem {
28 struct ipu_ch_param __iomem *base;
29 u32 module;
30 spinlock_t lock;
31 int use_count;
32 struct ipu_soc *ipu;
33};
34
35#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
36
37#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
38#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
39#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
40#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
41#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
42#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
43#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
44
45#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
46#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
47#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
48#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
49#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
50#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
51#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
52#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
53#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
54#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
55#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
56#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
57#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
58#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
59#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
60#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
61#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
62#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
63#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
64#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
65#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
66#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
67#define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3)
68#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
69#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
70#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
71#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
72#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
73#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
74#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
75#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
76#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
77#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
78#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
79#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
80#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
81#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
82#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
83#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
84#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
85#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
86#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
87#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
88#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
89#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
90#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
91#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
92#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
93#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
94#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
95#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
96
97static inline struct ipu_ch_param __iomem *
98ipu_get_cpmem(struct ipuv3_channel *ch)
99{
100 struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
101
102 return cpmem->base + ch->num;
103}
104
105static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
106{
107 struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
108 u32 bit = (wbs >> 8) % 160;
109 u32 size = wbs & 0xff;
110 u32 word = (wbs >> 8) / 160;
111 u32 i = bit / 32;
112 u32 ofs = bit % 32;
113 u32 mask = (1 << size) - 1;
114 u32 val;
115
116 pr_debug("%s %d %d %d\n", __func__, word, bit , size);
117
118 val = readl(&base->word[word].data[i]);
119 val &= ~(mask << ofs);
120 val |= v << ofs;
121 writel(val, &base->word[word].data[i]);
122
123 if ((bit + size - 1) / 32 > i) {
124 val = readl(&base->word[word].data[i + 1]);
125 val &= ~(mask >> (ofs ? (32 - ofs) : 0));
126 val |= v >> (ofs ? (32 - ofs) : 0);
127 writel(val, &base->word[word].data[i + 1]);
128 }
129}
130
131static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
132{
133 struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
134 u32 bit = (wbs >> 8) % 160;
135 u32 size = wbs & 0xff;
136 u32 word = (wbs >> 8) / 160;
137 u32 i = bit / 32;
138 u32 ofs = bit % 32;
139 u32 mask = (1 << size) - 1;
140 u32 val = 0;
141
142 pr_debug("%s %d %d %d\n", __func__, word, bit , size);
143
144 val = (readl(&base->word[word].data[i]) >> ofs) & mask;
145
146 if ((bit + size - 1) / 32 > i) {
147 u32 tmp;
148
149 tmp = readl(&base->word[word].data[i + 1]);
150 tmp &= mask >> (ofs ? (32 - ofs) : 0);
151 val |= tmp << (ofs ? (32 - ofs) : 0);
152 }
153
154 return val;
155}
156
157/*
158 * The V4L2 spec defines packed RGB formats in memory byte order, which from
159 * point of view of the IPU corresponds to little-endian words with the first
160 * component in the least significant bits.
161 * The DRM pixel formats and IPU internal representation are ordered the other
162 * way around, with the first named component ordered at the most significant
163 * bits. Further, V4L2 formats are not well defined:
164 * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
165 * We choose the interpretation which matches GStreamer behavior.
166 */
167static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
168{
169 switch (pixelformat) {
170 case V4L2_PIX_FMT_RGB565:
171 /*
172 * Here we choose the 'corrected' interpretation of RGBP, a
173 * little-endian 16-bit word with the red component at the most
174 * significant bits:
175 * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
176 */
177 return DRM_FORMAT_RGB565;
178 case V4L2_PIX_FMT_BGR24:
179 /* B G R <=> [24:0] R:G:B */
180 return DRM_FORMAT_RGB888;
181 case V4L2_PIX_FMT_RGB24:
182 /* R G B <=> [24:0] B:G:R */
183 return DRM_FORMAT_BGR888;
184 case V4L2_PIX_FMT_BGR32:
185 /* B G R A <=> [32:0] A:B:G:R */
186 return DRM_FORMAT_XRGB8888;
187 case V4L2_PIX_FMT_RGB32:
188 /* R G B A <=> [32:0] A:B:G:R */
189 return DRM_FORMAT_XBGR8888;
190 case V4L2_PIX_FMT_UYVY:
191 return DRM_FORMAT_UYVY;
192 case V4L2_PIX_FMT_YUYV:
193 return DRM_FORMAT_YUYV;
194 case V4L2_PIX_FMT_YUV420:
195 return DRM_FORMAT_YUV420;
196 case V4L2_PIX_FMT_YUV422P:
197 return DRM_FORMAT_YUV422;
198 case V4L2_PIX_FMT_YVU420:
199 return DRM_FORMAT_YVU420;
200 case V4L2_PIX_FMT_NV12:
201 return DRM_FORMAT_NV12;
202 case V4L2_PIX_FMT_NV16:
203 return DRM_FORMAT_NV16;
204 }
205
206 return -EINVAL;
207}
208
209void ipu_cpmem_zero(struct ipuv3_channel *ch)
210{
211 struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
212 void __iomem *base = p;
213 int i;
214
215 for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
216 writel(0, base + i * sizeof(u32));
217}
218EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
219
220void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
221{
222 ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
223 ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
224}
225EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
226
227void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
228{
229 ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
230}
231EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
232
233void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
234{
235 struct ipu_soc *ipu = ch->ipu;
236 u32 val;
237
238 if (ipu->ipu_type == IPUV3EX)
239 ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
240
241 val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
242 val |= 1 << (ch->num % 32);
243 ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
244};
245EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
246
247void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
248{
249 if (bufnum)
250 ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
251 else
252 ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
253}
254EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
255
256void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
257{
258 ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
259 ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8);
260 ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1);
261};
262EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
263
264void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
265{
266 id &= 0x3;
267 ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
268}
269EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
270
271void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
272{
273 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
274};
275EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
276
277void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
278{
279 ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
280}
281EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
282
283void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
284 enum ipu_rotate_mode rot)
285{
286 u32 temp_rot = bitrev8(rot) >> 5;
287
288 ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
289}
290EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
291
292int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
293 const struct ipu_rgb *rgb)
294{
295 int bpp = 0, npb = 0, ro, go, bo, to;
296
297 ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
298 go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
299 bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
300 to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
301
302 ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
303 ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
304 ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
305 ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
306 ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
307 ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
308
309 if (rgb->transp.length) {
310 ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
311 rgb->transp.length - 1);
312 ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
313 } else {
314 ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
315 ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
316 rgb->bits_per_pixel);
317 }
318
319 switch (rgb->bits_per_pixel) {
320 case 32:
321 bpp = 0;
322 npb = 15;
323 break;
324 case 24:
325 bpp = 1;
326 npb = 19;
327 break;
328 case 16:
329 bpp = 3;
330 npb = 31;
331 break;
332 case 8:
333 bpp = 5;
334 npb = 63;
335 break;
336 default:
337 return -EINVAL;
338 }
339 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
340 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
341 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
342
343 return 0;
344}
345EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
346
347int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
348{
349 int bpp = 0, npb = 0;
350
351 switch (width) {
352 case 32:
353 bpp = 0;
354 npb = 15;
355 break;
356 case 24:
357 bpp = 1;
358 npb = 19;
359 break;
360 case 16:
361 bpp = 3;
362 npb = 31;
363 break;
364 case 8:
365 bpp = 5;
366 npb = 63;
367 break;
368 default:
369 return -EINVAL;
370 }
371
372 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
373 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
374 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
375
376 return 0;
377}
378EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
379
380void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
381{
382 switch (pixel_format) {
383 case V4L2_PIX_FMT_UYVY:
384 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
385 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
386 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
387 break;
388 case V4L2_PIX_FMT_YUYV:
389 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
390 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
391 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
392 break;
393 }
394}
395EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
396
397void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
398 u32 pixel_format, int stride,
399 int u_offset, int v_offset)
400{
401 switch (pixel_format) {
402 case V4L2_PIX_FMT_YUV420:
403 case V4L2_PIX_FMT_YUV422P:
404 ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
405 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
406 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
407 break;
408 case V4L2_PIX_FMT_YVU420:
409 ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
410 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
411 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
412 break;
413 case V4L2_PIX_FMT_NV12:
414 case V4L2_PIX_FMT_NV16:
415 ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1);
416 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
417 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
418 break;
419 }
420}
421EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
422
423void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
424 u32 pixel_format, int stride, int height)
425{
426 int u_offset, v_offset;
427 int uv_stride = 0;
428
429 switch (pixel_format) {
430 case V4L2_PIX_FMT_YUV420:
431 case V4L2_PIX_FMT_YVU420:
432 uv_stride = stride / 2;
433 u_offset = stride * height;
434 v_offset = u_offset + (uv_stride * height / 2);
435 ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
436 u_offset, v_offset);
437 break;
438 case V4L2_PIX_FMT_YUV422P:
439 uv_stride = stride / 2;
440 u_offset = stride * height;
441 v_offset = u_offset + (uv_stride * height);
442 ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
443 u_offset, v_offset);
444 break;
445 case V4L2_PIX_FMT_NV12:
446 case V4L2_PIX_FMT_NV16:
447 u_offset = stride * height;
448 ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
449 u_offset, 0);
450 break;
451 }
452}
453EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
454
455static const struct ipu_rgb def_rgb_32 = {
456 .red = { .offset = 16, .length = 8, },
457 .green = { .offset = 8, .length = 8, },
458 .blue = { .offset = 0, .length = 8, },
459 .transp = { .offset = 24, .length = 8, },
460 .bits_per_pixel = 32,
461};
462
463static const struct ipu_rgb def_bgr_32 = {
464 .red = { .offset = 0, .length = 8, },
465 .green = { .offset = 8, .length = 8, },
466 .blue = { .offset = 16, .length = 8, },
467 .transp = { .offset = 24, .length = 8, },
468 .bits_per_pixel = 32,
469};
470
471static const struct ipu_rgb def_rgb_24 = {
472 .red = { .offset = 16, .length = 8, },
473 .green = { .offset = 8, .length = 8, },
474 .blue = { .offset = 0, .length = 8, },
475 .transp = { .offset = 0, .length = 0, },
476 .bits_per_pixel = 24,
477};
478
479static const struct ipu_rgb def_bgr_24 = {
480 .red = { .offset = 0, .length = 8, },
481 .green = { .offset = 8, .length = 8, },
482 .blue = { .offset = 16, .length = 8, },
483 .transp = { .offset = 0, .length = 0, },
484 .bits_per_pixel = 24,
485};
486
487static const struct ipu_rgb def_rgb_16 = {
488 .red = { .offset = 11, .length = 5, },
489 .green = { .offset = 5, .length = 6, },
490 .blue = { .offset = 0, .length = 5, },
491 .transp = { .offset = 0, .length = 0, },
492 .bits_per_pixel = 16,
493};
494
495static const struct ipu_rgb def_bgr_16 = {
496 .red = { .offset = 0, .length = 5, },
497 .green = { .offset = 5, .length = 6, },
498 .blue = { .offset = 11, .length = 5, },
499 .transp = { .offset = 0, .length = 0, },
500 .bits_per_pixel = 16,
501};
502
503#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
504#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
505 (pix->width * (y) / 4) + (x) / 2)
506#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
507 (pix->width * pix->height / 4) + \
508 (pix->width * (y) / 4) + (x) / 2)
509#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
510 (pix->width * (y) / 2) + (x) / 2)
511#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
512 (pix->width * pix->height / 2) + \
513 (pix->width * (y) / 2) + (x) / 2)
514#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \
515 (pix->width * (y) / 2) + (x))
516#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
517 (pix->width * y) + (x))
518
519int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
520{
521 switch (drm_fourcc) {
522 case DRM_FORMAT_YUV420:
523 case DRM_FORMAT_YVU420:
524 /* pix format */
525 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
526 /* burst size */
527 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
528 break;
529 case DRM_FORMAT_YUV422:
530 case DRM_FORMAT_YVU422:
531 /* pix format */
532 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
533 /* burst size */
534 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
535 break;
536 case DRM_FORMAT_NV12:
537 /* pix format */
538 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
539 /* burst size */
540 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
541 break;
542 case DRM_FORMAT_NV16:
543 /* pix format */
544 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
545 /* burst size */
546 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
547 break;
548 case DRM_FORMAT_UYVY:
549 /* bits/pixel */
550 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
551 /* pix format */
552 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
553 /* burst size */
554 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
555 break;
556 case DRM_FORMAT_YUYV:
557 /* bits/pixel */
558 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
559 /* pix format */
560 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
561 /* burst size */
562 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
563 break;
564 case DRM_FORMAT_ABGR8888:
565 case DRM_FORMAT_XBGR8888:
566 ipu_cpmem_set_format_rgb(ch, &def_bgr_32);
567 break;
568 case DRM_FORMAT_ARGB8888:
569 case DRM_FORMAT_XRGB8888:
570 ipu_cpmem_set_format_rgb(ch, &def_rgb_32);
571 break;
572 case DRM_FORMAT_BGR888:
573 ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
574 break;
575 case DRM_FORMAT_RGB888:
576 ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
577 break;
578 case DRM_FORMAT_RGB565:
579 ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
580 break;
581 case DRM_FORMAT_BGR565:
582 ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
583 break;
584 default:
585 return -EINVAL;
586 }
587
588 return 0;
589}
590EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
591
592int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
593{
594 struct v4l2_pix_format *pix = &image->pix;
595 int offset, u_offset, v_offset;
596
597 pr_debug("%s: resolution: %dx%d stride: %d\n",
598 __func__, pix->width, pix->height,
599 pix->bytesperline);
600
601 ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
602 ipu_cpmem_set_stride(ch, pix->bytesperline);
603
604 ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
605
606 switch (pix->pixelformat) {
607 case V4L2_PIX_FMT_YUV420:
608 case V4L2_PIX_FMT_YVU420:
609 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
610 u_offset = U_OFFSET(pix, image->rect.left,
611 image->rect.top) - offset;
612 v_offset = V_OFFSET(pix, image->rect.left,
613 image->rect.top) - offset;
614
615 ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
616 pix->bytesperline,
617 u_offset, v_offset);
618 break;
619 case V4L2_PIX_FMT_YUV422P:
620 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
621 u_offset = U2_OFFSET(pix, image->rect.left,
622 image->rect.top) - offset;
623 v_offset = V2_OFFSET(pix, image->rect.left,
624 image->rect.top) - offset;
625
626 ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
627 pix->bytesperline,
628 u_offset, v_offset);
629 break;
630 case V4L2_PIX_FMT_NV12:
631 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
632 u_offset = UV_OFFSET(pix, image->rect.left,
633 image->rect.top) - offset;
634 v_offset = 0;
635
636 ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
637 pix->bytesperline,
638 u_offset, v_offset);
639 break;
640 case V4L2_PIX_FMT_NV16:
641 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
642 u_offset = UV2_OFFSET(pix, image->rect.left,
643 image->rect.top) - offset;
644 v_offset = 0;
645
646 ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
647 pix->bytesperline,
648 u_offset, v_offset);
649 break;
650 case V4L2_PIX_FMT_UYVY:
651 case V4L2_PIX_FMT_YUYV:
652 case V4L2_PIX_FMT_RGB565:
653 offset = image->rect.left * 2 +
654 image->rect.top * pix->bytesperline;
655 break;
656 case V4L2_PIX_FMT_RGB32:
657 case V4L2_PIX_FMT_BGR32:
658 offset = image->rect.left * 4 +
659 image->rect.top * pix->bytesperline;
660 break;
661 case V4L2_PIX_FMT_RGB24:
662 case V4L2_PIX_FMT_BGR24:
663 offset = image->rect.left * 3 +
664 image->rect.top * pix->bytesperline;
665 break;
666 default:
667 return -EINVAL;
668 }
669
670 ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
671 ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
672
673 return 0;
674}
675EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
676
677void ipu_cpmem_dump(struct ipuv3_channel *ch)
678{
679 struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
680 struct ipu_soc *ipu = ch->ipu;
681 int chno = ch->num;
682
683 dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
684 readl(&p->word[0].data[0]),
685 readl(&p->word[0].data[1]),
686 readl(&p->word[0].data[2]),
687 readl(&p->word[0].data[3]),
688 readl(&p->word[0].data[4]));
689 dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
690 readl(&p->word[1].data[0]),
691 readl(&p->word[1].data[1]),
692 readl(&p->word[1].data[2]),
693 readl(&p->word[1].data[3]),
694 readl(&p->word[1].data[4]));
695 dev_dbg(ipu->dev, "PFS 0x%x, ",
696 ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
697 dev_dbg(ipu->dev, "BPP 0x%x, ",
698 ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
699 dev_dbg(ipu->dev, "NPB 0x%x\n",
700 ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
701
702 dev_dbg(ipu->dev, "FW %d, ",
703 ipu_ch_param_read_field(ch, IPU_FIELD_FW));
704 dev_dbg(ipu->dev, "FH %d, ",
705 ipu_ch_param_read_field(ch, IPU_FIELD_FH));
706 dev_dbg(ipu->dev, "EBA0 0x%x\n",
707 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
708 dev_dbg(ipu->dev, "EBA1 0x%x\n",
709 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
710 dev_dbg(ipu->dev, "Stride %d\n",
711 ipu_ch_param_read_field(ch, IPU_FIELD_SL));
712 dev_dbg(ipu->dev, "scan_order %d\n",
713 ipu_ch_param_read_field(ch, IPU_FIELD_SO));
714 dev_dbg(ipu->dev, "uv_stride %d\n",
715 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
716 dev_dbg(ipu->dev, "u_offset 0x%x\n",
717 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
718 dev_dbg(ipu->dev, "v_offset 0x%x\n",
719 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
720
721 dev_dbg(ipu->dev, "Width0 %d+1, ",
722 ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
723 dev_dbg(ipu->dev, "Width1 %d+1, ",
724 ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
725 dev_dbg(ipu->dev, "Width2 %d+1, ",
726 ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
727 dev_dbg(ipu->dev, "Width3 %d+1, ",
728 ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
729 dev_dbg(ipu->dev, "Offset0 %d, ",
730 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
731 dev_dbg(ipu->dev, "Offset1 %d, ",
732 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
733 dev_dbg(ipu->dev, "Offset2 %d, ",
734 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
735 dev_dbg(ipu->dev, "Offset3 %d\n",
736 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
737}
738EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
739
740int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
741{
742 struct ipu_cpmem *cpmem;
743
744 cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
745 if (!cpmem)
746 return -ENOMEM;
747
748 ipu->cpmem_priv = cpmem;
749
750 spin_lock_init(&cpmem->lock);
751 cpmem->base = devm_ioremap(dev, base, SZ_128K);
752 if (!cpmem->base)
753 return -ENOMEM;
754
755 dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
756 base, cpmem->base);
757 cpmem->ipu = ipu;
758
759 return 0;
760}
761
762void ipu_cpmem_exit(struct ipu_soc *ipu)
763{
764}
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
new file mode 100644
index 000000000000..d6f56471bd2a
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -0,0 +1,741 @@
1/*
2 * Copyright (C) 2012-2014 Mentor Graphics Inc.
3 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15#include <linux/export.h>
16#include <linux/module.h>
17#include <linux/types.h>
18#include <linux/errno.h>
19#include <linux/delay.h>
20#include <linux/io.h>
21#include <linux/err.h>
22#include <linux/platform_device.h>
23#include <linux/videodev2.h>
24#include <uapi/linux/v4l2-mediabus.h>
25#include <linux/clk.h>
26#include <linux/clk-provider.h>
27#include <linux/clkdev.h>
28
29#include "ipu-prv.h"
30
31struct ipu_csi {
32 void __iomem *base;
33 int id;
34 u32 module;
35 struct clk *clk_ipu; /* IPU bus clock */
36 spinlock_t lock;
37 bool inuse;
38 struct ipu_soc *ipu;
39};
40
41/* CSI Register Offsets */
42#define CSI_SENS_CONF 0x0000
43#define CSI_SENS_FRM_SIZE 0x0004
44#define CSI_ACT_FRM_SIZE 0x0008
45#define CSI_OUT_FRM_CTRL 0x000c
46#define CSI_TST_CTRL 0x0010
47#define CSI_CCIR_CODE_1 0x0014
48#define CSI_CCIR_CODE_2 0x0018
49#define CSI_CCIR_CODE_3 0x001c
50#define CSI_MIPI_DI 0x0020
51#define CSI_SKIP 0x0024
52#define CSI_CPD_CTRL 0x0028
53#define CSI_CPD_RC(n) (0x002c + ((n)*4))
54#define CSI_CPD_RS(n) (0x004c + ((n)*4))
55#define CSI_CPD_GRC(n) (0x005c + ((n)*4))
56#define CSI_CPD_GRS(n) (0x007c + ((n)*4))
57#define CSI_CPD_GBC(n) (0x008c + ((n)*4))
58#define CSI_CPD_GBS(n) (0x00Ac + ((n)*4))
59#define CSI_CPD_BC(n) (0x00Bc + ((n)*4))
60#define CSI_CPD_BS(n) (0x00Dc + ((n)*4))
61#define CSI_CPD_OFFSET1 0x00ec
62#define CSI_CPD_OFFSET2 0x00f0
63
64/* CSI Register Fields */
65#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
66#define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700
67#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L
68#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
69#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
70#define CSI_SENS_CONF_DATA_FMT_BAYER 3L
71#define CSI_SENS_CONF_DATA_FMT_RGB565 4L
72#define CSI_SENS_CONF_DATA_FMT_RGB555 5L
73#define CSI_SENS_CONF_DATA_FMT_RGB444 6L
74#define CSI_SENS_CONF_DATA_FMT_JPEG 7L
75
76#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
77#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
78#define CSI_SENS_CONF_DATA_POL_SHIFT 2
79#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
80#define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070
81#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
82#define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7
83#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11
84#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
85#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
86
87#define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000
88#define CSI_SENS_CONF_DATA_DEST_SHIFT 24
89#define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000
90#define CSI_SENS_CONF_JPEG8_EN_SHIFT 27
91#define CSI_SENS_CONF_JPEG_EN_SHIFT 28
92#define CSI_SENS_CONF_FORCE_EOF_SHIFT 29
93#define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31
94
95#define CSI_DATA_DEST_IC 2
96#define CSI_DATA_DEST_IDMAC 4
97
98#define CSI_CCIR_ERR_DET_EN 0x01000000
99#define CSI_HORI_DOWNSIZE_EN 0x80000000
100#define CSI_VERT_DOWNSIZE_EN 0x40000000
101#define CSI_TEST_GEN_MODE_EN 0x01000000
102
103#define CSI_HSC_MASK 0x1fff0000
104#define CSI_HSC_SHIFT 16
105#define CSI_VSC_MASK 0x00000fff
106#define CSI_VSC_SHIFT 0
107
108#define CSI_TEST_GEN_R_MASK 0x000000ff
109#define CSI_TEST_GEN_R_SHIFT 0
110#define CSI_TEST_GEN_G_MASK 0x0000ff00
111#define CSI_TEST_GEN_G_SHIFT 8
112#define CSI_TEST_GEN_B_MASK 0x00ff0000
113#define CSI_TEST_GEN_B_SHIFT 16
114
115#define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007
116#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0
117#define CSI_SKIP_SMFC_MASK 0x000000f8
118#define CSI_SKIP_SMFC_SHIFT 3
119#define CSI_ID_2_SKIP_MASK 0x00000300
120#define CSI_ID_2_SKIP_SHIFT 8
121
122#define CSI_COLOR_FIRST_ROW_MASK 0x00000002
123#define CSI_COLOR_FIRST_COMP_MASK 0x00000001
124
125/* MIPI CSI-2 data types */
126#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */
127#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */
128#define MIPI_DT_YUV422 0x1e /* UYVY... */
129#define MIPI_DT_RGB444 0x20
130#define MIPI_DT_RGB555 0x21
131#define MIPI_DT_RGB565 0x22
132#define MIPI_DT_RGB666 0x23
133#define MIPI_DT_RGB888 0x24
134#define MIPI_DT_RAW6 0x28
135#define MIPI_DT_RAW7 0x29
136#define MIPI_DT_RAW8 0x2a
137#define MIPI_DT_RAW10 0x2b
138#define MIPI_DT_RAW12 0x2c
139#define MIPI_DT_RAW14 0x2d
140
141/*
142 * Bitfield of CSI bus signal polarities and modes.
143 */
144struct ipu_csi_bus_config {
145 unsigned data_width:4;
146 unsigned clk_mode:3;
147 unsigned ext_vsync:1;
148 unsigned vsync_pol:1;
149 unsigned hsync_pol:1;
150 unsigned pixclk_pol:1;
151 unsigned data_pol:1;
152 unsigned sens_clksrc:1;
153 unsigned pack_tight:1;
154 unsigned force_eof:1;
155 unsigned data_en_pol:1;
156
157 unsigned data_fmt;
158 unsigned mipi_dt;
159};
160
161/*
162 * Enumeration of CSI data bus widths.
163 */
164enum ipu_csi_data_width {
165 IPU_CSI_DATA_WIDTH_4 = 0,
166 IPU_CSI_DATA_WIDTH_8 = 1,
167 IPU_CSI_DATA_WIDTH_10 = 3,
168 IPU_CSI_DATA_WIDTH_12 = 5,
169 IPU_CSI_DATA_WIDTH_16 = 9,
170};
171
172/*
173 * Enumeration of CSI clock modes.
174 */
175enum ipu_csi_clk_mode {
176 IPU_CSI_CLK_MODE_GATED_CLK,
177 IPU_CSI_CLK_MODE_NONGATED_CLK,
178 IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
179 IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
180 IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
181 IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
182 IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
183 IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
184};
185
186static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
187{
188 return readl(csi->base + offset);
189}
190
191static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
192 unsigned offset)
193{
194 writel(value, csi->base + offset);
195}
196
197/*
198 * Set mclk division ratio for generating test mode mclk. Only used
199 * for test generator.
200 */
201static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
202 u32 ipu_clk)
203{
204 u32 temp;
205 u32 div_ratio;
206
207 div_ratio = (ipu_clk / pixel_clk) - 1;
208
209 if (div_ratio > 0xFF || div_ratio < 0) {
210 dev_err(csi->ipu->dev,
211 "value of pixel_clk extends normal range\n");
212 return -EINVAL;
213 }
214
215 temp = ipu_csi_read(csi, CSI_SENS_CONF);
216 temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
217 ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
218 CSI_SENS_CONF);
219
220 return 0;
221}
222
223/*
224 * Find the CSI data format and data width for the given V4L2 media
225 * bus pixel format code.
226 */
227static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
228{
229 switch (mbus_code) {
230 case V4L2_MBUS_FMT_BGR565_2X8_BE:
231 case V4L2_MBUS_FMT_BGR565_2X8_LE:
232 case V4L2_MBUS_FMT_RGB565_2X8_BE:
233 case V4L2_MBUS_FMT_RGB565_2X8_LE:
234 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
235 cfg->mipi_dt = MIPI_DT_RGB565;
236 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
237 break;
238 case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
239 case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
240 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
241 cfg->mipi_dt = MIPI_DT_RGB444;
242 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
243 break;
244 case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
245 case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
246 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
247 cfg->mipi_dt = MIPI_DT_RGB555;
248 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
249 break;
250 case V4L2_MBUS_FMT_UYVY8_2X8:
251 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
252 cfg->mipi_dt = MIPI_DT_YUV422;
253 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
254 break;
255 case V4L2_MBUS_FMT_YUYV8_2X8:
256 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
257 cfg->mipi_dt = MIPI_DT_YUV422;
258 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
259 break;
260 case V4L2_MBUS_FMT_UYVY8_1X16:
261 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
262 cfg->mipi_dt = MIPI_DT_YUV422;
263 cfg->data_width = IPU_CSI_DATA_WIDTH_16;
264 break;
265 case V4L2_MBUS_FMT_YUYV8_1X16:
266 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
267 cfg->mipi_dt = MIPI_DT_YUV422;
268 cfg->data_width = IPU_CSI_DATA_WIDTH_16;
269 break;
270 case V4L2_MBUS_FMT_SBGGR8_1X8:
271 case V4L2_MBUS_FMT_SGBRG8_1X8:
272 case V4L2_MBUS_FMT_SGRBG8_1X8:
273 case V4L2_MBUS_FMT_SRGGB8_1X8:
274 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
275 cfg->mipi_dt = MIPI_DT_RAW8;
276 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
277 break;
278 case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
279 case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
280 case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
281 case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
282 case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
283 case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
284 case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
285 case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
286 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
287 cfg->mipi_dt = MIPI_DT_RAW10;
288 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
289 break;
290 case V4L2_MBUS_FMT_SBGGR10_1X10:
291 case V4L2_MBUS_FMT_SGBRG10_1X10:
292 case V4L2_MBUS_FMT_SGRBG10_1X10:
293 case V4L2_MBUS_FMT_SRGGB10_1X10:
294 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
295 cfg->mipi_dt = MIPI_DT_RAW10;
296 cfg->data_width = IPU_CSI_DATA_WIDTH_10;
297 break;
298 case V4L2_MBUS_FMT_SBGGR12_1X12:
299 case V4L2_MBUS_FMT_SGBRG12_1X12:
300 case V4L2_MBUS_FMT_SGRBG12_1X12:
301 case V4L2_MBUS_FMT_SRGGB12_1X12:
302 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
303 cfg->mipi_dt = MIPI_DT_RAW12;
304 cfg->data_width = IPU_CSI_DATA_WIDTH_12;
305 break;
306 case V4L2_MBUS_FMT_JPEG_1X8:
307 /* TODO */
308 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
309 cfg->mipi_dt = MIPI_DT_RAW8;
310 cfg->data_width = IPU_CSI_DATA_WIDTH_8;
311 break;
312 default:
313 return -EINVAL;
314 }
315
316 return 0;
317}
318
319/*
320 * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
321 */
322static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg,
323 struct v4l2_mbus_config *mbus_cfg,
324 struct v4l2_mbus_framefmt *mbus_fmt)
325{
326 memset(csicfg, 0, sizeof(*csicfg));
327
328 mbus_code_to_bus_cfg(csicfg, mbus_fmt->code);
329
330 switch (mbus_cfg->type) {
331 case V4L2_MBUS_PARALLEL:
332 csicfg->ext_vsync = 1;
333 csicfg->vsync_pol = (mbus_cfg->flags &
334 V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
335 csicfg->hsync_pol = (mbus_cfg->flags &
336 V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
337 csicfg->pixclk_pol = (mbus_cfg->flags &
338 V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
339 csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
340 break;
341 case V4L2_MBUS_BT656:
342 csicfg->ext_vsync = 0;
343 if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field))
344 csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
345 else
346 csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
347 break;
348 case V4L2_MBUS_CSI2:
349 /*
350 * MIPI CSI-2 requires non gated clock mode, all other
351 * parameters are not applicable for MIPI CSI-2 bus.
352 */
353 csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
354 break;
355 default:
356 /* will never get here, keep compiler quiet */
357 break;
358 }
359}
360
361int ipu_csi_init_interface(struct ipu_csi *csi,
362 struct v4l2_mbus_config *mbus_cfg,
363 struct v4l2_mbus_framefmt *mbus_fmt)
364{
365 struct ipu_csi_bus_config cfg;
366 unsigned long flags;
367 u32 data = 0;
368
369 fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt);
370
371 /* Set the CSI_SENS_CONF register remaining fields */
372 data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
373 cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
374 cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
375 cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
376 cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
377 cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
378 cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
379 cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
380 cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
381 cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
382 cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
383
384 spin_lock_irqsave(&csi->lock, flags);
385
386 ipu_csi_write(csi, data, CSI_SENS_CONF);
387
388 /* Setup sensor frame size */
389 ipu_csi_write(csi,
390 (mbus_fmt->width - 1) | ((mbus_fmt->height - 1) << 16),
391 CSI_SENS_FRM_SIZE);
392
393 /* Set CCIR registers */
394
395 switch (cfg.clk_mode) {
396 case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
397 ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
398 ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
399 break;
400 case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
401 if (mbus_fmt->width == 720 && mbus_fmt->height == 576) {
402 /*
403 * PAL case
404 *
405 * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
406 * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
407 * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
408 * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
409 */
410 ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN,
411 CSI_CCIR_CODE_1);
412 ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
413 ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
414
415 } else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) {
416 /*
417 * NTSC case
418 *
419 * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
420 * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
421 * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
422 * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
423 */
424 ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
425 CSI_CCIR_CODE_1);
426 ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
427 ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
428 } else {
429 dev_err(csi->ipu->dev,
430 "Unsupported CCIR656 interlaced video mode\n");
431 spin_unlock_irqrestore(&csi->lock, flags);
432 return -EINVAL;
433 }
434 break;
435 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
436 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
437 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
438 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
439 ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
440 CSI_CCIR_CODE_1);
441 ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
442 break;
443 case IPU_CSI_CLK_MODE_GATED_CLK:
444 case IPU_CSI_CLK_MODE_NONGATED_CLK:
445 ipu_csi_write(csi, 0, CSI_CCIR_CODE_1);
446 break;
447 }
448
449 dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
450 ipu_csi_read(csi, CSI_SENS_CONF));
451 dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
452 ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
453
454 spin_unlock_irqrestore(&csi->lock, flags);
455
456 return 0;
457}
458EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
459
460bool ipu_csi_is_interlaced(struct ipu_csi *csi)
461{
462 unsigned long flags;
463 u32 sensor_protocol;
464
465 spin_lock_irqsave(&csi->lock, flags);
466 sensor_protocol =
467 (ipu_csi_read(csi, CSI_SENS_CONF) &
468 CSI_SENS_CONF_SENS_PRTCL_MASK) >>
469 CSI_SENS_CONF_SENS_PRTCL_SHIFT;
470 spin_unlock_irqrestore(&csi->lock, flags);
471
472 switch (sensor_protocol) {
473 case IPU_CSI_CLK_MODE_GATED_CLK:
474 case IPU_CSI_CLK_MODE_NONGATED_CLK:
475 case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
476 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
477 case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
478 return false;
479 case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
480 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
481 case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
482 return true;
483 default:
484 dev_err(csi->ipu->dev,
485 "CSI %d sensor protocol unsupported\n", csi->id);
486 return false;
487 }
488}
489EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
490
491void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w)
492{
493 unsigned long flags;
494 u32 reg;
495
496 spin_lock_irqsave(&csi->lock, flags);
497
498 reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
499 w->width = (reg & 0xFFFF) + 1;
500 w->height = (reg >> 16 & 0xFFFF) + 1;
501
502 reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
503 w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT;
504 w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT;
505
506 spin_unlock_irqrestore(&csi->lock, flags);
507}
508EXPORT_SYMBOL_GPL(ipu_csi_get_window);
509
510void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w)
511{
512 unsigned long flags;
513 u32 reg;
514
515 spin_lock_irqsave(&csi->lock, flags);
516
517 ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16),
518 CSI_ACT_FRM_SIZE);
519
520 reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
521 reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
522 reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT));
523 ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL);
524
525 spin_unlock_irqrestore(&csi->lock, flags);
526}
527EXPORT_SYMBOL_GPL(ipu_csi_set_window);
528
529void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
530 u32 r_value, u32 g_value, u32 b_value,
531 u32 pix_clk)
532{
533 unsigned long flags;
534 u32 ipu_clk = clk_get_rate(csi->clk_ipu);
535 u32 temp;
536
537 spin_lock_irqsave(&csi->lock, flags);
538
539 temp = ipu_csi_read(csi, CSI_TST_CTRL);
540
541 if (active == false) {
542 temp &= ~CSI_TEST_GEN_MODE_EN;
543 ipu_csi_write(csi, temp, CSI_TST_CTRL);
544 } else {
545 /* Set sensb_mclk div_ratio */
546 ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
547
548 temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
549 CSI_TEST_GEN_B_MASK);
550 temp |= CSI_TEST_GEN_MODE_EN;
551 temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
552 (g_value << CSI_TEST_GEN_G_SHIFT) |
553 (b_value << CSI_TEST_GEN_B_SHIFT);
554 ipu_csi_write(csi, temp, CSI_TST_CTRL);
555 }
556
557 spin_unlock_irqrestore(&csi->lock, flags);
558}
559EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
560
561int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
562 struct v4l2_mbus_framefmt *mbus_fmt)
563{
564 struct ipu_csi_bus_config cfg;
565 unsigned long flags;
566 u32 temp;
567
568 if (vc > 3)
569 return -EINVAL;
570
571 mbus_code_to_bus_cfg(&cfg, mbus_fmt->code);
572
573 spin_lock_irqsave(&csi->lock, flags);
574
575 temp = ipu_csi_read(csi, CSI_MIPI_DI);
576 temp &= ~(0xff << (vc * 8));
577 temp |= (cfg.mipi_dt << (vc * 8));
578 ipu_csi_write(csi, temp, CSI_MIPI_DI);
579
580 spin_unlock_irqrestore(&csi->lock, flags);
581
582 return 0;
583}
584EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
585
586int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
587 u32 max_ratio, u32 id)
588{
589 unsigned long flags;
590 u32 temp;
591
592 if (max_ratio > 5 || id > 3)
593 return -EINVAL;
594
595 spin_lock_irqsave(&csi->lock, flags);
596
597 temp = ipu_csi_read(csi, CSI_SKIP);
598 temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
599 CSI_SKIP_SMFC_MASK);
600 temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
601 (id << CSI_ID_2_SKIP_SHIFT) |
602 (skip << CSI_SKIP_SMFC_SHIFT);
603 ipu_csi_write(csi, temp, CSI_SKIP);
604
605 spin_unlock_irqrestore(&csi->lock, flags);
606
607 return 0;
608}
609EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
610
611int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest)
612{
613 unsigned long flags;
614 u32 csi_sens_conf, dest;
615
616 if (csi_dest == IPU_CSI_DEST_IDMAC)
617 dest = CSI_DATA_DEST_IDMAC;
618 else
619 dest = CSI_DATA_DEST_IC; /* IC or VDIC */
620
621 spin_lock_irqsave(&csi->lock, flags);
622
623 csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
624 csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
625 csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
626 ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
627
628 spin_unlock_irqrestore(&csi->lock, flags);
629
630 return 0;
631}
632EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
633
634int ipu_csi_enable(struct ipu_csi *csi)
635{
636 ipu_module_enable(csi->ipu, csi->module);
637
638 return 0;
639}
640EXPORT_SYMBOL_GPL(ipu_csi_enable);
641
642int ipu_csi_disable(struct ipu_csi *csi)
643{
644 ipu_module_disable(csi->ipu, csi->module);
645
646 return 0;
647}
648EXPORT_SYMBOL_GPL(ipu_csi_disable);
649
650struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
651{
652 unsigned long flags;
653 struct ipu_csi *csi, *ret;
654
655 if (id > 1)
656 return ERR_PTR(-EINVAL);
657
658 csi = ipu->csi_priv[id];
659 ret = csi;
660
661 spin_lock_irqsave(&csi->lock, flags);
662
663 if (csi->inuse) {
664 ret = ERR_PTR(-EBUSY);
665 goto unlock;
666 }
667
668 csi->inuse = true;
669unlock:
670 spin_unlock_irqrestore(&csi->lock, flags);
671 return ret;
672}
673EXPORT_SYMBOL_GPL(ipu_csi_get);
674
675void ipu_csi_put(struct ipu_csi *csi)
676{
677 unsigned long flags;
678
679 spin_lock_irqsave(&csi->lock, flags);
680 csi->inuse = false;
681 spin_unlock_irqrestore(&csi->lock, flags);
682}
683EXPORT_SYMBOL_GPL(ipu_csi_put);
684
685int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
686 unsigned long base, u32 module, struct clk *clk_ipu)
687{
688 struct ipu_csi *csi;
689
690 if (id > 1)
691 return -ENODEV;
692
693 csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
694 if (!csi)
695 return -ENOMEM;
696
697 ipu->csi_priv[id] = csi;
698
699 spin_lock_init(&csi->lock);
700 csi->module = module;
701 csi->id = id;
702 csi->clk_ipu = clk_ipu;
703 csi->base = devm_ioremap(dev, base, PAGE_SIZE);
704 if (!csi->base)
705 return -ENOMEM;
706
707 dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
708 id, base, csi->base);
709 csi->ipu = ipu;
710
711 return 0;
712}
713
714void ipu_csi_exit(struct ipu_soc *ipu, int id)
715{
716}
717
718void ipu_csi_dump(struct ipu_csi *csi)
719{
720 dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n",
721 ipu_csi_read(csi, CSI_SENS_CONF));
722 dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
723 ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
724 dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n",
725 ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
726 dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n",
727 ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
728 dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n",
729 ipu_csi_read(csi, CSI_TST_CTRL));
730 dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n",
731 ipu_csi_read(csi, CSI_CCIR_CODE_1));
732 dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n",
733 ipu_csi_read(csi, CSI_CCIR_CODE_2));
734 dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n",
735 ipu_csi_read(csi, CSI_CCIR_CODE_3));
736 dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n",
737 ipu_csi_read(csi, CSI_MIPI_DI));
738 dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n",
739 ipu_csi_read(csi, CSI_SKIP));
740}
741EXPORT_SYMBOL_GPL(ipu_csi_dump);
diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
new file mode 100644
index 000000000000..ad75588e1629
--- /dev/null
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -0,0 +1,778 @@
1/*
2 * Copyright (C) 2012-2014 Mentor Graphics Inc.
3 * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12
13#include <linux/types.h>
14#include <linux/init.h>
15#include <linux/errno.h>
16#include <linux/spinlock.h>
17#include <linux/bitrev.h>
18#include <linux/io.h>
19#include <linux/err.h>
20#include "ipu-prv.h"
21
22/* IC Register Offsets */
23#define IC_CONF 0x0000
24#define IC_PRP_ENC_RSC 0x0004
25#define IC_PRP_VF_RSC 0x0008
26#define IC_PP_RSC 0x000C
27#define IC_CMBP_1 0x0010
28#define IC_CMBP_2 0x0014
29#define IC_IDMAC_1 0x0018
30#define IC_IDMAC_2 0x001C
31#define IC_IDMAC_3 0x0020
32#define IC_IDMAC_4 0x0024
33
34/* IC Register Fields */
35#define IC_CONF_PRPENC_EN (1 << 0)
36#define IC_CONF_PRPENC_CSC1 (1 << 1)
37#define IC_CONF_PRPENC_ROT_EN (1 << 2)
38#define IC_CONF_PRPVF_EN (1 << 8)
39#define IC_CONF_PRPVF_CSC1 (1 << 9)
40#define IC_CONF_PRPVF_CSC2 (1 << 10)
41#define IC_CONF_PRPVF_CMB (1 << 11)
42#define IC_CONF_PRPVF_ROT_EN (1 << 12)
43#define IC_CONF_PP_EN (1 << 16)
44#define IC_CONF_PP_CSC1 (1 << 17)
45#define IC_CONF_PP_CSC2 (1 << 18)
46#define IC_CONF_PP_CMB (1 << 19)
47#define IC_CONF_PP_ROT_EN (1 << 20)
48#define IC_CONF_IC_GLB_LOC_A (1 << 28)
49#define IC_CONF_KEY_COLOR_EN (1 << 29)
50#define IC_CONF_RWS_EN (1 << 30)
51#define IC_CONF_CSI_MEM_WR_EN (1 << 31)
52
53#define IC_IDMAC_1_CB0_BURST_16 (1 << 0)
54#define IC_IDMAC_1_CB1_BURST_16 (1 << 1)
55#define IC_IDMAC_1_CB2_BURST_16 (1 << 2)
56#define IC_IDMAC_1_CB3_BURST_16 (1 << 3)
57#define IC_IDMAC_1_CB4_BURST_16 (1 << 4)
58#define IC_IDMAC_1_CB5_BURST_16 (1 << 5)
59#define IC_IDMAC_1_CB6_BURST_16 (1 << 6)
60#define IC_IDMAC_1_CB7_BURST_16 (1 << 7)
61#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11)
62#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11
63#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14)
64#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14
65#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17)
66#define IC_IDMAC_1_PP_ROT_OFFSET 17
67#define IC_IDMAC_1_PP_FLIP_RS (1 << 22)
68#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21)
69#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20)
70
71#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0)
72#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
73#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10)
74#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10
75#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20)
76#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20
77
78#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0)
79#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0
80#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10)
81#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10
82#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20)
83#define IC_IDMAC_3_PP_WIDTH_OFFSET 20
84
85struct ic_task_regoffs {
86 u32 rsc;
87 u32 tpmem_csc[2];
88};
89
90struct ic_task_bitfields {
91 u32 ic_conf_en;
92 u32 ic_conf_rot_en;
93 u32 ic_conf_cmb_en;
94 u32 ic_conf_csc1_en;
95 u32 ic_conf_csc2_en;
96 u32 ic_cmb_galpha_bit;
97};
98
99static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
100 [IC_TASK_ENCODER] = {
101 .rsc = IC_PRP_ENC_RSC,
102 .tpmem_csc = {0x2008, 0},
103 },
104 [IC_TASK_VIEWFINDER] = {
105 .rsc = IC_PRP_VF_RSC,
106 .tpmem_csc = {0x4028, 0x4040},
107 },
108 [IC_TASK_POST_PROCESSOR] = {
109 .rsc = IC_PP_RSC,
110 .tpmem_csc = {0x6060, 0x6078},
111 },
112};
113
114static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
115 [IC_TASK_ENCODER] = {
116 .ic_conf_en = IC_CONF_PRPENC_EN,
117 .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
118 .ic_conf_cmb_en = 0, /* NA */
119 .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
120 .ic_conf_csc2_en = 0, /* NA */
121 .ic_cmb_galpha_bit = 0, /* NA */
122 },
123 [IC_TASK_VIEWFINDER] = {
124 .ic_conf_en = IC_CONF_PRPVF_EN,
125 .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
126 .ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
127 .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
128 .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
129 .ic_cmb_galpha_bit = 0,
130 },
131 [IC_TASK_POST_PROCESSOR] = {
132 .ic_conf_en = IC_CONF_PP_EN,
133 .ic_conf_rot_en = IC_CONF_PP_ROT_EN,
134 .ic_conf_cmb_en = IC_CONF_PP_CMB,
135 .ic_conf_csc1_en = IC_CONF_PP_CSC1,
136 .ic_conf_csc2_en = IC_CONF_PP_CSC2,
137 .ic_cmb_galpha_bit = 8,
138 },
139};
140
141struct ipu_ic_priv;
142
143struct ipu_ic {
144 enum ipu_ic_task task;
145 const struct ic_task_regoffs *reg;
146 const struct ic_task_bitfields *bit;
147
148 enum ipu_color_space in_cs, g_in_cs;
149 enum ipu_color_space out_cs;
150 bool graphics;
151 bool rotation;
152 bool in_use;
153
154 struct ipu_ic_priv *priv;
155};
156
157struct ipu_ic_priv {
158 void __iomem *base;
159 void __iomem *tpmem_base;
160 spinlock_t lock;
161 struct ipu_soc *ipu;
162 int use_count;
163 struct ipu_ic task[IC_NUM_TASKS];
164};
165
166static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
167{
168 return readl(ic->priv->base + offset);
169}
170
171static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset)
172{
173 writel(value, ic->priv->base + offset);
174}
175
176struct ic_csc_params {
177 s16 coeff[3][3]; /* signed 9-bit integer coefficients */
178 s16 offset[3]; /* signed 11+2-bit fixed point offset */
179 u8 scale:2; /* scale coefficients * 2^(scale-1) */
180 bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */
181};
182
183/*
184 * Y = R * .299 + G * .587 + B * .114;
185 * U = R * -.169 + G * -.332 + B * .500 + 128.;
186 * V = R * .500 + G * -.419 + B * -.0813 + 128.;
187 */
188static const struct ic_csc_params ic_csc_rgb2ycbcr = {
189 .coeff = {
190 { 77, 150, 29 },
191 { 469, 427, 128 },
192 { 128, 405, 491 },
193 },
194 .offset = { 0, 512, 512 },
195 .scale = 1,
196};
197
198/* transparent RGB->RGB matrix for graphics combining */
199static const struct ic_csc_params ic_csc_rgb2rgb = {
200 .coeff = {
201 { 128, 0, 0 },
202 { 0, 128, 0 },
203 { 0, 0, 128 },
204 },
205 .scale = 2,
206};
207
208/*
209 * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
210 * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
211 * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
212 */
213static const struct ic_csc_params ic_csc_ycbcr2rgb = {
214 .coeff = {
215 { 149, 0, 204 },
216 { 149, 462, 408 },
217 { 149, 255, 0 },
218 },
219 .offset = { -446, 266, -554 },
220 .scale = 2,
221};
222
223static int init_csc(struct ipu_ic *ic,
224 enum ipu_color_space inf,
225 enum ipu_color_space outf,
226 int csc_index)
227{
228 struct ipu_ic_priv *priv = ic->priv;
229 const struct ic_csc_params *params;
230 u32 __iomem *base;
231 const u16 (*c)[3];
232 const u16 *a;
233 u32 param;
234
235 base = (u32 __iomem *)
236 (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
237
238 if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB)
239 params = &ic_csc_ycbcr2rgb;
240 else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV)
241 params = &ic_csc_rgb2ycbcr;
242 else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB)
243 params = &ic_csc_rgb2rgb;
244 else {
245 dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
246 return -EINVAL;
247 }
248
249 /* Cast to unsigned */
250 c = (const u16 (*)[3])params->coeff;
251 a = (const u16 *)params->offset;
252
253 param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) |
254 ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff);
255 writel(param, base++);
256
257 param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
258 (params->sat << 9);
259 writel(param, base++);
260
261 param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
262 ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff);
263 writel(param, base++);
264
265 param = ((a[1] & 0x1fe0) >> 5);
266 writel(param, base++);
267
268 param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) |
269 ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff);
270 writel(param, base++);
271
272 param = ((a[2] & 0x1fe0) >> 5);
273 writel(param, base++);
274
275 return 0;
276}
277
278static int calc_resize_coeffs(struct ipu_ic *ic,
279 u32 in_size, u32 out_size,
280 u32 *resize_coeff,
281 u32 *downsize_coeff)
282{
283 struct ipu_ic_priv *priv = ic->priv;
284 struct ipu_soc *ipu = priv->ipu;
285 u32 temp_size, temp_downsize;
286
287 /*
288 * Input size cannot be more than 4096, and output size cannot
289 * be more than 1024
290 */
291 if (in_size > 4096) {
292 dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
293 return -EINVAL;
294 }
295 if (out_size > 1024) {
296 dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
297 return -EINVAL;
298 }
299
300 /* Cannot downsize more than 8:1 */
301 if ((out_size << 3) < in_size) {
302 dev_err(ipu->dev, "Unsupported downsize\n");
303 return -EINVAL;
304 }
305
306 /* Compute downsizing coefficient */
307 temp_downsize = 0;
308 temp_size = in_size;
309 while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
310 (temp_downsize < 2)) {
311 temp_size >>= 1;
312 temp_downsize++;
313 }
314 *downsize_coeff = temp_downsize;
315
316 /*
317 * compute resizing coefficient using the following equation:
318 * resize_coeff = M * (SI - 1) / (SO - 1)
319 * where M = 2^13, SI = input size, SO = output size
320 */
321 *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
322 if (*resize_coeff >= 16384L) {
323 dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
324 *resize_coeff = 0x3FFF;
325 }
326
327 return 0;
328}
329
330void ipu_ic_task_enable(struct ipu_ic *ic)
331{
332 struct ipu_ic_priv *priv = ic->priv;
333 unsigned long flags;
334 u32 ic_conf;
335
336 spin_lock_irqsave(&priv->lock, flags);
337
338 ic_conf = ipu_ic_read(ic, IC_CONF);
339
340 ic_conf |= ic->bit->ic_conf_en;
341
342 if (ic->rotation)
343 ic_conf |= ic->bit->ic_conf_rot_en;
344
345 if (ic->in_cs != ic->out_cs)
346 ic_conf |= ic->bit->ic_conf_csc1_en;
347
348 if (ic->graphics) {
349 ic_conf |= ic->bit->ic_conf_cmb_en;
350 ic_conf |= ic->bit->ic_conf_csc1_en;
351
352 if (ic->g_in_cs != ic->out_cs)
353 ic_conf |= ic->bit->ic_conf_csc2_en;
354 }
355
356 ipu_ic_write(ic, ic_conf, IC_CONF);
357
358 spin_unlock_irqrestore(&priv->lock, flags);
359}
360EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
361
362void ipu_ic_task_disable(struct ipu_ic *ic)
363{
364 struct ipu_ic_priv *priv = ic->priv;
365 unsigned long flags;
366 u32 ic_conf;
367
368 spin_lock_irqsave(&priv->lock, flags);
369
370 ic_conf = ipu_ic_read(ic, IC_CONF);
371
372 ic_conf &= ~(ic->bit->ic_conf_en |
373 ic->bit->ic_conf_csc1_en |
374 ic->bit->ic_conf_rot_en);
375 if (ic->bit->ic_conf_csc2_en)
376 ic_conf &= ~ic->bit->ic_conf_csc2_en;
377 if (ic->bit->ic_conf_cmb_en)
378 ic_conf &= ~ic->bit->ic_conf_cmb_en;
379
380 ipu_ic_write(ic, ic_conf, IC_CONF);
381
382 ic->rotation = ic->graphics = false;
383
384 spin_unlock_irqrestore(&priv->lock, flags);
385}
386EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
387
388int ipu_ic_task_graphics_init(struct ipu_ic *ic,
389 enum ipu_color_space in_g_cs,
390 bool galpha_en, u32 galpha,
391 bool colorkey_en, u32 colorkey)
392{
393 struct ipu_ic_priv *priv = ic->priv;
394 unsigned long flags;
395 u32 reg, ic_conf;
396 int ret = 0;
397
398 if (ic->task == IC_TASK_ENCODER)
399 return -EINVAL;
400
401 spin_lock_irqsave(&priv->lock, flags);
402
403 ic_conf = ipu_ic_read(ic, IC_CONF);
404
405 if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
406 /* need transparent CSC1 conversion */
407 ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
408 IPUV3_COLORSPACE_RGB, 0);
409 if (ret)
410 goto unlock;
411 }
412
413 ic->g_in_cs = in_g_cs;
414
415 if (ic->g_in_cs != ic->out_cs) {
416 ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
417 if (ret)
418 goto unlock;
419 }
420
421 if (galpha_en) {
422 ic_conf |= IC_CONF_IC_GLB_LOC_A;
423 reg = ipu_ic_read(ic, IC_CMBP_1);
424 reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
425 reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
426 ipu_ic_write(ic, reg, IC_CMBP_1);
427 } else
428 ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
429
430 if (colorkey_en) {
431 ic_conf |= IC_CONF_KEY_COLOR_EN;
432 ipu_ic_write(ic, colorkey, IC_CMBP_2);
433 } else
434 ic_conf &= ~IC_CONF_KEY_COLOR_EN;
435
436 ipu_ic_write(ic, ic_conf, IC_CONF);
437
438 ic->graphics = true;
439unlock:
440 spin_unlock_irqrestore(&priv->lock, flags);
441 return ret;
442}
443EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
444
445int ipu_ic_task_init(struct ipu_ic *ic,
446 int in_width, int in_height,
447 int out_width, int out_height,
448 enum ipu_color_space in_cs,
449 enum ipu_color_space out_cs)
450{
451 struct ipu_ic_priv *priv = ic->priv;
452 u32 reg, downsize_coeff, resize_coeff;
453 unsigned long flags;
454 int ret = 0;
455
456 /* Setup vertical resizing */
457 ret = calc_resize_coeffs(ic, in_height, out_height,
458 &resize_coeff, &downsize_coeff);
459 if (ret)
460 return ret;
461
462 reg = (downsize_coeff << 30) | (resize_coeff << 16);
463
464 /* Setup horizontal resizing */
465 ret = calc_resize_coeffs(ic, in_width, out_width,
466 &resize_coeff, &downsize_coeff);
467 if (ret)
468 return ret;
469
470 reg |= (downsize_coeff << 14) | resize_coeff;
471
472 spin_lock_irqsave(&priv->lock, flags);
473
474 ipu_ic_write(ic, reg, ic->reg->rsc);
475
476 /* Setup color space conversion */
477 ic->in_cs = in_cs;
478 ic->out_cs = out_cs;
479
480 if (ic->in_cs != ic->out_cs) {
481 ret = init_csc(ic, ic->in_cs, ic->out_cs, 0);
482 if (ret)
483 goto unlock;
484 }
485
486unlock:
487 spin_unlock_irqrestore(&priv->lock, flags);
488 return ret;
489}
490EXPORT_SYMBOL_GPL(ipu_ic_task_init);
491
492int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
493 u32 width, u32 height, int burst_size,
494 enum ipu_rotate_mode rot)
495{
496 struct ipu_ic_priv *priv = ic->priv;
497 struct ipu_soc *ipu = priv->ipu;
498 u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
499 u32 temp_rot = bitrev8(rot) >> 5;
500 bool need_hor_flip = false;
501 unsigned long flags;
502 int ret = 0;
503
504 if ((burst_size != 8) && (burst_size != 16)) {
505 dev_err(ipu->dev, "Illegal burst length for IC\n");
506 return -EINVAL;
507 }
508
509 width--;
510 height--;
511
512 if (temp_rot & 0x2) /* Need horizontal flip */
513 need_hor_flip = true;
514
515 spin_lock_irqsave(&priv->lock, flags);
516
517 ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
518 ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
519 ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
520
521 switch (channel->num) {
522 case IPUV3_CHANNEL_IC_PP_MEM:
523 if (burst_size == 16)
524 ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
525 else
526 ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
527
528 if (need_hor_flip)
529 ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
530 else
531 ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
532
533 ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
534 ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
535
536 ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
537 ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
538 break;
539 case IPUV3_CHANNEL_MEM_IC_PP:
540 if (burst_size == 16)
541 ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
542 else
543 ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
544 break;
545 case IPUV3_CHANNEL_MEM_ROT_PP:
546 ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
547 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
548 break;
549 case IPUV3_CHANNEL_MEM_IC_PRP_VF:
550 if (burst_size == 16)
551 ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
552 else
553 ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
554 break;
555 case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
556 if (burst_size == 16)
557 ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
558 else
559 ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
560
561 if (need_hor_flip)
562 ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
563 else
564 ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
565
566 ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
567 ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
568
569 ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
570 ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
571 break;
572 case IPUV3_CHANNEL_MEM_ROT_ENC:
573 ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
574 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
575 break;
576 case IPUV3_CHANNEL_IC_PRP_VF_MEM:
577 if (burst_size == 16)
578 ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
579 else
580 ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
581
582 if (need_hor_flip)
583 ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
584 else
585 ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
586
587 ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
588 ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
589
590 ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
591 ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
592 break;
593 case IPUV3_CHANNEL_MEM_ROT_VF:
594 ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
595 ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
596 break;
597 case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
598 if (burst_size == 16)
599 ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
600 else
601 ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
602 break;
603 case IPUV3_CHANNEL_G_MEM_IC_PP:
604 if (burst_size == 16)
605 ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
606 else
607 ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
608 break;
609 case IPUV3_CHANNEL_VDI_MEM_IC_VF:
610 if (burst_size == 16)
611 ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
612 else
613 ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
614 break;
615 default:
616 goto unlock;
617 }
618
619 ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
620 ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
621 ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
622
623 if (rot >= IPU_ROTATE_90_RIGHT)
624 ic->rotation = true;
625
626unlock:
627 spin_unlock_irqrestore(&priv->lock, flags);
628 return ret;
629}
630EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
631
632int ipu_ic_enable(struct ipu_ic *ic)
633{
634 struct ipu_ic_priv *priv = ic->priv;
635 unsigned long flags;
636 u32 module = IPU_CONF_IC_EN;
637
638 spin_lock_irqsave(&priv->lock, flags);
639
640 if (ic->rotation)
641 module |= IPU_CONF_ROT_EN;
642
643 if (!priv->use_count)
644 ipu_module_enable(priv->ipu, module);
645
646 priv->use_count++;
647
648 spin_unlock_irqrestore(&priv->lock, flags);
649
650 return 0;
651}
652EXPORT_SYMBOL_GPL(ipu_ic_enable);
653
654int ipu_ic_disable(struct ipu_ic *ic)
655{
656 struct ipu_ic_priv *priv = ic->priv;
657 unsigned long flags;
658 u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN;
659
660 spin_lock_irqsave(&priv->lock, flags);
661
662 priv->use_count--;
663
664 if (!priv->use_count)
665 ipu_module_disable(priv->ipu, module);
666
667 if (priv->use_count < 0)
668 priv->use_count = 0;
669
670 spin_unlock_irqrestore(&priv->lock, flags);
671
672 return 0;
673}
674EXPORT_SYMBOL_GPL(ipu_ic_disable);
675
676struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
677{
678 struct ipu_ic_priv *priv = ipu->ic_priv;
679 unsigned long flags;
680 struct ipu_ic *ic, *ret;
681
682 if (task >= IC_NUM_TASKS)
683 return ERR_PTR(-EINVAL);
684
685 ic = &priv->task[task];
686
687 spin_lock_irqsave(&priv->lock, flags);
688
689 if (ic->in_use) {
690 ret = ERR_PTR(-EBUSY);
691 goto unlock;
692 }
693
694 ic->in_use = true;
695 ret = ic;
696
697unlock:
698 spin_unlock_irqrestore(&priv->lock, flags);
699 return ret;
700}
701EXPORT_SYMBOL_GPL(ipu_ic_get);
702
703void ipu_ic_put(struct ipu_ic *ic)
704{
705 struct ipu_ic_priv *priv = ic->priv;
706 unsigned long flags;
707
708 spin_lock_irqsave(&priv->lock, flags);
709 ic->in_use = false;
710 spin_unlock_irqrestore(&priv->lock, flags);
711}
712EXPORT_SYMBOL_GPL(ipu_ic_put);
713
714int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
715 unsigned long base, unsigned long tpmem_base)
716{
717 struct ipu_ic_priv *priv;
718 int i;
719
720 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
721 if (!priv)
722 return -ENOMEM;
723
724 ipu->ic_priv = priv;
725
726 spin_lock_init(&priv->lock);
727 priv->base = devm_ioremap(dev, base, PAGE_SIZE);
728 if (!priv->base)
729 return -ENOMEM;
730 priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
731 if (!priv->tpmem_base)
732 return -ENOMEM;
733
734 dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
735
736 priv->ipu = ipu;
737
738 for (i = 0; i < IC_NUM_TASKS; i++) {
739 priv->task[i].task = i;
740 priv->task[i].priv = priv;
741 priv->task[i].reg = &ic_task_reg[i];
742 priv->task[i].bit = &ic_task_bit[i];
743 }
744
745 return 0;
746}
747
748void ipu_ic_exit(struct ipu_soc *ipu)
749{
750}
751
752void ipu_ic_dump(struct ipu_ic *ic)
753{
754 struct ipu_ic_priv *priv = ic->priv;
755 struct ipu_soc *ipu = priv->ipu;
756
757 dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
758 ipu_ic_read(ic, IC_CONF));
759 dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
760 ipu_ic_read(ic, IC_PRP_ENC_RSC));
761 dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
762 ipu_ic_read(ic, IC_PRP_VF_RSC));
763 dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
764 ipu_ic_read(ic, IC_PP_RSC));
765 dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
766 ipu_ic_read(ic, IC_CMBP_1));
767 dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
768 ipu_ic_read(ic, IC_CMBP_2));
769 dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
770 ipu_ic_read(ic, IC_IDMAC_1));
771 dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
772 ipu_ic_read(ic, IC_IDMAC_2));
773 dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
774 ipu_ic_read(ic, IC_IDMAC_3));
775 dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
776 ipu_ic_read(ic, IC_IDMAC_4));
777}
778EXPORT_SYMBOL_GPL(ipu_ic_dump);
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index c93f50ec04f7..bfb1e8a4483f 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -24,23 +24,6 @@ struct ipu_soc;
24 24
25#include <video/imx-ipu-v3.h> 25#include <video/imx-ipu-v3.h>
26 26
27#define IPUV3_CHANNEL_CSI0 0
28#define IPUV3_CHANNEL_CSI1 1
29#define IPUV3_CHANNEL_CSI2 2
30#define IPUV3_CHANNEL_CSI3 3
31#define IPUV3_CHANNEL_MEM_BG_SYNC 23
32#define IPUV3_CHANNEL_MEM_FG_SYNC 27
33#define IPUV3_CHANNEL_MEM_DC_SYNC 28
34#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
35#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
36#define IPUV3_CHANNEL_ROT_ENC_MEM 45
37#define IPUV3_CHANNEL_ROT_VF_MEM 46
38#define IPUV3_CHANNEL_ROT_PP_MEM 47
39#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48
40#define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49
41#define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50
42#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
43
44#define IPU_MCU_T_DEFAULT 8 27#define IPU_MCU_T_DEFAULT 8
45#define IPU_CM_IDMAC_REG_OFS 0x00008000 28#define IPU_CM_IDMAC_REG_OFS 0x00008000
46#define IPU_CM_IC_REG_OFS 0x00020000 29#define IPU_CM_IC_REG_OFS 0x00020000
@@ -85,6 +68,7 @@ struct ipu_soc;
85#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254) 68#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
86#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32)) 69#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
87#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32)) 70#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
71#define IPU_CHA_BUF2_RDY(ch) IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
88#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32)) 72#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
89#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32)) 73#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
90 74
@@ -148,9 +132,12 @@ struct ipuv3_channel {
148 struct ipu_soc *ipu; 132 struct ipu_soc *ipu;
149}; 133};
150 134
135struct ipu_cpmem;
136struct ipu_csi;
151struct ipu_dc_priv; 137struct ipu_dc_priv;
152struct ipu_dmfc_priv; 138struct ipu_dmfc_priv;
153struct ipu_di; 139struct ipu_di;
140struct ipu_ic_priv;
154struct ipu_smfc_priv; 141struct ipu_smfc_priv;
155 142
156struct ipu_devtype; 143struct ipu_devtype;
@@ -164,7 +151,6 @@ struct ipu_soc {
164 151
165 void __iomem *cm_reg; 152 void __iomem *cm_reg;
166 void __iomem *idmac_reg; 153 void __iomem *idmac_reg;
167 struct ipu_ch_param __iomem *cpmem_base;
168 154
169 int usecount; 155 int usecount;
170 156
@@ -176,13 +162,27 @@ struct ipu_soc {
176 int irq_err; 162 int irq_err;
177 struct irq_domain *domain; 163 struct irq_domain *domain;
178 164
165 struct ipu_cpmem *cpmem_priv;
179 struct ipu_dc_priv *dc_priv; 166 struct ipu_dc_priv *dc_priv;
180 struct ipu_dp_priv *dp_priv; 167 struct ipu_dp_priv *dp_priv;
181 struct ipu_dmfc_priv *dmfc_priv; 168 struct ipu_dmfc_priv *dmfc_priv;
182 struct ipu_di *di_priv[2]; 169 struct ipu_di *di_priv[2];
170 struct ipu_csi *csi_priv[2];
171 struct ipu_ic_priv *ic_priv;
183 struct ipu_smfc_priv *smfc_priv; 172 struct ipu_smfc_priv *smfc_priv;
184}; 173};
185 174
175static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
176{
177 return readl(ipu->idmac_reg + offset);
178}
179
180static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
181 unsigned offset)
182{
183 writel(value, ipu->idmac_reg + offset);
184}
185
186void ipu_srm_dp_sync_update(struct ipu_soc *ipu); 186void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
187 187
188int ipu_module_enable(struct ipu_soc *ipu, u32 mask); 188int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
@@ -191,6 +191,14 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
191bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno); 191bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
192int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms); 192int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms);
193 193
194int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
195 unsigned long base, u32 module, struct clk *clk_ipu);
196void ipu_csi_exit(struct ipu_soc *ipu, int id);
197
198int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
199 unsigned long base, unsigned long tpmem_base);
200void ipu_ic_exit(struct ipu_soc *ipu);
201
194int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, 202int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
195 unsigned long base, u32 module, struct clk *ipu_clk); 203 unsigned long base, u32 module, struct clk *ipu_clk);
196void ipu_di_exit(struct ipu_soc *ipu, int id); 204void ipu_di_exit(struct ipu_soc *ipu, int id);
diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c
index e4f85ad286fc..6ca9b43ce25a 100644
--- a/drivers/gpu/ipu-v3/ipu-smfc.c
+++ b/drivers/gpu/ipu-v3/ipu-smfc.c
@@ -21,9 +21,18 @@
21 21
22#include "ipu-prv.h" 22#include "ipu-prv.h"
23 23
24struct ipu_smfc {
25 struct ipu_smfc_priv *priv;
26 int chno;
27 bool inuse;
28};
29
24struct ipu_smfc_priv { 30struct ipu_smfc_priv {
25 void __iomem *base; 31 void __iomem *base;
26 spinlock_t lock; 32 spinlock_t lock;
33 struct ipu_soc *ipu;
34 struct ipu_smfc channel[4];
35 int use_count;
27}; 36};
28 37
29/*SMFC Registers */ 38/*SMFC Registers */
@@ -31,63 +40,166 @@ struct ipu_smfc_priv {
31#define SMFC_WMC 0x0004 40#define SMFC_WMC 0x0004
32#define SMFC_BS 0x0008 41#define SMFC_BS 0x0008
33 42
34int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize) 43int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
35{ 44{
36 struct ipu_smfc_priv *smfc = ipu->smfc_priv; 45 struct ipu_smfc_priv *priv = smfc->priv;
37 unsigned long flags; 46 unsigned long flags;
38 u32 val, shift; 47 u32 val, shift;
39 48
40 spin_lock_irqsave(&smfc->lock, flags); 49 spin_lock_irqsave(&priv->lock, flags);
41 50
42 shift = channel * 4; 51 shift = smfc->chno * 4;
43 val = readl(smfc->base + SMFC_BS); 52 val = readl(priv->base + SMFC_BS);
44 val &= ~(0xf << shift); 53 val &= ~(0xf << shift);
45 val |= burstsize << shift; 54 val |= burstsize << shift;
46 writel(val, smfc->base + SMFC_BS); 55 writel(val, priv->base + SMFC_BS);
47 56
48 spin_unlock_irqrestore(&smfc->lock, flags); 57 spin_unlock_irqrestore(&priv->lock, flags);
49 58
50 return 0; 59 return 0;
51} 60}
52EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize); 61EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
53 62
54int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id) 63int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
55{ 64{
56 struct ipu_smfc_priv *smfc = ipu->smfc_priv; 65 struct ipu_smfc_priv *priv = smfc->priv;
57 unsigned long flags; 66 unsigned long flags;
58 u32 val, shift; 67 u32 val, shift;
59 68
60 spin_lock_irqsave(&smfc->lock, flags); 69 spin_lock_irqsave(&priv->lock, flags);
61 70
62 shift = channel * 3; 71 shift = smfc->chno * 3;
63 val = readl(smfc->base + SMFC_MAP); 72 val = readl(priv->base + SMFC_MAP);
64 val &= ~(0x7 << shift); 73 val &= ~(0x7 << shift);
65 val |= ((csi_id << 2) | mipi_id) << shift; 74 val |= ((csi_id << 2) | mipi_id) << shift;
66 writel(val, smfc->base + SMFC_MAP); 75 writel(val, priv->base + SMFC_MAP);
67 76
68 spin_unlock_irqrestore(&smfc->lock, flags); 77 spin_unlock_irqrestore(&priv->lock, flags);
69 78
70 return 0; 79 return 0;
71} 80}
72EXPORT_SYMBOL_GPL(ipu_smfc_map_channel); 81EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
73 82
83int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
84{
85 struct ipu_smfc_priv *priv = smfc->priv;
86 unsigned long flags;
87 u32 val, shift;
88
89 spin_lock_irqsave(&priv->lock, flags);
90
91 shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
92 val = readl(priv->base + SMFC_WMC);
93 val &= ~(0x3f << shift);
94 val |= ((clr_level << 3) | set_level) << shift;
95 writel(val, priv->base + SMFC_WMC);
96
97 spin_unlock_irqrestore(&priv->lock, flags);
98
99 return 0;
100}
101EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
102
103int ipu_smfc_enable(struct ipu_smfc *smfc)
104{
105 struct ipu_smfc_priv *priv = smfc->priv;
106 unsigned long flags;
107
108 spin_lock_irqsave(&priv->lock, flags);
109
110 if (!priv->use_count)
111 ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
112
113 priv->use_count++;
114
115 spin_unlock_irqrestore(&priv->lock, flags);
116
117 return 0;
118}
119EXPORT_SYMBOL_GPL(ipu_smfc_enable);
120
121int ipu_smfc_disable(struct ipu_smfc *smfc)
122{
123 struct ipu_smfc_priv *priv = smfc->priv;
124 unsigned long flags;
125
126 spin_lock_irqsave(&priv->lock, flags);
127
128 priv->use_count--;
129
130 if (!priv->use_count)
131 ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
132
133 if (priv->use_count < 0)
134 priv->use_count = 0;
135
136 spin_unlock_irqrestore(&priv->lock, flags);
137
138 return 0;
139}
140EXPORT_SYMBOL_GPL(ipu_smfc_disable);
141
142struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
143{
144 struct ipu_smfc_priv *priv = ipu->smfc_priv;
145 struct ipu_smfc *smfc, *ret;
146 unsigned long flags;
147
148 if (chno >= 4)
149 return ERR_PTR(-EINVAL);
150
151 smfc = &priv->channel[chno];
152 ret = smfc;
153
154 spin_lock_irqsave(&priv->lock, flags);
155
156 if (smfc->inuse) {
157 ret = ERR_PTR(-EBUSY);
158 goto unlock;
159 }
160
161 smfc->inuse = true;
162unlock:
163 spin_unlock_irqrestore(&priv->lock, flags);
164 return ret;
165}
166EXPORT_SYMBOL_GPL(ipu_smfc_get);
167
168void ipu_smfc_put(struct ipu_smfc *smfc)
169{
170 struct ipu_smfc_priv *priv = smfc->priv;
171 unsigned long flags;
172
173 spin_lock_irqsave(&priv->lock, flags);
174 smfc->inuse = false;
175 spin_unlock_irqrestore(&priv->lock, flags);
176}
177EXPORT_SYMBOL_GPL(ipu_smfc_put);
178
74int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, 179int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
75 unsigned long base) 180 unsigned long base)
76{ 181{
77 struct ipu_smfc_priv *smfc; 182 struct ipu_smfc_priv *priv;
183 int i;
78 184
79 smfc = devm_kzalloc(dev, sizeof(*smfc), GFP_KERNEL); 185 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
80 if (!smfc) 186 if (!priv)
81 return -ENOMEM; 187 return -ENOMEM;
82 188
83 ipu->smfc_priv = smfc; 189 ipu->smfc_priv = priv;
84 spin_lock_init(&smfc->lock); 190 spin_lock_init(&priv->lock);
191 priv->ipu = ipu;
85 192
86 smfc->base = devm_ioremap(dev, base, PAGE_SIZE); 193 priv->base = devm_ioremap(dev, base, PAGE_SIZE);
87 if (!smfc->base) 194 if (!priv->base)
88 return -ENOMEM; 195 return -ENOMEM;
89 196
90 pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, smfc->base); 197 for (i = 0; i < 4; i++) {
198 priv->channel[i].priv = priv;
199 priv->channel[i].chno = i;
200 }
201
202 pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
91 203
92 return 0; 204 return 0;
93} 205}
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 6f393a11f44d..6ffe1bbbcf16 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -62,7 +62,6 @@ static inline int calc_bandwidth(int width, int height, unsigned int vref)
62int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, 62int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
63 int x, int y) 63 int x, int y)
64{ 64{
65 struct ipu_ch_param __iomem *cpmem;
66 struct drm_gem_cma_object *cma_obj; 65 struct drm_gem_cma_object *cma_obj;
67 unsigned long eba; 66 unsigned long eba;
68 67
@@ -75,13 +74,12 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
75 dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", 74 dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
76 &cma_obj->paddr, x, y); 75 &cma_obj->paddr, x, y);
77 76
78 cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); 77 ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
79 ipu_cpmem_set_stride(cpmem, fb->pitches[0]);
80 78
81 eba = cma_obj->paddr + fb->offsets[0] + 79 eba = cma_obj->paddr + fb->offsets[0] +
82 fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; 80 fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
83 ipu_cpmem_set_buffer(cpmem, 0, eba); 81 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
84 ipu_cpmem_set_buffer(cpmem, 1, eba); 82 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
85 83
86 /* cache offsets for subsequent pageflips */ 84 /* cache offsets for subsequent pageflips */
87 ipu_plane->x = x; 85 ipu_plane->x = x;
@@ -97,7 +95,6 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
97 uint32_t src_x, uint32_t src_y, 95 uint32_t src_x, uint32_t src_y,
98 uint32_t src_w, uint32_t src_h) 96 uint32_t src_w, uint32_t src_h)
99{ 97{
100 struct ipu_ch_param __iomem *cpmem;
101 struct device *dev = ipu_plane->base.dev->dev; 98 struct device *dev = ipu_plane->base.dev->dev;
102 int ret; 99 int ret;
103 100
@@ -175,10 +172,9 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
175 return ret; 172 return ret;
176 } 173 }
177 174
178 cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); 175 ipu_cpmem_zero(ipu_plane->ipu_ch);
179 ipu_ch_param_zero(cpmem); 176 ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
180 ipu_cpmem_set_resolution(cpmem, src_w, src_h); 177 ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
181 ret = ipu_cpmem_set_fmt(cpmem, fb->pixel_format);
182 if (ret < 0) { 178 if (ret < 0) {
183 dev_err(dev, "unsupported pixel format 0x%08x\n", 179 dev_err(dev, "unsupported pixel format 0x%08x\n",
184 fb->pixel_format); 180 fb->pixel_format);
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 3e43e22cdff9..c74bf4a0520e 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -16,6 +16,7 @@
16#include <linux/videodev2.h> 16#include <linux/videodev2.h>
17#include <linux/bitmap.h> 17#include <linux/bitmap.h>
18#include <linux/fb.h> 18#include <linux/fb.h>
19#include <media/v4l2-mediabus.h>
19 20
20struct ipu_soc; 21struct ipu_soc;
21 22
@@ -61,6 +62,29 @@ struct ipu_di_signal_cfg {
61 u8 vsync_pin; 62 u8 vsync_pin;
62}; 63};
63 64
65/*
66 * Enumeration of CSI destinations
67 */
68enum ipu_csi_dest {
69 IPU_CSI_DEST_IDMAC, /* to memory via SMFC */
70 IPU_CSI_DEST_IC, /* to Image Converter */
71 IPU_CSI_DEST_VDIC, /* to VDIC */
72};
73
74/*
75 * Enumeration of IPU rotation modes
76 */
77enum ipu_rotate_mode {
78 IPU_ROTATE_NONE = 0,
79 IPU_ROTATE_VERT_FLIP,
80 IPU_ROTATE_HORIZ_FLIP,
81 IPU_ROTATE_180,
82 IPU_ROTATE_90_RIGHT,
83 IPU_ROTATE_90_RIGHT_VFLIP,
84 IPU_ROTATE_90_RIGHT_HFLIP,
85 IPU_ROTATE_90_LEFT,
86};
87
64enum ipu_color_space { 88enum ipu_color_space {
65 IPUV3_COLORSPACE_RGB, 89 IPUV3_COLORSPACE_RGB,
66 IPUV3_COLORSPACE_YUV, 90 IPUV3_COLORSPACE_YUV,
@@ -76,6 +100,36 @@ enum ipu_channel_irq {
76 IPU_IRQ_EOS = 192, 100 IPU_IRQ_EOS = 192,
77}; 101};
78 102
103/*
104 * Enumeration of IDMAC channels
105 */
106#define IPUV3_CHANNEL_CSI0 0
107#define IPUV3_CHANNEL_CSI1 1
108#define IPUV3_CHANNEL_CSI2 2
109#define IPUV3_CHANNEL_CSI3 3
110#define IPUV3_CHANNEL_VDI_MEM_IC_VF 5
111#define IPUV3_CHANNEL_MEM_IC_PP 11
112#define IPUV3_CHANNEL_MEM_IC_PRP_VF 12
113#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF 14
114#define IPUV3_CHANNEL_G_MEM_IC_PP 15
115#define IPUV3_CHANNEL_IC_PRP_ENC_MEM 20
116#define IPUV3_CHANNEL_IC_PRP_VF_MEM 21
117#define IPUV3_CHANNEL_IC_PP_MEM 22
118#define IPUV3_CHANNEL_MEM_BG_SYNC 23
119#define IPUV3_CHANNEL_MEM_BG_ASYNC 24
120#define IPUV3_CHANNEL_MEM_FG_SYNC 27
121#define IPUV3_CHANNEL_MEM_DC_SYNC 28
122#define IPUV3_CHANNEL_MEM_FG_ASYNC 29
123#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
124#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
125#define IPUV3_CHANNEL_MEM_ROT_ENC 45
126#define IPUV3_CHANNEL_MEM_ROT_VF 46
127#define IPUV3_CHANNEL_MEM_ROT_PP 47
128#define IPUV3_CHANNEL_ROT_ENC_MEM 48
129#define IPUV3_CHANNEL_ROT_VF_MEM 49
130#define IPUV3_CHANNEL_ROT_PP_MEM 50
131#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
132
79int ipu_map_irq(struct ipu_soc *ipu, int irq); 133int ipu_map_irq(struct ipu_soc *ipu, int irq);
80int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, 134int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
81 enum ipu_channel_irq irq); 135 enum ipu_channel_irq irq);
@@ -93,6 +147,13 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
93#define IPU_IRQ_VSYNC_PRE_1 (448 + 15) 147#define IPU_IRQ_VSYNC_PRE_1 (448 + 15)
94 148
95/* 149/*
150 * IPU Common functions
151 */
152void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
153void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
154void ipu_dump(struct ipu_soc *ipu);
155
156/*
96 * IPU Image DMA Controller (idmac) functions 157 * IPU Image DMA Controller (idmac) functions
97 */ 158 */
98struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel); 159struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel);
@@ -100,12 +161,58 @@ void ipu_idmac_put(struct ipuv3_channel *);
100 161
101int ipu_idmac_enable_channel(struct ipuv3_channel *channel); 162int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
102int ipu_idmac_disable_channel(struct ipuv3_channel *channel); 163int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
164void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
165int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts);
103int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms); 166int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
104 167
105void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, 168void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
106 bool doublebuffer); 169 bool doublebuffer);
107int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel); 170int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel);
171bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
108void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num); 172void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
173void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
174
175/*
176 * IPU Channel Parameter Memory (cpmem) functions
177 */
178struct ipu_rgb {
179 struct fb_bitfield red;
180 struct fb_bitfield green;
181 struct fb_bitfield blue;
182 struct fb_bitfield transp;
183 int bits_per_pixel;
184};
185
186struct ipu_image {
187 struct v4l2_pix_format pix;
188 struct v4l2_rect rect;
189 dma_addr_t phys0;
190 dma_addr_t phys1;
191};
192
193void ipu_cpmem_zero(struct ipuv3_channel *ch);
194void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres);
195void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
196void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
197void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
198void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
199void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
200void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
201void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
202void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
203 enum ipu_rotate_mode rot);
204int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
205 const struct ipu_rgb *rgb);
206int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
207void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format);
208void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
209 u32 pixel_format, int stride,
210 int u_offset, int v_offset);
211void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
212 u32 pixel_format, int stride, int height);
213int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc);
214int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image);
215void ipu_cpmem_dump(struct ipuv3_channel *ch);
109 216
110/* 217/*
111 * IPU Display Controller (dc) functions 218 * IPU Display Controller (dc) functions
@@ -169,171 +276,78 @@ int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
169/* 276/*
170 * IPU CMOS Sensor Interface (csi) functions 277 * IPU CMOS Sensor Interface (csi) functions
171 */ 278 */
172int ipu_csi_enable(struct ipu_soc *ipu, int csi); 279struct ipu_csi;
173int ipu_csi_disable(struct ipu_soc *ipu, int csi); 280int ipu_csi_init_interface(struct ipu_csi *csi,
281 struct v4l2_mbus_config *mbus_cfg,
282 struct v4l2_mbus_framefmt *mbus_fmt);
283bool ipu_csi_is_interlaced(struct ipu_csi *csi);
284void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w);
285void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w);
286void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
287 u32 r_value, u32 g_value, u32 b_value,
288 u32 pix_clk);
289int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
290 struct v4l2_mbus_framefmt *mbus_fmt);
291int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
292 u32 max_ratio, u32 id);
293int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest);
294int ipu_csi_enable(struct ipu_csi *csi);
295int ipu_csi_disable(struct ipu_csi *csi);
296struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id);
297void ipu_csi_put(struct ipu_csi *csi);
298void ipu_csi_dump(struct ipu_csi *csi);
174 299
175/* 300/*
176 * IPU Sensor Multiple FIFO Controller (SMFC) functions 301 * IPU Image Converter (ic) functions
177 */ 302 */
178int ipu_smfc_enable(struct ipu_soc *ipu); 303enum ipu_ic_task {
179int ipu_smfc_disable(struct ipu_soc *ipu); 304 IC_TASK_ENCODER,
180int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id); 305 IC_TASK_VIEWFINDER,
181int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize); 306 IC_TASK_POST_PROCESSOR,
182 307 IC_NUM_TASKS,
183#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
184
185#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
186#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
187#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
188#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
189#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
190#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
191#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
192
193#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
194#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
195#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
196#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
197#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
198#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
199#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
200#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
201#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
202#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
203#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
204#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
205#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
206#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
207#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
208#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
209#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
210#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
211#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
212#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
213#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
214#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
215#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
216#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
217#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
218#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
219#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
220#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
221#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
222#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
223#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
224#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
225#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
226#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
227#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
228#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
229#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
230#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
231#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
232#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
233#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
234#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
235#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
236#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
237#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
238#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
239#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
240#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
241#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
242#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
243
244struct ipu_cpmem_word {
245 u32 data[5];
246 u32 res[3];
247};
248
249struct ipu_ch_param {
250 struct ipu_cpmem_word word[2];
251};
252
253void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v);
254u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs);
255struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel);
256void ipu_ch_param_dump(struct ipu_ch_param __iomem *p);
257
258static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p)
259{
260 int i;
261 void __iomem *base = p;
262
263 for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
264 writel(0, base + i * sizeof(u32));
265}
266
267static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p,
268 int bufnum, dma_addr_t buf)
269{
270 if (bufnum)
271 ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3);
272 else
273 ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3);
274}
275
276static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p,
277 int xres, int yres)
278{
279 ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1);
280 ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1);
281}
282
283static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p,
284 int stride)
285{
286 ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1);
287}
288
289void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel);
290
291struct ipu_rgb {
292 struct fb_bitfield red;
293 struct fb_bitfield green;
294 struct fb_bitfield blue;
295 struct fb_bitfield transp;
296 int bits_per_pixel;
297};
298
299struct ipu_image {
300 struct v4l2_pix_format pix;
301 struct v4l2_rect rect;
302 dma_addr_t phys;
303}; 308};
304 309
305int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, 310struct ipu_ic;
306 int width); 311int ipu_ic_task_init(struct ipu_ic *ic,
307 312 int in_width, int in_height,
308int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *, 313 int out_width, int out_height,
309 const struct ipu_rgb *rgb); 314 enum ipu_color_space in_cs,
310 315 enum ipu_color_space out_cs);
311static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p, 316int ipu_ic_task_graphics_init(struct ipu_ic *ic,
312 int stride) 317 enum ipu_color_space in_g_cs,
313{ 318 bool galpha_en, u32 galpha,
314 ipu_ch_param_write_field(p, IPU_FIELD_SO, 1); 319 bool colorkey_en, u32 colorkey);
315 ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8); 320void ipu_ic_task_enable(struct ipu_ic *ic);
316 ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1); 321void ipu_ic_task_disable(struct ipu_ic *ic);
317}; 322int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
323 u32 width, u32 height, int burst_size,
324 enum ipu_rotate_mode rot);
325int ipu_ic_enable(struct ipu_ic *ic);
326int ipu_ic_disable(struct ipu_ic *ic);
327struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task);
328void ipu_ic_put(struct ipu_ic *ic);
329void ipu_ic_dump(struct ipu_ic *ic);
318 330
319void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, 331/*
320 int stride, int height); 332 * IPU Sensor Multiple FIFO Controller (SMFC) functions
321void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, 333 */
322 u32 pixel_format); 334struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno);
323void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, 335void ipu_smfc_put(struct ipu_smfc *smfc);
324 u32 pixel_format, int stride, int u_offset, int v_offset); 336int ipu_smfc_enable(struct ipu_smfc *smfc);
325int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat); 337int ipu_smfc_disable(struct ipu_smfc *smfc);
326int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, 338int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id);
327 struct ipu_image *image); 339int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize);
340int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level);
328 341
329enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); 342enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
330enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); 343enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
331 344enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
332static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p, 345int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat);
333 int burstsize) 346bool ipu_pixelformat_is_planar(u32 pixelformat);
334{ 347int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
335 ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1); 348 bool hflip, bool vflip);
336}; 349int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
350 bool hflip, bool vflip);
337 351
338struct ipu_client_platformdata { 352struct ipu_client_platformdata {
339 int csi; 353 int csi;