linux/drivers/gpu/drm/imx/dcss/dcss-dpr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright 2019 NXP.
   4 */
   5
   6#include <linux/device.h>
   7#include <linux/slab.h>
   8
   9#include "dcss-dev.h"
  10
  11#define DCSS_DPR_SYSTEM_CTRL0                   0x000
  12#define   RUN_EN                                BIT(0)
  13#define   SOFT_RESET                            BIT(1)
  14#define   REPEAT_EN                             BIT(2)
  15#define   SHADOW_LOAD_EN                        BIT(3)
  16#define   SW_SHADOW_LOAD_SEL                    BIT(4)
  17#define   BCMD2AXI_MSTR_ID_CTRL                 BIT(16)
  18#define DCSS_DPR_IRQ_MASK                       0x020
  19#define DCSS_DPR_IRQ_MASK_STATUS                0x030
  20#define DCSS_DPR_IRQ_NONMASK_STATUS             0x040
  21#define   IRQ_DPR_CTRL_DONE                     BIT(0)
  22#define   IRQ_DPR_RUN                           BIT(1)
  23#define   IRQ_DPR_SHADOW_LOADED                 BIT(2)
  24#define   IRQ_AXI_READ_ERR                      BIT(3)
  25#define   DPR2RTR_YRGB_FIFO_OVFL                BIT(4)
  26#define   DPR2RTR_UV_FIFO_OVFL                  BIT(5)
  27#define   DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR      BIT(6)
  28#define   DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR        BIT(7)
  29#define DCSS_DPR_MODE_CTRL0                     0x050
  30#define   RTR_3BUF_EN                           BIT(0)
  31#define   RTR_4LINE_BUF_EN                      BIT(1)
  32#define   TILE_TYPE_POS                         2
  33#define   TILE_TYPE_MASK                        GENMASK(4, 2)
  34#define   YUV_EN                                BIT(6)
  35#define   COMP_2PLANE_EN                        BIT(7)
  36#define   PIX_SIZE_POS                          8
  37#define   PIX_SIZE_MASK                         GENMASK(9, 8)
  38#define   PIX_LUMA_UV_SWAP                      BIT(10)
  39#define   PIX_UV_SWAP                           BIT(11)
  40#define   B_COMP_SEL_POS                        12
  41#define   B_COMP_SEL_MASK                       GENMASK(13, 12)
  42#define   G_COMP_SEL_POS                        14
  43#define   G_COMP_SEL_MASK                       GENMASK(15, 14)
  44#define   R_COMP_SEL_POS                        16
  45#define   R_COMP_SEL_MASK                       GENMASK(17, 16)
  46#define   A_COMP_SEL_POS                        18
  47#define   A_COMP_SEL_MASK                       GENMASK(19, 18)
  48#define DCSS_DPR_FRAME_CTRL0                    0x070
  49#define   HFLIP_EN                              BIT(0)
  50#define   VFLIP_EN                              BIT(1)
  51#define   ROT_ENC_POS                           2
  52#define   ROT_ENC_MASK                          GENMASK(3, 2)
  53#define   ROT_FLIP_ORDER_EN                     BIT(4)
  54#define   PITCH_POS                             16
  55#define   PITCH_MASK                            GENMASK(31, 16)
  56#define DCSS_DPR_FRAME_1P_CTRL0                 0x090
  57#define DCSS_DPR_FRAME_1P_PIX_X_CTRL            0x0A0
  58#define DCSS_DPR_FRAME_1P_PIX_Y_CTRL            0x0B0
  59#define DCSS_DPR_FRAME_1P_BASE_ADDR             0x0C0
  60#define DCSS_DPR_FRAME_2P_CTRL0                 0x0E0
  61#define DCSS_DPR_FRAME_2P_PIX_X_CTRL            0x0F0
  62#define DCSS_DPR_FRAME_2P_PIX_Y_CTRL            0x100
  63#define DCSS_DPR_FRAME_2P_BASE_ADDR             0x110
  64#define DCSS_DPR_STATUS_CTRL0                   0x130
  65#define   STATUS_MUX_SEL_MASK                   GENMASK(2, 0)
  66#define   STATUS_SRC_SEL_POS                    16
  67#define   STATUS_SRC_SEL_MASK                   GENMASK(18, 16)
  68#define DCSS_DPR_STATUS_CTRL1                   0x140
  69#define DCSS_DPR_RTRAM_CTRL0                    0x200
  70#define   NUM_ROWS_ACTIVE                       BIT(0)
  71#define   THRES_HIGH_POS                        1
  72#define   THRES_HIGH_MASK                       GENMASK(3, 1)
  73#define   THRES_LOW_POS                         4
  74#define   THRES_LOW_MASK                        GENMASK(6, 4)
  75#define   ABORT_SEL                             BIT(7)
  76
  77enum dcss_tile_type {
  78        TILE_LINEAR = 0,
  79        TILE_GPU_STANDARD,
  80        TILE_GPU_SUPER,
  81        TILE_VPU_YUV420,
  82        TILE_VPU_VP9,
  83};
  84
  85enum dcss_pix_size {
  86        PIX_SIZE_8,
  87        PIX_SIZE_16,
  88        PIX_SIZE_32,
  89};
  90
  91struct dcss_dpr_ch {
  92        struct dcss_dpr *dpr;
  93        void __iomem *base_reg;
  94        u32 base_ofs;
  95
  96        struct drm_format_info format;
  97        enum dcss_pix_size pix_size;
  98        enum dcss_tile_type tile;
  99        bool rtram_4line_en;
 100        bool rtram_3buf_en;
 101
 102        u32 frame_ctrl;
 103        u32 mode_ctrl;
 104        u32 sys_ctrl;
 105        u32 rtram_ctrl;
 106
 107        bool sys_ctrl_chgd;
 108
 109        int ch_num;
 110        int irq;
 111};
 112
 113struct dcss_dpr {
 114        struct device *dev;
 115        struct dcss_ctxld *ctxld;
 116        u32  ctx_id;
 117
 118        struct dcss_dpr_ch ch[3];
 119};
 120
 121static void dcss_dpr_write(struct dcss_dpr_ch *ch, u32 val, u32 ofs)
 122{
 123        struct dcss_dpr *dpr = ch->dpr;
 124
 125        dcss_ctxld_write(dpr->ctxld, dpr->ctx_id, val, ch->base_ofs + ofs);
 126}
 127
 128static int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base)
 129{
 130        struct dcss_dpr_ch *ch;
 131        int i;
 132
 133        for (i = 0; i < 3; i++) {
 134                ch = &dpr->ch[i];
 135
 136                ch->base_ofs = dpr_base + i * 0x1000;
 137
 138                ch->base_reg = ioremap(ch->base_ofs, SZ_4K);
 139                if (!ch->base_reg) {
 140                        dev_err(dpr->dev, "dpr: unable to remap ch %d base\n",
 141                                i);
 142                        return -ENOMEM;
 143                }
 144
 145                ch->dpr = dpr;
 146                ch->ch_num = i;
 147
 148                dcss_writel(0xff, ch->base_reg + DCSS_DPR_IRQ_MASK);
 149        }
 150
 151        return 0;
 152}
 153
 154int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base)
 155{
 156        struct dcss_dpr *dpr;
 157
 158        dpr = kzalloc(sizeof(*dpr), GFP_KERNEL);
 159        if (!dpr)
 160                return -ENOMEM;
 161
 162        dcss->dpr = dpr;
 163        dpr->dev = dcss->dev;
 164        dpr->ctxld = dcss->ctxld;
 165        dpr->ctx_id = CTX_SB_HP;
 166
 167        if (dcss_dpr_ch_init_all(dpr, dpr_base)) {
 168                int i;
 169
 170                for (i = 0; i < 3; i++) {
 171                        if (dpr->ch[i].base_reg)
 172                                iounmap(dpr->ch[i].base_reg);
 173                }
 174
 175                kfree(dpr);
 176
 177                return -ENOMEM;
 178        }
 179
 180        return 0;
 181}
 182
 183void dcss_dpr_exit(struct dcss_dpr *dpr)
 184{
 185        int ch_no;
 186
 187        /* stop DPR on all channels */
 188        for (ch_no = 0; ch_no < 3; ch_no++) {
 189                struct dcss_dpr_ch *ch = &dpr->ch[ch_no];
 190
 191                dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0);
 192
 193                if (ch->base_reg)
 194                        iounmap(ch->base_reg);
 195        }
 196
 197        kfree(dpr);
 198}
 199
 200static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
 201                                      u32 pix_format)
 202{
 203        u8 pix_in_64byte_map[3][5] = {
 204                /* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */
 205                {   64,       8,       8,          8,     16}, /* PIX_SIZE_8  */
 206                {   32,       8,       8,          8,      8}, /* PIX_SIZE_16 */
 207                {   16,       4,       4,          8,      8}, /* PIX_SIZE_32 */
 208        };
 209        u32 offset;
 210        u32 div_64byte_mod, pix_in_64byte;
 211
 212        pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
 213
 214        div_64byte_mod = pix_wide % pix_in_64byte;
 215        offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
 216
 217        return pix_wide + offset;
 218}
 219
 220static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
 221                                      u32 pix_format)
 222{
 223        u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8;
 224        u32 offset, pix_y_mod;
 225
 226        pix_y_mod = pix_high % num_rows_buf;
 227        offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0;
 228
 229        return pix_high + offset;
 230}
 231
 232void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres)
 233{
 234        struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
 235        u32 pix_format = ch->format.format;
 236        u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
 237        int plane, max_planes = 1;
 238        u32 pix_x_wide, pix_y_high;
 239
 240        if (pix_format == DRM_FORMAT_NV12 ||
 241            pix_format == DRM_FORMAT_NV21)
 242                max_planes = 2;
 243
 244        for (plane = 0; plane < max_planes; plane++) {
 245                yres = plane == 1 ? yres >> 1 : yres;
 246
 247                pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
 248                pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
 249
 250                dcss_dpr_write(ch, pix_x_wide,
 251                               DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
 252                dcss_dpr_write(ch, pix_y_high,
 253                               DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
 254
 255                dcss_dpr_write(ch, 2, DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
 256        }
 257}
 258
 259void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
 260                       u32 chroma_base_addr, u16 pitch)
 261{
 262        struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
 263
 264        dcss_dpr_write(ch, luma_base_addr, DCSS_DPR_FRAME_1P_BASE_ADDR);
 265
 266        dcss_dpr_write(ch, chroma_base_addr, DCSS_DPR_FRAME_2P_BASE_ADDR);
 267
 268        ch->frame_ctrl &= ~PITCH_MASK;
 269        ch->frame_ctrl |= (((u32)pitch << PITCH_POS) & PITCH_MASK);
 270}
 271
 272static void dcss_dpr_argb_comp_sel(struct dcss_dpr_ch *ch, int a_sel, int r_sel,
 273                                   int g_sel, int b_sel)
 274{
 275        u32 sel;
 276
 277        sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) |
 278              ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) |
 279              ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) |
 280              ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK);
 281
 282        ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK |
 283                           G_COMP_SEL_MASK | B_COMP_SEL_MASK);
 284        ch->mode_ctrl |= sel;
 285}
 286
 287static void dcss_dpr_pix_size_set(struct dcss_dpr_ch *ch,
 288                                  const struct drm_format_info *format)
 289{
 290        u32 val;
 291
 292        switch (format->format) {
 293        case DRM_FORMAT_NV12:
 294        case DRM_FORMAT_NV21:
 295                val = PIX_SIZE_8;
 296                break;
 297
 298        case DRM_FORMAT_UYVY:
 299        case DRM_FORMAT_VYUY:
 300        case DRM_FORMAT_YUYV:
 301        case DRM_FORMAT_YVYU:
 302                val = PIX_SIZE_16;
 303                break;
 304
 305        default:
 306                val = PIX_SIZE_32;
 307                break;
 308        }
 309
 310        ch->pix_size = val;
 311
 312        ch->mode_ctrl &= ~PIX_SIZE_MASK;
 313        ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK);
 314}
 315
 316static void dcss_dpr_uv_swap(struct dcss_dpr_ch *ch, bool swap)
 317{
 318        ch->mode_ctrl &= ~PIX_UV_SWAP;
 319        ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
 320}
 321
 322static void dcss_dpr_y_uv_swap(struct dcss_dpr_ch *ch, bool swap)
 323{
 324        ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
 325        ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
 326}
 327
 328static void dcss_dpr_2plane_en(struct dcss_dpr_ch *ch, bool en)
 329{
 330        ch->mode_ctrl &= ~COMP_2PLANE_EN;
 331        ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
 332}
 333
 334static void dcss_dpr_yuv_en(struct dcss_dpr_ch *ch, bool en)
 335{
 336        ch->mode_ctrl &= ~YUV_EN;
 337        ch->mode_ctrl |= (en ? YUV_EN : 0);
 338}
 339
 340void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en)
 341{
 342        struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
 343        u32 sys_ctrl;
 344
 345        sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0);
 346
 347        if (en) {
 348                dcss_dpr_write(ch, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
 349                dcss_dpr_write(ch, ch->frame_ctrl, DCSS_DPR_FRAME_CTRL0);
 350                dcss_dpr_write(ch, ch->rtram_ctrl, DCSS_DPR_RTRAM_CTRL0);
 351        }
 352
 353        if (ch->sys_ctrl != sys_ctrl)
 354                ch->sys_ctrl_chgd = true;
 355
 356        ch->sys_ctrl = sys_ctrl;
 357}
 358
 359struct rgb_comp_sel {
 360        u32 drm_format;
 361        int a_sel;
 362        int r_sel;
 363        int g_sel;
 364        int b_sel;
 365};
 366
 367static struct rgb_comp_sel comp_sel_map[] = {
 368        {DRM_FORMAT_ARGB8888, 3, 2, 1, 0},
 369        {DRM_FORMAT_XRGB8888, 3, 2, 1, 0},
 370        {DRM_FORMAT_ABGR8888, 3, 0, 1, 2},
 371        {DRM_FORMAT_XBGR8888, 3, 0, 1, 2},
 372        {DRM_FORMAT_RGBA8888, 0, 3, 2, 1},
 373        {DRM_FORMAT_RGBX8888, 0, 3, 2, 1},
 374        {DRM_FORMAT_BGRA8888, 0, 1, 2, 3},
 375        {DRM_FORMAT_BGRX8888, 0, 1, 2, 3},
 376};
 377
 378static int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel,
 379                       int *b_sel)
 380{
 381        int i;
 382
 383        for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) {
 384                if (comp_sel_map[i].drm_format == pix_fmt) {
 385                        *a_sel = comp_sel_map[i].a_sel;
 386                        *r_sel = comp_sel_map[i].r_sel;
 387                        *g_sel = comp_sel_map[i].g_sel;
 388                        *b_sel = comp_sel_map[i].b_sel;
 389
 390                        return 0;
 391                }
 392        }
 393
 394        return -1;
 395}
 396
 397static void dcss_dpr_rtram_set(struct dcss_dpr_ch *ch, u32 pix_format)
 398{
 399        u32 val, mask;
 400
 401        switch (pix_format) {
 402        case DRM_FORMAT_NV21:
 403        case DRM_FORMAT_NV12:
 404                ch->rtram_3buf_en = true;
 405                ch->rtram_4line_en = false;
 406                break;
 407
 408        default:
 409                ch->rtram_3buf_en = true;
 410                ch->rtram_4line_en = true;
 411                break;
 412        }
 413
 414        val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0);
 415        val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0);
 416        mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN;
 417
 418        ch->mode_ctrl &= ~mask;
 419        ch->mode_ctrl |= (val & mask);
 420
 421        val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE);
 422        val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK;
 423        val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
 424        mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE;
 425
 426        ch->rtram_ctrl &= ~mask;
 427        ch->rtram_ctrl |= (val & mask);
 428}
 429
 430static void dcss_dpr_setup_components(struct dcss_dpr_ch *ch,
 431                                      const struct drm_format_info *format)
 432{
 433        int a_sel, r_sel, g_sel, b_sel;
 434        bool uv_swap, y_uv_swap;
 435
 436        switch (format->format) {
 437        case DRM_FORMAT_YVYU:
 438                uv_swap = true;
 439                y_uv_swap = true;
 440                break;
 441
 442        case DRM_FORMAT_VYUY:
 443        case DRM_FORMAT_NV21:
 444                uv_swap = true;
 445                y_uv_swap = false;
 446                break;
 447
 448        case DRM_FORMAT_YUYV:
 449                uv_swap = false;
 450                y_uv_swap = true;
 451                break;
 452
 453        default:
 454                uv_swap = false;
 455                y_uv_swap = false;
 456                break;
 457        }
 458
 459        dcss_dpr_uv_swap(ch, uv_swap);
 460
 461        dcss_dpr_y_uv_swap(ch, y_uv_swap);
 462
 463        if (!format->is_yuv) {
 464                if (!to_comp_sel(format->format, &a_sel, &r_sel,
 465                                 &g_sel, &b_sel)) {
 466                        dcss_dpr_argb_comp_sel(ch, a_sel, r_sel, g_sel, b_sel);
 467                } else {
 468                        dcss_dpr_argb_comp_sel(ch, 3, 2, 1, 0);
 469                }
 470        } else {
 471                dcss_dpr_argb_comp_sel(ch, 0, 0, 0, 0);
 472        }
 473}
 474
 475static void dcss_dpr_tile_set(struct dcss_dpr_ch *ch, uint64_t modifier)
 476{
 477        switch (ch->ch_num) {
 478        case 0:
 479                switch (modifier) {
 480                case DRM_FORMAT_MOD_LINEAR:
 481                        ch->tile = TILE_LINEAR;
 482                        break;
 483                case DRM_FORMAT_MOD_VIVANTE_TILED:
 484                        ch->tile = TILE_GPU_STANDARD;
 485                        break;
 486                case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
 487                        ch->tile = TILE_GPU_SUPER;
 488                        break;
 489                default:
 490                        WARN_ON(1);
 491                        break;
 492                }
 493                break;
 494        case 1:
 495        case 2:
 496                ch->tile = TILE_LINEAR;
 497                break;
 498        default:
 499                WARN_ON(1);
 500                return;
 501        }
 502
 503        ch->mode_ctrl &= ~TILE_TYPE_MASK;
 504        ch->mode_ctrl |= ((ch->tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
 505}
 506
 507void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
 508                         const struct drm_format_info *format, u64 modifier)
 509{
 510        struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
 511
 512        ch->format = *format;
 513
 514        dcss_dpr_yuv_en(ch, format->is_yuv);
 515
 516        dcss_dpr_pix_size_set(ch, format);
 517
 518        dcss_dpr_setup_components(ch, format);
 519
 520        dcss_dpr_2plane_en(ch, format->num_planes == 2);
 521
 522        dcss_dpr_rtram_set(ch, format->format);
 523
 524        dcss_dpr_tile_set(ch, modifier);
 525}
 526
 527/* This function will be called from interrupt context. */
 528void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr)
 529{
 530        int chnum;
 531
 532        dcss_ctxld_assert_locked(dpr->ctxld);
 533
 534        for (chnum = 0; chnum < 3; chnum++) {
 535                struct dcss_dpr_ch *ch = &dpr->ch[chnum];
 536
 537                if (ch->sys_ctrl_chgd) {
 538                        dcss_ctxld_write_irqsafe(dpr->ctxld, dpr->ctx_id,
 539                                                 ch->sys_ctrl,
 540                                                 ch->base_ofs +
 541                                                 DCSS_DPR_SYSTEM_CTRL0);
 542                        ch->sys_ctrl_chgd = false;
 543                }
 544        }
 545}
 546
 547void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation)
 548{
 549        struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
 550
 551        ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
 552
 553        ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0;
 554        ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0;
 555
 556        if (rotation & DRM_MODE_ROTATE_90)
 557                ch->frame_ctrl |= 1 << ROT_ENC_POS;
 558        else if (rotation & DRM_MODE_ROTATE_180)
 559                ch->frame_ctrl |= 2 << ROT_ENC_POS;
 560        else if (rotation & DRM_MODE_ROTATE_270)
 561                ch->frame_ctrl |= 3 << ROT_ENC_POS;
 562}
 563