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