diff options
Diffstat (limited to 'drivers/gpu/ipu-v3/ipu-common.c')
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 916 |
1 files changed, 451 insertions, 465 deletions
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 | ||
47 | static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) | ||
48 | { | ||
49 | return readl(ipu->idmac_reg + offset); | ||
50 | } | ||
51 | |||
52 | static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, | ||
53 | unsigned offset) | ||
54 | { | ||
55 | writel(value, ipu->idmac_reg + offset); | ||
56 | } | ||
57 | |||
58 | void ipu_srm_dp_sync_update(struct ipu_soc *ipu) | 47 | void 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 | } |
66 | EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); | 55 | EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); |
67 | 56 | ||
68 | struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel) | 57 | enum 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 | } | ||
74 | EXPORT_SYMBOL_GPL(ipu_get_cpmem); | ||
75 | |||
76 | void 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 | }; | ||
89 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); | ||
90 | |||
91 | void 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 | } | ||
115 | EXPORT_SYMBOL_GPL(ipu_ch_param_write_field); | ||
116 | |||
117 | u32 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 | } | ||
140 | EXPORT_SYMBOL_GPL(ipu_ch_param_read_field); | ||
141 | |||
142 | int 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 | } | ||
195 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); | ||
196 | |||
197 | int 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 | } |
229 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); | 88 | EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); |
230 | 89 | ||
231 | void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, | 90 | enum 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 | } |
247 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); | 113 | EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); |
248 | 114 | ||
249 | void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, | 115 | bool 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 | } | ||
265 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); | ||
266 | |||
267 | void 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 | } |
284 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); | 130 | EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar); |
285 | |||
286 | static 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 | |||
294 | static 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 | |||
302 | static 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 | |||
310 | static 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 | |||
318 | static 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 | ||
326 | static const struct ipu_rgb def_bgr_16 = { | 132 | enum 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 | |||
341 | int 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 | } |
393 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); | 143 | EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace); |
394 | 144 | ||
395 | /* | 145 | int 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 | */ | ||
405 | static 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 | } |
178 | EXPORT_SYMBOL_GPL(ipu_stride_to_bytes); | ||
440 | 179 | ||
441 | enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) | 180 | int 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 | } | ||
466 | EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); | ||
467 | 203 | ||
468 | int 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 | } |
210 | EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode); | ||
477 | 211 | ||
478 | ipu_cpmem_set_resolution(cpmem, image->rect.width, | 212 | int 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 | } |
526 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); | 242 | EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees); |
527 | |||
528 | enum 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 | } | ||
546 | EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); | ||
547 | 243 | ||
548 | struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) | 244 | struct 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 | } |
588 | EXPORT_SYMBOL_GPL(ipu_idmac_put); | 284 | EXPORT_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 | */ | ||
299 | static 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 | ||
592 | void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, | 307 | void 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 | } |
610 | EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer); | 327 | EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer); |
611 | 328 | ||
329 | static 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 | |||
353 | int 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 | } | ||
396 | EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable); | ||
397 | |||
612 | int ipu_module_enable(struct ipu_soc *ipu, u32 mask) | 398 | int 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 | } |
662 | EXPORT_SYMBOL_GPL(ipu_module_disable); | 448 | EXPORT_SYMBOL_GPL(ipu_module_disable); |
663 | 449 | ||
664 | int 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 | } | ||
668 | EXPORT_SYMBOL_GPL(ipu_csi_enable); | ||
669 | |||
670 | int 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 | } | ||
674 | EXPORT_SYMBOL_GPL(ipu_csi_disable); | ||
675 | |||
676 | int ipu_smfc_enable(struct ipu_soc *ipu) | ||
677 | { | ||
678 | return ipu_module_enable(ipu, IPU_CONF_SMFC_EN); | ||
679 | } | ||
680 | EXPORT_SYMBOL_GPL(ipu_smfc_enable); | ||
681 | |||
682 | int ipu_smfc_disable(struct ipu_soc *ipu) | ||
683 | { | ||
684 | return ipu_module_disable(ipu, IPU_CONF_SMFC_EN); | ||
685 | } | ||
686 | EXPORT_SYMBOL_GPL(ipu_smfc_disable); | ||
687 | |||
688 | int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel) | 450 | int 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 | } |
695 | EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer); | 457 | EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer); |
696 | 458 | ||
459 | bool 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 | } | ||
481 | EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready); | ||
482 | |||
697 | void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num) | 483 | void 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 | } |
713 | EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer); | 499 | EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer); |
714 | 500 | ||
501 | void 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 | } | ||
527 | EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer); | ||
528 | |||
715 | int ipu_idmac_enable_channel(struct ipuv3_channel *channel) | 529 | int 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 | } |
811 | EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel); | 627 | EXPORT_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 | */ | ||
635 | void 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 | } | ||
652 | EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark); | ||
653 | |||
813 | static int ipu_memory_reset(struct ipu_soc *ipu) | 654 | static 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 | */ | ||
674 | void 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 | } | ||
693 | EXPORT_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 | */ | ||
698 | void 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 | } | ||
719 | EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux); | ||
720 | |||
829 | struct ipu_devtype { | 721 | struct 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: | |||
949 | err_di_1: | 881 | err_di_1: |
950 | ipu_di_exit(ipu, 0); | 882 | ipu_di_exit(ipu, 0); |
951 | err_di_0: | 883 | err_di_0: |
884 | ipu_ic_exit(ipu); | ||
885 | err_ic: | ||
886 | ipu_csi_exit(ipu, 1); | ||
887 | err_csi_1: | ||
888 | ipu_csi_exit(ipu, 0); | ||
889 | err_csi_0: | ||
890 | ipu_cpmem_exit(ipu); | ||
891 | err_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 | ||
1030 | static int platform_remove_devices_fn(struct device *dev, void *unused) | 974 | static 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 | ||
1148 | void 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 | } | ||
1184 | EXPORT_SYMBOL_GPL(ipu_dump); | ||
1185 | |||
1204 | static int ipu_probe(struct platform_device *pdev) | 1186 | static 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"); |