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 <linux/sizes.h> 16 #include <drm/drm_fourcc.h> 17 #include "ipu-prv.h" 18 19 struct ipu_cpmem_word { 20 u32 data[5]; 21 u32 res[3]; 22 }; 23 24 struct ipu_ch_param { 25 struct ipu_cpmem_word word[2]; 26 }; 27 28 struct ipu_cpmem { 29 struct ipu_ch_param __iomem *base; 30 u32 module; 31 spinlock_t lock; 32 int use_count; 33 struct ipu_soc *ipu; 34 }; 35 36 #define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size)) 37 38 #define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22) 39 #define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22) 40 #define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4) 41 #define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1) 42 #define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1) 43 #define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14) 44 #define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14) 45 46 #define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10) 47 #define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9) 48 #define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13) 49 #define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12) 50 #define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1) 51 #define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1) 52 #define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12) 53 #define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11) 54 #define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10) 55 #define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7) 56 #define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10) 57 #define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1) 58 #define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1) 59 #define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7) 60 #define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1) 61 #define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1) 62 #define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3) 63 #define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2) 64 #define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1) 65 #define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3) 66 #define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2) 67 #define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1) 68 #define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3) 69 #define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1) 70 #define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1) 71 #define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1) 72 #define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1) 73 #define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1) 74 #define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13) 75 #define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12) 76 #define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29) 77 #define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29) 78 #define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20) 79 #define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7) 80 #define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4) 81 #define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1) 82 #define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3) 83 #define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2) 84 #define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7) 85 #define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14) 86 #define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3) 87 #define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3) 88 #define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3) 89 #define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3) 90 #define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5) 91 #define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5) 92 #define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5) 93 #define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5) 94 #define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1) 95 #define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1) 96 #define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1) 97 98 static inline struct ipu_ch_param __iomem * 99 ipu_get_cpmem(struct ipuv3_channel *ch) 100 { 101 struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv; 102 103 return cpmem->base + ch->num; 104 } 105 106 static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v) 107 { 108 struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); 109 u32 bit = (wbs >> 8) % 160; 110 u32 size = wbs & 0xff; 111 u32 word = (wbs >> 8) / 160; 112 u32 i = bit / 32; 113 u32 ofs = bit % 32; 114 u32 mask = (1 << size) - 1; 115 u32 val; 116 117 pr_debug("%s %d %d %d\n", __func__, word, bit , size); 118 119 val = readl(&base->word[word].data[i]); 120 val &= ~(mask << ofs); 121 val |= v << ofs; 122 writel(val, &base->word[word].data[i]); 123 124 if ((bit + size - 1) / 32 > i) { 125 val = readl(&base->word[word].data[i + 1]); 126 val &= ~(mask >> (ofs ? (32 - ofs) : 0)); 127 val |= v >> (ofs ? (32 - ofs) : 0); 128 writel(val, &base->word[word].data[i + 1]); 129 } 130 } 131 132 static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs) 133 { 134 struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); 135 u32 bit = (wbs >> 8) % 160; 136 u32 size = wbs & 0xff; 137 u32 word = (wbs >> 8) / 160; 138 u32 i = bit / 32; 139 u32 ofs = bit % 32; 140 u32 mask = (1 << size) - 1; 141 u32 val = 0; 142 143 pr_debug("%s %d %d %d\n", __func__, word, bit , size); 144 145 val = (readl(&base->word[word].data[i]) >> ofs) & mask; 146 147 if ((bit + size - 1) / 32 > i) { 148 u32 tmp; 149 150 tmp = readl(&base->word[word].data[i + 1]); 151 tmp &= mask >> (ofs ? (32 - ofs) : 0); 152 val |= tmp << (ofs ? (32 - ofs) : 0); 153 } 154 155 return val; 156 } 157 158 /* 159 * The V4L2 spec defines packed RGB formats in memory byte order, which from 160 * point of view of the IPU corresponds to little-endian words with the first 161 * component in the least significant bits. 162 * The DRM pixel formats and IPU internal representation are ordered the other 163 * way around, with the first named component ordered at the most significant 164 * bits. Further, V4L2 formats are not well defined: 165 * https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html 166 * We choose the interpretation which matches GStreamer behavior. 167 */ 168 static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) 169 { 170 switch (pixelformat) { 171 case V4L2_PIX_FMT_RGB565: 172 /* 173 * Here we choose the 'corrected' interpretation of RGBP, a 174 * little-endian 16-bit word with the red component at the most 175 * significant bits: 176 * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B 177 */ 178 return DRM_FORMAT_RGB565; 179 case V4L2_PIX_FMT_BGR24: 180 /* B G R <=> [24:0] R:G:B */ 181 return DRM_FORMAT_RGB888; 182 case V4L2_PIX_FMT_RGB24: 183 /* R G B <=> [24:0] B:G:R */ 184 return DRM_FORMAT_BGR888; 185 case V4L2_PIX_FMT_BGR32: 186 /* B G R A <=> [32:0] A:B:G:R */ 187 return DRM_FORMAT_XRGB8888; 188 case V4L2_PIX_FMT_RGB32: 189 /* R G B A <=> [32:0] A:B:G:R */ 190 return DRM_FORMAT_XBGR8888; 191 case V4L2_PIX_FMT_XBGR32: 192 /* B G R X <=> [32:0] X:R:G:B */ 193 return DRM_FORMAT_XRGB8888; 194 case V4L2_PIX_FMT_XRGB32: 195 /* X R G B <=> [32:0] B:G:R:X */ 196 return DRM_FORMAT_BGRX8888; 197 case V4L2_PIX_FMT_UYVY: 198 return DRM_FORMAT_UYVY; 199 case V4L2_PIX_FMT_YUYV: 200 return DRM_FORMAT_YUYV; 201 case V4L2_PIX_FMT_YUV420: 202 return DRM_FORMAT_YUV420; 203 case V4L2_PIX_FMT_YUV422P: 204 return DRM_FORMAT_YUV422; 205 case V4L2_PIX_FMT_YVU420: 206 return DRM_FORMAT_YVU420; 207 case V4L2_PIX_FMT_NV12: 208 return DRM_FORMAT_NV12; 209 case V4L2_PIX_FMT_NV16: 210 return DRM_FORMAT_NV16; 211 } 212 213 return -EINVAL; 214 } 215 216 void ipu_cpmem_zero(struct ipuv3_channel *ch) 217 { 218 struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch); 219 void __iomem *base = p; 220 int i; 221 222 for (i = 0; i < sizeof(*p) / sizeof(u32); i++) 223 writel(0, base + i * sizeof(u32)); 224 } 225 EXPORT_SYMBOL_GPL(ipu_cpmem_zero); 226 227 void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres) 228 { 229 ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1); 230 ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1); 231 } 232 EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution); 233 234 void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch) 235 { 236 ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1); 237 } 238 EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows); 239 240 void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride) 241 { 242 ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1); 243 } 244 EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride); 245 246 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch) 247 { 248 struct ipu_soc *ipu = ch->ipu; 249 u32 val; 250 251 if (ipu->ipu_type == IPUV3EX) 252 ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1); 253 254 val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num)); 255 val |= 1 << (ch->num % 32); 256 ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num)); 257 }; 258 EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); 259 260 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf) 261 { 262 WARN_ON_ONCE(buf & 0x7); 263 264 if (bufnum) 265 ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3); 266 else 267 ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3); 268 } 269 EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer); 270 271 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off) 272 { 273 WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7)); 274 275 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8); 276 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8); 277 } 278 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset); 279 280 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride) 281 { 282 u32 ilo, sly; 283 284 if (stride < 0) { 285 stride = -stride; 286 ilo = 0x100000 - (stride / 8); 287 } else { 288 ilo = stride / 8; 289 } 290 291 sly = (stride * 2) - 1; 292 293 ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1); 294 ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo); 295 ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly); 296 }; 297 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan); 298 299 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id) 300 { 301 id &= 0x3; 302 ipu_ch_param_write_field(ch, IPU_FIELD_ID, id); 303 } 304 EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id); 305 306 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch) 307 { 308 return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1; 309 } 310 EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize); 311 312 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize) 313 { 314 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1); 315 }; 316 EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize); 317 318 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch) 319 { 320 ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1); 321 } 322 EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode); 323 324 void ipu_cpmem_set_rotation(struct ipuv3_channel *ch, 325 enum ipu_rotate_mode rot) 326 { 327 u32 temp_rot = bitrev8(rot) >> 5; 328 329 ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot); 330 } 331 EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation); 332 333 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch, 334 const struct ipu_rgb *rgb) 335 { 336 int bpp = 0, npb = 0, ro, go, bo, to; 337 338 ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; 339 go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; 340 bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; 341 to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; 342 343 ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1); 344 ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro); 345 ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1); 346 ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go); 347 ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1); 348 ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo); 349 350 if (rgb->transp.length) { 351 ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 352 rgb->transp.length - 1); 353 ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to); 354 } else { 355 ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7); 356 ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, 357 rgb->bits_per_pixel); 358 } 359 360 switch (rgb->bits_per_pixel) { 361 case 32: 362 bpp = 0; 363 npb = 15; 364 break; 365 case 24: 366 bpp = 1; 367 npb = 19; 368 break; 369 case 16: 370 bpp = 3; 371 npb = 31; 372 break; 373 case 8: 374 bpp = 5; 375 npb = 63; 376 break; 377 default: 378 return -EINVAL; 379 } 380 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); 381 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); 382 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */ 383 384 return 0; 385 } 386 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); 387 388 int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width) 389 { 390 int bpp = 0, npb = 0; 391 392 switch (width) { 393 case 32: 394 bpp = 0; 395 npb = 15; 396 break; 397 case 24: 398 bpp = 1; 399 npb = 19; 400 break; 401 case 16: 402 bpp = 3; 403 npb = 31; 404 break; 405 case 8: 406 bpp = 5; 407 npb = 63; 408 break; 409 default: 410 return -EINVAL; 411 } 412 413 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); 414 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); 415 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */ 416 417 return 0; 418 } 419 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); 420 421 void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format) 422 { 423 switch (pixel_format) { 424 case V4L2_PIX_FMT_UYVY: 425 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ 426 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */ 427 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ 428 break; 429 case V4L2_PIX_FMT_YUYV: 430 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ 431 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */ 432 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ 433 break; 434 } 435 } 436 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); 437 438 void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, 439 unsigned int uv_stride, 440 unsigned int u_offset, unsigned int v_offset) 441 { 442 WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7)); 443 444 ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1); 445 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); 446 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); 447 } 448 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); 449 450 static const struct ipu_rgb def_xrgb_32 = { 451 .red = { .offset = 16, .length = 8, }, 452 .green = { .offset = 8, .length = 8, }, 453 .blue = { .offset = 0, .length = 8, }, 454 .transp = { .offset = 24, .length = 8, }, 455 .bits_per_pixel = 32, 456 }; 457 458 static const struct ipu_rgb def_xbgr_32 = { 459 .red = { .offset = 0, .length = 8, }, 460 .green = { .offset = 8, .length = 8, }, 461 .blue = { .offset = 16, .length = 8, }, 462 .transp = { .offset = 24, .length = 8, }, 463 .bits_per_pixel = 32, 464 }; 465 466 static const struct ipu_rgb def_rgbx_32 = { 467 .red = { .offset = 24, .length = 8, }, 468 .green = { .offset = 16, .length = 8, }, 469 .blue = { .offset = 8, .length = 8, }, 470 .transp = { .offset = 0, .length = 8, }, 471 .bits_per_pixel = 32, 472 }; 473 474 static const struct ipu_rgb def_bgrx_32 = { 475 .red = { .offset = 8, .length = 8, }, 476 .green = { .offset = 16, .length = 8, }, 477 .blue = { .offset = 24, .length = 8, }, 478 .transp = { .offset = 0, .length = 8, }, 479 .bits_per_pixel = 32, 480 }; 481 482 static const struct ipu_rgb def_rgb_24 = { 483 .red = { .offset = 16, .length = 8, }, 484 .green = { .offset = 8, .length = 8, }, 485 .blue = { .offset = 0, .length = 8, }, 486 .transp = { .offset = 0, .length = 0, }, 487 .bits_per_pixel = 24, 488 }; 489 490 static const struct ipu_rgb def_bgr_24 = { 491 .red = { .offset = 0, .length = 8, }, 492 .green = { .offset = 8, .length = 8, }, 493 .blue = { .offset = 16, .length = 8, }, 494 .transp = { .offset = 0, .length = 0, }, 495 .bits_per_pixel = 24, 496 }; 497 498 static const struct ipu_rgb def_rgb_16 = { 499 .red = { .offset = 11, .length = 5, }, 500 .green = { .offset = 5, .length = 6, }, 501 .blue = { .offset = 0, .length = 5, }, 502 .transp = { .offset = 0, .length = 0, }, 503 .bits_per_pixel = 16, 504 }; 505 506 static const struct ipu_rgb def_bgr_16 = { 507 .red = { .offset = 0, .length = 5, }, 508 .green = { .offset = 5, .length = 6, }, 509 .blue = { .offset = 11, .length = 5, }, 510 .transp = { .offset = 0, .length = 0, }, 511 .bits_per_pixel = 16, 512 }; 513 514 static const struct ipu_rgb def_argb_16 = { 515 .red = { .offset = 10, .length = 5, }, 516 .green = { .offset = 5, .length = 5, }, 517 .blue = { .offset = 0, .length = 5, }, 518 .transp = { .offset = 15, .length = 1, }, 519 .bits_per_pixel = 16, 520 }; 521 522 static const struct ipu_rgb def_argb_16_4444 = { 523 .red = { .offset = 8, .length = 4, }, 524 .green = { .offset = 4, .length = 4, }, 525 .blue = { .offset = 0, .length = 4, }, 526 .transp = { .offset = 12, .length = 4, }, 527 .bits_per_pixel = 16, 528 }; 529 530 static const struct ipu_rgb def_abgr_16 = { 531 .red = { .offset = 0, .length = 5, }, 532 .green = { .offset = 5, .length = 5, }, 533 .blue = { .offset = 10, .length = 5, }, 534 .transp = { .offset = 15, .length = 1, }, 535 .bits_per_pixel = 16, 536 }; 537 538 static const struct ipu_rgb def_rgba_16 = { 539 .red = { .offset = 11, .length = 5, }, 540 .green = { .offset = 6, .length = 5, }, 541 .blue = { .offset = 1, .length = 5, }, 542 .transp = { .offset = 0, .length = 1, }, 543 .bits_per_pixel = 16, 544 }; 545 546 static const struct ipu_rgb def_bgra_16 = { 547 .red = { .offset = 1, .length = 5, }, 548 .green = { .offset = 6, .length = 5, }, 549 .blue = { .offset = 11, .length = 5, }, 550 .transp = { .offset = 0, .length = 1, }, 551 .bits_per_pixel = 16, 552 }; 553 554 #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) 555 #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ 556 (pix->width * ((y) / 2) / 2) + (x) / 2) 557 #define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ 558 (pix->width * pix->height / 4) + \ 559 (pix->width * ((y) / 2) / 2) + (x) / 2) 560 #define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ 561 (pix->width * (y) / 2) + (x) / 2) 562 #define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ 563 (pix->width * pix->height / 2) + \ 564 (pix->width * (y) / 2) + (x) / 2) 565 #define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \ 566 (pix->width * ((y) / 2)) + (x)) 567 #define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ 568 (pix->width * y) + (x)) 569 570 #define NUM_ALPHA_CHANNELS 7 571 572 /* See Table 37-12. Alpha channels mapping. */ 573 static int ipu_channel_albm(int ch_num) 574 { 575 switch (ch_num) { 576 case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: return 0; 577 case IPUV3_CHANNEL_G_MEM_IC_PP: return 1; 578 case IPUV3_CHANNEL_MEM_FG_SYNC: return 2; 579 case IPUV3_CHANNEL_MEM_FG_ASYNC: return 3; 580 case IPUV3_CHANNEL_MEM_BG_SYNC: return 4; 581 case IPUV3_CHANNEL_MEM_BG_ASYNC: return 5; 582 case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6; 583 default: 584 return -EINVAL; 585 } 586 } 587 588 static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch) 589 { 590 struct ipu_soc *ipu = ch->ipu; 591 int albm; 592 u32 val; 593 594 albm = ipu_channel_albm(ch->num); 595 if (albm < 0) 596 return; 597 598 ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1); 599 ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm); 600 ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1); 601 602 val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA); 603 val |= BIT(ch->num); 604 ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA); 605 } 606 607 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) 608 { 609 switch (drm_fourcc) { 610 case DRM_FORMAT_YUV420: 611 case DRM_FORMAT_YVU420: 612 /* pix format */ 613 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2); 614 /* burst size */ 615 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); 616 break; 617 case DRM_FORMAT_YUV422: 618 case DRM_FORMAT_YVU422: 619 /* pix format */ 620 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1); 621 /* burst size */ 622 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); 623 break; 624 case DRM_FORMAT_YUV444: 625 case DRM_FORMAT_YVU444: 626 /* pix format */ 627 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0); 628 /* burst size */ 629 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); 630 break; 631 case DRM_FORMAT_NV12: 632 /* pix format */ 633 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4); 634 /* burst size */ 635 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); 636 break; 637 case DRM_FORMAT_NV16: 638 /* pix format */ 639 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3); 640 /* burst size */ 641 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); 642 break; 643 case DRM_FORMAT_UYVY: 644 /* bits/pixel */ 645 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); 646 /* pix format */ 647 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA); 648 /* burst size */ 649 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); 650 break; 651 case DRM_FORMAT_YUYV: 652 /* bits/pixel */ 653 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); 654 /* pix format */ 655 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8); 656 /* burst size */ 657 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); 658 break; 659 case DRM_FORMAT_ABGR8888: 660 case DRM_FORMAT_XBGR8888: 661 ipu_cpmem_set_format_rgb(ch, &def_xbgr_32); 662 break; 663 case DRM_FORMAT_ARGB8888: 664 case DRM_FORMAT_XRGB8888: 665 ipu_cpmem_set_format_rgb(ch, &def_xrgb_32); 666 break; 667 case DRM_FORMAT_RGBA8888: 668 case DRM_FORMAT_RGBX8888: 669 case DRM_FORMAT_RGBX8888_A8: 670 ipu_cpmem_set_format_rgb(ch, &def_rgbx_32); 671 break; 672 case DRM_FORMAT_BGRA8888: 673 case DRM_FORMAT_BGRX8888: 674 case DRM_FORMAT_BGRX8888_A8: 675 ipu_cpmem_set_format_rgb(ch, &def_bgrx_32); 676 break; 677 case DRM_FORMAT_BGR888: 678 case DRM_FORMAT_BGR888_A8: 679 ipu_cpmem_set_format_rgb(ch, &def_bgr_24); 680 break; 681 case DRM_FORMAT_RGB888: 682 case DRM_FORMAT_RGB888_A8: 683 ipu_cpmem_set_format_rgb(ch, &def_rgb_24); 684 break; 685 case DRM_FORMAT_RGB565: 686 case DRM_FORMAT_RGB565_A8: 687 ipu_cpmem_set_format_rgb(ch, &def_rgb_16); 688 break; 689 case DRM_FORMAT_BGR565: 690 case DRM_FORMAT_BGR565_A8: 691 ipu_cpmem_set_format_rgb(ch, &def_bgr_16); 692 break; 693 case DRM_FORMAT_ARGB1555: 694 ipu_cpmem_set_format_rgb(ch, &def_argb_16); 695 break; 696 case DRM_FORMAT_ABGR1555: 697 ipu_cpmem_set_format_rgb(ch, &def_abgr_16); 698 break; 699 case DRM_FORMAT_RGBA5551: 700 ipu_cpmem_set_format_rgb(ch, &def_rgba_16); 701 break; 702 case DRM_FORMAT_BGRA5551: 703 ipu_cpmem_set_format_rgb(ch, &def_bgra_16); 704 break; 705 case DRM_FORMAT_ARGB4444: 706 ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444); 707 break; 708 default: 709 return -EINVAL; 710 } 711 712 switch (drm_fourcc) { 713 case DRM_FORMAT_RGB565_A8: 714 case DRM_FORMAT_BGR565_A8: 715 case DRM_FORMAT_RGB888_A8: 716 case DRM_FORMAT_BGR888_A8: 717 case DRM_FORMAT_RGBX8888_A8: 718 case DRM_FORMAT_BGRX8888_A8: 719 ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7); 720 ipu_cpmem_set_separate_alpha(ch); 721 break; 722 default: 723 break; 724 } 725 726 return 0; 727 } 728 EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); 729 730 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) 731 { 732 struct v4l2_pix_format *pix = &image->pix; 733 int offset, u_offset, v_offset; 734 int ret = 0; 735 736 pr_debug("%s: resolution: %dx%d stride: %d\n", 737 __func__, pix->width, pix->height, 738 pix->bytesperline); 739 740 ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height); 741 ipu_cpmem_set_stride(ch, pix->bytesperline); 742 743 ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); 744 745 switch (pix->pixelformat) { 746 case V4L2_PIX_FMT_YUV420: 747 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 748 u_offset = image->u_offset ? 749 image->u_offset : U_OFFSET(pix, image->rect.left, 750 image->rect.top) - offset; 751 v_offset = image->v_offset ? 752 image->v_offset : V_OFFSET(pix, image->rect.left, 753 image->rect.top) - offset; 754 755 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, 756 u_offset, v_offset); 757 break; 758 case V4L2_PIX_FMT_YVU420: 759 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 760 u_offset = image->u_offset ? 761 image->u_offset : V_OFFSET(pix, image->rect.left, 762 image->rect.top) - offset; 763 v_offset = image->v_offset ? 764 image->v_offset : U_OFFSET(pix, image->rect.left, 765 image->rect.top) - offset; 766 767 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, 768 u_offset, v_offset); 769 break; 770 case V4L2_PIX_FMT_YUV422P: 771 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 772 u_offset = image->u_offset ? 773 image->u_offset : U2_OFFSET(pix, image->rect.left, 774 image->rect.top) - offset; 775 v_offset = image->v_offset ? 776 image->v_offset : V2_OFFSET(pix, image->rect.left, 777 image->rect.top) - offset; 778 779 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, 780 u_offset, v_offset); 781 break; 782 case V4L2_PIX_FMT_NV12: 783 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 784 u_offset = image->u_offset ? 785 image->u_offset : UV_OFFSET(pix, image->rect.left, 786 image->rect.top) - offset; 787 v_offset = image->v_offset ? image->v_offset : 0; 788 789 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline, 790 u_offset, v_offset); 791 break; 792 case V4L2_PIX_FMT_NV16: 793 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 794 u_offset = image->u_offset ? 795 image->u_offset : UV2_OFFSET(pix, image->rect.left, 796 image->rect.top) - offset; 797 v_offset = image->v_offset ? image->v_offset : 0; 798 799 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline, 800 u_offset, v_offset); 801 break; 802 case V4L2_PIX_FMT_UYVY: 803 case V4L2_PIX_FMT_YUYV: 804 case V4L2_PIX_FMT_RGB565: 805 offset = image->rect.left * 2 + 806 image->rect.top * pix->bytesperline; 807 break; 808 case V4L2_PIX_FMT_RGB32: 809 case V4L2_PIX_FMT_BGR32: 810 case V4L2_PIX_FMT_XRGB32: 811 case V4L2_PIX_FMT_XBGR32: 812 offset = image->rect.left * 4 + 813 image->rect.top * pix->bytesperline; 814 break; 815 case V4L2_PIX_FMT_RGB24: 816 case V4L2_PIX_FMT_BGR24: 817 offset = image->rect.left * 3 + 818 image->rect.top * pix->bytesperline; 819 break; 820 case V4L2_PIX_FMT_SBGGR8: 821 case V4L2_PIX_FMT_SGBRG8: 822 case V4L2_PIX_FMT_SGRBG8: 823 case V4L2_PIX_FMT_SRGGB8: 824 case V4L2_PIX_FMT_GREY: 825 offset = image->rect.left + image->rect.top * pix->bytesperline; 826 break; 827 case V4L2_PIX_FMT_SBGGR16: 828 case V4L2_PIX_FMT_SGBRG16: 829 case V4L2_PIX_FMT_SGRBG16: 830 case V4L2_PIX_FMT_SRGGB16: 831 case V4L2_PIX_FMT_Y16: 832 offset = image->rect.left * 2 + 833 image->rect.top * pix->bytesperline; 834 break; 835 default: 836 /* This should not happen */ 837 WARN_ON(1); 838 offset = 0; 839 ret = -EINVAL; 840 } 841 842 ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); 843 ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); 844 845 return ret; 846 } 847 EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); 848 849 void ipu_cpmem_dump(struct ipuv3_channel *ch) 850 { 851 struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch); 852 struct ipu_soc *ipu = ch->ipu; 853 int chno = ch->num; 854 855 dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno, 856 readl(&p->word[0].data[0]), 857 readl(&p->word[0].data[1]), 858 readl(&p->word[0].data[2]), 859 readl(&p->word[0].data[3]), 860 readl(&p->word[0].data[4])); 861 dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno, 862 readl(&p->word[1].data[0]), 863 readl(&p->word[1].data[1]), 864 readl(&p->word[1].data[2]), 865 readl(&p->word[1].data[3]), 866 readl(&p->word[1].data[4])); 867 dev_dbg(ipu->dev, "PFS 0x%x, ", 868 ipu_ch_param_read_field(ch, IPU_FIELD_PFS)); 869 dev_dbg(ipu->dev, "BPP 0x%x, ", 870 ipu_ch_param_read_field(ch, IPU_FIELD_BPP)); 871 dev_dbg(ipu->dev, "NPB 0x%x\n", 872 ipu_ch_param_read_field(ch, IPU_FIELD_NPB)); 873 874 dev_dbg(ipu->dev, "FW %d, ", 875 ipu_ch_param_read_field(ch, IPU_FIELD_FW)); 876 dev_dbg(ipu->dev, "FH %d, ", 877 ipu_ch_param_read_field(ch, IPU_FIELD_FH)); 878 dev_dbg(ipu->dev, "EBA0 0x%x\n", 879 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3); 880 dev_dbg(ipu->dev, "EBA1 0x%x\n", 881 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3); 882 dev_dbg(ipu->dev, "Stride %d\n", 883 ipu_ch_param_read_field(ch, IPU_FIELD_SL)); 884 dev_dbg(ipu->dev, "scan_order %d\n", 885 ipu_ch_param_read_field(ch, IPU_FIELD_SO)); 886 dev_dbg(ipu->dev, "uv_stride %d\n", 887 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV)); 888 dev_dbg(ipu->dev, "u_offset 0x%x\n", 889 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3); 890 dev_dbg(ipu->dev, "v_offset 0x%x\n", 891 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3); 892 893 dev_dbg(ipu->dev, "Width0 %d+1, ", 894 ipu_ch_param_read_field(ch, IPU_FIELD_WID0)); 895 dev_dbg(ipu->dev, "Width1 %d+1, ", 896 ipu_ch_param_read_field(ch, IPU_FIELD_WID1)); 897 dev_dbg(ipu->dev, "Width2 %d+1, ", 898 ipu_ch_param_read_field(ch, IPU_FIELD_WID2)); 899 dev_dbg(ipu->dev, "Width3 %d+1, ", 900 ipu_ch_param_read_field(ch, IPU_FIELD_WID3)); 901 dev_dbg(ipu->dev, "Offset0 %d, ", 902 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0)); 903 dev_dbg(ipu->dev, "Offset1 %d, ", 904 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1)); 905 dev_dbg(ipu->dev, "Offset2 %d, ", 906 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2)); 907 dev_dbg(ipu->dev, "Offset3 %d\n", 908 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3)); 909 } 910 EXPORT_SYMBOL_GPL(ipu_cpmem_dump); 911 912 int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base) 913 { 914 struct ipu_cpmem *cpmem; 915 916 cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL); 917 if (!cpmem) 918 return -ENOMEM; 919 920 ipu->cpmem_priv = cpmem; 921 922 spin_lock_init(&cpmem->lock); 923 cpmem->base = devm_ioremap(dev, base, SZ_128K); 924 if (!cpmem->base) 925 return -ENOMEM; 926 927 dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n", 928 base, cpmem->base); 929 cpmem->ipu = ipu; 930 931 return 0; 932 } 933 934 void ipu_cpmem_exit(struct ipu_soc *ipu) 935 { 936 } 937