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