linux/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015 MediaTek Inc.
   4 */
   5
   6#include <drm/drm_fourcc.h>
   7
   8#include <linux/clk.h>
   9#include <linux/component.h>
  10#include <linux/module.h>
  11#include <linux/of_device.h>
  12#include <linux/of_irq.h>
  13#include <linux/platform_device.h>
  14#include <linux/soc/mediatek/mtk-cmdq.h>
  15
  16#include "mtk_disp_drv.h"
  17#include "mtk_drm_crtc.h"
  18#include "mtk_drm_ddp_comp.h"
  19
  20#define DISP_REG_OVL_INTEN                      0x0004
  21#define OVL_FME_CPL_INT                                 BIT(1)
  22#define DISP_REG_OVL_INTSTA                     0x0008
  23#define DISP_REG_OVL_EN                         0x000c
  24#define DISP_REG_OVL_RST                        0x0014
  25#define DISP_REG_OVL_ROI_SIZE                   0x0020
  26#define DISP_REG_OVL_DATAPATH_CON               0x0024
  27#define OVL_LAYER_SMI_ID_EN                             BIT(0)
  28#define OVL_BGCLR_SEL_IN                                BIT(2)
  29#define DISP_REG_OVL_ROI_BGCLR                  0x0028
  30#define DISP_REG_OVL_SRC_CON                    0x002c
  31#define DISP_REG_OVL_CON(n)                     (0x0030 + 0x20 * (n))
  32#define DISP_REG_OVL_SRC_SIZE(n)                (0x0038 + 0x20 * (n))
  33#define DISP_REG_OVL_OFFSET(n)                  (0x003c + 0x20 * (n))
  34#define DISP_REG_OVL_PITCH(n)                   (0x0044 + 0x20 * (n))
  35#define DISP_REG_OVL_RDMA_CTRL(n)               (0x00c0 + 0x20 * (n))
  36#define DISP_REG_OVL_RDMA_GMC(n)                (0x00c8 + 0x20 * (n))
  37#define DISP_REG_OVL_ADDR_MT2701                0x0040
  38#define DISP_REG_OVL_ADDR_MT8173                0x0f40
  39#define DISP_REG_OVL_ADDR(ovl, n)               ((ovl)->data->addr + 0x20 * (n))
  40
  41#define GMC_THRESHOLD_BITS      16
  42#define GMC_THRESHOLD_HIGH      ((1 << GMC_THRESHOLD_BITS) / 4)
  43#define GMC_THRESHOLD_LOW       ((1 << GMC_THRESHOLD_BITS) / 8)
  44
  45#define OVL_CON_BYTE_SWAP       BIT(24)
  46#define OVL_CON_MTX_YUV_TO_RGB  (6 << 16)
  47#define OVL_CON_CLRFMT_RGB      (1 << 12)
  48#define OVL_CON_CLRFMT_RGBA8888 (2 << 12)
  49#define OVL_CON_CLRFMT_ARGB8888 (3 << 12)
  50#define OVL_CON_CLRFMT_UYVY     (4 << 12)
  51#define OVL_CON_CLRFMT_YUYV     (5 << 12)
  52#define OVL_CON_CLRFMT_RGB565(ovl)      ((ovl)->data->fmt_rgb565_is_0 ? \
  53                                        0 : OVL_CON_CLRFMT_RGB)
  54#define OVL_CON_CLRFMT_RGB888(ovl)      ((ovl)->data->fmt_rgb565_is_0 ? \
  55                                        OVL_CON_CLRFMT_RGB : 0)
  56#define OVL_CON_AEN             BIT(8)
  57#define OVL_CON_ALPHA           0xff
  58#define OVL_CON_VIRT_FLIP       BIT(9)
  59#define OVL_CON_HORZ_FLIP       BIT(10)
  60
  61struct mtk_disp_ovl_data {
  62        unsigned int addr;
  63        unsigned int gmc_bits;
  64        unsigned int layer_nr;
  65        bool fmt_rgb565_is_0;
  66        bool smi_id_en;
  67};
  68
  69/*
  70 * struct mtk_disp_ovl - DISP_OVL driver structure
  71 * @crtc: associated crtc to report vblank events to
  72 * @data: platform data
  73 */
  74struct mtk_disp_ovl {
  75        struct drm_crtc                 *crtc;
  76        struct clk                      *clk;
  77        void __iomem                    *regs;
  78        struct cmdq_client_reg          cmdq_reg;
  79        const struct mtk_disp_ovl_data  *data;
  80        void                            (*vblank_cb)(void *data);
  81        void                            *vblank_cb_data;
  82};
  83
  84static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
  85{
  86        struct mtk_disp_ovl *priv = dev_id;
  87
  88        /* Clear frame completion interrupt */
  89        writel(0x0, priv->regs + DISP_REG_OVL_INTSTA);
  90
  91        if (!priv->vblank_cb)
  92                return IRQ_NONE;
  93
  94        priv->vblank_cb(priv->vblank_cb_data);
  95
  96        return IRQ_HANDLED;
  97}
  98
  99void mtk_ovl_enable_vblank(struct device *dev,
 100                           void (*vblank_cb)(void *),
 101                           void *vblank_cb_data)
 102{
 103        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 104
 105        ovl->vblank_cb = vblank_cb;
 106        ovl->vblank_cb_data = vblank_cb_data;
 107        writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
 108        writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN);
 109}
 110
 111void mtk_ovl_disable_vblank(struct device *dev)
 112{
 113        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 114
 115        ovl->vblank_cb = NULL;
 116        ovl->vblank_cb_data = NULL;
 117        writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
 118}
 119
 120int mtk_ovl_clk_enable(struct device *dev)
 121{
 122        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 123
 124        return clk_prepare_enable(ovl->clk);
 125}
 126
 127void mtk_ovl_clk_disable(struct device *dev)
 128{
 129        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 130
 131        clk_disable_unprepare(ovl->clk);
 132}
 133
 134void mtk_ovl_start(struct device *dev)
 135{
 136        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 137
 138        if (ovl->data->smi_id_en) {
 139                unsigned int reg;
 140
 141                reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 142                reg = reg | OVL_LAYER_SMI_ID_EN;
 143                writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 144        }
 145        writel_relaxed(0x1, ovl->regs + DISP_REG_OVL_EN);
 146}
 147
 148void mtk_ovl_stop(struct device *dev)
 149{
 150        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 151
 152        writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_EN);
 153        if (ovl->data->smi_id_en) {
 154                unsigned int reg;
 155
 156                reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 157                reg = reg & ~OVL_LAYER_SMI_ID_EN;
 158                writel_relaxed(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 159        }
 160
 161}
 162
 163void mtk_ovl_config(struct device *dev, unsigned int w,
 164                    unsigned int h, unsigned int vrefresh,
 165                    unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
 166{
 167        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 168
 169        if (w != 0 && h != 0)
 170                mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs,
 171                                      DISP_REG_OVL_ROI_SIZE);
 172        mtk_ddp_write_relaxed(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_ROI_BGCLR);
 173
 174        mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
 175        mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
 176}
 177
 178unsigned int mtk_ovl_layer_nr(struct device *dev)
 179{
 180        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 181
 182        return ovl->data->layer_nr;
 183}
 184
 185unsigned int mtk_ovl_supported_rotations(struct device *dev)
 186{
 187        return DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
 188               DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
 189}
 190
 191int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
 192                        struct mtk_plane_state *mtk_state)
 193{
 194        struct drm_plane_state *state = &mtk_state->base;
 195        unsigned int rotation = 0;
 196
 197        rotation = drm_rotation_simplify(state->rotation,
 198                                         DRM_MODE_ROTATE_0 |
 199                                         DRM_MODE_REFLECT_X |
 200                                         DRM_MODE_REFLECT_Y);
 201        rotation &= ~DRM_MODE_ROTATE_0;
 202
 203        /* We can only do reflection, not rotation */
 204        if ((rotation & DRM_MODE_ROTATE_MASK) != 0)
 205                return -EINVAL;
 206
 207        /*
 208         * TODO: Rotating/reflecting YUV buffers is not supported at this time.
 209         *       Only RGB[AX] variants are supported.
 210         */
 211        if (state->fb->format->is_yuv && rotation != 0)
 212                return -EINVAL;
 213
 214        state->rotation = rotation;
 215
 216        return 0;
 217}
 218
 219void mtk_ovl_layer_on(struct device *dev, unsigned int idx,
 220                      struct cmdq_pkt *cmdq_pkt)
 221{
 222        unsigned int gmc_thrshd_l;
 223        unsigned int gmc_thrshd_h;
 224        unsigned int gmc_value;
 225        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 226
 227        mtk_ddp_write(cmdq_pkt, 0x1, &ovl->cmdq_reg, ovl->regs,
 228                      DISP_REG_OVL_RDMA_CTRL(idx));
 229        gmc_thrshd_l = GMC_THRESHOLD_LOW >>
 230                      (GMC_THRESHOLD_BITS - ovl->data->gmc_bits);
 231        gmc_thrshd_h = GMC_THRESHOLD_HIGH >>
 232                      (GMC_THRESHOLD_BITS - ovl->data->gmc_bits);
 233        if (ovl->data->gmc_bits == 10)
 234                gmc_value = gmc_thrshd_h | gmc_thrshd_h << 16;
 235        else
 236                gmc_value = gmc_thrshd_l | gmc_thrshd_l << 8 |
 237                            gmc_thrshd_h << 16 | gmc_thrshd_h << 24;
 238        mtk_ddp_write(cmdq_pkt, gmc_value,
 239                      &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RDMA_GMC(idx));
 240        mtk_ddp_write_mask(cmdq_pkt, BIT(idx), &ovl->cmdq_reg, ovl->regs,
 241                           DISP_REG_OVL_SRC_CON, BIT(idx));
 242}
 243
 244void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
 245                       struct cmdq_pkt *cmdq_pkt)
 246{
 247        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 248
 249        mtk_ddp_write_mask(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
 250                           DISP_REG_OVL_SRC_CON, BIT(idx));
 251        mtk_ddp_write(cmdq_pkt, 0, &ovl->cmdq_reg, ovl->regs,
 252                      DISP_REG_OVL_RDMA_CTRL(idx));
 253}
 254
 255static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
 256{
 257        /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
 258         * is defined in mediatek HW data sheet.
 259         * The alphabet order in XXX is no relation to data
 260         * arrangement in memory.
 261         */
 262        switch (fmt) {
 263        default:
 264        case DRM_FORMAT_RGB565:
 265                return OVL_CON_CLRFMT_RGB565(ovl);
 266        case DRM_FORMAT_BGR565:
 267                return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP;
 268        case DRM_FORMAT_RGB888:
 269                return OVL_CON_CLRFMT_RGB888(ovl);
 270        case DRM_FORMAT_BGR888:
 271                return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
 272        case DRM_FORMAT_RGBX8888:
 273        case DRM_FORMAT_RGBA8888:
 274                return OVL_CON_CLRFMT_ARGB8888;
 275        case DRM_FORMAT_BGRX8888:
 276        case DRM_FORMAT_BGRA8888:
 277                return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP;
 278        case DRM_FORMAT_XRGB8888:
 279        case DRM_FORMAT_ARGB8888:
 280                return OVL_CON_CLRFMT_RGBA8888;
 281        case DRM_FORMAT_XBGR8888:
 282        case DRM_FORMAT_ABGR8888:
 283                return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP;
 284        case DRM_FORMAT_UYVY:
 285                return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
 286        case DRM_FORMAT_YUYV:
 287                return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB;
 288        }
 289}
 290
 291void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
 292                          struct mtk_plane_state *state,
 293                          struct cmdq_pkt *cmdq_pkt)
 294{
 295        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 296        struct mtk_plane_pending_state *pending = &state->pending;
 297        unsigned int addr = pending->addr;
 298        unsigned int pitch = pending->pitch & 0xffff;
 299        unsigned int fmt = pending->format;
 300        unsigned int offset = (pending->y << 16) | pending->x;
 301        unsigned int src_size = (pending->height << 16) | pending->width;
 302        unsigned int con;
 303
 304        if (!pending->enable) {
 305                mtk_ovl_layer_off(dev, idx, cmdq_pkt);
 306                return;
 307        }
 308
 309        con = ovl_fmt_convert(ovl, fmt);
 310        if (state->base.fb && state->base.fb->format->has_alpha)
 311                con |= OVL_CON_AEN | OVL_CON_ALPHA;
 312
 313        if (pending->rotation & DRM_MODE_REFLECT_Y) {
 314                con |= OVL_CON_VIRT_FLIP;
 315                addr += (pending->height - 1) * pending->pitch;
 316        }
 317
 318        if (pending->rotation & DRM_MODE_REFLECT_X) {
 319                con |= OVL_CON_HORZ_FLIP;
 320                addr += pending->pitch - 1;
 321        }
 322
 323        mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
 324                              DISP_REG_OVL_CON(idx));
 325        mtk_ddp_write_relaxed(cmdq_pkt, pitch, &ovl->cmdq_reg, ovl->regs,
 326                              DISP_REG_OVL_PITCH(idx));
 327        mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs,
 328                              DISP_REG_OVL_SRC_SIZE(idx));
 329        mtk_ddp_write_relaxed(cmdq_pkt, offset, &ovl->cmdq_reg, ovl->regs,
 330                              DISP_REG_OVL_OFFSET(idx));
 331        mtk_ddp_write_relaxed(cmdq_pkt, addr, &ovl->cmdq_reg, ovl->regs,
 332                              DISP_REG_OVL_ADDR(ovl, idx));
 333
 334        mtk_ovl_layer_on(dev, idx, cmdq_pkt);
 335}
 336
 337void mtk_ovl_bgclr_in_on(struct device *dev)
 338{
 339        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 340        unsigned int reg;
 341
 342        reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 343        reg = reg | OVL_BGCLR_SEL_IN;
 344        writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 345}
 346
 347void mtk_ovl_bgclr_in_off(struct device *dev)
 348{
 349        struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
 350        unsigned int reg;
 351
 352        reg = readl(ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 353        reg = reg & ~OVL_BGCLR_SEL_IN;
 354        writel(reg, ovl->regs + DISP_REG_OVL_DATAPATH_CON);
 355}
 356
 357static int mtk_disp_ovl_bind(struct device *dev, struct device *master,
 358                             void *data)
 359{
 360        return 0;
 361}
 362
 363static void mtk_disp_ovl_unbind(struct device *dev, struct device *master,
 364                                void *data)
 365{
 366}
 367
 368static const struct component_ops mtk_disp_ovl_component_ops = {
 369        .bind   = mtk_disp_ovl_bind,
 370        .unbind = mtk_disp_ovl_unbind,
 371};
 372
 373static int mtk_disp_ovl_probe(struct platform_device *pdev)
 374{
 375        struct device *dev = &pdev->dev;
 376        struct mtk_disp_ovl *priv;
 377        struct resource *res;
 378        int irq;
 379        int ret;
 380
 381        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 382        if (!priv)
 383                return -ENOMEM;
 384
 385        irq = platform_get_irq(pdev, 0);
 386        if (irq < 0)
 387                return irq;
 388
 389        priv->clk = devm_clk_get(dev, NULL);
 390        if (IS_ERR(priv->clk)) {
 391                dev_err(dev, "failed to get ovl clk\n");
 392                return PTR_ERR(priv->clk);
 393        }
 394
 395        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 396        priv->regs = devm_ioremap_resource(dev, res);
 397        if (IS_ERR(priv->regs)) {
 398                dev_err(dev, "failed to ioremap ovl\n");
 399                return PTR_ERR(priv->regs);
 400        }
 401#if IS_REACHABLE(CONFIG_MTK_CMDQ)
 402        ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
 403        if (ret)
 404                dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
 405#endif
 406
 407        priv->data = of_device_get_match_data(dev);
 408        platform_set_drvdata(pdev, priv);
 409
 410        ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
 411                               IRQF_TRIGGER_NONE, dev_name(dev), priv);
 412        if (ret < 0) {
 413                dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
 414                return ret;
 415        }
 416
 417        ret = component_add(dev, &mtk_disp_ovl_component_ops);
 418        if (ret)
 419                dev_err(dev, "Failed to add component: %d\n", ret);
 420
 421        return ret;
 422}
 423
 424static int mtk_disp_ovl_remove(struct platform_device *pdev)
 425{
 426        component_del(&pdev->dev, &mtk_disp_ovl_component_ops);
 427
 428        return 0;
 429}
 430
 431static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
 432        .addr = DISP_REG_OVL_ADDR_MT2701,
 433        .gmc_bits = 8,
 434        .layer_nr = 4,
 435        .fmt_rgb565_is_0 = false,
 436};
 437
 438static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
 439        .addr = DISP_REG_OVL_ADDR_MT8173,
 440        .gmc_bits = 8,
 441        .layer_nr = 4,
 442        .fmt_rgb565_is_0 = true,
 443};
 444
 445static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
 446        .addr = DISP_REG_OVL_ADDR_MT8173,
 447        .gmc_bits = 10,
 448        .layer_nr = 4,
 449        .fmt_rgb565_is_0 = true,
 450};
 451
 452static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
 453        .addr = DISP_REG_OVL_ADDR_MT8173,
 454        .gmc_bits = 10,
 455        .layer_nr = 2,
 456        .fmt_rgb565_is_0 = true,
 457};
 458
 459static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
 460        { .compatible = "mediatek,mt2701-disp-ovl",
 461          .data = &mt2701_ovl_driver_data},
 462        { .compatible = "mediatek,mt8173-disp-ovl",
 463          .data = &mt8173_ovl_driver_data},
 464        { .compatible = "mediatek,mt8183-disp-ovl",
 465          .data = &mt8183_ovl_driver_data},
 466        { .compatible = "mediatek,mt8183-disp-ovl-2l",
 467          .data = &mt8183_ovl_2l_driver_data},
 468        {},
 469};
 470MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
 471
 472struct platform_driver mtk_disp_ovl_driver = {
 473        .probe          = mtk_disp_ovl_probe,
 474        .remove         = mtk_disp_ovl_remove,
 475        .driver         = {
 476                .name   = "mediatek-disp-ovl",
 477                .owner  = THIS_MODULE,
 478                .of_match_table = mtk_disp_ovl_driver_dt_match,
 479        },
 480};
 481