0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/bitops.h>
0010 #include <linux/clk.h>
0011 #include <linux/module.h>
0012 #include <linux/of_address.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/regmap.h>
0015 #include <linux/reset.h>
0016
0017 #include <linux/phy/phy.h>
0018 #include <linux/phy/phy-mipi-dphy.h>
0019
0020 #define SUN6I_DPHY_GCTL_REG 0x00
0021 #define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
0022 #define SUN6I_DPHY_GCTL_EN BIT(0)
0023
0024 #define SUN6I_DPHY_TX_CTL_REG 0x04
0025 #define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
0026
0027 #define SUN6I_DPHY_RX_CTL_REG 0x08
0028 #define SUN6I_DPHY_RX_CTL_EN_DBC BIT(31)
0029 #define SUN6I_DPHY_RX_CTL_RX_CLK_FORCE BIT(24)
0030 #define SUN6I_DPHY_RX_CTL_RX_D3_FORCE BIT(23)
0031 #define SUN6I_DPHY_RX_CTL_RX_D2_FORCE BIT(22)
0032 #define SUN6I_DPHY_RX_CTL_RX_D1_FORCE BIT(21)
0033 #define SUN6I_DPHY_RX_CTL_RX_D0_FORCE BIT(20)
0034
0035 #define SUN6I_DPHY_TX_TIME0_REG 0x10
0036 #define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
0037 #define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
0038 #define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff)
0039
0040 #define SUN6I_DPHY_TX_TIME1_REG 0x14
0041 #define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24)
0042 #define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16)
0043 #define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8)
0044 #define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff)
0045
0046 #define SUN6I_DPHY_TX_TIME2_REG 0x18
0047 #define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff)
0048
0049 #define SUN6I_DPHY_TX_TIME3_REG 0x1c
0050
0051 #define SUN6I_DPHY_TX_TIME4_REG 0x20
0052 #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
0053 #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
0054
0055 #define SUN6I_DPHY_RX_TIME0_REG 0x30
0056 #define SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(n) (((n) & 0xff) << 24)
0057 #define SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(n) (((n) & 0xff) << 16)
0058 #define SUN6I_DPHY_RX_TIME0_LP_RX(n) (((n) & 0xff) << 8)
0059
0060 #define SUN6I_DPHY_RX_TIME1_REG 0x34
0061 #define SUN6I_DPHY_RX_TIME1_RX_DLY(n) (((n) & 0xfff) << 20)
0062 #define SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(n) ((n) & 0xfffff)
0063
0064 #define SUN6I_DPHY_RX_TIME2_REG 0x38
0065 #define SUN6I_DPHY_RX_TIME2_HS_RX_ANA1(n) (((n) & 0xff) << 8)
0066 #define SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(n) ((n) & 0xff)
0067
0068 #define SUN6I_DPHY_RX_TIME3_REG 0x40
0069 #define SUN6I_DPHY_RX_TIME3_LPRST_DLY(n) (((n) & 0xffff) << 16)
0070
0071 #define SUN6I_DPHY_ANA0_REG 0x4c
0072 #define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
0073 #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
0074 #define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
0075 #define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
0076 #define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
0077 #define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2)
0078
0079 #define SUN6I_DPHY_ANA1_REG 0x50
0080 #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
0081 #define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28)
0082 #define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24)
0083
0084 #define SUN6I_DPHY_ANA2_REG 0x54
0085 #define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24)
0086 #define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24)
0087 #define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4)
0088 #define SUN6I_DPHY_ANA2_REG_ENIB BIT(1)
0089
0090 #define SUN6I_DPHY_ANA3_REG 0x58
0091 #define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28)
0092 #define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28)
0093 #define SUN6I_DPHY_ANA3_EN_VTTC BIT(27)
0094 #define SUN6I_DPHY_ANA3_EN_DIV BIT(26)
0095 #define SUN6I_DPHY_ANA3_EN_LDOC BIT(25)
0096 #define SUN6I_DPHY_ANA3_EN_LDOD BIT(24)
0097 #define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
0098
0099 #define SUN6I_DPHY_ANA4_REG 0x5c
0100 #define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
0101 #define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
0102 #define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
0103 #define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
0104 #define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
0105 #define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6)
0106 #define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4)
0107 #define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2)
0108 #define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3)
0109
0110 #define SUN6I_DPHY_DBG5_REG 0xf4
0111
0112 enum sun6i_dphy_direction {
0113 SUN6I_DPHY_DIRECTION_TX,
0114 SUN6I_DPHY_DIRECTION_RX,
0115 };
0116
0117 struct sun6i_dphy {
0118 struct clk *bus_clk;
0119 struct clk *mod_clk;
0120 struct regmap *regs;
0121 struct reset_control *reset;
0122
0123 struct phy *phy;
0124 struct phy_configure_opts_mipi_dphy config;
0125
0126 enum sun6i_dphy_direction direction;
0127 };
0128
0129 static int sun6i_dphy_init(struct phy *phy)
0130 {
0131 struct sun6i_dphy *dphy = phy_get_drvdata(phy);
0132
0133 reset_control_deassert(dphy->reset);
0134 clk_prepare_enable(dphy->mod_clk);
0135 clk_set_rate_exclusive(dphy->mod_clk, 150000000);
0136
0137 return 0;
0138 }
0139
0140 static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
0141 {
0142 struct sun6i_dphy *dphy = phy_get_drvdata(phy);
0143 int ret;
0144
0145 ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
0146 if (ret)
0147 return ret;
0148
0149 memcpy(&dphy->config, opts, sizeof(dphy->config));
0150
0151 return 0;
0152 }
0153
0154 static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
0155 {
0156 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
0157
0158 regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
0159 SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
0160
0161 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
0162 SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
0163 SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
0164 SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
0165
0166 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
0167 SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
0168 SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
0169 SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
0170 SUN6I_DPHY_TX_TIME1_CLK_POST(10));
0171
0172 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
0173 SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
0174
0175 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
0176
0177 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
0178 SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
0179 SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
0180
0181 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
0182 SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
0183 SUN6I_DPHY_GCTL_EN);
0184
0185 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
0186 SUN6I_DPHY_ANA0_REG_PWS |
0187 SUN6I_DPHY_ANA0_REG_DMPC |
0188 SUN6I_DPHY_ANA0_REG_SLV(7) |
0189 SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
0190 SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
0191
0192 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
0193 SUN6I_DPHY_ANA1_REG_CSMPS(1) |
0194 SUN6I_DPHY_ANA1_REG_SVTT(7));
0195
0196 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
0197 SUN6I_DPHY_ANA4_REG_CKDV(1) |
0198 SUN6I_DPHY_ANA4_REG_TMSC(1) |
0199 SUN6I_DPHY_ANA4_REG_TMSD(1) |
0200 SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
0201 SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
0202 SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
0203 SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
0204 SUN6I_DPHY_ANA4_REG_DMPLVC |
0205 SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
0206
0207 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
0208 SUN6I_DPHY_ANA2_REG_ENIB);
0209 udelay(5);
0210
0211 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
0212 SUN6I_DPHY_ANA3_EN_LDOR |
0213 SUN6I_DPHY_ANA3_EN_LDOC |
0214 SUN6I_DPHY_ANA3_EN_LDOD);
0215 udelay(1);
0216
0217 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
0218 SUN6I_DPHY_ANA3_EN_VTTC |
0219 SUN6I_DPHY_ANA3_EN_VTTD_MASK,
0220 SUN6I_DPHY_ANA3_EN_VTTC |
0221 SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
0222 udelay(1);
0223
0224 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
0225 SUN6I_DPHY_ANA3_EN_DIV,
0226 SUN6I_DPHY_ANA3_EN_DIV);
0227 udelay(1);
0228
0229 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
0230 SUN6I_DPHY_ANA2_EN_CK_CPU,
0231 SUN6I_DPHY_ANA2_EN_CK_CPU);
0232 udelay(1);
0233
0234 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
0235 SUN6I_DPHY_ANA1_REG_VTTMODE,
0236 SUN6I_DPHY_ANA1_REG_VTTMODE);
0237
0238 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
0239 SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
0240 SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
0241
0242 return 0;
0243 }
0244
0245 static int sun6i_dphy_rx_power_on(struct sun6i_dphy *dphy)
0246 {
0247
0248 unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate;
0249 unsigned long dphy_clk_rate;
0250 unsigned int rx_dly;
0251 unsigned int lprst_dly;
0252 u32 value;
0253
0254 dphy_clk_rate = clk_get_rate(dphy->mod_clk);
0255 if (!dphy_clk_rate)
0256 return -EINVAL;
0257
0258
0259 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME0_REG,
0260 SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(255) |
0261 SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(255) |
0262 SUN6I_DPHY_RX_TIME0_LP_RX(255));
0263
0264
0265
0266
0267
0268 rx_dly = 8 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 8));
0269
0270
0271
0272
0273
0274
0275 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME1_REG,
0276 SUN6I_DPHY_RX_TIME1_RX_DLY(rx_dly) |
0277 SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(255));
0278
0279
0280 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME2_REG,
0281 SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(4));
0282
0283
0284
0285
0286
0287 lprst_dly = 4 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 2));
0288
0289 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME3_REG,
0290 SUN6I_DPHY_RX_TIME3_LPRST_DLY(lprst_dly));
0291
0292
0293 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
0294 SUN6I_DPHY_ANA0_REG_PWS |
0295 SUN6I_DPHY_ANA0_REG_SLV(7) |
0296 SUN6I_DPHY_ANA0_REG_SFB(2));
0297
0298 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
0299 SUN6I_DPHY_ANA1_REG_SVTT(4));
0300
0301 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
0302 SUN6I_DPHY_ANA4_REG_DMPLVC |
0303 SUN6I_DPHY_ANA4_REG_DMPLVD(1));
0304
0305 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
0306 SUN6I_DPHY_ANA2_REG_ENIB);
0307
0308 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
0309 SUN6I_DPHY_ANA3_EN_LDOR |
0310 SUN6I_DPHY_ANA3_EN_LDOC |
0311 SUN6I_DPHY_ANA3_EN_LDOD);
0312
0313
0314
0315
0316
0317 udelay(3);
0318
0319 value = SUN6I_DPHY_RX_CTL_EN_DBC | SUN6I_DPHY_RX_CTL_RX_CLK_FORCE;
0320
0321
0322
0323
0324
0325 if (dphy->config.lanes >= 1)
0326 value |= SUN6I_DPHY_RX_CTL_RX_D0_FORCE;
0327 if (dphy->config.lanes >= 2)
0328 value |= SUN6I_DPHY_RX_CTL_RX_D1_FORCE;
0329 if (dphy->config.lanes >= 3)
0330 value |= SUN6I_DPHY_RX_CTL_RX_D2_FORCE;
0331 if (dphy->config.lanes == 4)
0332 value |= SUN6I_DPHY_RX_CTL_RX_D3_FORCE;
0333
0334 regmap_write(dphy->regs, SUN6I_DPHY_RX_CTL_REG, value);
0335
0336 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
0337 SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
0338 SUN6I_DPHY_GCTL_EN);
0339
0340 return 0;
0341 }
0342
0343 static int sun6i_dphy_power_on(struct phy *phy)
0344 {
0345 struct sun6i_dphy *dphy = phy_get_drvdata(phy);
0346
0347 switch (dphy->direction) {
0348 case SUN6I_DPHY_DIRECTION_TX:
0349 return sun6i_dphy_tx_power_on(dphy);
0350 case SUN6I_DPHY_DIRECTION_RX:
0351 return sun6i_dphy_rx_power_on(dphy);
0352 default:
0353 return -EINVAL;
0354 }
0355 }
0356
0357 static int sun6i_dphy_power_off(struct phy *phy)
0358 {
0359 struct sun6i_dphy *dphy = phy_get_drvdata(phy);
0360
0361 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 0);
0362
0363 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 0);
0364 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 0);
0365 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 0);
0366 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 0);
0367 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 0);
0368
0369 return 0;
0370 }
0371
0372 static int sun6i_dphy_exit(struct phy *phy)
0373 {
0374 struct sun6i_dphy *dphy = phy_get_drvdata(phy);
0375
0376 clk_rate_exclusive_put(dphy->mod_clk);
0377 clk_disable_unprepare(dphy->mod_clk);
0378 reset_control_assert(dphy->reset);
0379
0380 return 0;
0381 }
0382
0383
0384 static const struct phy_ops sun6i_dphy_ops = {
0385 .configure = sun6i_dphy_configure,
0386 .power_on = sun6i_dphy_power_on,
0387 .power_off = sun6i_dphy_power_off,
0388 .init = sun6i_dphy_init,
0389 .exit = sun6i_dphy_exit,
0390 };
0391
0392 static const struct regmap_config sun6i_dphy_regmap_config = {
0393 .reg_bits = 32,
0394 .val_bits = 32,
0395 .reg_stride = 4,
0396 .max_register = SUN6I_DPHY_DBG5_REG,
0397 .name = "mipi-dphy",
0398 };
0399
0400 static int sun6i_dphy_probe(struct platform_device *pdev)
0401 {
0402 struct phy_provider *phy_provider;
0403 struct sun6i_dphy *dphy;
0404 const char *direction;
0405 void __iomem *regs;
0406 int ret;
0407
0408 dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
0409 if (!dphy)
0410 return -ENOMEM;
0411
0412 regs = devm_platform_ioremap_resource(pdev, 0);
0413 if (IS_ERR(regs)) {
0414 dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n");
0415 return PTR_ERR(regs);
0416 }
0417
0418 dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus",
0419 regs, &sun6i_dphy_regmap_config);
0420 if (IS_ERR(dphy->regs)) {
0421 dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n");
0422 return PTR_ERR(dphy->regs);
0423 }
0424
0425 dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL);
0426 if (IS_ERR(dphy->reset)) {
0427 dev_err(&pdev->dev, "Couldn't get our reset line\n");
0428 return PTR_ERR(dphy->reset);
0429 }
0430
0431 dphy->mod_clk = devm_clk_get(&pdev->dev, "mod");
0432 if (IS_ERR(dphy->mod_clk)) {
0433 dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n");
0434 return PTR_ERR(dphy->mod_clk);
0435 }
0436
0437 dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops);
0438 if (IS_ERR(dphy->phy)) {
0439 dev_err(&pdev->dev, "failed to create PHY\n");
0440 return PTR_ERR(dphy->phy);
0441 }
0442
0443 dphy->direction = SUN6I_DPHY_DIRECTION_TX;
0444
0445 ret = of_property_read_string(pdev->dev.of_node, "allwinner,direction",
0446 &direction);
0447
0448 if (!ret && !strncmp(direction, "rx", 2))
0449 dphy->direction = SUN6I_DPHY_DIRECTION_RX;
0450
0451 phy_set_drvdata(dphy->phy, dphy);
0452 phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
0453
0454 return PTR_ERR_OR_ZERO(phy_provider);
0455 }
0456
0457 static const struct of_device_id sun6i_dphy_of_table[] = {
0458 { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
0459 { }
0460 };
0461 MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);
0462
0463 static struct platform_driver sun6i_dphy_platform_driver = {
0464 .probe = sun6i_dphy_probe,
0465 .driver = {
0466 .name = "sun6i-mipi-dphy",
0467 .of_match_table = sun6i_dphy_of_table,
0468 },
0469 };
0470 module_platform_driver(sun6i_dphy_platform_driver);
0471
0472 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin>");
0473 MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");
0474 MODULE_LICENSE("GPL");