uboot/drivers/video/rockchip/rk3288_mipi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
   4 * Author: Eric Gao <eric.gao@rock-chips.com>
   5 */
   6
   7#include <common.h>
   8#include <clk.h>
   9#include <display.h>
  10#include <dm.h>
  11#include <log.h>
  12#include <panel.h>
  13#include <regmap.h>
  14#include "rk_mipi.h"
  15#include <syscon.h>
  16#include <asm/gpio.h>
  17#include <asm/io.h>
  18#include <dm/uclass-internal.h>
  19#include <linux/err.h>
  20#include <linux/kernel.h>
  21#include <asm/arch-rockchip/clock.h>
  22#include <asm/arch-rockchip/cru.h>
  23#include <asm/arch-rockchip/grf_rk3288.h>
  24#include <asm/arch-rockchip/hardware.h>
  25#include <asm/arch-rockchip/rockchip_mipi_dsi.h>
  26
  27#define MHz 1000000
  28
  29/* Select mipi dsi source, big or little vop */
  30static int rk_mipi_dsi_source_select(struct udevice *dev)
  31{
  32        struct rk_mipi_priv *priv = dev_get_priv(dev);
  33        struct rk3288_grf *grf = priv->grf;
  34        struct display_plat *disp_uc_plat = dev_get_uclass_plat(dev);
  35
  36        /* Select the video source */
  37        switch (disp_uc_plat->source_id) {
  38        case VOP_B:
  39                rk_clrsetreg(&grf->soc_con6, RK3288_DSI0_LCDC_SEL_MASK,
  40                             RK3288_DSI0_LCDC_SEL_BIG
  41                             << RK3288_DSI0_LCDC_SEL_SHIFT);
  42                break;
  43        case VOP_L:
  44                rk_clrsetreg(&grf->soc_con6, RK3288_DSI0_LCDC_SEL_MASK,
  45                             RK3288_DSI0_LCDC_SEL_LIT
  46                             << RK3288_DSI0_LCDC_SEL_SHIFT);
  47                break;
  48        default:
  49                debug("%s: Invalid VOP id\n", __func__);
  50                return -EINVAL;
  51        }
  52
  53        return 0;
  54}
  55
  56/* Setup mipi dphy working mode */
  57static void rk_mipi_dphy_mode_set(struct udevice *dev)
  58{
  59        struct rk_mipi_priv *priv = dev_get_priv(dev);
  60        struct rk3288_grf *grf = priv->grf;
  61        int val;
  62
  63        /* Set Controller as TX mode */
  64        val = RK3288_DPHY_TX0_RXMODE_DIS << RK3288_DPHY_TX0_RXMODE_SHIFT;
  65        rk_clrsetreg(&grf->soc_con8, RK3288_DPHY_TX0_RXMODE_MASK, val);
  66
  67        /* Exit tx stop mode */
  68        val |= RK3288_DPHY_TX0_TXSTOPMODE_EN
  69                        << RK3288_DPHY_TX0_TXSTOPMODE_SHIFT;
  70        rk_clrsetreg(&grf->soc_con8,
  71                     RK3288_DPHY_TX0_TXSTOPMODE_MASK, val);
  72
  73        /* Disable turnequest */
  74        val |= RK3288_DPHY_TX0_TURNREQUEST_EN
  75                << RK3288_DPHY_TX0_TURNREQUEST_SHIFT;
  76        rk_clrsetreg(&grf->soc_con8,
  77                     RK3288_DPHY_TX0_TURNREQUEST_MASK, val);
  78}
  79
  80/*
  81 * This function is called by rk_display_init() using rk_mipi_dsi_enable() and
  82 * rk_mipi_phy_enable() to initialize mipi controller and dphy. If success,
  83 * enable backlight.
  84 */
  85static int rk_mipi_enable(struct udevice *dev, int panel_bpp,
  86                          const struct display_timing *timing)
  87{
  88        int ret;
  89        struct rk_mipi_priv *priv = dev_get_priv(dev);
  90
  91        /* Fill the mipi controller parameter */
  92        priv->ref_clk = 24 * MHz;
  93        priv->sys_clk = priv->ref_clk;
  94        priv->pix_clk = timing->pixelclock.typ;
  95        priv->phy_clk = priv->pix_clk * 6;
  96        priv->txbyte_clk = priv->phy_clk / 8;
  97        priv->txesc_clk = 20 * MHz;
  98
  99        /* Select vop port, big or little */
 100        rk_mipi_dsi_source_select(dev);
 101
 102        /* Set mipi dphy work mode */
 103        rk_mipi_dphy_mode_set(dev);
 104
 105        /* Config  and enable mipi dsi according to timing */
 106        ret = rk_mipi_dsi_enable(dev, timing);
 107        if (ret) {
 108                debug("%s: rk_mipi_dsi_enable() failed (err=%d)\n",
 109                      __func__, ret);
 110                return ret;
 111        }
 112
 113        /* Config and enable mipi phy */
 114        ret = rk_mipi_phy_enable(dev);
 115        if (ret) {
 116                debug("%s: rk_mipi_phy_enable() failed (err=%d)\n",
 117                      __func__, ret);
 118                return ret;
 119        }
 120
 121        /* Enable backlight */
 122        ret = panel_enable_backlight(priv->panel);
 123        if (ret) {
 124                debug("%s: panel_enable_backlight() failed (err=%d)\n",
 125                      __func__, ret);
 126                return ret;
 127        }
 128
 129        return 0;
 130}
 131
 132static int rk_mipi_of_to_plat(struct udevice *dev)
 133{
 134        struct rk_mipi_priv *priv = dev_get_priv(dev);
 135
 136        priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
 137        if (IS_ERR_OR_NULL(priv->grf)) {
 138                debug("%s: Get syscon grf failed (ret=%p)\n",
 139                      __func__, priv->grf);
 140                return  -ENXIO;
 141        }
 142        priv->regs = dev_read_addr(dev);
 143        if (priv->regs == FDT_ADDR_T_NONE) {
 144                debug("%s: Get MIPI dsi address failed (ret=%lu)\n", __func__,
 145                      priv->regs);
 146                return  -ENXIO;
 147        }
 148
 149        return 0;
 150}
 151
 152/*
 153 * Probe function: check panel existence and readingit's timing. Then config
 154 * mipi dsi controller and enable it according to the timing parameter.
 155 */
 156static int rk_mipi_probe(struct udevice *dev)
 157{
 158        int ret;
 159        struct rk_mipi_priv *priv = dev_get_priv(dev);
 160
 161        ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
 162                                           &priv->panel);
 163        if (ret) {
 164                debug("%s: Can not find panel (err=%d)\n", __func__, ret);
 165                return ret;
 166        }
 167
 168        return 0;
 169}
 170
 171static const struct dm_display_ops rk_mipi_dsi_ops = {
 172        .read_timing = rk_mipi_read_timing,
 173        .enable = rk_mipi_enable,
 174};
 175
 176static const struct udevice_id rk_mipi_dsi_ids[] = {
 177        { .compatible = "rockchip,rk3288_mipi_dsi" },
 178        { }
 179};
 180
 181U_BOOT_DRIVER(rk_mipi_dsi) = {
 182        .name   = "rk_mipi_dsi",
 183        .id     = UCLASS_DISPLAY,
 184        .of_match = rk_mipi_dsi_ids,
 185        .of_to_plat = rk_mipi_of_to_plat,
 186        .probe  = rk_mipi_probe,
 187        .ops    = &rk_mipi_dsi_ops,
 188        .priv_auto        = sizeof(struct rk_mipi_priv),
 189};
 190