Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2012 Mentor Graphics Inc.
0004  * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
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  * The V4L2 spec defines packed RGB formats in memory byte order, which from
0154  * point of view of the IPU corresponds to little-endian words with the first
0155  * component in the least significant bits.
0156  * The DRM pixel formats and IPU internal representation are ordered the other
0157  * way around, with the first named component ordered at the most significant
0158  * bits. Further, V4L2 formats are not well defined:
0159  *     https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
0160  * We choose the interpretation which matches GStreamer behavior.
0161  */
0162 static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
0163 {
0164     switch (pixelformat) {
0165     case V4L2_PIX_FMT_RGB565:
0166         /*
0167          * Here we choose the 'corrected' interpretation of RGBP, a
0168          * little-endian 16-bit word with the red component at the most
0169          * significant bits:
0170          * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
0171          */
0172         return DRM_FORMAT_RGB565;
0173     case V4L2_PIX_FMT_BGR24:
0174         /* B G R <=> [24:0] R:G:B */
0175         return DRM_FORMAT_RGB888;
0176     case V4L2_PIX_FMT_RGB24:
0177         /* R G B <=> [24:0] B:G:R */
0178         return DRM_FORMAT_BGR888;
0179     case V4L2_PIX_FMT_BGR32:
0180         /* B G R A <=> [32:0] A:B:G:R */
0181         return DRM_FORMAT_XRGB8888;
0182     case V4L2_PIX_FMT_RGB32:
0183         /* R G B A <=> [32:0] A:B:G:R */
0184         return DRM_FORMAT_XBGR8888;
0185     case V4L2_PIX_FMT_ABGR32:
0186         /* B G R A <=> [32:0] A:R:G:B */
0187         return DRM_FORMAT_ARGB8888;
0188     case V4L2_PIX_FMT_XBGR32:
0189         /* B G R X <=> [32:0] X:R:G:B */
0190         return DRM_FORMAT_XRGB8888;
0191     case V4L2_PIX_FMT_BGRA32:
0192         /* A B G R <=> [32:0] R:G:B:A */
0193         return DRM_FORMAT_RGBA8888;
0194     case V4L2_PIX_FMT_BGRX32:
0195         /* X B G R <=> [32:0] R:G:B:X */
0196         return DRM_FORMAT_RGBX8888;
0197     case V4L2_PIX_FMT_RGBA32:
0198         /* R G B A <=> [32:0] A:B:G:R */
0199         return DRM_FORMAT_ABGR8888;
0200     case V4L2_PIX_FMT_RGBX32:
0201         /* R G B X <=> [32:0] X:B:G:R */
0202         return DRM_FORMAT_XBGR8888;
0203     case V4L2_PIX_FMT_ARGB32:
0204         /* A R G B <=> [32:0] B:G:R:A */
0205         return DRM_FORMAT_BGRA8888;
0206     case V4L2_PIX_FMT_XRGB32:
0207         /* X R G B <=> [32:0] B:G:R:X */
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); /* rgb mode */
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); /* raw mode */
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); /* bits/pixel */
0460         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
0461         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
0462         break;
0463     case V4L2_PIX_FMT_YUYV:
0464         ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
0465         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
0466         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
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 /* See Table 37-12. Alpha channels mapping. */
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         /* pix format */
0647         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
0648         /* burst size */
0649         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0650         break;
0651     case DRM_FORMAT_YUV422:
0652     case DRM_FORMAT_YVU422:
0653         /* pix format */
0654         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
0655         /* burst size */
0656         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0657         break;
0658     case DRM_FORMAT_YUV444:
0659     case DRM_FORMAT_YVU444:
0660         /* pix format */
0661         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
0662         /* burst size */
0663         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0664         break;
0665     case DRM_FORMAT_NV12:
0666         /* pix format */
0667         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
0668         /* burst size */
0669         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0670         break;
0671     case DRM_FORMAT_NV16:
0672         /* pix format */
0673         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
0674         /* burst size */
0675         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0676         break;
0677     case DRM_FORMAT_UYVY:
0678         /* bits/pixel */
0679         ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
0680         /* pix format */
0681         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
0682         /* burst size */
0683         ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
0684         break;
0685     case DRM_FORMAT_YUYV:
0686         /* bits/pixel */
0687         ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
0688         /* pix format */
0689         ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
0690         /* burst size */
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         /* This should not happen */
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 }