linux/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 MediaTek Inc.
   3 * Authors:
   4 *      YT Shen <yt.shen@mediatek.com>
   5 *      CK Hu <ck.hu@mediatek.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/clk.h>
  18#include <linux/of.h>
  19#include <linux/of_address.h>
  20#include <linux/of_irq.h>
  21#include <linux/of_platform.h>
  22#include <linux/platform_device.h>
  23#include <drm/drmP.h>
  24#include "mtk_drm_drv.h"
  25#include "mtk_drm_plane.h"
  26#include "mtk_drm_ddp_comp.h"
  27
  28#define DISP_OD_EN                              0x0000
  29#define DISP_OD_INTEN                           0x0008
  30#define DISP_OD_INTSTA                          0x000c
  31#define DISP_OD_CFG                             0x0020
  32#define DISP_OD_SIZE                            0x0030
  33
  34#define DISP_REG_UFO_START                      0x0000
  35
  36#define DISP_COLOR_CFG_MAIN                     0x0400
  37#define DISP_COLOR_START                        0x0c00
  38#define DISP_COLOR_WIDTH                        0x0c50
  39#define DISP_COLOR_HEIGHT                       0x0c54
  40
  41#define OD_RELAY_MODE           BIT(0)
  42
  43#define UFO_BYPASS              BIT(2)
  44
  45#define COLOR_BYPASS_ALL        BIT(7)
  46#define COLOR_SEQ_SEL           BIT(13)
  47
  48static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
  49                             unsigned int h, unsigned int vrefresh)
  50{
  51        writel(w, comp->regs + DISP_COLOR_WIDTH);
  52        writel(h, comp->regs + DISP_COLOR_HEIGHT);
  53}
  54
  55static void mtk_color_start(struct mtk_ddp_comp *comp)
  56{
  57        writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
  58               comp->regs + DISP_COLOR_CFG_MAIN);
  59        writel(0x1, comp->regs + DISP_COLOR_START);
  60}
  61
  62static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
  63                          unsigned int h, unsigned int vrefresh)
  64{
  65        writel(w << 16 | h, comp->regs + DISP_OD_SIZE);
  66}
  67
  68static void mtk_od_start(struct mtk_ddp_comp *comp)
  69{
  70        writel(OD_RELAY_MODE, comp->regs + DISP_OD_CFG);
  71        writel(1, comp->regs + DISP_OD_EN);
  72}
  73
  74static void mtk_ufoe_start(struct mtk_ddp_comp *comp)
  75{
  76        writel(UFO_BYPASS, comp->regs + DISP_REG_UFO_START);
  77}
  78
  79static const struct mtk_ddp_comp_funcs ddp_color = {
  80        .config = mtk_color_config,
  81        .start = mtk_color_start,
  82};
  83
  84static const struct mtk_ddp_comp_funcs ddp_od = {
  85        .config = mtk_od_config,
  86        .start = mtk_od_start,
  87};
  88
  89static const struct mtk_ddp_comp_funcs ddp_ufoe = {
  90        .start = mtk_ufoe_start,
  91};
  92
  93static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
  94        [MTK_DISP_OVL] = "ovl",
  95        [MTK_DISP_RDMA] = "rdma",
  96        [MTK_DISP_WDMA] = "wdma",
  97        [MTK_DISP_COLOR] = "color",
  98        [MTK_DISP_AAL] = "aal",
  99        [MTK_DISP_GAMMA] = "gamma",
 100        [MTK_DISP_UFOE] = "ufoe",
 101        [MTK_DSI] = "dsi",
 102        [MTK_DPI] = "dpi",
 103        [MTK_DISP_PWM] = "pwm",
 104        [MTK_DISP_MUTEX] = "mutex",
 105        [MTK_DISP_OD] = "od",
 106};
 107
 108struct mtk_ddp_comp_match {
 109        enum mtk_ddp_comp_type type;
 110        int alias_id;
 111        const struct mtk_ddp_comp_funcs *funcs;
 112};
 113
 114static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = {
 115        [DDP_COMPONENT_AAL]     = { MTK_DISP_AAL,       0, NULL },
 116        [DDP_COMPONENT_COLOR0]  = { MTK_DISP_COLOR,     0, &ddp_color },
 117        [DDP_COMPONENT_COLOR1]  = { MTK_DISP_COLOR,     1, &ddp_color },
 118        [DDP_COMPONENT_DPI0]    = { MTK_DPI,            0, NULL },
 119        [DDP_COMPONENT_DSI0]    = { MTK_DSI,            0, NULL },
 120        [DDP_COMPONENT_DSI1]    = { MTK_DSI,            1, NULL },
 121        [DDP_COMPONENT_GAMMA]   = { MTK_DISP_GAMMA,     0, NULL },
 122        [DDP_COMPONENT_OD]      = { MTK_DISP_OD,        0, &ddp_od },
 123        [DDP_COMPONENT_OVL0]    = { MTK_DISP_OVL,       0, NULL },
 124        [DDP_COMPONENT_OVL1]    = { MTK_DISP_OVL,       1, NULL },
 125        [DDP_COMPONENT_PWM0]    = { MTK_DISP_PWM,       0, NULL },
 126        [DDP_COMPONENT_RDMA0]   = { MTK_DISP_RDMA,      0, NULL },
 127        [DDP_COMPONENT_RDMA1]   = { MTK_DISP_RDMA,      1, NULL },
 128        [DDP_COMPONENT_RDMA2]   = { MTK_DISP_RDMA,      2, NULL },
 129        [DDP_COMPONENT_UFOE]    = { MTK_DISP_UFOE,      0, &ddp_ufoe },
 130        [DDP_COMPONENT_WDMA0]   = { MTK_DISP_WDMA,      0, NULL },
 131        [DDP_COMPONENT_WDMA1]   = { MTK_DISP_WDMA,      1, NULL },
 132};
 133
 134int mtk_ddp_comp_get_id(struct device_node *node,
 135                        enum mtk_ddp_comp_type comp_type)
 136{
 137        int id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]);
 138        int i;
 139
 140        for (i = 0; i < ARRAY_SIZE(mtk_ddp_matches); i++) {
 141                if (comp_type == mtk_ddp_matches[i].type &&
 142                    (id < 0 || id == mtk_ddp_matches[i].alias_id))
 143                        return i;
 144        }
 145
 146        return -EINVAL;
 147}
 148
 149int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
 150                      struct mtk_ddp_comp *comp, enum mtk_ddp_comp_id comp_id,
 151                      const struct mtk_ddp_comp_funcs *funcs)
 152{
 153        enum mtk_ddp_comp_type type;
 154        struct device_node *larb_node;
 155        struct platform_device *larb_pdev;
 156
 157        if (comp_id < 0 || comp_id >= DDP_COMPONENT_ID_MAX)
 158                return -EINVAL;
 159
 160        comp->id = comp_id;
 161        comp->funcs = funcs ?: mtk_ddp_matches[comp_id].funcs;
 162
 163        if (comp_id == DDP_COMPONENT_DPI0 ||
 164            comp_id == DDP_COMPONENT_DSI0 ||
 165            comp_id == DDP_COMPONENT_PWM0) {
 166                comp->regs = NULL;
 167                comp->clk = NULL;
 168                comp->irq = 0;
 169                return 0;
 170        }
 171
 172        comp->regs = of_iomap(node, 0);
 173        comp->irq = of_irq_get(node, 0);
 174        comp->clk = of_clk_get(node, 0);
 175        if (IS_ERR(comp->clk))
 176                comp->clk = NULL;
 177
 178        type = mtk_ddp_matches[comp_id].type;
 179
 180        /* Only DMA capable components need the LARB property */
 181        comp->larb_dev = NULL;
 182        if (type != MTK_DISP_OVL &&
 183            type != MTK_DISP_RDMA &&
 184            type != MTK_DISP_WDMA)
 185                return 0;
 186
 187        larb_node = of_parse_phandle(node, "mediatek,larb", 0);
 188        if (!larb_node) {
 189                dev_err(dev,
 190                        "Missing mediadek,larb phandle in %s node\n",
 191                        node->full_name);
 192                return -EINVAL;
 193        }
 194
 195        larb_pdev = of_find_device_by_node(larb_node);
 196        if (!larb_pdev) {
 197                dev_warn(dev, "Waiting for larb device %s\n",
 198                         larb_node->full_name);
 199                of_node_put(larb_node);
 200                return -EPROBE_DEFER;
 201        }
 202        of_node_put(larb_node);
 203
 204        comp->larb_dev = &larb_pdev->dev;
 205
 206        return 0;
 207}
 208
 209int mtk_ddp_comp_register(struct drm_device *drm, struct mtk_ddp_comp *comp)
 210{
 211        struct mtk_drm_private *private = drm->dev_private;
 212
 213        if (private->ddp_comp[comp->id])
 214                return -EBUSY;
 215
 216        private->ddp_comp[comp->id] = comp;
 217        return 0;
 218}
 219
 220void mtk_ddp_comp_unregister(struct drm_device *drm, struct mtk_ddp_comp *comp)
 221{
 222        struct mtk_drm_private *private = drm->dev_private;
 223
 224        private->ddp_comp[comp->id] = NULL;
 225}
 226