diff options
author | Steve Longerbeam <slongerbeam@gmail.com> | 2014-06-25 21:05:47 -0400 |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2014-08-18 08:17:41 -0400 |
commit | 7d2691da901d71ff62ad974510ea7149b391bdfe (patch) | |
tree | c86091bbb9219ebe50196a2bab3250b0bc869fa2 /drivers/gpu/ipu-v3 | |
parent | 7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (diff) |
gpu: ipu-v3: Add ipu-cpmem unit
Move channel parameter memory setup functions and macros into a new
submodule ipu-cpmem. In the process, cleanup arguments to the functions
to take a channel pointer instead of a pointer into cpmem for that
channel. That allows the structure of the parameter memory to be
private to ipu-cpmem.c.
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Diffstat (limited to 'drivers/gpu/ipu-v3')
-rw-r--r-- | drivers/gpu/ipu-v3/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 457 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-cpmem.c | 597 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prv.h | 14 |
4 files changed, 622 insertions, 449 deletions
diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile index 1887972b4ac2..0b42836caae1 100644 --- a/drivers/gpu/ipu-v3/Makefile +++ b/drivers/gpu/ipu-v3/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o | 1 | obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o |
2 | 2 | ||
3 | imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o ipu-smfc.o | 3 | imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-dc.o ipu-di.o \ |
4 | ipu-dp.o ipu-dmfc.o ipu-smfc.o | ||
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 04e7b2eafbdd..5978e7aab8ed 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,379 +54,6 @@ 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) | ||
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 | { | ||
200 | int bpp = 0, npb = 0; | ||
201 | |||
202 | switch (width) { | ||
203 | case 32: | ||
204 | bpp = 0; | ||
205 | npb = 15; | ||
206 | break; | ||
207 | case 24: | ||
208 | bpp = 1; | ||
209 | npb = 19; | ||
210 | break; | ||
211 | case 16: | ||
212 | bpp = 3; | ||
213 | npb = 31; | ||
214 | break; | ||
215 | case 8: | ||
216 | bpp = 5; | ||
217 | npb = 63; | ||
218 | break; | ||
219 | default: | ||
220 | return -EINVAL; | ||
221 | } | ||
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 | } | ||
229 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); | ||
230 | |||
231 | void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, | ||
232 | u32 pixel_format) | ||
233 | { | ||
234 | switch (pixel_format) { | ||
235 | 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: | ||
241 | ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */ | ||
242 | ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0x8); /* pix format */ | ||
243 | ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */ | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); | ||
248 | |||
249 | void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, | ||
250 | u32 pixel_format, int stride, int u_offset, int v_offset) | ||
251 | { | ||
252 | switch (pixel_format) { | ||
253 | 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: | ||
259 | ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1); | ||
260 | ipu_ch_param_write_field(p, IPU_FIELD_UBO, v_offset / 8); | ||
261 | ipu_ch_param_write_field(p, IPU_FIELD_VBO, u_offset / 8); | ||
262 | break; | ||
263 | } | ||
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 | |||
273 | switch (pixel_format) { | ||
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 | } | ||
284 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_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 | |||
326 | static const struct ipu_rgb def_bgr_16 = { | ||
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 | { | ||
343 | switch (drm_fourcc) { | ||
344 | case DRM_FORMAT_YUV420: | ||
345 | case DRM_FORMAT_YVU420: | ||
346 | /* pix format */ | ||
347 | ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2); | ||
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: | ||
388 | return -EINVAL; | ||
389 | } | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); | ||
394 | |||
395 | /* | ||
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 | { | ||
407 | switch (pixelformat) { | ||
408 | case V4L2_PIX_FMT_RGB565: | ||
409 | /* | ||
410 | * Here we choose the 'corrected' interpretation of RGBP, a | ||
411 | * little-endian 16-bit word with the red component at the most | ||
412 | * significant bits: | ||
413 | * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B | ||
414 | */ | ||
415 | return DRM_FORMAT_RGB565; | ||
416 | 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: | ||
420 | /* R G B <=> [24:0] B:G:R */ | ||
421 | return DRM_FORMAT_BGR888; | ||
422 | 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: | ||
426 | /* R G B A <=> [32:0] A:B:G:R */ | ||
427 | return DRM_FORMAT_XBGR8888; | ||
428 | case V4L2_PIX_FMT_UYVY: | ||
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 | } | ||
437 | |||
438 | return -EINVAL; | ||
439 | } | ||
440 | |||
441 | enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) | 57 | enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) |
442 | { | 58 | { |
443 | switch (drm_fourcc) { | 59 | switch (drm_fourcc) { |
@@ -465,66 +81,6 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) | |||
465 | } | 81 | } |
466 | EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); | 82 | EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); |
467 | 83 | ||
468 | int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, | ||
469 | struct ipu_image *image) | ||
470 | { | ||
471 | struct v4l2_pix_format *pix = &image->pix; | ||
472 | int y_offset, u_offset, v_offset; | ||
473 | |||
474 | pr_debug("%s: resolution: %dx%d stride: %d\n", | ||
475 | __func__, pix->width, pix->height, | ||
476 | pix->bytesperline); | ||
477 | |||
478 | ipu_cpmem_set_resolution(cpmem, image->rect.width, | ||
479 | image->rect.height); | ||
480 | ipu_cpmem_set_stride(cpmem, pix->bytesperline); | ||
481 | |||
482 | ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); | ||
483 | |||
484 | switch (pix->pixelformat) { | ||
485 | case V4L2_PIX_FMT_YUV420: | ||
486 | case V4L2_PIX_FMT_YVU420: | ||
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; | ||
497 | case V4L2_PIX_FMT_UYVY: | ||
498 | case V4L2_PIX_FMT_YUYV: | ||
499 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + | ||
500 | image->rect.left * 2 + | ||
501 | image->rect.top * image->pix.bytesperline); | ||
502 | break; | ||
503 | case V4L2_PIX_FMT_RGB32: | ||
504 | case V4L2_PIX_FMT_BGR32: | ||
505 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + | ||
506 | image->rect.left * 4 + | ||
507 | image->rect.top * image->pix.bytesperline); | ||
508 | break; | ||
509 | case V4L2_PIX_FMT_RGB565: | ||
510 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + | ||
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; | ||
520 | default: | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); | ||
527 | |||
528 | enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) | 84 | enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) |
529 | { | 85 | { |
530 | switch (pixelformat) { | 86 | switch (pixelformat) { |
@@ -895,6 +451,12 @@ static int ipu_submodules_init(struct ipu_soc *ipu, | |||
895 | struct device *dev = &pdev->dev; | 451 | struct device *dev = &pdev->dev; |
896 | const struct ipu_devtype *devtype = ipu->devtype; | 452 | const struct ipu_devtype *devtype = ipu->devtype; |
897 | 453 | ||
454 | ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs); | ||
455 | if (ret) { | ||
456 | unit = "cpmem"; | ||
457 | goto err_cpmem; | ||
458 | } | ||
459 | |||
898 | ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, | 460 | ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, |
899 | IPU_CONF_DI0_EN, ipu_clk); | 461 | IPU_CONF_DI0_EN, ipu_clk); |
900 | if (ret) { | 462 | if (ret) { |
@@ -949,6 +511,8 @@ err_dc: | |||
949 | err_di_1: | 511 | err_di_1: |
950 | ipu_di_exit(ipu, 0); | 512 | ipu_di_exit(ipu, 0); |
951 | err_di_0: | 513 | err_di_0: |
514 | ipu_cpmem_exit(ipu); | ||
515 | err_cpmem: | ||
952 | dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); | 516 | dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); |
953 | return ret; | 517 | return ret; |
954 | } | 518 | } |
@@ -1025,6 +589,7 @@ static void ipu_submodules_exit(struct ipu_soc *ipu) | |||
1025 | ipu_dc_exit(ipu); | 589 | ipu_dc_exit(ipu); |
1026 | ipu_di_exit(ipu, 1); | 590 | ipu_di_exit(ipu, 1); |
1027 | ipu_di_exit(ipu, 0); | 591 | ipu_di_exit(ipu, 0); |
592 | ipu_cpmem_exit(ipu); | ||
1028 | } | 593 | } |
1029 | 594 | ||
1030 | static int platform_remove_devices_fn(struct device *dev, void *unused) | 595 | static int platform_remove_devices_fn(struct device *dev, void *unused) |
@@ -1265,10 +830,8 @@ static int ipu_probe(struct platform_device *pdev) | |||
1265 | ipu->idmac_reg = devm_ioremap(&pdev->dev, | 830 | ipu->idmac_reg = devm_ioremap(&pdev->dev, |
1266 | ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, | 831 | ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, |
1267 | PAGE_SIZE); | 832 | PAGE_SIZE); |
1268 | ipu->cpmem_base = devm_ioremap(&pdev->dev, | ||
1269 | ipu_base + devtype->cpmem_ofs, PAGE_SIZE); | ||
1270 | 833 | ||
1271 | if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) | 834 | if (!ipu->cm_reg || !ipu->idmac_reg) |
1272 | return -ENOMEM; | 835 | return -ENOMEM; |
1273 | 836 | ||
1274 | ipu->clk = devm_clk_get(&pdev->dev, "bus"); | 837 | 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..7adfa78a48bc --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c | |||
@@ -0,0 +1,597 @@ | |||
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 | |||
18 | struct ipu_cpmem_word { | ||
19 | u32 data[5]; | ||
20 | u32 res[3]; | ||
21 | }; | ||
22 | |||
23 | struct ipu_ch_param { | ||
24 | struct ipu_cpmem_word word[2]; | ||
25 | }; | ||
26 | |||
27 | struct 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_HF IPU_CPMEM_WORD(0, 120, 1) | ||
68 | #define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1) | ||
69 | #define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1) | ||
70 | #define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1) | ||
71 | #define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1) | ||
72 | #define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13) | ||
73 | #define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12) | ||
74 | #define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29) | ||
75 | #define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29) | ||
76 | #define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20) | ||
77 | #define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7) | ||
78 | #define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4) | ||
79 | #define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1) | ||
80 | #define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3) | ||
81 | #define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2) | ||
82 | #define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7) | ||
83 | #define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14) | ||
84 | #define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3) | ||
85 | #define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3) | ||
86 | #define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3) | ||
87 | #define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3) | ||
88 | #define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5) | ||
89 | #define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5) | ||
90 | #define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5) | ||
91 | #define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5) | ||
92 | #define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1) | ||
93 | #define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1) | ||
94 | #define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1) | ||
95 | |||
96 | static inline struct ipu_ch_param __iomem * | ||
97 | ipu_get_cpmem(struct ipuv3_channel *ch) | ||
98 | { | ||
99 | struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv; | ||
100 | |||
101 | return cpmem->base + ch->num; | ||
102 | } | ||
103 | |||
104 | static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v) | ||
105 | { | ||
106 | struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); | ||
107 | u32 bit = (wbs >> 8) % 160; | ||
108 | u32 size = wbs & 0xff; | ||
109 | u32 word = (wbs >> 8) / 160; | ||
110 | u32 i = bit / 32; | ||
111 | u32 ofs = bit % 32; | ||
112 | u32 mask = (1 << size) - 1; | ||
113 | u32 val; | ||
114 | |||
115 | pr_debug("%s %d %d %d\n", __func__, word, bit , size); | ||
116 | |||
117 | val = readl(&base->word[word].data[i]); | ||
118 | val &= ~(mask << ofs); | ||
119 | val |= v << ofs; | ||
120 | writel(val, &base->word[word].data[i]); | ||
121 | |||
122 | if ((bit + size - 1) / 32 > i) { | ||
123 | val = readl(&base->word[word].data[i + 1]); | ||
124 | val &= ~(mask >> (ofs ? (32 - ofs) : 0)); | ||
125 | val |= v >> (ofs ? (32 - ofs) : 0); | ||
126 | writel(val, &base->word[word].data[i + 1]); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs) | ||
131 | { | ||
132 | struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); | ||
133 | u32 bit = (wbs >> 8) % 160; | ||
134 | u32 size = wbs & 0xff; | ||
135 | u32 word = (wbs >> 8) / 160; | ||
136 | u32 i = bit / 32; | ||
137 | u32 ofs = bit % 32; | ||
138 | u32 mask = (1 << size) - 1; | ||
139 | u32 val = 0; | ||
140 | |||
141 | pr_debug("%s %d %d %d\n", __func__, word, bit , size); | ||
142 | |||
143 | val = (readl(&base->word[word].data[i]) >> ofs) & mask; | ||
144 | |||
145 | if ((bit + size - 1) / 32 > i) { | ||
146 | u32 tmp; | ||
147 | |||
148 | tmp = readl(&base->word[word].data[i + 1]); | ||
149 | tmp &= mask >> (ofs ? (32 - ofs) : 0); | ||
150 | val |= tmp << (ofs ? (32 - ofs) : 0); | ||
151 | } | ||
152 | |||
153 | return val; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * The V4L2 spec defines packed RGB formats in memory byte order, which from | ||
158 | * point of view of the IPU corresponds to little-endian words with the first | ||
159 | * component in the least significant bits. | ||
160 | * The DRM pixel formats and IPU internal representation are ordered the other | ||
161 | * way around, with the first named component ordered at the most significant | ||
162 | * bits. Further, V4L2 formats are not well defined: | ||
163 | * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html | ||
164 | * We choose the interpretation which matches GStreamer behavior. | ||
165 | */ | ||
166 | static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) | ||
167 | { | ||
168 | switch (pixelformat) { | ||
169 | case V4L2_PIX_FMT_RGB565: | ||
170 | /* | ||
171 | * Here we choose the 'corrected' interpretation of RGBP, a | ||
172 | * little-endian 16-bit word with the red component at the most | ||
173 | * significant bits: | ||
174 | * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B | ||
175 | */ | ||
176 | return DRM_FORMAT_RGB565; | ||
177 | case V4L2_PIX_FMT_BGR24: | ||
178 | /* B G R <=> [24:0] R:G:B */ | ||
179 | return DRM_FORMAT_RGB888; | ||
180 | case V4L2_PIX_FMT_RGB24: | ||
181 | /* R G B <=> [24:0] B:G:R */ | ||
182 | return DRM_FORMAT_BGR888; | ||
183 | case V4L2_PIX_FMT_BGR32: | ||
184 | /* B G R A <=> [32:0] A:B:G:R */ | ||
185 | return DRM_FORMAT_XRGB8888; | ||
186 | case V4L2_PIX_FMT_RGB32: | ||
187 | /* R G B A <=> [32:0] A:B:G:R */ | ||
188 | return DRM_FORMAT_XBGR8888; | ||
189 | case V4L2_PIX_FMT_UYVY: | ||
190 | return DRM_FORMAT_UYVY; | ||
191 | case V4L2_PIX_FMT_YUYV: | ||
192 | return DRM_FORMAT_YUYV; | ||
193 | case V4L2_PIX_FMT_YUV420: | ||
194 | return DRM_FORMAT_YUV420; | ||
195 | case V4L2_PIX_FMT_YVU420: | ||
196 | return DRM_FORMAT_YVU420; | ||
197 | } | ||
198 | |||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | void ipu_cpmem_zero(struct ipuv3_channel *ch) | ||
203 | { | ||
204 | struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch); | ||
205 | void __iomem *base = p; | ||
206 | int i; | ||
207 | |||
208 | for (i = 0; i < sizeof(*p) / sizeof(u32); i++) | ||
209 | writel(0, base + i * sizeof(u32)); | ||
210 | } | ||
211 | EXPORT_SYMBOL_GPL(ipu_cpmem_zero); | ||
212 | |||
213 | void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres) | ||
214 | { | ||
215 | ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1); | ||
216 | ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1); | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution); | ||
219 | |||
220 | void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride) | ||
221 | { | ||
222 | ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1); | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride); | ||
225 | |||
226 | void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch) | ||
227 | { | ||
228 | struct ipu_soc *ipu = ch->ipu; | ||
229 | u32 val; | ||
230 | |||
231 | if (ipu->ipu_type == IPUV3EX) | ||
232 | ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1); | ||
233 | |||
234 | val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num)); | ||
235 | val |= 1 << (ch->num % 32); | ||
236 | ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num)); | ||
237 | }; | ||
238 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); | ||
239 | |||
240 | void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf) | ||
241 | { | ||
242 | if (bufnum) | ||
243 | ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3); | ||
244 | else | ||
245 | ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3); | ||
246 | } | ||
247 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer); | ||
248 | |||
249 | void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride) | ||
250 | { | ||
251 | ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1); | ||
252 | ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8); | ||
253 | ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1); | ||
254 | }; | ||
255 | EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan); | ||
256 | |||
257 | void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize) | ||
258 | { | ||
259 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1); | ||
260 | }; | ||
261 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize); | ||
262 | |||
263 | int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch, | ||
264 | const struct ipu_rgb *rgb) | ||
265 | { | ||
266 | int bpp = 0, npb = 0, ro, go, bo, to; | ||
267 | |||
268 | ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; | ||
269 | go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; | ||
270 | bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; | ||
271 | to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; | ||
272 | |||
273 | ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1); | ||
274 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro); | ||
275 | ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1); | ||
276 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go); | ||
277 | ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1); | ||
278 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo); | ||
279 | |||
280 | if (rgb->transp.length) { | ||
281 | ipu_ch_param_write_field(ch, IPU_FIELD_WID3, | ||
282 | rgb->transp.length - 1); | ||
283 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to); | ||
284 | } else { | ||
285 | ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7); | ||
286 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, | ||
287 | rgb->bits_per_pixel); | ||
288 | } | ||
289 | |||
290 | switch (rgb->bits_per_pixel) { | ||
291 | case 32: | ||
292 | bpp = 0; | ||
293 | npb = 15; | ||
294 | break; | ||
295 | case 24: | ||
296 | bpp = 1; | ||
297 | npb = 19; | ||
298 | break; | ||
299 | case 16: | ||
300 | bpp = 3; | ||
301 | npb = 31; | ||
302 | break; | ||
303 | case 8: | ||
304 | bpp = 5; | ||
305 | npb = 63; | ||
306 | break; | ||
307 | default: | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); | ||
311 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); | ||
312 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */ | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); | ||
317 | |||
318 | int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width) | ||
319 | { | ||
320 | int bpp = 0, npb = 0; | ||
321 | |||
322 | switch (width) { | ||
323 | case 32: | ||
324 | bpp = 0; | ||
325 | npb = 15; | ||
326 | break; | ||
327 | case 24: | ||
328 | bpp = 1; | ||
329 | npb = 19; | ||
330 | break; | ||
331 | case 16: | ||
332 | bpp = 3; | ||
333 | npb = 31; | ||
334 | break; | ||
335 | case 8: | ||
336 | bpp = 5; | ||
337 | npb = 63; | ||
338 | break; | ||
339 | default: | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | |||
343 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); | ||
344 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); | ||
345 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */ | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); | ||
350 | |||
351 | void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format) | ||
352 | { | ||
353 | switch (pixel_format) { | ||
354 | case V4L2_PIX_FMT_UYVY: | ||
355 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ | ||
356 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */ | ||
357 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ | ||
358 | break; | ||
359 | case V4L2_PIX_FMT_YUYV: | ||
360 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ | ||
361 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */ | ||
362 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ | ||
363 | break; | ||
364 | } | ||
365 | } | ||
366 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); | ||
367 | |||
368 | void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, | ||
369 | u32 pixel_format, int stride, | ||
370 | int u_offset, int v_offset) | ||
371 | { | ||
372 | switch (pixel_format) { | ||
373 | case V4L2_PIX_FMT_YUV420: | ||
374 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); | ||
375 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); | ||
376 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); | ||
377 | break; | ||
378 | case V4L2_PIX_FMT_YVU420: | ||
379 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); | ||
380 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8); | ||
381 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); | ||
386 | |||
387 | void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, | ||
388 | u32 pixel_format, int stride, int height) | ||
389 | { | ||
390 | int u_offset, v_offset; | ||
391 | int uv_stride = 0; | ||
392 | |||
393 | switch (pixel_format) { | ||
394 | case V4L2_PIX_FMT_YUV420: | ||
395 | case V4L2_PIX_FMT_YVU420: | ||
396 | uv_stride = stride / 2; | ||
397 | u_offset = stride * height; | ||
398 | v_offset = u_offset + (uv_stride * height / 2); | ||
399 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, | ||
400 | u_offset, v_offset); | ||
401 | break; | ||
402 | } | ||
403 | } | ||
404 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); | ||
405 | |||
406 | static const struct ipu_rgb def_rgb_32 = { | ||
407 | .red = { .offset = 16, .length = 8, }, | ||
408 | .green = { .offset = 8, .length = 8, }, | ||
409 | .blue = { .offset = 0, .length = 8, }, | ||
410 | .transp = { .offset = 24, .length = 8, }, | ||
411 | .bits_per_pixel = 32, | ||
412 | }; | ||
413 | |||
414 | static const struct ipu_rgb def_bgr_32 = { | ||
415 | .red = { .offset = 0, .length = 8, }, | ||
416 | .green = { .offset = 8, .length = 8, }, | ||
417 | .blue = { .offset = 16, .length = 8, }, | ||
418 | .transp = { .offset = 24, .length = 8, }, | ||
419 | .bits_per_pixel = 32, | ||
420 | }; | ||
421 | |||
422 | static const struct ipu_rgb def_rgb_24 = { | ||
423 | .red = { .offset = 16, .length = 8, }, | ||
424 | .green = { .offset = 8, .length = 8, }, | ||
425 | .blue = { .offset = 0, .length = 8, }, | ||
426 | .transp = { .offset = 0, .length = 0, }, | ||
427 | .bits_per_pixel = 24, | ||
428 | }; | ||
429 | |||
430 | static const struct ipu_rgb def_bgr_24 = { | ||
431 | .red = { .offset = 0, .length = 8, }, | ||
432 | .green = { .offset = 8, .length = 8, }, | ||
433 | .blue = { .offset = 16, .length = 8, }, | ||
434 | .transp = { .offset = 0, .length = 0, }, | ||
435 | .bits_per_pixel = 24, | ||
436 | }; | ||
437 | |||
438 | static const struct ipu_rgb def_rgb_16 = { | ||
439 | .red = { .offset = 11, .length = 5, }, | ||
440 | .green = { .offset = 5, .length = 6, }, | ||
441 | .blue = { .offset = 0, .length = 5, }, | ||
442 | .transp = { .offset = 0, .length = 0, }, | ||
443 | .bits_per_pixel = 16, | ||
444 | }; | ||
445 | |||
446 | static const struct ipu_rgb def_bgr_16 = { | ||
447 | .red = { .offset = 0, .length = 5, }, | ||
448 | .green = { .offset = 5, .length = 6, }, | ||
449 | .blue = { .offset = 11, .length = 5, }, | ||
450 | .transp = { .offset = 0, .length = 0, }, | ||
451 | .bits_per_pixel = 16, | ||
452 | }; | ||
453 | |||
454 | #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) | ||
455 | #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
456 | (pix->width * (y) / 4) + (x) / 2) | ||
457 | #define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
458 | (pix->width * pix->height / 4) + \ | ||
459 | (pix->width * (y) / 4) + (x) / 2) | ||
460 | |||
461 | int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) | ||
462 | { | ||
463 | switch (drm_fourcc) { | ||
464 | case DRM_FORMAT_YUV420: | ||
465 | case DRM_FORMAT_YVU420: | ||
466 | /* pix format */ | ||
467 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2); | ||
468 | /* burst size */ | ||
469 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
470 | break; | ||
471 | case DRM_FORMAT_UYVY: | ||
472 | /* bits/pixel */ | ||
473 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); | ||
474 | /* pix format */ | ||
475 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA); | ||
476 | /* burst size */ | ||
477 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
478 | break; | ||
479 | case DRM_FORMAT_YUYV: | ||
480 | /* bits/pixel */ | ||
481 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); | ||
482 | /* pix format */ | ||
483 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8); | ||
484 | /* burst size */ | ||
485 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
486 | break; | ||
487 | case DRM_FORMAT_ABGR8888: | ||
488 | case DRM_FORMAT_XBGR8888: | ||
489 | ipu_cpmem_set_format_rgb(ch, &def_bgr_32); | ||
490 | break; | ||
491 | case DRM_FORMAT_ARGB8888: | ||
492 | case DRM_FORMAT_XRGB8888: | ||
493 | ipu_cpmem_set_format_rgb(ch, &def_rgb_32); | ||
494 | break; | ||
495 | case DRM_FORMAT_BGR888: | ||
496 | ipu_cpmem_set_format_rgb(ch, &def_bgr_24); | ||
497 | break; | ||
498 | case DRM_FORMAT_RGB888: | ||
499 | ipu_cpmem_set_format_rgb(ch, &def_rgb_24); | ||
500 | break; | ||
501 | case DRM_FORMAT_RGB565: | ||
502 | ipu_cpmem_set_format_rgb(ch, &def_rgb_16); | ||
503 | break; | ||
504 | case DRM_FORMAT_BGR565: | ||
505 | ipu_cpmem_set_format_rgb(ch, &def_bgr_16); | ||
506 | break; | ||
507 | default: | ||
508 | return -EINVAL; | ||
509 | } | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); | ||
514 | |||
515 | int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) | ||
516 | { | ||
517 | struct v4l2_pix_format *pix = &image->pix; | ||
518 | int y_offset, u_offset, v_offset; | ||
519 | |||
520 | pr_debug("%s: resolution: %dx%d stride: %d\n", | ||
521 | __func__, pix->width, pix->height, | ||
522 | pix->bytesperline); | ||
523 | |||
524 | ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height); | ||
525 | ipu_cpmem_set_stride(ch, pix->bytesperline); | ||
526 | |||
527 | ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); | ||
528 | |||
529 | switch (pix->pixelformat) { | ||
530 | case V4L2_PIX_FMT_YUV420: | ||
531 | case V4L2_PIX_FMT_YVU420: | ||
532 | y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
533 | u_offset = U_OFFSET(pix, image->rect.left, | ||
534 | image->rect.top) - y_offset; | ||
535 | v_offset = V_OFFSET(pix, image->rect.left, | ||
536 | image->rect.top) - y_offset; | ||
537 | |||
538 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
539 | pix->bytesperline, u_offset, v_offset); | ||
540 | ipu_cpmem_set_buffer(ch, 0, image->phys + y_offset); | ||
541 | break; | ||
542 | case V4L2_PIX_FMT_UYVY: | ||
543 | case V4L2_PIX_FMT_YUYV: | ||
544 | ipu_cpmem_set_buffer(ch, 0, image->phys + | ||
545 | image->rect.left * 2 + | ||
546 | image->rect.top * image->pix.bytesperline); | ||
547 | break; | ||
548 | case V4L2_PIX_FMT_RGB32: | ||
549 | case V4L2_PIX_FMT_BGR32: | ||
550 | ipu_cpmem_set_buffer(ch, 0, image->phys + | ||
551 | image->rect.left * 4 + | ||
552 | image->rect.top * image->pix.bytesperline); | ||
553 | break; | ||
554 | case V4L2_PIX_FMT_RGB565: | ||
555 | ipu_cpmem_set_buffer(ch, 0, image->phys + | ||
556 | image->rect.left * 2 + | ||
557 | image->rect.top * image->pix.bytesperline); | ||
558 | break; | ||
559 | case V4L2_PIX_FMT_RGB24: | ||
560 | case V4L2_PIX_FMT_BGR24: | ||
561 | ipu_cpmem_set_buffer(ch, 0, image->phys + | ||
562 | image->rect.left * 3 + | ||
563 | image->rect.top * image->pix.bytesperline); | ||
564 | break; | ||
565 | default: | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); | ||
572 | |||
573 | int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base) | ||
574 | { | ||
575 | struct ipu_cpmem *cpmem; | ||
576 | |||
577 | cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL); | ||
578 | if (!cpmem) | ||
579 | return -ENOMEM; | ||
580 | |||
581 | ipu->cpmem_priv = cpmem; | ||
582 | |||
583 | spin_lock_init(&cpmem->lock); | ||
584 | cpmem->base = devm_ioremap(dev, base, SZ_128K); | ||
585 | if (!cpmem->base) | ||
586 | return -ENOMEM; | ||
587 | |||
588 | dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n", | ||
589 | base, cpmem->base); | ||
590 | cpmem->ipu = ipu; | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | void ipu_cpmem_exit(struct ipu_soc *ipu) | ||
596 | { | ||
597 | } | ||
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index c93f50ec04f7..0a7b2adaba39 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h | |||
@@ -148,6 +148,7 @@ struct ipuv3_channel { | |||
148 | struct ipu_soc *ipu; | 148 | struct ipu_soc *ipu; |
149 | }; | 149 | }; |
150 | 150 | ||
151 | struct ipu_cpmem; | ||
151 | struct ipu_dc_priv; | 152 | struct ipu_dc_priv; |
152 | struct ipu_dmfc_priv; | 153 | struct ipu_dmfc_priv; |
153 | struct ipu_di; | 154 | struct ipu_di; |
@@ -164,7 +165,6 @@ struct ipu_soc { | |||
164 | 165 | ||
165 | void __iomem *cm_reg; | 166 | void __iomem *cm_reg; |
166 | void __iomem *idmac_reg; | 167 | void __iomem *idmac_reg; |
167 | struct ipu_ch_param __iomem *cpmem_base; | ||
168 | 168 | ||
169 | int usecount; | 169 | int usecount; |
170 | 170 | ||
@@ -176,6 +176,7 @@ struct ipu_soc { | |||
176 | int irq_err; | 176 | int irq_err; |
177 | struct irq_domain *domain; | 177 | struct irq_domain *domain; |
178 | 178 | ||
179 | struct ipu_cpmem *cpmem_priv; | ||
179 | struct ipu_dc_priv *dc_priv; | 180 | struct ipu_dc_priv *dc_priv; |
180 | struct ipu_dp_priv *dp_priv; | 181 | struct ipu_dp_priv *dp_priv; |
181 | struct ipu_dmfc_priv *dmfc_priv; | 182 | struct ipu_dmfc_priv *dmfc_priv; |
@@ -183,6 +184,17 @@ struct ipu_soc { | |||
183 | struct ipu_smfc_priv *smfc_priv; | 184 | struct ipu_smfc_priv *smfc_priv; |
184 | }; | 185 | }; |
185 | 186 | ||
187 | static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) | ||
188 | { | ||
189 | return readl(ipu->idmac_reg + offset); | ||
190 | } | ||
191 | |||
192 | static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, | ||
193 | unsigned offset) | ||
194 | { | ||
195 | writel(value, ipu->idmac_reg + offset); | ||
196 | } | ||
197 | |||
186 | void ipu_srm_dp_sync_update(struct ipu_soc *ipu); | 198 | void ipu_srm_dp_sync_update(struct ipu_soc *ipu); |
187 | 199 | ||
188 | int ipu_module_enable(struct ipu_soc *ipu, u32 mask); | 200 | int ipu_module_enable(struct ipu_soc *ipu, u32 mask); |