Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc5 292 lines 8.5 kB view raw
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/of_address.h> 12#include <linux/regmap.h> 13#include <linux/reset.h> 14 15#include "sun6i_mipi_dsi.h" 16 17#define SUN6I_DPHY_GCTL_REG 0x00 18#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4) 19#define SUN6I_DPHY_GCTL_EN BIT(0) 20 21#define SUN6I_DPHY_TX_CTL_REG 0x04 22#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28) 23 24#define SUN6I_DPHY_TX_TIME0_REG 0x10 25#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24) 26#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16) 27#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff) 28 29#define SUN6I_DPHY_TX_TIME1_REG 0x14 30#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24) 31#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16) 32#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8) 33#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff) 34 35#define SUN6I_DPHY_TX_TIME2_REG 0x18 36#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff) 37 38#define SUN6I_DPHY_TX_TIME3_REG 0x1c 39 40#define SUN6I_DPHY_TX_TIME4_REG 0x20 41#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8) 42#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff) 43 44#define SUN6I_DPHY_ANA0_REG 0x4c 45#define SUN6I_DPHY_ANA0_REG_PWS BIT(31) 46#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) 47#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) 48#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) 49#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) 50 51#define SUN6I_DPHY_ANA1_REG 0x50 52#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) 53#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28) 54#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24) 55 56#define SUN6I_DPHY_ANA2_REG 0x54 57#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24) 58#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24) 59#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4) 60#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1) 61 62#define SUN6I_DPHY_ANA3_REG 0x58 63#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28) 64#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28) 65#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27) 66#define SUN6I_DPHY_ANA3_EN_DIV BIT(26) 67#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25) 68#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24) 69#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18) 70 71#define SUN6I_DPHY_ANA4_REG 0x5c 72#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24) 73#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20) 74#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12) 75#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10) 76#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8) 77#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6) 78#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4) 79#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2) 80#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3) 81 82#define SUN6I_DPHY_DBG5_REG 0xf4 83 84int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes) 85{ 86 reset_control_deassert(dphy->reset); 87 clk_prepare_enable(dphy->mod_clk); 88 clk_set_rate_exclusive(dphy->mod_clk, 150000000); 89 90 regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, 91 SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT); 92 93 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, 94 SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) | 95 SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) | 96 SUN6I_DPHY_TX_TIME0_HS_TRAIL(10)); 97 98 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, 99 SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) | 100 SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) | 101 SUN6I_DPHY_TX_TIME1_CLK_PRE(3) | 102 SUN6I_DPHY_TX_TIME1_CLK_POST(10)); 103 104 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, 105 SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30)); 106 107 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); 108 109 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, 110 SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) | 111 SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3)); 112 113 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 114 SUN6I_DPHY_GCTL_LANE_NUM(lanes) | 115 SUN6I_DPHY_GCTL_EN); 116 117 return 0; 118} 119 120int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes) 121{ 122 u8 lanes_mask = GENMASK(lanes - 1, 0); 123 124 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 125 SUN6I_DPHY_ANA0_REG_PWS | 126 SUN6I_DPHY_ANA0_REG_DMPC | 127 SUN6I_DPHY_ANA0_REG_SLV(7) | 128 SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) | 129 SUN6I_DPHY_ANA0_REG_DEN(lanes_mask)); 130 131 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 132 SUN6I_DPHY_ANA1_REG_CSMPS(1) | 133 SUN6I_DPHY_ANA1_REG_SVTT(7)); 134 135 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 136 SUN6I_DPHY_ANA4_REG_CKDV(1) | 137 SUN6I_DPHY_ANA4_REG_TMSC(1) | 138 SUN6I_DPHY_ANA4_REG_TMSD(1) | 139 SUN6I_DPHY_ANA4_REG_TXDNSC(1) | 140 SUN6I_DPHY_ANA4_REG_TXDNSD(1) | 141 SUN6I_DPHY_ANA4_REG_TXPUSC(1) | 142 SUN6I_DPHY_ANA4_REG_TXPUSD(1) | 143 SUN6I_DPHY_ANA4_REG_DMPLVC | 144 SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask)); 145 146 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 147 SUN6I_DPHY_ANA2_REG_ENIB); 148 udelay(5); 149 150 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 151 SUN6I_DPHY_ANA3_EN_LDOR | 152 SUN6I_DPHY_ANA3_EN_LDOC | 153 SUN6I_DPHY_ANA3_EN_LDOD); 154 udelay(1); 155 156 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, 157 SUN6I_DPHY_ANA3_EN_VTTC | 158 SUN6I_DPHY_ANA3_EN_VTTD_MASK, 159 SUN6I_DPHY_ANA3_EN_VTTC | 160 SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask)); 161 udelay(1); 162 163 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, 164 SUN6I_DPHY_ANA3_EN_DIV, 165 SUN6I_DPHY_ANA3_EN_DIV); 166 udelay(1); 167 168 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, 169 SUN6I_DPHY_ANA2_EN_CK_CPU, 170 SUN6I_DPHY_ANA2_EN_CK_CPU); 171 udelay(1); 172 173 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, 174 SUN6I_DPHY_ANA1_REG_VTTMODE, 175 SUN6I_DPHY_ANA1_REG_VTTMODE); 176 177 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, 178 SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK, 179 SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask)); 180 181 return 0; 182} 183 184int sun6i_dphy_power_off(struct sun6i_dphy *dphy) 185{ 186 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, 187 SUN6I_DPHY_ANA1_REG_VTTMODE, 0); 188 189 return 0; 190} 191 192int sun6i_dphy_exit(struct sun6i_dphy *dphy) 193{ 194 clk_rate_exclusive_put(dphy->mod_clk); 195 clk_disable_unprepare(dphy->mod_clk); 196 reset_control_assert(dphy->reset); 197 198 return 0; 199} 200 201static struct regmap_config sun6i_dphy_regmap_config = { 202 .reg_bits = 32, 203 .val_bits = 32, 204 .reg_stride = 4, 205 .max_register = SUN6I_DPHY_DBG5_REG, 206 .name = "mipi-dphy", 207}; 208 209static const struct of_device_id sun6i_dphy_of_table[] = { 210 { .compatible = "allwinner,sun6i-a31-mipi-dphy" }, 211 { } 212}; 213 214int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node) 215{ 216 struct sun6i_dphy *dphy; 217 struct resource res; 218 void __iomem *regs; 219 int ret; 220 221 if (!of_match_node(sun6i_dphy_of_table, node)) { 222 dev_err(dsi->dev, "Incompatible D-PHY\n"); 223 return -EINVAL; 224 } 225 226 dphy = devm_kzalloc(dsi->dev, sizeof(*dphy), GFP_KERNEL); 227 if (!dphy) 228 return -ENOMEM; 229 230 ret = of_address_to_resource(node, 0, &res); 231 if (ret) { 232 dev_err(dsi->dev, "phy: Couldn't get our resources\n"); 233 return ret; 234 } 235 236 regs = devm_ioremap_resource(dsi->dev, &res); 237 if (IS_ERR(regs)) { 238 dev_err(dsi->dev, "Couldn't map the DPHY encoder registers\n"); 239 return PTR_ERR(regs); 240 } 241 242 dphy->regs = devm_regmap_init_mmio(dsi->dev, regs, 243 &sun6i_dphy_regmap_config); 244 if (IS_ERR(dphy->regs)) { 245 dev_err(dsi->dev, "Couldn't create the DPHY encoder regmap\n"); 246 return PTR_ERR(dphy->regs); 247 } 248 249 dphy->reset = of_reset_control_get_shared(node, NULL); 250 if (IS_ERR(dphy->reset)) { 251 dev_err(dsi->dev, "Couldn't get our reset line\n"); 252 return PTR_ERR(dphy->reset); 253 } 254 255 dphy->bus_clk = of_clk_get_by_name(node, "bus"); 256 if (IS_ERR(dphy->bus_clk)) { 257 dev_err(dsi->dev, "Couldn't get the DPHY bus clock\n"); 258 ret = PTR_ERR(dphy->bus_clk); 259 goto err_free_reset; 260 } 261 regmap_mmio_attach_clk(dphy->regs, dphy->bus_clk); 262 263 dphy->mod_clk = of_clk_get_by_name(node, "mod"); 264 if (IS_ERR(dphy->mod_clk)) { 265 dev_err(dsi->dev, "Couldn't get the DPHY mod clock\n"); 266 ret = PTR_ERR(dphy->mod_clk); 267 goto err_free_bus; 268 } 269 270 dsi->dphy = dphy; 271 272 return 0; 273 274err_free_bus: 275 regmap_mmio_detach_clk(dphy->regs); 276 clk_put(dphy->bus_clk); 277err_free_reset: 278 reset_control_put(dphy->reset); 279 return ret; 280} 281 282int sun6i_dphy_remove(struct sun6i_dsi *dsi) 283{ 284 struct sun6i_dphy *dphy = dsi->dphy; 285 286 regmap_mmio_detach_clk(dphy->regs); 287 clk_put(dphy->mod_clk); 288 clk_put(dphy->bus_clk); 289 reset_control_put(dphy->reset); 290 291 return 0; 292}