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