linux/drivers/gpu/drm/mediatek/mtk_drm_ddp.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 MediaTek Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/iopoll.h>
  16#include <linux/module.h>
  17#include <linux/of_device.h>
  18#include <linux/platform_device.h>
  19#include <linux/regmap.h>
  20
  21#include "mtk_drm_ddp.h"
  22#include "mtk_drm_ddp_comp.h"
  23
  24#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN       0x040
  25#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN       0x044
  26#define DISP_REG_CONFIG_DISP_OD_MOUT_EN         0x048
  27#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN      0x04c
  28#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN       0x050
  29#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN      0x084
  30#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN      0x088
  31#define DISP_REG_CONFIG_DPI_SEL_IN              0x0ac
  32#define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN      0x0c8
  33#define DISP_REG_CONFIG_MMSYS_CG_CON0           0x100
  34
  35#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN        0x030
  36#define DISP_REG_CONFIG_OUT_SEL                 0x04c
  37#define DISP_REG_CONFIG_DSI_SEL                 0x050
  38
  39#define DISP_REG_MUTEX_EN(n)    (0x20 + 0x20 * (n))
  40#define DISP_REG_MUTEX(n)       (0x24 + 0x20 * (n))
  41#define DISP_REG_MUTEX_RST(n)   (0x28 + 0x20 * (n))
  42#define DISP_REG_MUTEX_MOD(n)   (0x2c + 0x20 * (n))
  43#define DISP_REG_MUTEX_SOF(n)   (0x30 + 0x20 * (n))
  44
  45#define INT_MUTEX                               BIT(1)
  46
  47#define MT8173_MUTEX_MOD_DISP_OVL0              BIT(11)
  48#define MT8173_MUTEX_MOD_DISP_OVL1              BIT(12)
  49#define MT8173_MUTEX_MOD_DISP_RDMA0             BIT(13)
  50#define MT8173_MUTEX_MOD_DISP_RDMA1             BIT(14)
  51#define MT8173_MUTEX_MOD_DISP_RDMA2             BIT(15)
  52#define MT8173_MUTEX_MOD_DISP_WDMA0             BIT(16)
  53#define MT8173_MUTEX_MOD_DISP_WDMA1             BIT(17)
  54#define MT8173_MUTEX_MOD_DISP_COLOR0            BIT(18)
  55#define MT8173_MUTEX_MOD_DISP_COLOR1            BIT(19)
  56#define MT8173_MUTEX_MOD_DISP_AAL               BIT(20)
  57#define MT8173_MUTEX_MOD_DISP_GAMMA             BIT(21)
  58#define MT8173_MUTEX_MOD_DISP_UFOE              BIT(22)
  59#define MT8173_MUTEX_MOD_DISP_PWM0              BIT(23)
  60#define MT8173_MUTEX_MOD_DISP_PWM1              BIT(24)
  61#define MT8173_MUTEX_MOD_DISP_OD                BIT(25)
  62
  63#define MT2701_MUTEX_MOD_DISP_OVL               BIT(3)
  64#define MT2701_MUTEX_MOD_DISP_WDMA              BIT(6)
  65#define MT2701_MUTEX_MOD_DISP_COLOR             BIT(7)
  66#define MT2701_MUTEX_MOD_DISP_BLS               BIT(9)
  67#define MT2701_MUTEX_MOD_DISP_RDMA0             BIT(10)
  68#define MT2701_MUTEX_MOD_DISP_RDMA1             BIT(12)
  69
  70#define MUTEX_SOF_SINGLE_MODE           0
  71#define MUTEX_SOF_DSI0                  1
  72#define MUTEX_SOF_DSI1                  2
  73#define MUTEX_SOF_DPI0                  3
  74
  75#define OVL0_MOUT_EN_COLOR0             0x1
  76#define OD_MOUT_EN_RDMA0                0x1
  77#define UFOE_MOUT_EN_DSI0               0x1
  78#define COLOR0_SEL_IN_OVL0              0x1
  79#define OVL1_MOUT_EN_COLOR1             0x1
  80#define GAMMA_MOUT_EN_RDMA1             0x1
  81#define RDMA1_MOUT_DPI0                 0x2
  82#define DPI0_SEL_IN_RDMA1               0x1
  83#define COLOR1_SEL_IN_OVL1              0x1
  84
  85#define OVL_MOUT_EN_RDMA                0x1
  86#define BLS_TO_DSI_RDMA1_TO_DPI1        0x8
  87#define DSI_SEL_IN_BLS                  0x0
  88
  89struct mtk_disp_mutex {
  90        int id;
  91        bool claimed;
  92};
  93
  94struct mtk_ddp {
  95        struct device                   *dev;
  96        struct clk                      *clk;
  97        void __iomem                    *regs;
  98        struct mtk_disp_mutex           mutex[10];
  99        const unsigned int              *mutex_mod;
 100};
 101
 102static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
 103        [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
 104        [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
 105        [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
 106        [DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
 107        [DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
 108        [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
 109};
 110
 111static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
 112        [DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL,
 113        [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
 114        [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
 115        [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
 116        [DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD,
 117        [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
 118        [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
 119        [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
 120        [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
 121        [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
 122        [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
 123        [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
 124        [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
 125        [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
 126        [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
 127};
 128
 129static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
 130                                    enum mtk_ddp_comp_id next,
 131                                    unsigned int *addr)
 132{
 133        unsigned int value;
 134
 135        if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
 136                *addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN;
 137                value = OVL0_MOUT_EN_COLOR0;
 138        } else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) {
 139                *addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN;
 140                value = OVL_MOUT_EN_RDMA;
 141        } else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) {
 142                *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN;
 143                value = OD_MOUT_EN_RDMA0;
 144        } else if (cur == DDP_COMPONENT_UFOE && next == DDP_COMPONENT_DSI0) {
 145                *addr = DISP_REG_CONFIG_DISP_UFOE_MOUT_EN;
 146                value = UFOE_MOUT_EN_DSI0;
 147        } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
 148                *addr = DISP_REG_CONFIG_DISP_OVL1_MOUT_EN;
 149                value = OVL1_MOUT_EN_COLOR1;
 150        } else if (cur == DDP_COMPONENT_GAMMA && next == DDP_COMPONENT_RDMA1) {
 151                *addr = DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN;
 152                value = GAMMA_MOUT_EN_RDMA1;
 153        } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) {
 154                *addr = DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN;
 155                value = RDMA1_MOUT_DPI0;
 156        } else {
 157                value = 0;
 158        }
 159
 160        return value;
 161}
 162
 163static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
 164                                   enum mtk_ddp_comp_id next,
 165                                   unsigned int *addr)
 166{
 167        unsigned int value;
 168
 169        if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
 170                *addr = DISP_REG_CONFIG_DISP_COLOR0_SEL_IN;
 171                value = COLOR0_SEL_IN_OVL0;
 172        } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) {
 173                *addr = DISP_REG_CONFIG_DPI_SEL_IN;
 174                value = DPI0_SEL_IN_RDMA1;
 175        } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
 176                *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN;
 177                value = COLOR1_SEL_IN_OVL1;
 178        } else if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0) {
 179                *addr = DISP_REG_CONFIG_DSI_SEL;
 180                value = DSI_SEL_IN_BLS;
 181        } else {
 182                value = 0;
 183        }
 184
 185        return value;
 186}
 187
 188static void mtk_ddp_sout_sel(void __iomem *config_regs,
 189                             enum mtk_ddp_comp_id cur,
 190                             enum mtk_ddp_comp_id next)
 191{
 192        if (cur == DDP_COMPONENT_BLS && next == DDP_COMPONENT_DSI0)
 193                writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1,
 194                               config_regs + DISP_REG_CONFIG_OUT_SEL);
 195}
 196
 197void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
 198                              enum mtk_ddp_comp_id cur,
 199                              enum mtk_ddp_comp_id next)
 200{
 201        unsigned int addr, value, reg;
 202
 203        value = mtk_ddp_mout_en(cur, next, &addr);
 204        if (value) {
 205                reg = readl_relaxed(config_regs + addr) | value;
 206                writel_relaxed(reg, config_regs + addr);
 207        }
 208
 209        mtk_ddp_sout_sel(config_regs, cur, next);
 210
 211        value = mtk_ddp_sel_in(cur, next, &addr);
 212        if (value) {
 213                reg = readl_relaxed(config_regs + addr) | value;
 214                writel_relaxed(reg, config_regs + addr);
 215        }
 216}
 217
 218void mtk_ddp_remove_comp_from_path(void __iomem *config_regs,
 219                                   enum mtk_ddp_comp_id cur,
 220                                   enum mtk_ddp_comp_id next)
 221{
 222        unsigned int addr, value, reg;
 223
 224        value = mtk_ddp_mout_en(cur, next, &addr);
 225        if (value) {
 226                reg = readl_relaxed(config_regs + addr) & ~value;
 227                writel_relaxed(reg, config_regs + addr);
 228        }
 229
 230        value = mtk_ddp_sel_in(cur, next, &addr);
 231        if (value) {
 232                reg = readl_relaxed(config_regs + addr) & ~value;
 233                writel_relaxed(reg, config_regs + addr);
 234        }
 235}
 236
 237struct mtk_disp_mutex *mtk_disp_mutex_get(struct device *dev, unsigned int id)
 238{
 239        struct mtk_ddp *ddp = dev_get_drvdata(dev);
 240
 241        if (id >= 10)
 242                return ERR_PTR(-EINVAL);
 243        if (ddp->mutex[id].claimed)
 244                return ERR_PTR(-EBUSY);
 245
 246        ddp->mutex[id].claimed = true;
 247
 248        return &ddp->mutex[id];
 249}
 250
 251void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex)
 252{
 253        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 254                                           mutex[mutex->id]);
 255
 256        WARN_ON(&ddp->mutex[mutex->id] != mutex);
 257
 258        mutex->claimed = false;
 259}
 260
 261int mtk_disp_mutex_prepare(struct mtk_disp_mutex *mutex)
 262{
 263        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 264                                           mutex[mutex->id]);
 265        return clk_prepare_enable(ddp->clk);
 266}
 267
 268void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex)
 269{
 270        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 271                                           mutex[mutex->id]);
 272        clk_disable_unprepare(ddp->clk);
 273}
 274
 275void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
 276                             enum mtk_ddp_comp_id id)
 277{
 278        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 279                                           mutex[mutex->id]);
 280        unsigned int reg;
 281
 282        WARN_ON(&ddp->mutex[mutex->id] != mutex);
 283
 284        switch (id) {
 285        case DDP_COMPONENT_DSI0:
 286                reg = MUTEX_SOF_DSI0;
 287                break;
 288        case DDP_COMPONENT_DSI1:
 289                reg = MUTEX_SOF_DSI0;
 290                break;
 291        case DDP_COMPONENT_DPI0:
 292                reg = MUTEX_SOF_DPI0;
 293                break;
 294        default:
 295                reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 296                reg |= ddp->mutex_mod[id];
 297                writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 298                return;
 299        }
 300
 301        writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_SOF(mutex->id));
 302}
 303
 304void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
 305                                enum mtk_ddp_comp_id id)
 306{
 307        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 308                                           mutex[mutex->id]);
 309        unsigned int reg;
 310
 311        WARN_ON(&ddp->mutex[mutex->id] != mutex);
 312
 313        switch (id) {
 314        case DDP_COMPONENT_DSI0:
 315        case DDP_COMPONENT_DSI1:
 316        case DDP_COMPONENT_DPI0:
 317                writel_relaxed(MUTEX_SOF_SINGLE_MODE,
 318                               ddp->regs + DISP_REG_MUTEX_SOF(mutex->id));
 319                break;
 320        default:
 321                reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 322                reg &= ~(ddp->mutex_mod[id]);
 323                writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
 324                break;
 325        }
 326}
 327
 328void mtk_disp_mutex_enable(struct mtk_disp_mutex *mutex)
 329{
 330        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 331                                           mutex[mutex->id]);
 332
 333        WARN_ON(&ddp->mutex[mutex->id] != mutex);
 334
 335        writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
 336}
 337
 338void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
 339{
 340        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 341                                           mutex[mutex->id]);
 342
 343        WARN_ON(&ddp->mutex[mutex->id] != mutex);
 344
 345        writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
 346}
 347
 348void mtk_disp_mutex_acquire(struct mtk_disp_mutex *mutex)
 349{
 350        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 351                                           mutex[mutex->id]);
 352        u32 tmp;
 353
 354        writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
 355        writel(1, ddp->regs + DISP_REG_MUTEX(mutex->id));
 356        if (readl_poll_timeout_atomic(ddp->regs + DISP_REG_MUTEX(mutex->id),
 357                                      tmp, tmp & INT_MUTEX, 1, 10000))
 358                pr_err("could not acquire mutex %d\n", mutex->id);
 359}
 360
 361void mtk_disp_mutex_release(struct mtk_disp_mutex *mutex)
 362{
 363        struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
 364                                           mutex[mutex->id]);
 365
 366        writel(0, ddp->regs + DISP_REG_MUTEX(mutex->id));
 367}
 368
 369static int mtk_ddp_probe(struct platform_device *pdev)
 370{
 371        struct device *dev = &pdev->dev;
 372        struct mtk_ddp *ddp;
 373        struct resource *regs;
 374        int i;
 375
 376        ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL);
 377        if (!ddp)
 378                return -ENOMEM;
 379
 380        for (i = 0; i < 10; i++)
 381                ddp->mutex[i].id = i;
 382
 383        ddp->clk = devm_clk_get(dev, NULL);
 384        if (IS_ERR(ddp->clk)) {
 385                dev_err(dev, "Failed to get clock\n");
 386                return PTR_ERR(ddp->clk);
 387        }
 388
 389        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 390        ddp->regs = devm_ioremap_resource(dev, regs);
 391        if (IS_ERR(ddp->regs)) {
 392                dev_err(dev, "Failed to map mutex registers\n");
 393                return PTR_ERR(ddp->regs);
 394        }
 395
 396        ddp->mutex_mod = of_device_get_match_data(dev);
 397
 398        platform_set_drvdata(pdev, ddp);
 399
 400        return 0;
 401}
 402
 403static int mtk_ddp_remove(struct platform_device *pdev)
 404{
 405        return 0;
 406}
 407
 408static const struct of_device_id ddp_driver_dt_match[] = {
 409        { .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod},
 410        { .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod},
 411        {},
 412};
 413MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
 414
 415struct platform_driver mtk_ddp_driver = {
 416        .probe          = mtk_ddp_probe,
 417        .remove         = mtk_ddp_remove,
 418        .driver         = {
 419                .name   = "mediatek-ddp",
 420                .owner  = THIS_MODULE,
 421                .of_match_table = ddp_driver_dt_match,
 422        },
 423};
 424