0001
0002
0003
0004
0005
0006 #include <linux/types.h>
0007 #include <linux/bitrev.h>
0008 #include <linux/io.h>
0009 #include <linux/sizes.h>
0010 #include <drm/drm_fourcc.h>
0011 #include "ipu-prv.h"
0012
0013 struct ipu_cpmem_word {
0014 u32 data[5];
0015 u32 res[3];
0016 };
0017
0018 struct ipu_ch_param {
0019 struct ipu_cpmem_word word[2];
0020 };
0021
0022 struct ipu_cpmem {
0023 struct ipu_ch_param __iomem *base;
0024 u32 module;
0025 spinlock_t lock;
0026 int use_count;
0027 struct ipu_soc *ipu;
0028 };
0029
0030 #define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
0031
0032 #define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
0033 #define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
0034 #define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
0035 #define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
0036 #define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
0037 #define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
0038 #define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
0039
0040 #define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
0041 #define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
0042 #define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
0043 #define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
0044 #define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
0045 #define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
0046 #define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
0047 #define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
0048 #define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
0049 #define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
0050 #define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
0051 #define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
0052 #define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
0053 #define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
0054 #define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
0055 #define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
0056 #define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
0057 #define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
0058 #define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
0059 #define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
0060 #define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
0061 #define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
0062 #define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3)
0063 #define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
0064 #define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
0065 #define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
0066 #define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
0067 #define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
0068 #define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
0069 #define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
0070 #define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
0071 #define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
0072 #define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
0073 #define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
0074 #define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
0075 #define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
0076 #define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
0077 #define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
0078 #define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
0079 #define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
0080 #define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
0081 #define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
0082 #define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
0083 #define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
0084 #define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
0085 #define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
0086 #define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
0087 #define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
0088 #define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
0089 #define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
0090 #define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
0091
0092 static inline struct ipu_ch_param __iomem *
0093 ipu_get_cpmem(struct ipuv3_channel *ch)
0094 {
0095 struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
0096
0097 return cpmem->base + ch->num;
0098 }
0099
0100 static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
0101 {
0102 struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
0103 u32 bit = (wbs >> 8) % 160;
0104 u32 size = wbs & 0xff;
0105 u32 word = (wbs >> 8) / 160;
0106 u32 i = bit / 32;
0107 u32 ofs = bit % 32;
0108 u32 mask = (1 << size) - 1;
0109 u32 val;
0110
0111 pr_debug("%s %d %d %d\n", __func__, word, bit , size);
0112
0113 val = readl(&base->word[word].data[i]);
0114 val &= ~(mask << ofs);
0115 val |= v << ofs;
0116 writel(val, &base->word[word].data[i]);
0117
0118 if ((bit + size - 1) / 32 > i) {
0119 val = readl(&base->word[word].data[i + 1]);
0120 val &= ~(mask >> (ofs ? (32 - ofs) : 0));
0121 val |= v >> (ofs ? (32 - ofs) : 0);
0122 writel(val, &base->word[word].data[i + 1]);
0123 }
0124 }
0125
0126 static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
0127 {
0128 struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
0129 u32 bit = (wbs >> 8) % 160;
0130 u32 size = wbs & 0xff;
0131 u32 word = (wbs >> 8) / 160;
0132 u32 i = bit / 32;
0133 u32 ofs = bit % 32;
0134 u32 mask = (1 << size) - 1;
0135 u32 val = 0;
0136
0137 pr_debug("%s %d %d %d\n", __func__, word, bit , size);
0138
0139 val = (readl(&base->word[word].data[i]) >> ofs) & mask;
0140
0141 if ((bit + size - 1) / 32 > i) {
0142 u32 tmp;
0143
0144 tmp = readl(&base->word[word].data[i + 1]);
0145 tmp &= mask >> (ofs ? (32 - ofs) : 0);
0146 val |= tmp << (ofs ? (32 - ofs) : 0);
0147 }
0148
0149 return val;
0150 }
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
0163 {
0164 switch (pixelformat) {
0165 case V4L2_PIX_FMT_RGB565:
0166
0167
0168
0169
0170
0171
0172 return DRM_FORMAT_RGB565;
0173 case V4L2_PIX_FMT_BGR24:
0174
0175 return DRM_FORMAT_RGB888;
0176 case V4L2_PIX_FMT_RGB24:
0177
0178 return DRM_FORMAT_BGR888;
0179 case V4L2_PIX_FMT_BGR32:
0180
0181 return DRM_FORMAT_XRGB8888;
0182 case V4L2_PIX_FMT_RGB32:
0183
0184 return DRM_FORMAT_XBGR8888;
0185 case V4L2_PIX_FMT_ABGR32:
0186
0187 return DRM_FORMAT_ARGB8888;
0188 case V4L2_PIX_FMT_XBGR32:
0189
0190 return DRM_FORMAT_XRGB8888;
0191 case V4L2_PIX_FMT_BGRA32:
0192
0193 return DRM_FORMAT_RGBA8888;
0194 case V4L2_PIX_FMT_BGRX32:
0195
0196 return DRM_FORMAT_RGBX8888;
0197 case V4L2_PIX_FMT_RGBA32:
0198
0199 return DRM_FORMAT_ABGR8888;
0200 case V4L2_PIX_FMT_RGBX32:
0201
0202 return DRM_FORMAT_XBGR8888;
0203 case V4L2_PIX_FMT_ARGB32:
0204
0205 return DRM_FORMAT_BGRA8888;
0206 case V4L2_PIX_FMT_XRGB32:
0207
0208 return DRM_FORMAT_BGRX8888;
0209 case V4L2_PIX_FMT_UYVY:
0210 return DRM_FORMAT_UYVY;
0211 case V4L2_PIX_FMT_YUYV:
0212 return DRM_FORMAT_YUYV;
0213 case V4L2_PIX_FMT_YUV420:
0214 return DRM_FORMAT_YUV420;
0215 case V4L2_PIX_FMT_YUV422P:
0216 return DRM_FORMAT_YUV422;
0217 case V4L2_PIX_FMT_YVU420:
0218 return DRM_FORMAT_YVU420;
0219 case V4L2_PIX_FMT_NV12:
0220 return DRM_FORMAT_NV12;
0221 case V4L2_PIX_FMT_NV16:
0222 return DRM_FORMAT_NV16;
0223 }
0224
0225 return -EINVAL;
0226 }
0227
0228 void ipu_cpmem_zero(struct ipuv3_channel *ch)
0229 {
0230 struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
0231 void __iomem *base = p;
0232 int i;
0233
0234 for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
0235 writel(0, base + i * sizeof(u32));
0236 }
0237 EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
0238
0239 void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
0240 {
0241 ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
0242 ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
0243 }
0244 EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
0245
0246 void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
0247 {
0248 ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
0249 }
0250 EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
0251
0252 void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
0253 {
0254 ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
0255 }
0256 EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
0257
0258 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
0259 {
0260 struct ipu_soc *ipu = ch->ipu;
0261 u32 val;
0262
0263 if (ipu->ipu_type == IPUV3EX)
0264 ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
0265
0266 val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
0267 val |= 1 << (ch->num % 32);
0268 ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
0269 };
0270 EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
0271
0272 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
0273 {
0274 WARN_ON_ONCE(buf & 0x7);
0275
0276 if (bufnum)
0277 ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
0278 else
0279 ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
0280 }
0281 EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
0282
0283 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
0284 {
0285 WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
0286
0287 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
0288 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
0289 }
0290 EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
0291
0292 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
0293 u32 pixelformat)
0294 {
0295 u32 ilo, sly, sluv;
0296
0297 if (stride < 0) {
0298 stride = -stride;
0299 ilo = 0x100000 - (stride / 8);
0300 } else {
0301 ilo = stride / 8;
0302 }
0303
0304 sly = (stride * 2) - 1;
0305
0306 switch (pixelformat) {
0307 case V4L2_PIX_FMT_YUV420:
0308 case V4L2_PIX_FMT_YVU420:
0309 sluv = stride / 2 - 1;
0310 break;
0311 case V4L2_PIX_FMT_NV12:
0312 sluv = stride - 1;
0313 break;
0314 case V4L2_PIX_FMT_YUV422P:
0315 sluv = stride - 1;
0316 break;
0317 case V4L2_PIX_FMT_NV16:
0318 sluv = stride * 2 - 1;
0319 break;
0320 default:
0321 sluv = 0;
0322 break;
0323 }
0324
0325 ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
0326 ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
0327 ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
0328 if (sluv)
0329 ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
0330 };
0331 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
0332
0333 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
0334 {
0335 id &= 0x3;
0336 ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
0337 }
0338 EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
0339
0340 int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
0341 {
0342 return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
0343 }
0344 EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
0345
0346 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
0347 {
0348 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
0349 };
0350 EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
0351
0352 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
0353 {
0354 ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
0355 }
0356 EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
0357
0358 void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
0359 enum ipu_rotate_mode rot)
0360 {
0361 u32 temp_rot = bitrev8(rot) >> 5;
0362
0363 ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
0364 }
0365 EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
0366
0367 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
0368 const struct ipu_rgb *rgb)
0369 {
0370 int bpp = 0, npb = 0, ro, go, bo, to;
0371
0372 ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
0373 go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
0374 bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
0375 to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
0376
0377 ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
0378 ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
0379 ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
0380 ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
0381 ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
0382 ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
0383
0384 if (rgb->transp.length) {
0385 ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
0386 rgb->transp.length - 1);
0387 ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
0388 } else {
0389 ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
0390 ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
0391 rgb->bits_per_pixel);
0392 }
0393
0394 switch (rgb->bits_per_pixel) {
0395 case 32:
0396 bpp = 0;
0397 npb = 15;
0398 break;
0399 case 24:
0400 bpp = 1;
0401 npb = 19;
0402 break;
0403 case 16:
0404 bpp = 3;
0405 npb = 31;
0406 break;
0407 case 8:
0408 bpp = 5;
0409 npb = 63;
0410 break;
0411 default:
0412 return -EINVAL;
0413 }
0414 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
0415 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
0416 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7);
0417
0418 return 0;
0419 }
0420 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
0421
0422 int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
0423 {
0424 int bpp = 0, npb = 0;
0425
0426 switch (width) {
0427 case 32:
0428 bpp = 0;
0429 npb = 15;
0430 break;
0431 case 24:
0432 bpp = 1;
0433 npb = 19;
0434 break;
0435 case 16:
0436 bpp = 3;
0437 npb = 31;
0438 break;
0439 case 8:
0440 bpp = 5;
0441 npb = 63;
0442 break;
0443 default:
0444 return -EINVAL;
0445 }
0446
0447 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
0448 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
0449 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6);
0450
0451 return 0;
0452 }
0453 EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
0454
0455 void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
0456 {
0457 switch (pixel_format) {
0458 case V4L2_PIX_FMT_UYVY:
0459 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
0460 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
0461 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0462 break;
0463 case V4L2_PIX_FMT_YUYV:
0464 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
0465 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
0466 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0467 break;
0468 }
0469 }
0470 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
0471
0472 void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
0473 unsigned int uv_stride,
0474 unsigned int u_offset, unsigned int v_offset)
0475 {
0476 WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
0477
0478 ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
0479 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
0480 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
0481 }
0482 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
0483
0484 static const struct ipu_rgb def_xrgb_32 = {
0485 .red = { .offset = 16, .length = 8, },
0486 .green = { .offset = 8, .length = 8, },
0487 .blue = { .offset = 0, .length = 8, },
0488 .transp = { .offset = 24, .length = 8, },
0489 .bits_per_pixel = 32,
0490 };
0491
0492 static const struct ipu_rgb def_xbgr_32 = {
0493 .red = { .offset = 0, .length = 8, },
0494 .green = { .offset = 8, .length = 8, },
0495 .blue = { .offset = 16, .length = 8, },
0496 .transp = { .offset = 24, .length = 8, },
0497 .bits_per_pixel = 32,
0498 };
0499
0500 static const struct ipu_rgb def_rgbx_32 = {
0501 .red = { .offset = 24, .length = 8, },
0502 .green = { .offset = 16, .length = 8, },
0503 .blue = { .offset = 8, .length = 8, },
0504 .transp = { .offset = 0, .length = 8, },
0505 .bits_per_pixel = 32,
0506 };
0507
0508 static const struct ipu_rgb def_bgrx_32 = {
0509 .red = { .offset = 8, .length = 8, },
0510 .green = { .offset = 16, .length = 8, },
0511 .blue = { .offset = 24, .length = 8, },
0512 .transp = { .offset = 0, .length = 8, },
0513 .bits_per_pixel = 32,
0514 };
0515
0516 static const struct ipu_rgb def_rgb_24 = {
0517 .red = { .offset = 16, .length = 8, },
0518 .green = { .offset = 8, .length = 8, },
0519 .blue = { .offset = 0, .length = 8, },
0520 .transp = { .offset = 0, .length = 0, },
0521 .bits_per_pixel = 24,
0522 };
0523
0524 static const struct ipu_rgb def_bgr_24 = {
0525 .red = { .offset = 0, .length = 8, },
0526 .green = { .offset = 8, .length = 8, },
0527 .blue = { .offset = 16, .length = 8, },
0528 .transp = { .offset = 0, .length = 0, },
0529 .bits_per_pixel = 24,
0530 };
0531
0532 static const struct ipu_rgb def_rgb_16 = {
0533 .red = { .offset = 11, .length = 5, },
0534 .green = { .offset = 5, .length = 6, },
0535 .blue = { .offset = 0, .length = 5, },
0536 .transp = { .offset = 0, .length = 0, },
0537 .bits_per_pixel = 16,
0538 };
0539
0540 static const struct ipu_rgb def_bgr_16 = {
0541 .red = { .offset = 0, .length = 5, },
0542 .green = { .offset = 5, .length = 6, },
0543 .blue = { .offset = 11, .length = 5, },
0544 .transp = { .offset = 0, .length = 0, },
0545 .bits_per_pixel = 16,
0546 };
0547
0548 static const struct ipu_rgb def_argb_16 = {
0549 .red = { .offset = 10, .length = 5, },
0550 .green = { .offset = 5, .length = 5, },
0551 .blue = { .offset = 0, .length = 5, },
0552 .transp = { .offset = 15, .length = 1, },
0553 .bits_per_pixel = 16,
0554 };
0555
0556 static const struct ipu_rgb def_argb_16_4444 = {
0557 .red = { .offset = 8, .length = 4, },
0558 .green = { .offset = 4, .length = 4, },
0559 .blue = { .offset = 0, .length = 4, },
0560 .transp = { .offset = 12, .length = 4, },
0561 .bits_per_pixel = 16,
0562 };
0563
0564 static const struct ipu_rgb def_abgr_16 = {
0565 .red = { .offset = 0, .length = 5, },
0566 .green = { .offset = 5, .length = 5, },
0567 .blue = { .offset = 10, .length = 5, },
0568 .transp = { .offset = 15, .length = 1, },
0569 .bits_per_pixel = 16,
0570 };
0571
0572 static const struct ipu_rgb def_rgba_16 = {
0573 .red = { .offset = 11, .length = 5, },
0574 .green = { .offset = 6, .length = 5, },
0575 .blue = { .offset = 1, .length = 5, },
0576 .transp = { .offset = 0, .length = 1, },
0577 .bits_per_pixel = 16,
0578 };
0579
0580 static const struct ipu_rgb def_bgra_16 = {
0581 .red = { .offset = 1, .length = 5, },
0582 .green = { .offset = 6, .length = 5, },
0583 .blue = { .offset = 11, .length = 5, },
0584 .transp = { .offset = 0, .length = 1, },
0585 .bits_per_pixel = 16,
0586 };
0587
0588 #define Y_OFFSET(pix, x, y) ((x) + pix->bytesperline * (y))
0589 #define U_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \
0590 (pix->bytesperline * ((y) / 2) / 2) + (x) / 2)
0591 #define V_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \
0592 (pix->bytesperline * pix->height / 4) + \
0593 (pix->bytesperline * ((y) / 2) / 2) + (x) / 2)
0594 #define U2_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \
0595 (pix->bytesperline * (y) / 2) + (x) / 2)
0596 #define V2_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \
0597 (pix->bytesperline * pix->height / 2) + \
0598 (pix->bytesperline * (y) / 2) + (x) / 2)
0599 #define UV_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \
0600 (pix->bytesperline * ((y) / 2)) + (x))
0601 #define UV2_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \
0602 (pix->bytesperline * y) + (x))
0603
0604 #define NUM_ALPHA_CHANNELS 7
0605
0606
0607 static int ipu_channel_albm(int ch_num)
0608 {
0609 switch (ch_num) {
0610 case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: return 0;
0611 case IPUV3_CHANNEL_G_MEM_IC_PP: return 1;
0612 case IPUV3_CHANNEL_MEM_FG_SYNC: return 2;
0613 case IPUV3_CHANNEL_MEM_FG_ASYNC: return 3;
0614 case IPUV3_CHANNEL_MEM_BG_SYNC: return 4;
0615 case IPUV3_CHANNEL_MEM_BG_ASYNC: return 5;
0616 case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
0617 default:
0618 return -EINVAL;
0619 }
0620 }
0621
0622 static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
0623 {
0624 struct ipu_soc *ipu = ch->ipu;
0625 int albm;
0626 u32 val;
0627
0628 albm = ipu_channel_albm(ch->num);
0629 if (albm < 0)
0630 return;
0631
0632 ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
0633 ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
0634 ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
0635
0636 val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
0637 val |= BIT(ch->num);
0638 ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
0639 }
0640
0641 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
0642 {
0643 switch (drm_fourcc) {
0644 case DRM_FORMAT_YUV420:
0645 case DRM_FORMAT_YVU420:
0646
0647 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
0648
0649 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0650 break;
0651 case DRM_FORMAT_YUV422:
0652 case DRM_FORMAT_YVU422:
0653
0654 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
0655
0656 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0657 break;
0658 case DRM_FORMAT_YUV444:
0659 case DRM_FORMAT_YVU444:
0660
0661 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
0662
0663 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0664 break;
0665 case DRM_FORMAT_NV12:
0666
0667 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
0668
0669 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0670 break;
0671 case DRM_FORMAT_NV16:
0672
0673 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
0674
0675 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0676 break;
0677 case DRM_FORMAT_UYVY:
0678
0679 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
0680
0681 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
0682
0683 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0684 break;
0685 case DRM_FORMAT_YUYV:
0686
0687 ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
0688
0689 ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
0690
0691 ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0692 break;
0693 case DRM_FORMAT_ABGR8888:
0694 case DRM_FORMAT_XBGR8888:
0695 ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
0696 break;
0697 case DRM_FORMAT_ARGB8888:
0698 case DRM_FORMAT_XRGB8888:
0699 ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
0700 break;
0701 case DRM_FORMAT_RGBA8888:
0702 case DRM_FORMAT_RGBX8888:
0703 case DRM_FORMAT_RGBX8888_A8:
0704 ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
0705 break;
0706 case DRM_FORMAT_BGRA8888:
0707 case DRM_FORMAT_BGRX8888:
0708 case DRM_FORMAT_BGRX8888_A8:
0709 ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
0710 break;
0711 case DRM_FORMAT_BGR888:
0712 case DRM_FORMAT_BGR888_A8:
0713 ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
0714 break;
0715 case DRM_FORMAT_RGB888:
0716 case DRM_FORMAT_RGB888_A8:
0717 ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
0718 break;
0719 case DRM_FORMAT_RGB565:
0720 case DRM_FORMAT_RGB565_A8:
0721 ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
0722 break;
0723 case DRM_FORMAT_BGR565:
0724 case DRM_FORMAT_BGR565_A8:
0725 ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
0726 break;
0727 case DRM_FORMAT_ARGB1555:
0728 ipu_cpmem_set_format_rgb(ch, &def_argb_16);
0729 break;
0730 case DRM_FORMAT_ABGR1555:
0731 ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
0732 break;
0733 case DRM_FORMAT_RGBA5551:
0734 ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
0735 break;
0736 case DRM_FORMAT_BGRA5551:
0737 ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
0738 break;
0739 case DRM_FORMAT_ARGB4444:
0740 ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
0741 break;
0742 default:
0743 return -EINVAL;
0744 }
0745
0746 switch (drm_fourcc) {
0747 case DRM_FORMAT_RGB565_A8:
0748 case DRM_FORMAT_BGR565_A8:
0749 case DRM_FORMAT_RGB888_A8:
0750 case DRM_FORMAT_BGR888_A8:
0751 case DRM_FORMAT_RGBX8888_A8:
0752 case DRM_FORMAT_BGRX8888_A8:
0753 ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
0754 ipu_cpmem_set_separate_alpha(ch);
0755 break;
0756 default:
0757 break;
0758 }
0759
0760 return 0;
0761 }
0762 EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
0763
0764 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
0765 {
0766 struct v4l2_pix_format *pix = &image->pix;
0767 int offset, u_offset, v_offset;
0768 int ret = 0;
0769
0770 pr_debug("%s: resolution: %dx%d stride: %d\n",
0771 __func__, pix->width, pix->height,
0772 pix->bytesperline);
0773
0774 ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
0775 ipu_cpmem_set_stride(ch, pix->bytesperline);
0776
0777 ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
0778
0779 switch (pix->pixelformat) {
0780 case V4L2_PIX_FMT_YUV420:
0781 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
0782 u_offset = image->u_offset ?
0783 image->u_offset : U_OFFSET(pix, image->rect.left,
0784 image->rect.top) - offset;
0785 v_offset = image->v_offset ?
0786 image->v_offset : V_OFFSET(pix, image->rect.left,
0787 image->rect.top) - offset;
0788
0789 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
0790 u_offset, v_offset);
0791 break;
0792 case V4L2_PIX_FMT_YVU420:
0793 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
0794 u_offset = image->u_offset ?
0795 image->u_offset : V_OFFSET(pix, image->rect.left,
0796 image->rect.top) - offset;
0797 v_offset = image->v_offset ?
0798 image->v_offset : U_OFFSET(pix, image->rect.left,
0799 image->rect.top) - offset;
0800
0801 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
0802 u_offset, v_offset);
0803 break;
0804 case V4L2_PIX_FMT_YUV422P:
0805 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
0806 u_offset = image->u_offset ?
0807 image->u_offset : U2_OFFSET(pix, image->rect.left,
0808 image->rect.top) - offset;
0809 v_offset = image->v_offset ?
0810 image->v_offset : V2_OFFSET(pix, image->rect.left,
0811 image->rect.top) - offset;
0812
0813 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
0814 u_offset, v_offset);
0815 break;
0816 case V4L2_PIX_FMT_NV12:
0817 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
0818 u_offset = image->u_offset ?
0819 image->u_offset : UV_OFFSET(pix, image->rect.left,
0820 image->rect.top) - offset;
0821 v_offset = image->v_offset ? image->v_offset : 0;
0822
0823 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
0824 u_offset, v_offset);
0825 break;
0826 case V4L2_PIX_FMT_NV16:
0827 offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
0828 u_offset = image->u_offset ?
0829 image->u_offset : UV2_OFFSET(pix, image->rect.left,
0830 image->rect.top) - offset;
0831 v_offset = image->v_offset ? image->v_offset : 0;
0832
0833 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
0834 u_offset, v_offset);
0835 break;
0836 case V4L2_PIX_FMT_UYVY:
0837 case V4L2_PIX_FMT_YUYV:
0838 case V4L2_PIX_FMT_RGB565:
0839 offset = image->rect.left * 2 +
0840 image->rect.top * pix->bytesperline;
0841 break;
0842 case V4L2_PIX_FMT_RGB32:
0843 case V4L2_PIX_FMT_BGR32:
0844 case V4L2_PIX_FMT_ABGR32:
0845 case V4L2_PIX_FMT_XBGR32:
0846 case V4L2_PIX_FMT_BGRA32:
0847 case V4L2_PIX_FMT_BGRX32:
0848 case V4L2_PIX_FMT_RGBA32:
0849 case V4L2_PIX_FMT_RGBX32:
0850 case V4L2_PIX_FMT_ARGB32:
0851 case V4L2_PIX_FMT_XRGB32:
0852 offset = image->rect.left * 4 +
0853 image->rect.top * pix->bytesperline;
0854 break;
0855 case V4L2_PIX_FMT_RGB24:
0856 case V4L2_PIX_FMT_BGR24:
0857 offset = image->rect.left * 3 +
0858 image->rect.top * pix->bytesperline;
0859 break;
0860 case V4L2_PIX_FMT_SBGGR8:
0861 case V4L2_PIX_FMT_SGBRG8:
0862 case V4L2_PIX_FMT_SGRBG8:
0863 case V4L2_PIX_FMT_SRGGB8:
0864 case V4L2_PIX_FMT_GREY:
0865 offset = image->rect.left + image->rect.top * pix->bytesperline;
0866 break;
0867 case V4L2_PIX_FMT_SBGGR16:
0868 case V4L2_PIX_FMT_SGBRG16:
0869 case V4L2_PIX_FMT_SGRBG16:
0870 case V4L2_PIX_FMT_SRGGB16:
0871 case V4L2_PIX_FMT_Y16:
0872 offset = image->rect.left * 2 +
0873 image->rect.top * pix->bytesperline;
0874 break;
0875 default:
0876
0877 WARN_ON(1);
0878 offset = 0;
0879 ret = -EINVAL;
0880 }
0881
0882 ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
0883 ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
0884
0885 return ret;
0886 }
0887 EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
0888
0889 void ipu_cpmem_dump(struct ipuv3_channel *ch)
0890 {
0891 struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
0892 struct ipu_soc *ipu = ch->ipu;
0893 int chno = ch->num;
0894
0895 dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
0896 readl(&p->word[0].data[0]),
0897 readl(&p->word[0].data[1]),
0898 readl(&p->word[0].data[2]),
0899 readl(&p->word[0].data[3]),
0900 readl(&p->word[0].data[4]));
0901 dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
0902 readl(&p->word[1].data[0]),
0903 readl(&p->word[1].data[1]),
0904 readl(&p->word[1].data[2]),
0905 readl(&p->word[1].data[3]),
0906 readl(&p->word[1].data[4]));
0907 dev_dbg(ipu->dev, "PFS 0x%x, ",
0908 ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
0909 dev_dbg(ipu->dev, "BPP 0x%x, ",
0910 ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
0911 dev_dbg(ipu->dev, "NPB 0x%x\n",
0912 ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
0913
0914 dev_dbg(ipu->dev, "FW %d, ",
0915 ipu_ch_param_read_field(ch, IPU_FIELD_FW));
0916 dev_dbg(ipu->dev, "FH %d, ",
0917 ipu_ch_param_read_field(ch, IPU_FIELD_FH));
0918 dev_dbg(ipu->dev, "EBA0 0x%x\n",
0919 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
0920 dev_dbg(ipu->dev, "EBA1 0x%x\n",
0921 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
0922 dev_dbg(ipu->dev, "Stride %d\n",
0923 ipu_ch_param_read_field(ch, IPU_FIELD_SL));
0924 dev_dbg(ipu->dev, "scan_order %d\n",
0925 ipu_ch_param_read_field(ch, IPU_FIELD_SO));
0926 dev_dbg(ipu->dev, "uv_stride %d\n",
0927 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
0928 dev_dbg(ipu->dev, "u_offset 0x%x\n",
0929 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
0930 dev_dbg(ipu->dev, "v_offset 0x%x\n",
0931 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
0932
0933 dev_dbg(ipu->dev, "Width0 %d+1, ",
0934 ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
0935 dev_dbg(ipu->dev, "Width1 %d+1, ",
0936 ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
0937 dev_dbg(ipu->dev, "Width2 %d+1, ",
0938 ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
0939 dev_dbg(ipu->dev, "Width3 %d+1, ",
0940 ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
0941 dev_dbg(ipu->dev, "Offset0 %d, ",
0942 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
0943 dev_dbg(ipu->dev, "Offset1 %d, ",
0944 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
0945 dev_dbg(ipu->dev, "Offset2 %d, ",
0946 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
0947 dev_dbg(ipu->dev, "Offset3 %d\n",
0948 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
0949 }
0950 EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
0951
0952 int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
0953 {
0954 struct ipu_cpmem *cpmem;
0955
0956 cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
0957 if (!cpmem)
0958 return -ENOMEM;
0959
0960 ipu->cpmem_priv = cpmem;
0961
0962 spin_lock_init(&cpmem->lock);
0963 cpmem->base = devm_ioremap(dev, base, SZ_128K);
0964 if (!cpmem->base)
0965 return -ENOMEM;
0966
0967 dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
0968 base, cpmem->base);
0969 cpmem->ipu = ipu;
0970
0971 return 0;
0972 }
0973
0974 void ipu_cpmem_exit(struct ipu_soc *ipu)
0975 {
0976 }