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_XBGR32:
 186                /* B G R X <=> [32:0] X:R:G:B */
 187                return DRM_FORMAT_XRGB8888;
 188        case V4L2_PIX_FMT_XRGB32:
 189                /* X R G B <=> [32:0] B:G:R:X */
 190                return DRM_FORMAT_BGRX8888;
 191        case V4L2_PIX_FMT_UYVY:
 192                return DRM_FORMAT_UYVY;
 193        case V4L2_PIX_FMT_YUYV:
 194                return DRM_FORMAT_YUYV;
 195        case V4L2_PIX_FMT_YUV420:
 196                return DRM_FORMAT_YUV420;
 197        case V4L2_PIX_FMT_YUV422P:
 198                return DRM_FORMAT_YUV422;
 199        case V4L2_PIX_FMT_YVU420:
 200                return DRM_FORMAT_YVU420;
 201        case V4L2_PIX_FMT_NV12:
 202                return DRM_FORMAT_NV12;
 203        case V4L2_PIX_FMT_NV16:
 204                return DRM_FORMAT_NV16;
 205        }
 206
 207        return -EINVAL;
 208}
 209
 210void ipu_cpmem_zero(struct ipuv3_channel *ch)
 211{
 212        struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
 213        void __iomem *base = p;
 214        int i;
 215
 216        for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
 217                writel(0, base + i * sizeof(u32));
 218}
 219EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
 220
 221void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
 222{
 223        ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
 224        ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
 225}
 226EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
 227
 228void ipu_cpmem_skip_odd_chroma_rows(struct ipuv3_channel *ch)
 229{
 230        ipu_ch_param_write_field(ch, IPU_FIELD_RDRW, 1);
 231}
 232EXPORT_SYMBOL_GPL(ipu_cpmem_skip_odd_chroma_rows);
 233
 234void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
 235{
 236        ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
 237}
 238EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
 239
 240void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
 241{
 242        struct ipu_soc *ipu = ch->ipu;
 243        u32 val;
 244
 245        if (ipu->ipu_type == IPUV3EX)
 246                ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
 247
 248        val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
 249        val |= 1 << (ch->num % 32);
 250        ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
 251};
 252EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
 253
 254void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
 255{
 256        WARN_ON_ONCE(buf & 0x7);
 257
 258        if (bufnum)
 259                ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
 260        else
 261                ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
 262}
 263EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
 264
 265void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off)
 266{
 267        WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7));
 268
 269        ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8);
 270        ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8);
 271}
 272EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset);
 273
 274void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride,
 275                               u32 pixelformat)
 276{
 277        u32 ilo, sly, sluv;
 278
 279        if (stride < 0) {
 280                stride = -stride;
 281                ilo = 0x100000 - (stride / 8);
 282        } else {
 283                ilo = stride / 8;
 284        }
 285
 286        sly = (stride * 2) - 1;
 287
 288        switch (pixelformat) {
 289        case V4L2_PIX_FMT_YUV420:
 290        case V4L2_PIX_FMT_YVU420:
 291                sluv = stride / 2 - 1;
 292                break;
 293        case V4L2_PIX_FMT_NV12:
 294                sluv = stride - 1;
 295                break;
 296        case V4L2_PIX_FMT_YUV422P:
 297                sluv = stride - 1;
 298                break;
 299        case V4L2_PIX_FMT_NV16:
 300                sluv = stride * 2 - 1;
 301                break;
 302        default:
 303                sluv = 0;
 304                break;
 305        }
 306
 307        ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
 308        ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo);
 309        ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly);
 310        if (sluv)
 311                ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, sluv);
 312};
 313EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 314
 315void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
 316{
 317        id &= 0x3;
 318        ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
 319}
 320EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
 321
 322int ipu_cpmem_get_burstsize(struct ipuv3_channel *ch)
 323{
 324        return ipu_ch_param_read_field(ch, IPU_FIELD_NPB) + 1;
 325}
 326EXPORT_SYMBOL_GPL(ipu_cpmem_get_burstsize);
 327
 328void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
 329{
 330        ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
 331};
 332EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
 333
 334void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
 335{
 336        ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
 337}
 338EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
 339
 340void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
 341                            enum ipu_rotate_mode rot)
 342{
 343        u32 temp_rot = bitrev8(rot) >> 5;
 344
 345        ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
 346}
 347EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
 348
 349int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
 350                             const struct ipu_rgb *rgb)
 351{
 352        int bpp = 0, npb = 0, ro, go, bo, to;
 353
 354        ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
 355        go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
 356        bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
 357        to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
 358
 359        ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
 360        ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
 361        ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
 362        ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
 363        ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
 364        ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
 365
 366        if (rgb->transp.length) {
 367                ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
 368                                rgb->transp.length - 1);
 369                ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
 370        } else {
 371                ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
 372                ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
 373                                rgb->bits_per_pixel);
 374        }
 375
 376        switch (rgb->bits_per_pixel) {
 377        case 32:
 378                bpp = 0;
 379                npb = 15;
 380                break;
 381        case 24:
 382                bpp = 1;
 383                npb = 19;
 384                break;
 385        case 16:
 386                bpp = 3;
 387                npb = 31;
 388                break;
 389        case 8:
 390                bpp = 5;
 391                npb = 63;
 392                break;
 393        default:
 394                return -EINVAL;
 395        }
 396        ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
 397        ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
 398        ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
 399
 400        return 0;
 401}
 402EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
 403
 404int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
 405{
 406        int bpp = 0, npb = 0;
 407
 408        switch (width) {
 409        case 32:
 410                bpp = 0;
 411                npb = 15;
 412                break;
 413        case 24:
 414                bpp = 1;
 415                npb = 19;
 416                break;
 417        case 16:
 418                bpp = 3;
 419                npb = 31;
 420                break;
 421        case 8:
 422                bpp = 5;
 423                npb = 63;
 424                break;
 425        default:
 426                return -EINVAL;
 427        }
 428
 429        ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
 430        ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
 431        ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
 432
 433        return 0;
 434}
 435EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
 436
 437void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
 438{
 439        switch (pixel_format) {
 440        case V4L2_PIX_FMT_UYVY:
 441                ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
 442                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
 443                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
 444                break;
 445        case V4L2_PIX_FMT_YUYV:
 446                ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
 447                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
 448                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
 449                break;
 450        }
 451}
 452EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
 453
 454void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
 455                                   unsigned int uv_stride,
 456                                   unsigned int u_offset, unsigned int v_offset)
 457{
 458        WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7));
 459
 460        ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1);
 461        ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
 462        ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
 463}
 464EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
 465
 466static const struct ipu_rgb def_xrgb_32 = {
 467        .red    = { .offset = 16, .length = 8, },
 468        .green  = { .offset =  8, .length = 8, },
 469        .blue   = { .offset =  0, .length = 8, },
 470        .transp = { .offset = 24, .length = 8, },
 471        .bits_per_pixel = 32,
 472};
 473
 474static const struct ipu_rgb def_xbgr_32 = {
 475        .red    = { .offset =  0, .length = 8, },
 476        .green  = { .offset =  8, .length = 8, },
 477        .blue   = { .offset = 16, .length = 8, },
 478        .transp = { .offset = 24, .length = 8, },
 479        .bits_per_pixel = 32,
 480};
 481
 482static const struct ipu_rgb def_rgbx_32 = {
 483        .red    = { .offset = 24, .length = 8, },
 484        .green  = { .offset = 16, .length = 8, },
 485        .blue   = { .offset =  8, .length = 8, },
 486        .transp = { .offset =  0, .length = 8, },
 487        .bits_per_pixel = 32,
 488};
 489
 490static const struct ipu_rgb def_bgrx_32 = {
 491        .red    = { .offset =  8, .length = 8, },
 492        .green  = { .offset = 16, .length = 8, },
 493        .blue   = { .offset = 24, .length = 8, },
 494        .transp = { .offset =  0, .length = 8, },
 495        .bits_per_pixel = 32,
 496};
 497
 498static const struct ipu_rgb def_rgb_24 = {
 499        .red    = { .offset = 16, .length = 8, },
 500        .green  = { .offset =  8, .length = 8, },
 501        .blue   = { .offset =  0, .length = 8, },
 502        .transp = { .offset =  0, .length = 0, },
 503        .bits_per_pixel = 24,
 504};
 505
 506static const struct ipu_rgb def_bgr_24 = {
 507        .red    = { .offset =  0, .length = 8, },
 508        .green  = { .offset =  8, .length = 8, },
 509        .blue   = { .offset = 16, .length = 8, },
 510        .transp = { .offset =  0, .length = 0, },
 511        .bits_per_pixel = 24,
 512};
 513
 514static const struct ipu_rgb def_rgb_16 = {
 515        .red    = { .offset = 11, .length = 5, },
 516        .green  = { .offset =  5, .length = 6, },
 517        .blue   = { .offset =  0, .length = 5, },
 518        .transp = { .offset =  0, .length = 0, },
 519        .bits_per_pixel = 16,
 520};
 521
 522static const struct ipu_rgb def_bgr_16 = {
 523        .red    = { .offset =  0, .length = 5, },
 524        .green  = { .offset =  5, .length = 6, },
 525        .blue   = { .offset = 11, .length = 5, },
 526        .transp = { .offset =  0, .length = 0, },
 527        .bits_per_pixel = 16,
 528};
 529
 530static const struct ipu_rgb def_argb_16 = {
 531        .red    = { .offset = 10, .length = 5, },
 532        .green  = { .offset =  5, .length = 5, },
 533        .blue   = { .offset =  0, .length = 5, },
 534        .transp = { .offset = 15, .length = 1, },
 535        .bits_per_pixel = 16,
 536};
 537
 538static const struct ipu_rgb def_argb_16_4444 = {
 539        .red    = { .offset =  8, .length = 4, },
 540        .green  = { .offset =  4, .length = 4, },
 541        .blue   = { .offset =  0, .length = 4, },
 542        .transp = { .offset = 12, .length = 4, },
 543        .bits_per_pixel = 16,
 544};
 545
 546static const struct ipu_rgb def_abgr_16 = {
 547        .red    = { .offset =  0, .length = 5, },
 548        .green  = { .offset =  5, .length = 5, },
 549        .blue   = { .offset = 10, .length = 5, },
 550        .transp = { .offset = 15, .length = 1, },
 551        .bits_per_pixel = 16,
 552};
 553
 554static const struct ipu_rgb def_rgba_16 = {
 555        .red    = { .offset = 11, .length = 5, },
 556        .green  = { .offset =  6, .length = 5, },
 557        .blue   = { .offset =  1, .length = 5, },
 558        .transp = { .offset =  0, .length = 1, },
 559        .bits_per_pixel = 16,
 560};
 561
 562static const struct ipu_rgb def_bgra_16 = {
 563        .red    = { .offset =  1, .length = 5, },
 564        .green  = { .offset =  6, .length = 5, },
 565        .blue   = { .offset = 11, .length = 5, },
 566        .transp = { .offset =  0, .length = 1, },
 567        .bits_per_pixel = 16,
 568};
 569
 570#define Y_OFFSET(pix, x, y)     ((x) + pix->width * (y))
 571#define U_OFFSET(pix, x, y)     ((pix->width * pix->height) +           \
 572                                 (pix->width * ((y) / 2) / 2) + (x) / 2)
 573#define V_OFFSET(pix, x, y)     ((pix->width * pix->height) +           \
 574                                 (pix->width * pix->height / 4) +       \
 575                                 (pix->width * ((y) / 2) / 2) + (x) / 2)
 576#define U2_OFFSET(pix, x, y)    ((pix->width * pix->height) +           \
 577                                 (pix->width * (y) / 2) + (x) / 2)
 578#define V2_OFFSET(pix, x, y)    ((pix->width * pix->height) +           \
 579                                 (pix->width * pix->height / 2) +       \
 580                                 (pix->width * (y) / 2) + (x) / 2)
 581#define UV_OFFSET(pix, x, y)    ((pix->width * pix->height) +   \
 582                                 (pix->width * ((y) / 2)) + (x))
 583#define UV2_OFFSET(pix, x, y)   ((pix->width * pix->height) +   \
 584                                 (pix->width * y) + (x))
 585
 586#define NUM_ALPHA_CHANNELS      7
 587
 588/* See Table 37-12. Alpha channels mapping. */
 589static int ipu_channel_albm(int ch_num)
 590{
 591        switch (ch_num) {
 592        case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:     return 0;
 593        case IPUV3_CHANNEL_G_MEM_IC_PP:         return 1;
 594        case IPUV3_CHANNEL_MEM_FG_SYNC:         return 2;
 595        case IPUV3_CHANNEL_MEM_FG_ASYNC:        return 3;
 596        case IPUV3_CHANNEL_MEM_BG_SYNC:         return 4;
 597        case IPUV3_CHANNEL_MEM_BG_ASYNC:        return 5;
 598        case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
 599        default:
 600                return -EINVAL;
 601        }
 602}
 603
 604static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
 605{
 606        struct ipu_soc *ipu = ch->ipu;
 607        int albm;
 608        u32 val;
 609
 610        albm = ipu_channel_albm(ch->num);
 611        if (albm < 0)
 612                return;
 613
 614        ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
 615        ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
 616        ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
 617
 618        val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
 619        val |= BIT(ch->num);
 620        ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
 621}
 622
 623int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
 624{
 625        switch (drm_fourcc) {
 626        case DRM_FORMAT_YUV420:
 627        case DRM_FORMAT_YVU420:
 628                /* pix format */
 629                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
 630                /* burst size */
 631                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 632                break;
 633        case DRM_FORMAT_YUV422:
 634        case DRM_FORMAT_YVU422:
 635                /* pix format */
 636                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
 637                /* burst size */
 638                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 639                break;
 640        case DRM_FORMAT_YUV444:
 641        case DRM_FORMAT_YVU444:
 642                /* pix format */
 643                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0);
 644                /* burst size */
 645                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 646                break;
 647        case DRM_FORMAT_NV12:
 648                /* pix format */
 649                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
 650                /* burst size */
 651                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 652                break;
 653        case DRM_FORMAT_NV16:
 654                /* pix format */
 655                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
 656                /* burst size */
 657                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 658                break;
 659        case DRM_FORMAT_UYVY:
 660                /* bits/pixel */
 661                ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
 662                /* pix format */
 663                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
 664                /* burst size */
 665                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 666                break;
 667        case DRM_FORMAT_YUYV:
 668                /* bits/pixel */
 669                ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
 670                /* pix format */
 671                ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
 672                /* burst size */
 673                ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 674                break;
 675        case DRM_FORMAT_ABGR8888:
 676        case DRM_FORMAT_XBGR8888:
 677                ipu_cpmem_set_format_rgb(ch, &def_xbgr_32);
 678                break;
 679        case DRM_FORMAT_ARGB8888:
 680        case DRM_FORMAT_XRGB8888:
 681                ipu_cpmem_set_format_rgb(ch, &def_xrgb_32);
 682                break;
 683        case DRM_FORMAT_RGBA8888:
 684        case DRM_FORMAT_RGBX8888:
 685        case DRM_FORMAT_RGBX8888_A8:
 686                ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
 687                break;
 688        case DRM_FORMAT_BGRA8888:
 689        case DRM_FORMAT_BGRX8888:
 690        case DRM_FORMAT_BGRX8888_A8:
 691                ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
 692                break;
 693        case DRM_FORMAT_BGR888:
 694        case DRM_FORMAT_BGR888_A8:
 695                ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
 696                break;
 697        case DRM_FORMAT_RGB888:
 698        case DRM_FORMAT_RGB888_A8:
 699                ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
 700                break;
 701        case DRM_FORMAT_RGB565:
 702        case DRM_FORMAT_RGB565_A8:
 703                ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
 704                break;
 705        case DRM_FORMAT_BGR565:
 706        case DRM_FORMAT_BGR565_A8:
 707                ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
 708                break;
 709        case DRM_FORMAT_ARGB1555:
 710                ipu_cpmem_set_format_rgb(ch, &def_argb_16);
 711                break;
 712        case DRM_FORMAT_ABGR1555:
 713                ipu_cpmem_set_format_rgb(ch, &def_abgr_16);
 714                break;
 715        case DRM_FORMAT_RGBA5551:
 716                ipu_cpmem_set_format_rgb(ch, &def_rgba_16);
 717                break;
 718        case DRM_FORMAT_BGRA5551:
 719                ipu_cpmem_set_format_rgb(ch, &def_bgra_16);
 720                break;
 721        case DRM_FORMAT_ARGB4444:
 722                ipu_cpmem_set_format_rgb(ch, &def_argb_16_4444);
 723                break;
 724        default:
 725                return -EINVAL;
 726        }
 727
 728        switch (drm_fourcc) {
 729        case DRM_FORMAT_RGB565_A8:
 730        case DRM_FORMAT_BGR565_A8:
 731        case DRM_FORMAT_RGB888_A8:
 732        case DRM_FORMAT_BGR888_A8:
 733        case DRM_FORMAT_RGBX8888_A8:
 734        case DRM_FORMAT_BGRX8888_A8:
 735                ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
 736                ipu_cpmem_set_separate_alpha(ch);
 737                break;
 738        default:
 739                break;
 740        }
 741
 742        return 0;
 743}
 744EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
 745
 746int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 747{
 748        struct v4l2_pix_format *pix = &image->pix;
 749        int offset, u_offset, v_offset;
 750        int ret = 0;
 751
 752        pr_debug("%s: resolution: %dx%d stride: %d\n",
 753                 __func__, pix->width, pix->height,
 754                 pix->bytesperline);
 755
 756        ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
 757        ipu_cpmem_set_stride(ch, pix->bytesperline);
 758
 759        ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
 760
 761        switch (pix->pixelformat) {
 762        case V4L2_PIX_FMT_YUV420:
 763                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 764                u_offset = image->u_offset ?
 765                        image->u_offset : U_OFFSET(pix, image->rect.left,
 766                                                   image->rect.top) - offset;
 767                v_offset = image->v_offset ?
 768                        image->v_offset : V_OFFSET(pix, image->rect.left,
 769                                                   image->rect.top) - offset;
 770
 771                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
 772                                              u_offset, v_offset);
 773                break;
 774        case V4L2_PIX_FMT_YVU420:
 775                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 776                u_offset = image->u_offset ?
 777                        image->u_offset : V_OFFSET(pix, image->rect.left,
 778                                                   image->rect.top) - offset;
 779                v_offset = image->v_offset ?
 780                        image->v_offset : U_OFFSET(pix, image->rect.left,
 781                                                   image->rect.top) - offset;
 782
 783                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
 784                                              u_offset, v_offset);
 785                break;
 786        case V4L2_PIX_FMT_YUV422P:
 787                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 788                u_offset = image->u_offset ?
 789                        image->u_offset : U2_OFFSET(pix, image->rect.left,
 790                                                    image->rect.top) - offset;
 791                v_offset = image->v_offset ?
 792                        image->v_offset : V2_OFFSET(pix, image->rect.left,
 793                                                    image->rect.top) - offset;
 794
 795                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2,
 796                                              u_offset, v_offset);
 797                break;
 798        case V4L2_PIX_FMT_NV12:
 799                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 800                u_offset = image->u_offset ?
 801                        image->u_offset : UV_OFFSET(pix, image->rect.left,
 802                                                    image->rect.top) - offset;
 803                v_offset = image->v_offset ? image->v_offset : 0;
 804
 805                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
 806                                              u_offset, v_offset);
 807                break;
 808        case V4L2_PIX_FMT_NV16:
 809                offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
 810                u_offset = image->u_offset ?
 811                        image->u_offset : UV2_OFFSET(pix, image->rect.left,
 812                                                     image->rect.top) - offset;
 813                v_offset = image->v_offset ? image->v_offset : 0;
 814
 815                ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline,
 816                                              u_offset, v_offset);
 817                break;
 818        case V4L2_PIX_FMT_UYVY:
 819        case V4L2_PIX_FMT_YUYV:
 820        case V4L2_PIX_FMT_RGB565:
 821                offset = image->rect.left * 2 +
 822                        image->rect.top * pix->bytesperline;
 823                break;
 824        case V4L2_PIX_FMT_RGB32:
 825        case V4L2_PIX_FMT_BGR32:
 826        case V4L2_PIX_FMT_XRGB32:
 827        case V4L2_PIX_FMT_XBGR32:
 828                offset = image->rect.left * 4 +
 829                        image->rect.top * pix->bytesperline;
 830                break;
 831        case V4L2_PIX_FMT_RGB24:
 832        case V4L2_PIX_FMT_BGR24:
 833                offset = image->rect.left * 3 +
 834                        image->rect.top * pix->bytesperline;
 835                break;
 836        case V4L2_PIX_FMT_SBGGR8:
 837        case V4L2_PIX_FMT_SGBRG8:
 838        case V4L2_PIX_FMT_SGRBG8:
 839        case V4L2_PIX_FMT_SRGGB8:
 840        case V4L2_PIX_FMT_GREY:
 841                offset = image->rect.left + image->rect.top * pix->bytesperline;
 842                break;
 843        case V4L2_PIX_FMT_SBGGR16:
 844        case V4L2_PIX_FMT_SGBRG16:
 845        case V4L2_PIX_FMT_SGRBG16:
 846        case V4L2_PIX_FMT_SRGGB16:
 847        case V4L2_PIX_FMT_Y16:
 848                offset = image->rect.left * 2 +
 849                         image->rect.top * pix->bytesperline;
 850                break;
 851        default:
 852                /* This should not happen */
 853                WARN_ON(1);
 854                offset = 0;
 855                ret = -EINVAL;
 856        }
 857
 858        ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
 859        ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
 860
 861        return ret;
 862}
 863EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
 864
 865void ipu_cpmem_dump(struct ipuv3_channel *ch)
 866{
 867        struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
 868        struct ipu_soc *ipu = ch->ipu;
 869        int chno = ch->num;
 870
 871        dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
 872                readl(&p->word[0].data[0]),
 873                readl(&p->word[0].data[1]),
 874                readl(&p->word[0].data[2]),
 875                readl(&p->word[0].data[3]),
 876                readl(&p->word[0].data[4]));
 877        dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
 878                readl(&p->word[1].data[0]),
 879                readl(&p->word[1].data[1]),
 880                readl(&p->word[1].data[2]),
 881                readl(&p->word[1].data[3]),
 882                readl(&p->word[1].data[4]));
 883        dev_dbg(ipu->dev, "PFS 0x%x, ",
 884                 ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
 885        dev_dbg(ipu->dev, "BPP 0x%x, ",
 886                ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
 887        dev_dbg(ipu->dev, "NPB 0x%x\n",
 888                 ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
 889
 890        dev_dbg(ipu->dev, "FW %d, ",
 891                 ipu_ch_param_read_field(ch, IPU_FIELD_FW));
 892        dev_dbg(ipu->dev, "FH %d, ",
 893                 ipu_ch_param_read_field(ch, IPU_FIELD_FH));
 894        dev_dbg(ipu->dev, "EBA0 0x%x\n",
 895                 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
 896        dev_dbg(ipu->dev, "EBA1 0x%x\n",
 897                 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
 898        dev_dbg(ipu->dev, "Stride %d\n",
 899                 ipu_ch_param_read_field(ch, IPU_FIELD_SL));
 900        dev_dbg(ipu->dev, "scan_order %d\n",
 901                 ipu_ch_param_read_field(ch, IPU_FIELD_SO));
 902        dev_dbg(ipu->dev, "uv_stride %d\n",
 903                 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
 904        dev_dbg(ipu->dev, "u_offset 0x%x\n",
 905                 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
 906        dev_dbg(ipu->dev, "v_offset 0x%x\n",
 907                 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
 908
 909        dev_dbg(ipu->dev, "Width0 %d+1, ",
 910                 ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
 911        dev_dbg(ipu->dev, "Width1 %d+1, ",
 912                 ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
 913        dev_dbg(ipu->dev, "Width2 %d+1, ",
 914                 ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
 915        dev_dbg(ipu->dev, "Width3 %d+1, ",
 916                 ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
 917        dev_dbg(ipu->dev, "Offset0 %d, ",
 918                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
 919        dev_dbg(ipu->dev, "Offset1 %d, ",
 920                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
 921        dev_dbg(ipu->dev, "Offset2 %d, ",
 922                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
 923        dev_dbg(ipu->dev, "Offset3 %d\n",
 924                 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
 925}
 926EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
 927
 928int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
 929{
 930        struct ipu_cpmem *cpmem;
 931
 932        cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
 933        if (!cpmem)
 934                return -ENOMEM;
 935
 936        ipu->cpmem_priv = cpmem;
 937
 938        spin_lock_init(&cpmem->lock);
 939        cpmem->base = devm_ioremap(dev, base, SZ_128K);
 940        if (!cpmem->base)
 941                return -ENOMEM;
 942
 943        dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
 944                base, cpmem->base);
 945        cpmem->ipu = ipu;
 946
 947        return 0;
 948}
 949
 950void ipu_cpmem_exit(struct ipu_soc *ipu)
 951{
 952}
 953