linux/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015 MediaTek Inc.
   4 */
   5
   6#include <linux/clk.h>
   7#include <linux/component.h>
   8#include <linux/module.h>
   9#include <linux/of_device.h>
  10#include <linux/of_irq.h>
  11#include <linux/platform_device.h>
  12#include <linux/soc/mediatek/mtk-cmdq.h>
  13
  14#include "mtk_disp_drv.h"
  15#include "mtk_drm_crtc.h"
  16#include "mtk_drm_ddp_comp.h"
  17
  18#define DISP_REG_RDMA_INT_ENABLE                0x0000
  19#define DISP_REG_RDMA_INT_STATUS                0x0004
  20#define RDMA_TARGET_LINE_INT                            BIT(5)
  21#define RDMA_FIFO_UNDERFLOW_INT                         BIT(4)
  22#define RDMA_EOF_ABNORMAL_INT                           BIT(3)
  23#define RDMA_FRAME_END_INT                              BIT(2)
  24#define RDMA_FRAME_START_INT                            BIT(1)
  25#define RDMA_REG_UPDATE_INT                             BIT(0)
  26#define DISP_REG_RDMA_GLOBAL_CON                0x0010
  27#define RDMA_ENGINE_EN                                  BIT(0)
  28#define RDMA_MODE_MEMORY                                BIT(1)
  29#define DISP_REG_RDMA_SIZE_CON_0                0x0014
  30#define RDMA_MATRIX_ENABLE                              BIT(17)
  31#define RDMA_MATRIX_INT_MTX_SEL                         GENMASK(23, 20)
  32#define RDMA_MATRIX_INT_MTX_BT601_to_RGB                (6 << 20)
  33#define DISP_REG_RDMA_SIZE_CON_1                0x0018
  34#define DISP_REG_RDMA_TARGET_LINE               0x001c
  35#define DISP_RDMA_MEM_CON                       0x0024
  36#define MEM_MODE_INPUT_FORMAT_RGB565                    (0x000 << 4)
  37#define MEM_MODE_INPUT_FORMAT_RGB888                    (0x001 << 4)
  38#define MEM_MODE_INPUT_FORMAT_RGBA8888                  (0x002 << 4)
  39#define MEM_MODE_INPUT_FORMAT_ARGB8888                  (0x003 << 4)
  40#define MEM_MODE_INPUT_FORMAT_UYVY                      (0x004 << 4)
  41#define MEM_MODE_INPUT_FORMAT_YUYV                      (0x005 << 4)
  42#define MEM_MODE_INPUT_SWAP                             BIT(8)
  43#define DISP_RDMA_MEM_SRC_PITCH                 0x002c
  44#define DISP_RDMA_MEM_GMC_SETTING_0             0x0030
  45#define DISP_REG_RDMA_FIFO_CON                  0x0040
  46#define RDMA_FIFO_UNDERFLOW_EN                          BIT(31)
  47#define RDMA_FIFO_PSEUDO_SIZE(bytes)                    (((bytes) / 16) << 16)
  48#define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes)         ((bytes) / 16)
  49#define RDMA_FIFO_SIZE(rdma)                    ((rdma)->data->fifo_size)
  50#define DISP_RDMA_MEM_START_ADDR                0x0f00
  51
  52#define RDMA_MEM_GMC                            0x40402020
  53
  54struct mtk_disp_rdma_data {
  55        unsigned int fifo_size;
  56};
  57
  58/*
  59 * struct mtk_disp_rdma - DISP_RDMA driver structure
  60 * @data: local driver data
  61 */
  62struct mtk_disp_rdma {
  63        struct clk                      *clk;
  64        void __iomem                    *regs;
  65        struct cmdq_client_reg          cmdq_reg;
  66        const struct mtk_disp_rdma_data *data;
  67        void                            (*vblank_cb)(void *data);
  68        void                            *vblank_cb_data;
  69        u32                             fifo_size;
  70};
  71
  72static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id)
  73{
  74        struct mtk_disp_rdma *priv = dev_id;
  75
  76        /* Clear frame completion interrupt */
  77        writel(0x0, priv->regs + DISP_REG_RDMA_INT_STATUS);
  78
  79        if (!priv->vblank_cb)
  80                return IRQ_NONE;
  81
  82        priv->vblank_cb(priv->vblank_cb_data);
  83
  84        return IRQ_HANDLED;
  85}
  86
  87static void rdma_update_bits(struct device *dev, unsigned int reg,
  88                             unsigned int mask, unsigned int val)
  89{
  90        struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
  91        unsigned int tmp = readl(rdma->regs + reg);
  92
  93        tmp = (tmp & ~mask) | (val & mask);
  94        writel(tmp, rdma->regs + reg);
  95}
  96
  97void mtk_rdma_enable_vblank(struct device *dev,
  98                            void (*vblank_cb)(void *),
  99                            void *vblank_cb_data)
 100{
 101        struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
 102
 103        rdma->vblank_cb = vblank_cb;
 104        rdma->vblank_cb_data = vblank_cb_data;
 105        rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
 106                         RDMA_FRAME_END_INT);
 107}
 108
 109void mtk_rdma_disable_vblank(struct device *dev)
 110{
 111        struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
 112
 113        rdma->vblank_cb = NULL;
 114        rdma->vblank_cb_data = NULL;
 115        rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
 116}
 117
 118int mtk_rdma_clk_enable(struct device *dev)
 119{
 120        struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
 121
 122        return clk_prepare_enable(rdma->clk);
 123}
 124
 125void mtk_rdma_clk_disable(struct device *dev)
 126{
 127        struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
 128
 129        clk_disable_unprepare(rdma->clk);
 130}
 131
 132void mtk_rdma_start(struct device *dev)
 133{
 134        rdma_update_bits(dev, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN,
 135                         RDMA_ENGINE_EN);
 136}
 137
 138void mtk_rdma_stop(struct device *dev)
 139{
 140        rdma_update_bits(dev, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 0);
 141}
 142
 143void mtk_rdma_config(struct device *dev, unsigned int width,
 144                     unsigned int height, unsigned int vrefresh,
 145                     unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
 146{
 147        unsigned int threshold;
 148        unsigned int reg;
 149        struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
 150        u32 rdma_fifo_size;
 151
 152        mtk_ddp_write_mask(cmdq_pkt, width, &rdma->cmdq_reg, rdma->regs,
 153                           DISP_REG_RDMA_SIZE_CON_0, 0xfff);
 154        mtk_ddp_write_mask(cmdq_pkt, height, &rdma->cmdq_reg, rdma->regs,
 155                           DISP_REG_RDMA_SIZE_CON_1, 0xfffff);
 156
 157        if (rdma->fifo_size)
 158                rdma_fifo_size = rdma->fifo_size;
 159        else
 160                rdma_fifo_size = RDMA_FIFO_SIZE(rdma);
 161
 162        /*
 163         * Enable FIFO underflow since DSI and DPI can't be blocked.
 164         * Keep the FIFO pseudo size reset default of 8 KiB. Set the
 165         * output threshold to 70% of max fifo size to make sure the
 166         * threhold will not overflow
 167         */
 168        threshold = rdma_fifo_size * 7 / 10;
 169        reg = RDMA_FIFO_UNDERFLOW_EN |
 170              RDMA_FIFO_PSEUDO_SIZE(rdma_fifo_size) |
 171              RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
 172        mtk_ddp_write(cmdq_pkt, reg, &rdma->cmdq_reg, rdma->regs, DISP_REG_RDMA_FIFO_CON);
 173}
 174
 175static unsigned int rdma_fmt_convert(struct mtk_disp_rdma *rdma,
 176                                     unsigned int fmt)
 177{
 178        /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
 179         * is defined in mediatek HW data sheet.
 180         * The alphabet order in XXX is no relation to data
 181         * arrangement in memory.
 182         */
 183        switch (fmt) {
 184        default:
 185        case DRM_FORMAT_RGB565:
 186                return MEM_MODE_INPUT_FORMAT_RGB565;
 187        case DRM_FORMAT_BGR565:
 188                return MEM_MODE_INPUT_FORMAT_RGB565 | MEM_MODE_INPUT_SWAP;
 189        case DRM_FORMAT_RGB888:
 190                return MEM_MODE_INPUT_FORMAT_RGB888;
 191        case DRM_FORMAT_BGR888:
 192                return MEM_MODE_INPUT_FORMAT_RGB888 | MEM_MODE_INPUT_SWAP;
 193        case DRM_FORMAT_RGBX8888:
 194        case DRM_FORMAT_RGBA8888:
 195                return MEM_MODE_INPUT_FORMAT_ARGB8888;
 196        case DRM_FORMAT_BGRX8888:
 197        case DRM_FORMAT_BGRA8888:
 198                return MEM_MODE_INPUT_FORMAT_ARGB8888 | MEM_MODE_INPUT_SWAP;
 199        case DRM_FORMAT_XRGB8888:
 200        case DRM_FORMAT_ARGB8888:
 201                return MEM_MODE_INPUT_FORMAT_RGBA8888;
 202        case DRM_FORMAT_XBGR8888:
 203        case DRM_FORMAT_ABGR8888:
 204                return MEM_MODE_INPUT_FORMAT_RGBA8888 | MEM_MODE_INPUT_SWAP;
 205        case DRM_FORMAT_UYVY:
 206                return MEM_MODE_INPUT_FORMAT_UYVY;
 207        case DRM_FORMAT_YUYV:
 208                return MEM_MODE_INPUT_FORMAT_YUYV;
 209        }
 210}
 211
 212unsigned int mtk_rdma_layer_nr(struct device *dev)
 213{
 214        return 1;
 215}
 216
 217void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
 218                           struct mtk_plane_state *state,
 219                           struct cmdq_pkt *cmdq_pkt)
 220{
 221        struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
 222        struct mtk_plane_pending_state *pending = &state->pending;
 223        unsigned int addr = pending->addr;
 224        unsigned int pitch = pending->pitch & 0xffff;
 225        unsigned int fmt = pending->format;
 226        unsigned int con;
 227
 228        con = rdma_fmt_convert(rdma, fmt);
 229        mtk_ddp_write_relaxed(cmdq_pkt, con, &rdma->cmdq_reg, rdma->regs, DISP_RDMA_MEM_CON);
 230
 231        if (fmt == DRM_FORMAT_UYVY || fmt == DRM_FORMAT_YUYV) {
 232                mtk_ddp_write_mask(cmdq_pkt, RDMA_MATRIX_ENABLE, &rdma->cmdq_reg, rdma->regs,
 233                                   DISP_REG_RDMA_SIZE_CON_0,
 234                                   RDMA_MATRIX_ENABLE);
 235                mtk_ddp_write_mask(cmdq_pkt, RDMA_MATRIX_INT_MTX_BT601_to_RGB,
 236                                   &rdma->cmdq_reg, rdma->regs, DISP_REG_RDMA_SIZE_CON_0,
 237                                   RDMA_MATRIX_INT_MTX_SEL);
 238        } else {
 239                mtk_ddp_write_mask(cmdq_pkt, 0, &rdma->cmdq_reg, rdma->regs,
 240                                   DISP_REG_RDMA_SIZE_CON_0,
 241                                   RDMA_MATRIX_ENABLE);
 242        }
 243        mtk_ddp_write_relaxed(cmdq_pkt, addr, &rdma->cmdq_reg, rdma->regs,
 244                              DISP_RDMA_MEM_START_ADDR);
 245        mtk_ddp_write_relaxed(cmdq_pkt, pitch, &rdma->cmdq_reg, rdma->regs,
 246                              DISP_RDMA_MEM_SRC_PITCH);
 247        mtk_ddp_write(cmdq_pkt, RDMA_MEM_GMC, &rdma->cmdq_reg, rdma->regs,
 248                      DISP_RDMA_MEM_GMC_SETTING_0);
 249        mtk_ddp_write_mask(cmdq_pkt, RDMA_MODE_MEMORY, &rdma->cmdq_reg, rdma->regs,
 250                           DISP_REG_RDMA_GLOBAL_CON, RDMA_MODE_MEMORY);
 251
 252}
 253
 254static int mtk_disp_rdma_bind(struct device *dev, struct device *master,
 255                              void *data)
 256{
 257        return 0;
 258
 259}
 260
 261static void mtk_disp_rdma_unbind(struct device *dev, struct device *master,
 262                                 void *data)
 263{
 264}
 265
 266static const struct component_ops mtk_disp_rdma_component_ops = {
 267        .bind   = mtk_disp_rdma_bind,
 268        .unbind = mtk_disp_rdma_unbind,
 269};
 270
 271static int mtk_disp_rdma_probe(struct platform_device *pdev)
 272{
 273        struct device *dev = &pdev->dev;
 274        struct mtk_disp_rdma *priv;
 275        struct resource *res;
 276        int irq;
 277        int ret;
 278
 279        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 280        if (!priv)
 281                return -ENOMEM;
 282
 283        irq = platform_get_irq(pdev, 0);
 284        if (irq < 0)
 285                return irq;
 286
 287        priv->clk = devm_clk_get(dev, NULL);
 288        if (IS_ERR(priv->clk)) {
 289                dev_err(dev, "failed to get rdma clk\n");
 290                return PTR_ERR(priv->clk);
 291        }
 292
 293        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 294        priv->regs = devm_ioremap_resource(dev, res);
 295        if (IS_ERR(priv->regs)) {
 296                dev_err(dev, "failed to ioremap rdma\n");
 297                return PTR_ERR(priv->regs);
 298        }
 299#if IS_REACHABLE(CONFIG_MTK_CMDQ)
 300        ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
 301        if (ret)
 302                dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
 303#endif
 304
 305        if (of_find_property(dev->of_node, "mediatek,rdma-fifo-size", &ret)) {
 306                ret = of_property_read_u32(dev->of_node,
 307                                           "mediatek,rdma-fifo-size",
 308                                           &priv->fifo_size);
 309                if (ret) {
 310                        dev_err(dev, "Failed to get rdma fifo size\n");
 311                        return ret;
 312                }
 313        }
 314
 315        /* Disable and clear pending interrupts */
 316        writel(0x0, priv->regs + DISP_REG_RDMA_INT_ENABLE);
 317        writel(0x0, priv->regs + DISP_REG_RDMA_INT_STATUS);
 318
 319        ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler,
 320                               IRQF_TRIGGER_NONE, dev_name(dev), priv);
 321        if (ret < 0) {
 322                dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
 323                return ret;
 324        }
 325
 326        priv->data = of_device_get_match_data(dev);
 327
 328        platform_set_drvdata(pdev, priv);
 329
 330        ret = component_add(dev, &mtk_disp_rdma_component_ops);
 331        if (ret)
 332                dev_err(dev, "Failed to add component: %d\n", ret);
 333
 334        return ret;
 335}
 336
 337static int mtk_disp_rdma_remove(struct platform_device *pdev)
 338{
 339        component_del(&pdev->dev, &mtk_disp_rdma_component_ops);
 340
 341        return 0;
 342}
 343
 344static const struct mtk_disp_rdma_data mt2701_rdma_driver_data = {
 345        .fifo_size = SZ_4K,
 346};
 347
 348static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = {
 349        .fifo_size = SZ_8K,
 350};
 351
 352static const struct mtk_disp_rdma_data mt8183_rdma_driver_data = {
 353        .fifo_size = 5 * SZ_1K,
 354};
 355
 356static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
 357        { .compatible = "mediatek,mt2701-disp-rdma",
 358          .data = &mt2701_rdma_driver_data},
 359        { .compatible = "mediatek,mt8173-disp-rdma",
 360          .data = &mt8173_rdma_driver_data},
 361        { .compatible = "mediatek,mt8183-disp-rdma",
 362          .data = &mt8183_rdma_driver_data},
 363        {},
 364};
 365MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
 366
 367struct platform_driver mtk_disp_rdma_driver = {
 368        .probe          = mtk_disp_rdma_probe,
 369        .remove         = mtk_disp_rdma_remove,
 370        .driver         = {
 371                .name   = "mediatek-disp-rdma",
 372                .owner  = THIS_MODULE,
 373                .of_match_table = mtk_disp_rdma_driver_dt_match,
 374        },
 375};
 376