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 } 598