1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2016 Allwinnertech Co., Ltd. 4 * Copyright (C) 2017-2018 Bootlin 5 * 6 * Maxime Ripard <maxime.ripard@free-electrons.com> 7 */ 8 9 #include <linux/bitops.h> 10 #include <linux/clk.h> 11 #include <linux/module.h> 12 #include <linux/of_address.h> 13 #include <linux/platform_device.h> 14 #include <linux/regmap.h> 15 #include <linux/reset.h> 16 17 #include <linux/phy/phy.h> 18 #include <linux/phy/phy-mipi-dphy.h> 19 20 #define SUN6I_DPHY_GCTL_REG 0x00 21 #define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4) 22 #define SUN6I_DPHY_GCTL_EN BIT(0) 23 24 #define SUN6I_DPHY_TX_CTL_REG 0x04 25 #define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28) 26 27 #define SUN6I_DPHY_TX_TIME0_REG 0x10 28 #define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24) 29 #define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16) 30 #define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff) 31 32 #define SUN6I_DPHY_TX_TIME1_REG 0x14 33 #define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24) 34 #define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16) 35 #define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8) 36 #define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff) 37 38 #define SUN6I_DPHY_TX_TIME2_REG 0x18 39 #define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff) 40 41 #define SUN6I_DPHY_TX_TIME3_REG 0x1c 42 43 #define SUN6I_DPHY_TX_TIME4_REG 0x20 44 #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8) 45 #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff) 46 47 #define SUN6I_DPHY_ANA0_REG 0x4c 48 #define SUN6I_DPHY_ANA0_REG_PWS BIT(31) 49 #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) 50 #define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) 51 #define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) 52 #define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) 53 54 #define SUN6I_DPHY_ANA1_REG 0x50 55 #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) 56 #define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28) 57 #define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24) 58 59 #define SUN6I_DPHY_ANA2_REG 0x54 60 #define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24) 61 #define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24) 62 #define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4) 63 #define SUN6I_DPHY_ANA2_REG_ENIB BIT(1) 64 65 #define SUN6I_DPHY_ANA3_REG 0x58 66 #define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28) 67 #define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28) 68 #define SUN6I_DPHY_ANA3_EN_VTTC BIT(27) 69 #define SUN6I_DPHY_ANA3_EN_DIV BIT(26) 70 #define SUN6I_DPHY_ANA3_EN_LDOC BIT(25) 71 #define SUN6I_DPHY_ANA3_EN_LDOD BIT(24) 72 #define SUN6I_DPHY_ANA3_EN_LDOR BIT(18) 73 74 #define SUN6I_DPHY_ANA4_REG 0x5c 75 #define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24) 76 #define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20) 77 #define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12) 78 #define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10) 79 #define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8) 80 #define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6) 81 #define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4) 82 #define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2) 83 #define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3) 84 85 #define SUN6I_DPHY_DBG5_REG 0xf4 86 87 struct sun6i_dphy { 88 struct clk *bus_clk; 89 struct clk *mod_clk; 90 struct regmap *regs; 91 struct reset_control *reset; 92 93 struct phy *phy; 94 struct phy_configure_opts_mipi_dphy config; 95 }; 96 97 static int sun6i_dphy_init(struct phy *phy) 98 { 99 struct sun6i_dphy *dphy = phy_get_drvdata(phy); 100 101 reset_control_deassert(dphy->reset); 102 clk_prepare_enable(dphy->mod_clk); 103 clk_set_rate_exclusive(dphy->mod_clk, 150000000); 104 105 return 0; 106 } 107 108 static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) 109 { 110 struct sun6i_dphy *dphy = phy_get_drvdata(phy); 111 int ret; 112 113 ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); 114 if (ret) 115 return ret; 116 117 memcpy(&dphy->config, opts, sizeof(dphy->config)); 118 119 return 0; 120 } 121 122 static int sun6i_dphy_power_on(struct phy *phy) 123 { 124 struct sun6i_dphy *dphy = phy_get_drvdata(phy); 125 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); 126 127 regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, 128 SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT); 129 130 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, 131 SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) | 132 SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) | 133 SUN6I_DPHY_TX_TIME0_HS_TRAIL(10)); 134 135 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, 136 SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) | 137 SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) | 138 SUN6I_DPHY_TX_TIME1_CLK_PRE(3) | 139 SUN6I_DPHY_TX_TIME1_CLK_POST(10)); 140 141 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, 142 SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30)); 143 144 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); 145 146 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, 147 SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) | 148 SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); 149 150 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 151 SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | 152 SUN6I_DPHY_GCTL_EN); 153 154 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 155 SUN6I_DPHY_ANA0_REG_PWS | 156 SUN6I_DPHY_ANA0_REG_DMPC | 157 SUN6I_DPHY_ANA0_REG_SLV(7) | 158 SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) | 159 SUN6I_DPHY_ANA0_REG_DEN(lanes_mask)); 160 161 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 162 SUN6I_DPHY_ANA1_REG_CSMPS(1) | 163 SUN6I_DPHY_ANA1_REG_SVTT(7)); 164 165 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 166 SUN6I_DPHY_ANA4_REG_CKDV(1) | 167 SUN6I_DPHY_ANA4_REG_TMSC(1) | 168 SUN6I_DPHY_ANA4_REG_TMSD(1) | 169 SUN6I_DPHY_ANA4_REG_TXDNSC(1) | 170 SUN6I_DPHY_ANA4_REG_TXDNSD(1) | 171 SUN6I_DPHY_ANA4_REG_TXPUSC(1) | 172 SUN6I_DPHY_ANA4_REG_TXPUSD(1) | 173 SUN6I_DPHY_ANA4_REG_DMPLVC | 174 SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask)); 175 176 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 177 SUN6I_DPHY_ANA2_REG_ENIB); 178 udelay(5); 179 180 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 181 SUN6I_DPHY_ANA3_EN_LDOR | 182 SUN6I_DPHY_ANA3_EN_LDOC | 183 SUN6I_DPHY_ANA3_EN_LDOD); 184 udelay(1); 185 186 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, 187 SUN6I_DPHY_ANA3_EN_VTTC | 188 SUN6I_DPHY_ANA3_EN_VTTD_MASK, 189 SUN6I_DPHY_ANA3_EN_VTTC | 190 SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask)); 191 udelay(1); 192 193 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, 194 SUN6I_DPHY_ANA3_EN_DIV, 195 SUN6I_DPHY_ANA3_EN_DIV); 196 udelay(1); 197 198 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, 199 SUN6I_DPHY_ANA2_EN_CK_CPU, 200 SUN6I_DPHY_ANA2_EN_CK_CPU); 201 udelay(1); 202 203 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, 204 SUN6I_DPHY_ANA1_REG_VTTMODE, 205 SUN6I_DPHY_ANA1_REG_VTTMODE); 206 207 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, 208 SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK, 209 SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask)); 210 211 return 0; 212 } 213 214 static int sun6i_dphy_power_off(struct phy *phy) 215 { 216 struct sun6i_dphy *dphy = phy_get_drvdata(phy); 217 218 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, 219 SUN6I_DPHY_ANA1_REG_VTTMODE, 0); 220 221 return 0; 222 } 223 224 static int sun6i_dphy_exit(struct phy *phy) 225 { 226 struct sun6i_dphy *dphy = phy_get_drvdata(phy); 227 228 clk_rate_exclusive_put(dphy->mod_clk); 229 clk_disable_unprepare(dphy->mod_clk); 230 reset_control_assert(dphy->reset); 231 232 return 0; 233 } 234 235 236 static struct phy_ops sun6i_dphy_ops = { 237 .configure = sun6i_dphy_configure, 238 .power_on = sun6i_dphy_power_on, 239 .power_off = sun6i_dphy_power_off, 240 .init = sun6i_dphy_init, 241 .exit = sun6i_dphy_exit, 242 }; 243 244 static struct regmap_config sun6i_dphy_regmap_config = { 245 .reg_bits = 32, 246 .val_bits = 32, 247 .reg_stride = 4, 248 .max_register = SUN6I_DPHY_DBG5_REG, 249 .name = "mipi-dphy", 250 }; 251 252 static int sun6i_dphy_probe(struct platform_device *pdev) 253 { 254 struct phy_provider *phy_provider; 255 struct sun6i_dphy *dphy; 256 struct resource *res; 257 void __iomem *regs; 258 259 dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); 260 if (!dphy) 261 return -ENOMEM; 262 263 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 264 regs = devm_ioremap_resource(&pdev->dev, res); 265 if (IS_ERR(regs)) { 266 dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); 267 return PTR_ERR(regs); 268 } 269 270 dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus", 271 regs, &sun6i_dphy_regmap_config); 272 if (IS_ERR(dphy->regs)) { 273 dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n"); 274 return PTR_ERR(dphy->regs); 275 } 276 277 dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL); 278 if (IS_ERR(dphy->reset)) { 279 dev_err(&pdev->dev, "Couldn't get our reset line\n"); 280 return PTR_ERR(dphy->reset); 281 } 282 283 dphy->mod_clk = devm_clk_get(&pdev->dev, "mod"); 284 if (IS_ERR(dphy->mod_clk)) { 285 dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n"); 286 return PTR_ERR(dphy->mod_clk); 287 } 288 289 dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops); 290 if (IS_ERR(dphy->phy)) { 291 dev_err(&pdev->dev, "failed to create PHY\n"); 292 return PTR_ERR(dphy->phy); 293 } 294 295 phy_set_drvdata(dphy->phy, dphy); 296 phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); 297 298 return PTR_ERR_OR_ZERO(phy_provider); 299 } 300 301 static const struct of_device_id sun6i_dphy_of_table[] = { 302 { .compatible = "allwinner,sun6i-a31-mipi-dphy" }, 303 { } 304 }; 305 MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table); 306 307 static struct platform_driver sun6i_dphy_platform_driver = { 308 .probe = sun6i_dphy_probe, 309 .driver = { 310 .name = "sun6i-mipi-dphy", 311 .of_match_table = sun6i_dphy_of_table, 312 }, 313 }; 314 module_platform_driver(sun6i_dphy_platform_driver); 315 316 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin>"); 317 MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver"); 318 MODULE_LICENSE("GPL"); 319