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 */ 7 #include <linux/bitfield.h> 8 #include <linux/bitops.h> 9 #include <linux/module.h> 10 #include <linux/phy/phy.h> 11 #include <linux/regmap.h> 12 #include <linux/delay.h> 13 #include <linux/mfd/syscon.h> 14 #include <linux/of.h> 15 #include <linux/platform_device.h> 16 #include <dt-bindings/phy/phy.h> 17 18 #define HHI_MIPI_CNTL0 0x00 19 #define HHI_MIPI_CNTL0_COMMON_BLOCK GENMASK(31, 28) 20 #define HHI_MIPI_CNTL0_ENABLE BIT(29) 21 #define HHI_MIPI_CNTL0_BANDGAP BIT(26) 22 #define HHI_MIPI_CNTL0_DIF_REF_CTL1 GENMASK(25, 16) 23 #define HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0) 24 25 #define HHI_MIPI_CNTL1 0x04 26 #define HHI_MIPI_CNTL1_CH0_CML_PDR_EN BIT(12) 27 #define HHI_MIPI_CNTL1_LP_ABILITY GENMASK(5, 4) 28 #define HHI_MIPI_CNTL1_LP_RESISTER BIT(3) 29 #define HHI_MIPI_CNTL1_INPUT_SETTING BIT(2) 30 #define HHI_MIPI_CNTL1_INPUT_SEL BIT(1) 31 #define HHI_MIPI_CNTL1_PRBS7_EN BIT(0) 32 33 #define HHI_MIPI_CNTL2 0x08 34 #define HHI_MIPI_CNTL2_CH_PU GENMASK(31, 25) 35 #define HHI_MIPI_CNTL2_CH_CTL GENMASK(24, 19) 36 #define HHI_MIPI_CNTL2_CH0_DIGDR_EN BIT(18) 37 #define HHI_MIPI_CNTL2_CH_DIGDR_EN BIT(17) 38 #define HHI_MIPI_CNTL2_LPULPS_EN BIT(16) 39 #define HHI_MIPI_CNTL2_CH_EN GENMASK(15, 11) 40 #define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1) 41 42 #define DSI_LANE_0 BIT(4) 43 #define DSI_LANE_1 BIT(3) 44 #define DSI_LANE_CLK BIT(2) 45 #define DSI_LANE_2 BIT(1) 46 #define DSI_LANE_3 BIT(0) 47 48 struct phy_axg_mipi_pcie_analog_priv { 49 struct phy *phy; 50 struct regmap *regmap; 51 bool dsi_configured; 52 bool dsi_enabled; 53 bool powered; 54 struct phy_configure_opts_mipi_dphy config; 55 }; 56 57 static void phy_bandgap_enable(struct phy_axg_mipi_pcie_analog_priv *priv) 58 { 59 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 60 HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP); 61 62 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 63 HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE); 64 } 65 66 static void phy_bandgap_disable(struct phy_axg_mipi_pcie_analog_priv *priv) 67 { 68 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 69 HHI_MIPI_CNTL0_BANDGAP, 0); 70 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 71 HHI_MIPI_CNTL0_ENABLE, 0); 72 } 73 74 static void phy_dsi_analog_enable(struct phy_axg_mipi_pcie_analog_priv *priv) 75 { 76 u32 reg; 77 78 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 79 HHI_MIPI_CNTL0_DIF_REF_CTL1, 80 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0x1b8)); 81 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 82 BIT(31), BIT(31)); 83 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 84 HHI_MIPI_CNTL0_DIF_REF_CTL0, 85 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0, 0x8)); 86 87 regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x001e); 88 89 regmap_write(priv->regmap, HHI_MIPI_CNTL2, 90 (0x26e0 << 16) | (0x459 << 0)); 91 92 reg = DSI_LANE_CLK; 93 switch (priv->config.lanes) { 94 case 4: 95 reg |= DSI_LANE_3; 96 fallthrough; 97 case 3: 98 reg |= DSI_LANE_2; 99 fallthrough; 100 case 2: 101 reg |= DSI_LANE_1; 102 fallthrough; 103 case 1: 104 reg |= DSI_LANE_0; 105 break; 106 default: 107 reg = 0; 108 } 109 110 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL2, 111 HHI_MIPI_CNTL2_CH_EN, 112 FIELD_PREP(HHI_MIPI_CNTL2_CH_EN, reg)); 113 114 priv->dsi_enabled = true; 115 } 116 117 static void phy_dsi_analog_disable(struct phy_axg_mipi_pcie_analog_priv *priv) 118 { 119 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 120 HHI_MIPI_CNTL0_DIF_REF_CTL1, 121 FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0)); 122 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, BIT(31), 0); 123 regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, 124 HHI_MIPI_CNTL0_DIF_REF_CTL1, 0); 125 126 regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x6); 127 128 regmap_write(priv->regmap, HHI_MIPI_CNTL2, 0x00200000); 129 130 priv->dsi_enabled = false; 131 } 132 133 static int phy_axg_mipi_pcie_analog_configure(struct phy *phy, 134 union phy_configure_opts *opts) 135 { 136 struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy); 137 int ret; 138 139 ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); 140 if (ret) 141 return ret; 142 143 memcpy(&priv->config, opts, sizeof(priv->config)); 144 145 priv->dsi_configured = true; 146 147 /* If PHY was already powered on, setup the DSI analog part */ 148 if (priv->powered) { 149 /* If reconfiguring, disable & reconfigure */ 150 if (priv->dsi_enabled) 151 phy_dsi_analog_disable(priv); 152 153 usleep_range(100, 200); 154 155 phy_dsi_analog_enable(priv); 156 } 157 158 return 0; 159 } 160 161 static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy) 162 { 163 struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy); 164 165 phy_bandgap_enable(priv); 166 167 if (priv->dsi_configured) 168 phy_dsi_analog_enable(priv); 169 170 priv->powered = true; 171 172 return 0; 173 } 174 175 static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy) 176 { 177 struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy); 178 179 phy_bandgap_disable(priv); 180 181 if (priv->dsi_enabled) 182 phy_dsi_analog_disable(priv); 183 184 priv->powered = false; 185 186 return 0; 187 } 188 189 static const struct phy_ops phy_axg_mipi_pcie_analog_ops = { 190 .configure = phy_axg_mipi_pcie_analog_configure, 191 .power_on = phy_axg_mipi_pcie_analog_power_on, 192 .power_off = phy_axg_mipi_pcie_analog_power_off, 193 .owner = THIS_MODULE, 194 }; 195 196 static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev) 197 { 198 struct phy_provider *phy; 199 struct device *dev = &pdev->dev; 200 struct phy_axg_mipi_pcie_analog_priv *priv; 201 struct device_node *np = dev->of_node, *parent_np; 202 struct regmap *map; 203 int ret; 204 205 priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL); 206 if (!priv) 207 return -ENOMEM; 208 209 /* Get the hhi system controller node */ 210 parent_np = of_get_parent(dev->of_node); 211 map = syscon_node_to_regmap(parent_np); 212 of_node_put(parent_np); 213 if (IS_ERR(map)) { 214 dev_err(dev, 215 "failed to get HHI regmap\n"); 216 return PTR_ERR(map); 217 } 218 219 priv->regmap = map; 220 221 priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops); 222 if (IS_ERR(priv->phy)) { 223 ret = PTR_ERR(priv->phy); 224 if (ret != -EPROBE_DEFER) 225 dev_err(dev, "failed to create PHY\n"); 226 return ret; 227 } 228 229 phy_set_drvdata(priv->phy, priv); 230 dev_set_drvdata(dev, priv); 231 232 phy = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 233 234 return PTR_ERR_OR_ZERO(phy); 235 } 236 237 static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = { 238 { 239 .compatible = "amlogic,axg-mipi-pcie-analog-phy", 240 }, 241 { }, 242 }; 243 MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match); 244 245 static struct platform_driver phy_axg_mipi_pcie_analog_driver = { 246 .probe = phy_axg_mipi_pcie_analog_probe, 247 .driver = { 248 .name = "phy-axg-mipi-pcie-analog", 249 .of_match_table = phy_axg_mipi_pcie_analog_of_match, 250 }, 251 }; 252 module_platform_driver(phy_axg_mipi_pcie_analog_driver); 253 254 MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>"); 255 MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver"); 256 MODULE_LICENSE("GPL v2"); 257