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 *     http://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                                   u32 pixel_format, int stride,
 399                                   int u_offset, int v_offset)
 400{
 401        switch (pixel_format) {
 402        case V4L2_PIX_FMT_YUV420:
 403        case V4L2_PIX_FMT_YUV422P:
 404                ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
 405                ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
 406                ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
 407                break;
 408        case V4L2_PIX_FMT_YVU420:
 409                ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
 410                ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
 411                ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
 412                break;
 413        case V4L2_PIX_FMT_NV12:
 414        case V4L2_PIX_FMT_NV16:
 415                ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1);
 416                ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
 417                ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
 418                break;
 419        }
 420}
 421EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
 422
 423void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
 424                              u32 pixel_format, int stride, int height)
 425{
 426        int u_offset, v_offset;
 427        int uv_stride = 0;
 428
 429        switch (pixel_format) {
 430        case V4L2_PIX_FMT_YUV420:
 431        case V4L2_PIX_FMT_YVU420:
 432                uv_stride = stride / 2;
 433                u_offset = stride * height;
 434                v_offset = u_offset + (uv_stride * height / 2);
 435                ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
 436                                              u_offset, v_offset);
 437                break;
 438        case V4L2_PIX_FMT_YUV422P:
 439                uv_stride = stride / 2;
 440                u_offset = stride * height;
 441                v_offset = u_offset + (uv_stride * height);
 442                ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
 443                                              u_offset, v_offset);
 444                break;
 445        case V4L2_PIX_FMT_NV12:
 446        case V4L2_PIX_FMT_NV16:
 447                u_offset = stride * height;
 448                ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
 449                                              u_offset, 0);
 450                break;
 451        }
 452}
 453EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
 454
 455static const struct ipu_rgb def_rgb_32 = {
 456        .red    = { .offset = 16, .length = 8, },
 457        .green  = { .offset =  8, .length = 8, },
 458        .blue   = { .offset =  0, .length = 8, },
 459        .transp = { .offset = 24, .length = 8, },
 460        .bits_per_pixel = 32,
 461};
 462
 463static const struct ipu_rgb def_bgr_32 = {
 464        .red    = { .offset =  0, .length = 8, },
 465        .green  = { .offset =  8, .length = 8, },
 466        .blue   = { .offset = 16, .length = 8, },
 467        .transp = { .offset = 24, .length = 8, },
 468        .bits_per_pixel = 32,
 469};
 470
 471static const struct ipu_rgb def_rgb_24 = {
 472        .red    = { .offset = 16, .length = 8, },
 473        .green  = { .offset =  8, .length = 8, },
 474        .blue   = { .offset =  0, .length = 8, },
 475        .transp = { .offset =  0, .length = 0, },
 476        .bits_per_pixel = 24,
 477};
 478
 479static const struct ipu_rgb def_bgr_24 = {
 480        .red    = { .offset =  0, .length = 8, },
 481        .green  = { .offset =  8, .length = 8, },
 482        .blue   = { .offset = 16, .length = 8, },
 483        .transp = { .offset =  0, .length = 0, },
 484        .bits_per_pixel = 24,
 485};
 486
 487static const struct ipu_rgb def_rgb_16 = {
 488        .red    = { .offset = 11, .length = 5, },
 489        .green  = { .offset =  5, .length = 6, },
 490        .blue   = { .offset =  0, .length = 5, },
 491        .transp = { .offset =  0, .length = 0, },
 492        .bits_per_pixel = 16,
 493};
 494
 495static const struct ipu_rgb def_bgr_16 = {
 496        .red    = { .offset =  0, .length = 5, },
 497        .green  = { .offset =  5, .length = 6, },
 498        .blue   = { .offset = 11, .length = 5, },
 499        .transp = { .offset =  0, .length = 0, },
 500        .bits_per_pixel = 16,
 501};
 502
 503#define Y_OFFSET(pix, x, y)     ((x) + pix->width * (y))
 504#define U_OFFSET(pix, x, y)     ((pix->width * pix->height) +           \
 505                                 (pix->width * (y) / 4) + (x) / 2)
 506#define V_OFFSET(pix, x, y)     ((pix->width * pix->height) +           \
 507                                 (pix->width * pix->height / 4) +       \
 508                                 (pix->width * (y) / 4) + (x) / 2)
 509#define U2_OFFSET(pix, x, y)    ((pix->width * pix->height) +           \
 510                                 (pix->width * (y) / 2) + (x) / 2)
 511#define V2_OFFSET(pix, x, y)    ((pix->width * pix->height) +           \
 512                                 (pix->width * pix->height / 2) +       \
 513                                 (pix->width * (y) / 2) + (x) / 2)
 514#define UV_OFFSET(pix, x, y)    ((pix->width * pix->height) +   \
 515                                 (pix->width * (y) / 2) + (x))
 516#define UV2_OFFSET(pix, x, y)   ((pix->width * pix->height) +   \
 517                                 (pix->width * y) + (x))
 518
 519int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
 520{
 521        switch (drm_fourcc) {
 522        case DRM_FORMAT_YUV420:
 523        case DRM_FORMAT_YVU420:
 524                /* pix format */
 525                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
 526                /* burst size */
 527                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 528                break;
 529        case DRM_FORMAT_YUV422:
 530        case DRM_FORMAT_YVU422:
 531                /* pix format */
 532                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
 533                /* burst size */
 534                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 535                break;
 536        case DRM_FORMAT_NV12:
 537                /* pix format */
 538                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
 539                /* burst size */
 540                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 541                break;
 542        case DRM_FORMAT_NV16:
 543                /* pix format */
 544                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
 545                /* burst size */
 546                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 547                break;
 548        case DRM_FORMAT_UYVY:
 549                /* bits/pixel */
 550                ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
 551                /* pix format */
 552                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
 553                /* burst size */
 554                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 555                break;
 556        case DRM_FORMAT_YUYV:
 557                /* bits/pixel */
 558                ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
 559                /* pix format */
 560                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
 561                /* burst size */
 562                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 563                break;
 564        case DRM_FORMAT_ABGR8888:
 565        case DRM_FORMAT_XBGR8888:
 566                ipu_cpmem_set_format_rgb(ch, &def_bgr_32);
 567                break;
 568        case DRM_FORMAT_ARGB8888:
 569        case DRM_FORMAT_XRGB8888:
 570                ipu_cpmem_set_format_rgb(ch, &def_rgb_32);
 571                break;
 572        case DRM_FORMAT_BGR888:
 573                ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
 574                break;
 575        case DRM_FORMAT_RGB888:
 576                ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
 577                break;
 578        case DRM_FORMAT_RGB565:
 579                ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
 580                break;
 581        case DRM_FORMAT_BGR565:
 582                ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
 583                break;
 584        default:
 585                return -EINVAL;
 586        }
 587
 588        return 0;
 589}
 590EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
 591
 592int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 593{
 594        struct v4l2_pix_format *pix = &image->pix;
 595        int offset, u_offset, v_offset;
 596
 597        pr_debug("%s: resolution: %dx%d stride: %d\n",
 598                 __func__, pix->width, pix->height,
 599                 pix->bytesperline);
 600
 601        ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
 602        ipu_cpmem_set_stride(ch, pix->bytesperline);
 603
 604        ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
 605
 606        switch (pix->pixelformat) {
 607        case V4L2_PIX_FMT_YUV420:
 608        case V4L2_PIX_FMT_YVU420:
 609                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 610                u_offset = U_OFFSET(pix, image->rect.left,
 611                                    image->rect.top) - offset;
 612                v_offset = V_OFFSET(pix, image->rect.left,
 613                                    image->rect.top) - offset;
 614
 615                ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
 616                                              pix->bytesperline,
 617                                              u_offset, v_offset);
 618                break;
 619        case V4L2_PIX_FMT_YUV422P:
 620                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 621                u_offset = U2_OFFSET(pix, image->rect.left,
 622                                     image->rect.top) - offset;
 623                v_offset = V2_OFFSET(pix, image->rect.left,
 624                                     image->rect.top) - offset;
 625
 626                ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
 627                                              pix->bytesperline,
 628                                              u_offset, v_offset);
 629                break;
 630        case V4L2_PIX_FMT_NV12:
 631                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 632                u_offset = UV_OFFSET(pix, image->rect.left,
 633                                     image->rect.top) - offset;
 634                v_offset = 0;
 635
 636                ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
 637                                              pix->bytesperline,
 638                                              u_offset, v_offset);
 639                break;
 640        case V4L2_PIX_FMT_NV16:
 641                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 642                u_offset = UV2_OFFSET(pix, image->rect.left,
 643                                      image->rect.top) - offset;
 644                v_offset = 0;
 645
 646                ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
 647                                              pix->bytesperline,
 648                                              u_offset, v_offset);
 649                break;
 650        case V4L2_PIX_FMT_UYVY:
 651        case V4L2_PIX_FMT_YUYV:
 652        case V4L2_PIX_FMT_RGB565:
 653                offset = image->rect.left * 2 +
 654                        image->rect.top * pix->bytesperline;
 655                break;
 656        case V4L2_PIX_FMT_RGB32:
 657        case V4L2_PIX_FMT_BGR32:
 658                offset = image->rect.left * 4 +
 659                        image->rect.top * pix->bytesperline;
 660                break;
 661        case V4L2_PIX_FMT_RGB24:
 662        case V4L2_PIX_FMT_BGR24:
 663                offset = image->rect.left * 3 +
 664                        image->rect.top * pix->bytesperline;
 665                break;
 666        default:
 667                return -EINVAL;
 668        }
 669
 670        ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
 671        ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
 672
 673        return 0;
 674}
 675EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
 676
 677void ipu_cpmem_dump(struct ipuv3_channel *ch)
 678{
 679        struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
 680        struct ipu_soc *ipu = ch->ipu;
 681        int chno = ch->num;
 682
 683        dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
 684                readl(&p->word[0].data[0]),
 685                readl(&p->word[0].data[1]),
 686                readl(&p->word[0].data[2]),
 687                readl(&p->word[0].data[3]),
 688                readl(&p->word[0].data[4]));
 689        dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
 690                readl(&p->word[1].data[0]),
 691                readl(&p->word[1].data[1]),
 692                readl(&p->word[1].data[2]),
 693                readl(&p->word[1].data[3]),
 694                readl(&p->word[1].data[4]));
 695        dev_dbg(ipu->dev, "PFS 0x%x, ",
 696                 ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
 697        dev_dbg(ipu->dev, "BPP 0x%x, ",
 698                ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
 699        dev_dbg(ipu->dev, "NPB 0x%x\n",
 700                 ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
 701
 702        dev_dbg(ipu->dev, "FW %d, ",
 703                 ipu_ch_param_read_field(ch, IPU_FIELD_FW));
 704        dev_dbg(ipu->dev, "FH %d, ",
 705                 ipu_ch_param_read_field(ch, IPU_FIELD_FH));
 706        dev_dbg(ipu->dev, "EBA0 0x%x\n",
 707                 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
 708        dev_dbg(ipu->dev, "EBA1 0x%x\n",
 709                 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
 710        dev_dbg(ipu->dev, "Stride %d\n",
 711                 ipu_ch_param_read_field(ch, IPU_FIELD_SL));
 712        dev_dbg(ipu->dev, "scan_order %d\n",
 713                 ipu_ch_param_read_field(ch, IPU_FIELD_SO));
 714        dev_dbg(ipu->dev, "uv_stride %d\n",
 715                 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
 716        dev_dbg(ipu->dev, "u_offset 0x%x\n",
 717                 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
 718        dev_dbg(ipu->dev, "v_offset 0x%x\n",
 719                 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
 720
 721        dev_dbg(ipu->dev, "Width0 %d+1, ",
 722                 ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
 723        dev_dbg(ipu->dev, "Width1 %d+1, ",
 724                 ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
 725        dev_dbg(ipu->dev, "Width2 %d+1, ",
 726                 ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
 727        dev_dbg(ipu->dev, "Width3 %d+1, ",
 728                 ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
 729        dev_dbg(ipu->dev, "Offset0 %d, ",
 730                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
 731        dev_dbg(ipu->dev, "Offset1 %d, ",
 732                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
 733        dev_dbg(ipu->dev, "Offset2 %d, ",
 734                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
 735        dev_dbg(ipu->dev, "Offset3 %d\n",
 736                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
 737}
 738EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
 739
 740int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
 741{
 742        struct ipu_cpmem *cpmem;
 743
 744        cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
 745        if (!cpmem)
 746                return -ENOMEM;
 747
 748        ipu->cpmem_priv = cpmem;
 749
 750        spin_lock_init(&cpmem->lock);
 751        cpmem->base = devm_ioremap(dev, base, SZ_128K);
 752        if (!cpmem->base)
 753                return -ENOMEM;
 754
 755        dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
 756                base, cpmem->base);
 757        cpmem->ipu = ipu;
 758
 759        return 0;
 760}
 761
 762void ipu_cpmem_exit(struct ipu_soc *ipu)
 763{
 764}
 765