linux/drivers/gpu/drm/meson/meson_osd_afbcd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2019 BayLibre, SAS
   4 * Author: Neil Armstrong <narmstrong@baylibre.com>
   5 */
   6
   7#include <linux/bitfield.h>
   8
   9#include <drm/drm_print.h>
  10#include <drm/drm_fourcc.h>
  11
  12#include "meson_drv.h"
  13#include "meson_registers.h"
  14#include "meson_viu.h"
  15#include "meson_rdma.h"
  16#include "meson_osd_afbcd.h"
  17
  18/*
  19 * DOC: Driver for the ARM FrameBuffer Compression Decoders
  20 *
  21 * The Amlogic GXM and G12A SoC families embeds an AFBC Decoder,
  22 * to decode compressed buffers generated by the ARM Mali GPU.
  23 *
  24 * For the GXM Family, Amlogic designed their own Decoder, named in
  25 * the vendor source as "MESON_AFBC", and a single decoder is available
  26 * for the 2 OSD planes.
  27 * This decoder is compatible with the AFBC 1.0 specifications and the
  28 * Mali T820 GPU capabilities.
  29 * It supports :
  30 * - basic AFBC buffer for RGB32 only, thus YTR feature is mandatory
  31 * - SPARSE layout and SPLIT layout
  32 * - only 16x16 superblock
  33 *
  34 * The decoder reads the data from the SDRAM, decodes and sends the
  35 * decoded pixel stream to the OSD1 Plane pixel composer.
  36 *
  37 * For the G12A Family, Amlogic integrated an ARM AFBC Decoder, named
  38 * in the vendor source as "MALI_AFBC", and the decoder can decode up
  39 * to 4 surfaces, one for each of the 4 available OSDs.
  40 * This decoder is compatible with the AFBC 1.2 specifications for the
  41 * Mali G31 and G52 GPUs.
  42 * Is supports :
  43 * - basic AFBC buffer for multiple RGB and YUV pixel formats
  44 * - SPARSE layout and SPLIT layout
  45 * - 16x16 and 32x8 "wideblk" superblocks
  46 * - Tiled header
  47 *
  48 * The ARM AFBC Decoder independent from the VPU Pixel Pipeline, so
  49 * the ARM AFBC Decoder reads the data from the SDRAM then decodes
  50 * into a private internal physical address where the OSD1 Plane pixel
  51 * composer unpacks the decoded data.
  52 */
  53
  54/* Amlogic AFBC Decoder for GXM Family */
  55
  56#define OSD1_AFBCD_RGB32        0x15
  57
  58static int meson_gxm_afbcd_pixel_fmt(u64 modifier, uint32_t format)
  59{
  60        switch (format) {
  61        case DRM_FORMAT_XBGR8888:
  62        case DRM_FORMAT_ABGR8888:
  63                return OSD1_AFBCD_RGB32;
  64        /* TOFIX support mode formats */
  65        default:
  66                DRM_DEBUG("unsupported afbc format[%08x]\n", format);
  67                return -EINVAL;
  68        }
  69}
  70
  71static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format)
  72{
  73        if (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
  74                return false;
  75
  76        if (!(modifier & AFBC_FORMAT_MOD_YTR))
  77                return false;
  78
  79        return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0;
  80}
  81
  82static int meson_gxm_afbcd_init(struct meson_drm *priv)
  83{
  84        return 0;
  85}
  86
  87static int meson_gxm_afbcd_reset(struct meson_drm *priv)
  88{
  89        writel_relaxed(VIU_SW_RESET_OSD1_AFBCD,
  90                       priv->io_base + _REG(VIU_SW_RESET));
  91        writel_relaxed(0, priv->io_base + _REG(VIU_SW_RESET));
  92
  93        return 0;
  94}
  95
  96static int meson_gxm_afbcd_enable(struct meson_drm *priv)
  97{
  98        writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) |
  99                       OSD1_AFBCD_DEC_ENABLE,
 100                       priv->io_base + _REG(OSD1_AFBCD_ENABLE));
 101
 102        return 0;
 103}
 104
 105static int meson_gxm_afbcd_disable(struct meson_drm *priv)
 106{
 107        writel_bits_relaxed(OSD1_AFBCD_DEC_ENABLE, 0,
 108                            priv->io_base + _REG(OSD1_AFBCD_ENABLE));
 109
 110        return 0;
 111}
 112
 113static int meson_gxm_afbcd_setup(struct meson_drm *priv)
 114{
 115        u32 conv_lbuf_len;
 116        u32 mode = FIELD_PREP(OSD1_AFBCD_MIF_URGENT, 3) |
 117                   FIELD_PREP(OSD1_AFBCD_HOLD_LINE_NUM, 4) |
 118                   FIELD_PREP(OSD1_AFBCD_RGBA_EXCHAN_CTRL, 0x34) |
 119                   meson_gxm_afbcd_pixel_fmt(priv->afbcd.modifier,
 120                                             priv->afbcd.format);
 121
 122        if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPARSE)
 123                mode |= OSD1_AFBCD_HREG_HALF_BLOCK;
 124
 125        if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
 126                mode |= OSD1_AFBCD_HREG_BLOCK_SPLIT;
 127
 128        writel_relaxed(mode, priv->io_base + _REG(OSD1_AFBCD_MODE));
 129
 130        writel_relaxed(FIELD_PREP(OSD1_AFBCD_HREG_VSIZE_IN,
 131                                  priv->viu.osd1_width) |
 132                       FIELD_PREP(OSD1_AFBCD_HREG_HSIZE_IN,
 133                                  priv->viu.osd1_height),
 134                       priv->io_base + _REG(OSD1_AFBCD_SIZE_IN));
 135
 136        writel_relaxed(priv->viu.osd1_addr >> 4,
 137                       priv->io_base + _REG(OSD1_AFBCD_HDR_PTR));
 138        writel_relaxed(priv->viu.osd1_addr >> 4,
 139                       priv->io_base + _REG(OSD1_AFBCD_FRAME_PTR));
 140        /* TOFIX: bits 31:24 are not documented, nor the meaning of 0xe4 */
 141        writel_relaxed((0xe4 << 24) | (priv->viu.osd1_addr & 0xffffff),
 142                       priv->io_base + _REG(OSD1_AFBCD_CHROMA_PTR));
 143
 144        if (priv->viu.osd1_width <= 128)
 145                conv_lbuf_len = 32;
 146        else if (priv->viu.osd1_width <= 256)
 147                conv_lbuf_len = 64;
 148        else if (priv->viu.osd1_width <= 512)
 149                conv_lbuf_len = 128;
 150        else if (priv->viu.osd1_width <= 1024)
 151                conv_lbuf_len = 256;
 152        else if (priv->viu.osd1_width <= 2048)
 153                conv_lbuf_len = 512;
 154        else
 155                conv_lbuf_len = 1024;
 156
 157        writel_relaxed(conv_lbuf_len,
 158                       priv->io_base + _REG(OSD1_AFBCD_CONV_CTRL));
 159
 160        writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_H, 0) |
 161                       FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_H,
 162                                  priv->viu.osd1_width - 1),
 163                       priv->io_base + _REG(OSD1_AFBCD_PIXEL_HSCOPE));
 164
 165        writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_V, 0) |
 166                       FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_V,
 167                                  priv->viu.osd1_height - 1),
 168                       priv->io_base + _REG(OSD1_AFBCD_PIXEL_VSCOPE));
 169
 170        return 0;
 171}
 172
 173struct meson_afbcd_ops meson_afbcd_gxm_ops = {
 174        .init = meson_gxm_afbcd_init,
 175        .reset = meson_gxm_afbcd_reset,
 176        .enable = meson_gxm_afbcd_enable,
 177        .disable = meson_gxm_afbcd_disable,
 178        .setup = meson_gxm_afbcd_setup,
 179        .supported_fmt = meson_gxm_afbcd_supported_fmt,
 180};
 181
 182/* ARM AFBC Decoder for G12A Family */
 183
 184/* Amlogic G12A Mali AFBC Decoder supported formats */
 185enum {
 186        MAFBC_FMT_RGB565 = 0,
 187        MAFBC_FMT_RGBA5551,
 188        MAFBC_FMT_RGBA1010102,
 189        MAFBC_FMT_YUV420_10B,
 190        MAFBC_FMT_RGB888,
 191        MAFBC_FMT_RGBA8888,
 192        MAFBC_FMT_RGBA4444,
 193        MAFBC_FMT_R8,
 194        MAFBC_FMT_RG88,
 195        MAFBC_FMT_YUV420_8B,
 196        MAFBC_FMT_YUV422_8B = 11,
 197        MAFBC_FMT_YUV422_10B = 14,
 198};
 199
 200static int meson_g12a_afbcd_pixel_fmt(u64 modifier, uint32_t format)
 201{
 202        switch (format) {
 203        case DRM_FORMAT_XRGB8888:
 204        case DRM_FORMAT_ARGB8888:
 205                /* YTR is forbidden for non XBGR formats */
 206                if (modifier & AFBC_FORMAT_MOD_YTR)
 207                        return -EINVAL;
 208                fallthrough;
 209        case DRM_FORMAT_XBGR8888:
 210        case DRM_FORMAT_ABGR8888:
 211                return MAFBC_FMT_RGBA8888;
 212        case DRM_FORMAT_RGB888:
 213                /* YTR is forbidden for non XBGR formats */
 214                if (modifier & AFBC_FORMAT_MOD_YTR)
 215                        return -EINVAL;
 216                return MAFBC_FMT_RGB888;
 217        case DRM_FORMAT_RGB565:
 218                /* YTR is forbidden for non XBGR formats */
 219                if (modifier & AFBC_FORMAT_MOD_YTR)
 220                        return -EINVAL;
 221                return MAFBC_FMT_RGB565;
 222        /* TOFIX support mode formats */
 223        default:
 224                DRM_DEBUG("unsupported afbc format[%08x]\n", format);
 225                return -EINVAL;
 226        }
 227}
 228
 229static int meson_g12a_afbcd_bpp(uint32_t format)
 230{
 231        switch (format) {
 232        case DRM_FORMAT_XRGB8888:
 233        case DRM_FORMAT_ARGB8888:
 234        case DRM_FORMAT_XBGR8888:
 235        case DRM_FORMAT_ABGR8888:
 236                return 32;
 237        case DRM_FORMAT_RGB888:
 238                return 24;
 239        case DRM_FORMAT_RGB565:
 240                return 16;
 241        /* TOFIX support mode formats */
 242        default:
 243                DRM_ERROR("unsupported afbc format[%08x]\n", format);
 244                return 0;
 245        }
 246}
 247
 248static int meson_g12a_afbcd_fmt_to_blk_mode(u64 modifier, uint32_t format)
 249{
 250        switch (format) {
 251        case DRM_FORMAT_XRGB8888:
 252        case DRM_FORMAT_ARGB8888:
 253        case DRM_FORMAT_XBGR8888:
 254        case DRM_FORMAT_ABGR8888:
 255                return OSD_MALI_COLOR_MODE_RGBA8888;
 256        case DRM_FORMAT_RGB888:
 257                return OSD_MALI_COLOR_MODE_RGB888;
 258        case DRM_FORMAT_RGB565:
 259                return OSD_MALI_COLOR_MODE_RGB565;
 260        /* TOFIX support mode formats */
 261        default:
 262                DRM_DEBUG("unsupported afbc format[%08x]\n", format);
 263                return -EINVAL;
 264        }
 265}
 266
 267static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format)
 268{
 269        return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0;
 270}
 271
 272static int meson_g12a_afbcd_init(struct meson_drm *priv)
 273{
 274        int ret;
 275
 276        ret = meson_rdma_init(priv);
 277        if (ret)
 278                return ret;
 279
 280        meson_rdma_setup(priv);
 281
 282        /* Handle AFBC Decoder reset manually */
 283        writel_bits_relaxed(MALI_AFBCD_MANUAL_RESET, MALI_AFBCD_MANUAL_RESET,
 284                            priv->io_base + _REG(MALI_AFBCD_TOP_CTRL));
 285
 286        return 0;
 287}
 288
 289static int meson_g12a_afbcd_reset(struct meson_drm *priv)
 290{
 291        meson_rdma_reset(priv);
 292
 293        meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB |
 294                               VIU_SW_RESET_G12A_OSD1_AFBCD,
 295                               VIU_SW_RESET);
 296        meson_rdma_writel_sync(priv, 0, VIU_SW_RESET);
 297
 298        return 0;
 299}
 300
 301static int meson_g12a_afbcd_enable(struct meson_drm *priv)
 302{
 303        meson_rdma_writel_sync(priv, VPU_MAFBC_IRQ_SURFACES_COMPLETED |
 304                               VPU_MAFBC_IRQ_CONFIGURATION_SWAPPED |
 305                               VPU_MAFBC_IRQ_DECODE_ERROR |
 306                               VPU_MAFBC_IRQ_DETILING_ERROR,
 307                               VPU_MAFBC_IRQ_MASK);
 308
 309        meson_rdma_writel_sync(priv, VPU_MAFBC_S0_ENABLE,
 310                               VPU_MAFBC_SURFACE_CFG);
 311
 312        meson_rdma_writel_sync(priv, VPU_MAFBC_DIRECT_SWAP,
 313                               VPU_MAFBC_COMMAND);
 314
 315        /* This will enable the RDMA replaying the register writes on vsync */
 316        meson_rdma_flush(priv);
 317
 318        return 0;
 319}
 320
 321static int meson_g12a_afbcd_disable(struct meson_drm *priv)
 322{
 323        writel_bits_relaxed(VPU_MAFBC_S0_ENABLE, 0,
 324                            priv->io_base + _REG(VPU_MAFBC_SURFACE_CFG));
 325
 326        return 0;
 327}
 328
 329static int meson_g12a_afbcd_setup(struct meson_drm *priv)
 330{
 331        u32 format = meson_g12a_afbcd_pixel_fmt(priv->afbcd.modifier,
 332                                                priv->afbcd.format);
 333
 334        if (priv->afbcd.modifier & AFBC_FORMAT_MOD_YTR)
 335                format |= VPU_MAFBC_YUV_TRANSFORM;
 336
 337        if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
 338                format |= VPU_MAFBC_BLOCK_SPLIT;
 339
 340        if (priv->afbcd.modifier & AFBC_FORMAT_MOD_TILED)
 341                format |= VPU_MAFBC_TILED_HEADER_EN;
 342
 343        if ((priv->afbcd.modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
 344                AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
 345                format |= FIELD_PREP(VPU_MAFBC_SUPER_BLOCK_ASPECT, 1);
 346
 347        meson_rdma_writel_sync(priv, format,
 348                               VPU_MAFBC_FORMAT_SPECIFIER_S0);
 349
 350        meson_rdma_writel_sync(priv, priv->viu.osd1_addr,
 351                               VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0);
 352        meson_rdma_writel_sync(priv, 0,
 353                               VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0);
 354
 355        meson_rdma_writel_sync(priv, priv->viu.osd1_width,
 356                               VPU_MAFBC_BUFFER_WIDTH_S0);
 357        meson_rdma_writel_sync(priv, ALIGN(priv->viu.osd1_height, 32),
 358                               VPU_MAFBC_BUFFER_HEIGHT_S0);
 359
 360        meson_rdma_writel_sync(priv, 0,
 361                               VPU_MAFBC_BOUNDING_BOX_X_START_S0);
 362        meson_rdma_writel_sync(priv, priv->viu.osd1_width - 1,
 363                               VPU_MAFBC_BOUNDING_BOX_X_END_S0);
 364        meson_rdma_writel_sync(priv, 0,
 365                               VPU_MAFBC_BOUNDING_BOX_Y_START_S0);
 366        meson_rdma_writel_sync(priv, priv->viu.osd1_height - 1,
 367                               VPU_MAFBC_BOUNDING_BOX_Y_END_S0);
 368
 369        meson_rdma_writel_sync(priv, MESON_G12A_AFBCD_OUT_ADDR,
 370                               VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0);
 371        meson_rdma_writel_sync(priv, 0,
 372                               VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0);
 373
 374        meson_rdma_writel_sync(priv, priv->viu.osd1_width *
 375                               (meson_g12a_afbcd_bpp(priv->afbcd.format) / 8),
 376                               VPU_MAFBC_OUTPUT_BUF_STRIDE_S0);
 377
 378        return 0;
 379}
 380
 381struct meson_afbcd_ops meson_afbcd_g12a_ops = {
 382        .init = meson_g12a_afbcd_init,
 383        .reset = meson_g12a_afbcd_reset,
 384        .enable = meson_g12a_afbcd_enable,
 385        .disable = meson_g12a_afbcd_disable,
 386        .setup = meson_g12a_afbcd_setup,
 387        .fmt_to_blk_mode = meson_g12a_afbcd_fmt_to_blk_mode,
 388        .supported_fmt = meson_g12a_afbcd_supported_fmt,
 389};
 390