root/drivers/gpu/drm/mediatek/mtk_disp_ovl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. comp_to_ovl
  2. mtk_disp_ovl_irq_handler
  3. mtk_ovl_enable_vblank
  4. mtk_ovl_disable_vblank
  5. mtk_ovl_start
  6. mtk_ovl_stop
  7. mtk_ovl_config
  8. mtk_ovl_layer_nr
  9. mtk_ovl_layer_on
  10. mtk_ovl_layer_off
  11. ovl_fmt_convert
  12. mtk_ovl_layer_config
  13. mtk_disp_ovl_bind
  14. mtk_disp_ovl_unbind
  15. mtk_disp_ovl_probe
  16. mtk_disp_ovl_remove

   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 
  13 #include "mtk_drm_crtc.h"
  14 #include "mtk_drm_ddp_comp.h"
  15 
  16 #define DISP_REG_OVL_INTEN                      0x0004
  17 #define OVL_FME_CPL_INT                                 BIT(1)
  18 #define DISP_REG_OVL_INTSTA                     0x0008
  19 #define DISP_REG_OVL_EN                         0x000c
  20 #define DISP_REG_OVL_RST                        0x0014
  21 #define DISP_REG_OVL_ROI_SIZE                   0x0020
  22 #define DISP_REG_OVL_ROI_BGCLR                  0x0028
  23 #define DISP_REG_OVL_SRC_CON                    0x002c
  24 #define DISP_REG_OVL_CON(n)                     (0x0030 + 0x20 * (n))
  25 #define DISP_REG_OVL_SRC_SIZE(n)                (0x0038 + 0x20 * (n))
  26 #define DISP_REG_OVL_OFFSET(n)                  (0x003c + 0x20 * (n))
  27 #define DISP_REG_OVL_PITCH(n)                   (0x0044 + 0x20 * (n))
  28 #define DISP_REG_OVL_RDMA_CTRL(n)               (0x00c0 + 0x20 * (n))
  29 #define DISP_REG_OVL_RDMA_GMC(n)                (0x00c8 + 0x20 * (n))
  30 #define DISP_REG_OVL_ADDR_MT2701                0x0040
  31 #define DISP_REG_OVL_ADDR_MT8173                0x0f40
  32 #define DISP_REG_OVL_ADDR(ovl, n)               ((ovl)->data->addr + 0x20 * (n))
  33 
  34 #define OVL_RDMA_MEM_GMC        0x40402020
  35 
  36 #define OVL_CON_BYTE_SWAP       BIT(24)
  37 #define OVL_CON_MTX_YUV_TO_RGB  (6 << 16)
  38 #define OVL_CON_CLRFMT_RGB      (1 << 12)
  39 #define OVL_CON_CLRFMT_RGBA8888 (2 << 12)
  40 #define OVL_CON_CLRFMT_ARGB8888 (3 << 12)
  41 #define OVL_CON_CLRFMT_UYVY     (4 << 12)
  42 #define OVL_CON_CLRFMT_YUYV     (5 << 12)
  43 #define OVL_CON_CLRFMT_RGB565(ovl)      ((ovl)->data->fmt_rgb565_is_0 ? \
  44                                         0 : OVL_CON_CLRFMT_RGB)
  45 #define OVL_CON_CLRFMT_RGB888(ovl)      ((ovl)->data->fmt_rgb565_is_0 ? \
  46                                         OVL_CON_CLRFMT_RGB : 0)
  47 #define OVL_CON_AEN             BIT(8)
  48 #define OVL_CON_ALPHA           0xff
  49 
  50 struct mtk_disp_ovl_data {
  51         unsigned int addr;
  52         bool fmt_rgb565_is_0;
  53 };
  54 
  55 /**
  56  * struct mtk_disp_ovl - DISP_OVL driver structure
  57  * @ddp_comp - structure containing type enum and hardware resources
  58  * @crtc - associated crtc to report vblank events to
  59  */
  60 struct mtk_disp_ovl {
  61         struct mtk_ddp_comp             ddp_comp;
  62         struct drm_crtc                 *crtc;
  63         const struct mtk_disp_ovl_data  *data;
  64 };
  65 
  66 static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp)
  67 {
  68         return container_of(comp, struct mtk_disp_ovl, ddp_comp);
  69 }
  70 
  71 static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
  72 {
  73         struct mtk_disp_ovl *priv = dev_id;
  74         struct mtk_ddp_comp *ovl = &priv->ddp_comp;
  75 
  76         /* Clear frame completion interrupt */
  77         writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
  78 
  79         if (!priv->crtc)
  80                 return IRQ_NONE;
  81 
  82         mtk_crtc_ddp_irq(priv->crtc, ovl);
  83 
  84         return IRQ_HANDLED;
  85 }
  86 
  87 static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp,
  88                                   struct drm_crtc *crtc)
  89 {
  90         struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
  91 
  92         ovl->crtc = crtc;
  93         writel(0x0, comp->regs + DISP_REG_OVL_INTSTA);
  94         writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN);
  95 }
  96 
  97 static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp)
  98 {
  99         struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
 100 
 101         ovl->crtc = NULL;
 102         writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN);
 103 }
 104 
 105 static void mtk_ovl_start(struct mtk_ddp_comp *comp)
 106 {
 107         writel_relaxed(0x1, comp->regs + DISP_REG_OVL_EN);
 108 }
 109 
 110 static void mtk_ovl_stop(struct mtk_ddp_comp *comp)
 111 {
 112         writel_relaxed(0x0, comp->regs + DISP_REG_OVL_EN);
 113 }
 114 
 115 static void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
 116                            unsigned int h, unsigned int vrefresh,
 117                            unsigned int bpc)
 118 {
 119         if (w != 0 && h != 0)
 120                 writel_relaxed(h << 16 | w, comp->regs + DISP_REG_OVL_ROI_SIZE);
 121         writel_relaxed(0x0, comp->regs + DISP_REG_OVL_ROI_BGCLR);
 122 
 123         writel(0x1, comp->regs + DISP_REG_OVL_RST);
 124         writel(0x0, comp->regs + DISP_REG_OVL_RST);
 125 }
 126 
 127 static unsigned int mtk_ovl_layer_nr(struct mtk_ddp_comp *comp)
 128 {
 129         return 4;
 130 }
 131 
 132 static void mtk_ovl_layer_on(struct mtk_ddp_comp *comp, unsigned int idx)
 133 {
 134         unsigned int reg;
 135 
 136         writel(0x1, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx));
 137         writel(OVL_RDMA_MEM_GMC, comp->regs + DISP_REG_OVL_RDMA_GMC(idx));
 138 
 139         reg = readl(comp->regs + DISP_REG_OVL_SRC_CON);
 140         reg = reg | BIT(idx);
 141         writel(reg, comp->regs + DISP_REG_OVL_SRC_CON);
 142 }
 143 
 144 static void mtk_ovl_layer_off(struct mtk_ddp_comp *comp, unsigned int idx)
 145 {
 146         unsigned int reg;
 147 
 148         reg = readl(comp->regs + DISP_REG_OVL_SRC_CON);
 149         reg = reg & ~BIT(idx);
 150         writel(reg, comp->regs + DISP_REG_OVL_SRC_CON);
 151 
 152         writel(0x0, comp->regs + DISP_REG_OVL_RDMA_CTRL(idx));
 153 }
 154 
 155 static unsigned int ovl_fmt_convert(struct mtk_disp_ovl *ovl, unsigned int fmt)
 156 {
 157         /* The return value in switch "MEM_MODE_INPUT_FORMAT_XXX"
 158          * is defined in mediatek HW data sheet.
 159          * The alphabet order in XXX is no relation to data
 160          * arrangement in memory.
 161          */
 162         switch (fmt) {
 163         default:
 164         case DRM_FORMAT_RGB565:
 165                 return OVL_CON_CLRFMT_RGB565(ovl);
 166         case DRM_FORMAT_BGR565:
 167                 return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP;
 168         case DRM_FORMAT_RGB888:
 169                 return OVL_CON_CLRFMT_RGB888(ovl);
 170         case DRM_FORMAT_BGR888:
 171                 return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
 172         case DRM_FORMAT_RGBX8888:
 173         case DRM_FORMAT_RGBA8888:
 174                 return OVL_CON_CLRFMT_ARGB8888;
 175         case DRM_FORMAT_BGRX8888:
 176         case DRM_FORMAT_BGRA8888:
 177                 return OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP;
 178         case DRM_FORMAT_XRGB8888:
 179         case DRM_FORMAT_ARGB8888:
 180                 return OVL_CON_CLRFMT_RGBA8888;
 181         case DRM_FORMAT_XBGR8888:
 182         case DRM_FORMAT_ABGR8888:
 183                 return OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP;
 184         case DRM_FORMAT_UYVY:
 185                 return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
 186         case DRM_FORMAT_YUYV:
 187                 return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB;
 188         }
 189 }
 190 
 191 static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
 192                                  struct mtk_plane_state *state)
 193 {
 194         struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
 195         struct mtk_plane_pending_state *pending = &state->pending;
 196         unsigned int addr = pending->addr;
 197         unsigned int pitch = pending->pitch & 0xffff;
 198         unsigned int fmt = pending->format;
 199         unsigned int offset = (pending->y << 16) | pending->x;
 200         unsigned int src_size = (pending->height << 16) | pending->width;
 201         unsigned int con;
 202 
 203         if (!pending->enable)
 204                 mtk_ovl_layer_off(comp, idx);
 205 
 206         con = ovl_fmt_convert(ovl, fmt);
 207         if (idx != 0)
 208                 con |= OVL_CON_AEN | OVL_CON_ALPHA;
 209 
 210         writel_relaxed(con, comp->regs + DISP_REG_OVL_CON(idx));
 211         writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx));
 212         writel_relaxed(src_size, comp->regs + DISP_REG_OVL_SRC_SIZE(idx));
 213         writel_relaxed(offset, comp->regs + DISP_REG_OVL_OFFSET(idx));
 214         writel_relaxed(addr, comp->regs + DISP_REG_OVL_ADDR(ovl, idx));
 215 
 216         if (pending->enable)
 217                 mtk_ovl_layer_on(comp, idx);
 218 }
 219 
 220 static const struct mtk_ddp_comp_funcs mtk_disp_ovl_funcs = {
 221         .config = mtk_ovl_config,
 222         .start = mtk_ovl_start,
 223         .stop = mtk_ovl_stop,
 224         .enable_vblank = mtk_ovl_enable_vblank,
 225         .disable_vblank = mtk_ovl_disable_vblank,
 226         .layer_nr = mtk_ovl_layer_nr,
 227         .layer_on = mtk_ovl_layer_on,
 228         .layer_off = mtk_ovl_layer_off,
 229         .layer_config = mtk_ovl_layer_config,
 230 };
 231 
 232 static int mtk_disp_ovl_bind(struct device *dev, struct device *master,
 233                              void *data)
 234 {
 235         struct mtk_disp_ovl *priv = dev_get_drvdata(dev);
 236         struct drm_device *drm_dev = data;
 237         int ret;
 238 
 239         ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
 240         if (ret < 0) {
 241                 dev_err(dev, "Failed to register component %pOF: %d\n",
 242                         dev->of_node, ret);
 243                 return ret;
 244         }
 245 
 246         return 0;
 247 }
 248 
 249 static void mtk_disp_ovl_unbind(struct device *dev, struct device *master,
 250                                 void *data)
 251 {
 252         struct mtk_disp_ovl *priv = dev_get_drvdata(dev);
 253         struct drm_device *drm_dev = data;
 254 
 255         mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
 256 }
 257 
 258 static const struct component_ops mtk_disp_ovl_component_ops = {
 259         .bind   = mtk_disp_ovl_bind,
 260         .unbind = mtk_disp_ovl_unbind,
 261 };
 262 
 263 static int mtk_disp_ovl_probe(struct platform_device *pdev)
 264 {
 265         struct device *dev = &pdev->dev;
 266         struct mtk_disp_ovl *priv;
 267         int comp_id;
 268         int irq;
 269         int ret;
 270 
 271         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 272         if (!priv)
 273                 return -ENOMEM;
 274 
 275         irq = platform_get_irq(pdev, 0);
 276         if (irq < 0)
 277                 return irq;
 278 
 279         comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_OVL);
 280         if (comp_id < 0) {
 281                 dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
 282                 return comp_id;
 283         }
 284 
 285         ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
 286                                 &mtk_disp_ovl_funcs);
 287         if (ret) {
 288                 dev_err(dev, "Failed to initialize component: %d\n", ret);
 289                 return ret;
 290         }
 291 
 292         priv->data = of_device_get_match_data(dev);
 293 
 294         platform_set_drvdata(pdev, priv);
 295 
 296         ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
 297                                IRQF_TRIGGER_NONE, dev_name(dev), priv);
 298         if (ret < 0) {
 299                 dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
 300                 return ret;
 301         }
 302 
 303         ret = component_add(dev, &mtk_disp_ovl_component_ops);
 304         if (ret)
 305                 dev_err(dev, "Failed to add component: %d\n", ret);
 306 
 307         return ret;
 308 }
 309 
 310 static int mtk_disp_ovl_remove(struct platform_device *pdev)
 311 {
 312         component_del(&pdev->dev, &mtk_disp_ovl_component_ops);
 313 
 314         return 0;
 315 }
 316 
 317 static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
 318         .addr = DISP_REG_OVL_ADDR_MT2701,
 319         .fmt_rgb565_is_0 = false,
 320 };
 321 
 322 static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
 323         .addr = DISP_REG_OVL_ADDR_MT8173,
 324         .fmt_rgb565_is_0 = true,
 325 };
 326 
 327 static const struct of_device_id mtk_disp_ovl_driver_dt_match[] = {
 328         { .compatible = "mediatek,mt2701-disp-ovl",
 329           .data = &mt2701_ovl_driver_data},
 330         { .compatible = "mediatek,mt8173-disp-ovl",
 331           .data = &mt8173_ovl_driver_data},
 332         {},
 333 };
 334 MODULE_DEVICE_TABLE(of, mtk_disp_ovl_driver_dt_match);
 335 
 336 struct platform_driver mtk_disp_ovl_driver = {
 337         .probe          = mtk_disp_ovl_probe,
 338         .remove         = mtk_disp_ovl_remove,
 339         .driver         = {
 340                 .name   = "mediatek-disp-ovl",
 341                 .owner  = THIS_MODULE,
 342                 .of_match_table = mtk_disp_ovl_driver_dt_match,
 343         },
 344 };

/* [<][>][^][v][top][bottom][index][help] */