uboot/drivers/phy/meson-axg-mipi-pcie-analog.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Amlogic AXG MIPI + PCIE analog PHY driver
   4 *
   5 * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
   6 * Copyright (C) 2020 BayLibre, SAS
   7 * Author: Neil Armstrong <narmstrong@baylibre.com>
   8 */
   9
  10#include <common.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <asm/io.h>
  14#include <bitfield.h>
  15#include <dm.h>
  16#include <errno.h>
  17#include <generic-phy.h>
  18#include <regmap.h>
  19#include <syscon.h>
  20#include <linux/delay.h>
  21#include <power/regulator.h>
  22#include <reset.h>
  23#include <clk.h>
  24#include <phy-mipi-dphy.h>
  25
  26#include <linux/bitops.h>
  27#include <linux/compat.h>
  28#include <linux/bitfield.h>
  29
  30#define HHI_MIPI_CNTL0 0x00
  31#define         HHI_MIPI_CNTL0_COMMON_BLOCK     GENMASK(31, 28)
  32#define         HHI_MIPI_CNTL0_ENABLE           BIT(29)
  33#define         HHI_MIPI_CNTL0_BANDGAP          BIT(26)
  34#define         HHI_MIPI_CNTL0_DIF_REF_CTL1     GENMASK(25, 16)
  35#define         HHI_MIPI_CNTL0_DIF_REF_CTL0     GENMASK(15, 0)
  36
  37#define HHI_MIPI_CNTL1 0x04
  38#define         HHI_MIPI_CNTL1_CH0_CML_PDR_EN   BIT(12)
  39#define         HHI_MIPI_CNTL1_LP_ABILITY       GENMASK(5, 4)
  40#define         HHI_MIPI_CNTL1_LP_RESISTER      BIT(3)
  41#define         HHI_MIPI_CNTL1_INPUT_SETTING    BIT(2)
  42#define         HHI_MIPI_CNTL1_INPUT_SEL        BIT(1)
  43#define         HHI_MIPI_CNTL1_PRBS7_EN         BIT(0)
  44
  45#define HHI_MIPI_CNTL2 0x08
  46#define         HHI_MIPI_CNTL2_CH_PU            GENMASK(31, 25)
  47#define         HHI_MIPI_CNTL2_CH_CTL           GENMASK(24, 19)
  48#define         HHI_MIPI_CNTL2_CH0_DIGDR_EN     BIT(18)
  49#define         HHI_MIPI_CNTL2_CH_DIGDR_EN      BIT(17)
  50#define         HHI_MIPI_CNTL2_LPULPS_EN        BIT(16)
  51#define         HHI_MIPI_CNTL2_CH_EN            GENMASK(15, 11)
  52#define         HHI_MIPI_CNTL2_CH0_LP_CTL       GENMASK(10, 1)
  53
  54#define DSI_LANE_0              (1 << 4)
  55#define DSI_LANE_1              (1 << 3)
  56#define DSI_LANE_CLK            (1 << 2)
  57#define DSI_LANE_2              (1 << 1)
  58#define DSI_LANE_3              (1 << 0)
  59#define DSI_LANE_MASK           (0x1F)
  60
  61struct phy_meson_axg_mipi_pcie_analog_priv {
  62        struct regmap *regmap;
  63        struct phy_configure_opts_mipi_dphy config;
  64        bool dsi_configured;
  65        bool dsi_enabled;
  66        bool powered;
  67};
  68
  69static void phy_bandgap_enable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
  70{
  71        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  72                        HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
  73
  74        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  75                        HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
  76}
  77
  78static void phy_bandgap_disable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
  79{
  80        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  81                        HHI_MIPI_CNTL0_BANDGAP, 0);
  82        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  83                        HHI_MIPI_CNTL0_ENABLE, 0);
  84}
  85
  86static void phy_dsi_analog_enable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
  87{
  88        u32 reg;
  89
  90        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  91                           HHI_MIPI_CNTL0_DIF_REF_CTL1,
  92                           FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0x1b8));
  93        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  94                           BIT(31), BIT(31));
  95        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  96                           HHI_MIPI_CNTL0_DIF_REF_CTL0,
  97                           FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0, 0x8));
  98
  99        regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x001e);
 100
 101        regmap_write(priv->regmap, HHI_MIPI_CNTL2,
 102                     (0x26e0 << 16) | (0x459 << 0));
 103
 104        reg = DSI_LANE_CLK;
 105        switch (priv->config.lanes) {
 106        case 4:
 107                reg |= DSI_LANE_3;
 108                fallthrough;
 109        case 3:
 110                reg |= DSI_LANE_2;
 111                fallthrough;
 112        case 2:
 113                reg |= DSI_LANE_1;
 114                fallthrough;
 115        case 1:
 116                reg |= DSI_LANE_0;
 117                break;
 118        default:
 119                reg = 0;
 120        }
 121
 122        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL2,
 123                           HHI_MIPI_CNTL2_CH_EN,
 124                           FIELD_PREP(HHI_MIPI_CNTL2_CH_EN, reg));
 125
 126        priv->dsi_enabled = true;
 127}
 128
 129static void phy_dsi_analog_disable(struct phy_meson_axg_mipi_pcie_analog_priv *priv)
 130{
 131        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
 132                        HHI_MIPI_CNTL0_DIF_REF_CTL1,
 133                        FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0));
 134        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, BIT(31), 0);
 135        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
 136                        HHI_MIPI_CNTL0_DIF_REF_CTL1, 0);
 137
 138        regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x6);
 139
 140        regmap_write(priv->regmap, HHI_MIPI_CNTL2, 0x00200000);
 141
 142        priv->dsi_enabled = false;
 143}
 144
 145static int phy_meson_axg_mipi_pcie_analog_configure(struct phy *phy, void *params)
 146{
 147        struct udevice *dev = phy->dev;
 148        struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
 149        struct phy_configure_opts_mipi_dphy *config = params;
 150        int ret;
 151
 152        ret = phy_mipi_dphy_config_validate(config);
 153        if (ret)
 154                return ret;
 155
 156        memcpy(&priv->config, config, sizeof(priv->config));
 157
 158        priv->dsi_configured = true;
 159
 160        /* If PHY was already powered on, setup the DSI analog part */
 161        if (priv->powered) {
 162                /* If reconfiguring, disable & reconfigure */
 163                if (priv->dsi_enabled)
 164                        phy_dsi_analog_disable(priv);
 165
 166                udelay(100);
 167
 168                phy_dsi_analog_enable(priv);
 169        }
 170
 171        return 0;
 172}
 173
 174static int phy_meson_axg_mipi_pcie_analog_power_on(struct phy *phy)
 175{
 176        struct udevice *dev = phy->dev;
 177        struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
 178
 179        phy_bandgap_enable(priv);
 180
 181        if (priv->dsi_configured)
 182                phy_dsi_analog_enable(priv);
 183
 184        priv->powered = true;
 185
 186        return 0;
 187}
 188
 189static int phy_meson_axg_mipi_pcie_analog_power_off(struct phy *phy)
 190{
 191        struct udevice *dev = phy->dev;
 192        struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
 193
 194        phy_bandgap_disable(priv);
 195
 196        if (priv->dsi_enabled)
 197                phy_dsi_analog_disable(priv);
 198
 199        priv->powered = false;
 200
 201        return 0;
 202}
 203
 204struct phy_ops meson_axg_mipi_pcie_analog_ops = {
 205        .power_on = phy_meson_axg_mipi_pcie_analog_power_on,
 206        .power_off = phy_meson_axg_mipi_pcie_analog_power_off,
 207        .configure = phy_meson_axg_mipi_pcie_analog_configure,
 208};
 209
 210int meson_axg_mipi_pcie_analog_probe(struct udevice *dev)
 211{
 212        struct phy_meson_axg_mipi_pcie_analog_priv *priv = dev_get_priv(dev);
 213
 214        priv->regmap = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
 215        if (IS_ERR(priv->regmap))
 216                return PTR_ERR(priv->regmap);
 217
 218        return 0;
 219}
 220
 221static const struct udevice_id meson_axg_mipi_pcie_analog_ids[] = {
 222        { .compatible = "amlogic,axg-mipi-pcie-analog-phy" },
 223        { }
 224};
 225
 226U_BOOT_DRIVER(meson_axg_mipi_pcie_analog) = {
 227        .name = "meson_axg_mipi_pcie_analog",
 228        .id = UCLASS_PHY,
 229        .of_match = meson_axg_mipi_pcie_analog_ids,
 230        .probe = meson_axg_mipi_pcie_analog_probe,
 231        .ops = &meson_axg_mipi_pcie_analog_ops,
 232        .priv_auto = sizeof(struct phy_meson_axg_mipi_pcie_analog_priv),
 233};
 234