diff options
Diffstat (limited to 'drivers/ata/ahci_imx.c')
-rw-r--r-- | drivers/ata/ahci_imx.c | 179 |
1 files changed, 172 insertions, 7 deletions
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 497c7abe1c7d..8befeb69eeb1 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c | |||
@@ -29,9 +29,25 @@ | |||
29 | #include "ahci.h" | 29 | #include "ahci.h" |
30 | 30 | ||
31 | enum { | 31 | enum { |
32 | PORT_PHY_CTL = 0x178, /* Port0 PHY Control */ | 32 | /* Timer 1-ms Register */ |
33 | PORT_PHY_CTL_PDDQ_LOC = 0x100000, /* PORT_PHY_CTL bits */ | 33 | IMX_TIMER1MS = 0x00e0, |
34 | HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ | 34 | /* Port0 PHY Control Register */ |
35 | IMX_P0PHYCR = 0x0178, | ||
36 | IMX_P0PHYCR_TEST_PDDQ = 1 << 20, | ||
37 | IMX_P0PHYCR_CR_READ = 1 << 19, | ||
38 | IMX_P0PHYCR_CR_WRITE = 1 << 18, | ||
39 | IMX_P0PHYCR_CR_CAP_DATA = 1 << 17, | ||
40 | IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16, | ||
41 | /* Port0 PHY Status Register */ | ||
42 | IMX_P0PHYSR = 0x017c, | ||
43 | IMX_P0PHYSR_CR_ACK = 1 << 18, | ||
44 | IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0, | ||
45 | /* Lane0 Output Status Register */ | ||
46 | IMX_LANE0_OUT_STAT = 0x2003, | ||
47 | IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1, | ||
48 | /* Clock Reset Register */ | ||
49 | IMX_CLOCK_RESET = 0x7f3f, | ||
50 | IMX_CLOCK_RESET_RESET = 1 << 0, | ||
35 | }; | 51 | }; |
36 | 52 | ||
37 | enum ahci_imx_type { | 53 | enum ahci_imx_type { |
@@ -54,9 +70,149 @@ MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support | |||
54 | 70 | ||
55 | static void ahci_imx_host_stop(struct ata_host *host); | 71 | static void ahci_imx_host_stop(struct ata_host *host); |
56 | 72 | ||
73 | static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert) | ||
74 | { | ||
75 | int timeout = 10; | ||
76 | u32 crval; | ||
77 | u32 srval; | ||
78 | |||
79 | /* Assert or deassert the bit */ | ||
80 | crval = readl(mmio + IMX_P0PHYCR); | ||
81 | if (assert) | ||
82 | crval |= bit; | ||
83 | else | ||
84 | crval &= ~bit; | ||
85 | writel(crval, mmio + IMX_P0PHYCR); | ||
86 | |||
87 | /* Wait for the cr_ack signal */ | ||
88 | do { | ||
89 | srval = readl(mmio + IMX_P0PHYSR); | ||
90 | if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) | ||
91 | break; | ||
92 | usleep_range(100, 200); | ||
93 | } while (--timeout); | ||
94 | |||
95 | return timeout ? 0 : -ETIMEDOUT; | ||
96 | } | ||
97 | |||
98 | static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) | ||
99 | { | ||
100 | u32 crval = addr; | ||
101 | int ret; | ||
102 | |||
103 | /* Supply the address on cr_data_in */ | ||
104 | writel(crval, mmio + IMX_P0PHYCR); | ||
105 | |||
106 | /* Assert the cr_cap_addr signal */ | ||
107 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); | ||
108 | if (ret) | ||
109 | return ret; | ||
110 | |||
111 | /* Deassert cr_cap_addr */ | ||
112 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); | ||
113 | if (ret) | ||
114 | return ret; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int imx_phy_reg_write(u16 val, void __iomem *mmio) | ||
120 | { | ||
121 | u32 crval = val; | ||
122 | int ret; | ||
123 | |||
124 | /* Supply the data on cr_data_in */ | ||
125 | writel(crval, mmio + IMX_P0PHYCR); | ||
126 | |||
127 | /* Assert the cr_cap_data signal */ | ||
128 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | |||
132 | /* Deassert cr_cap_data */ | ||
133 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); | ||
134 | if (ret) | ||
135 | return ret; | ||
136 | |||
137 | if (val & IMX_CLOCK_RESET_RESET) { | ||
138 | /* | ||
139 | * In case we're resetting the phy, it's unable to acknowledge, | ||
140 | * so we return immediately here. | ||
141 | */ | ||
142 | crval |= IMX_P0PHYCR_CR_WRITE; | ||
143 | writel(crval, mmio + IMX_P0PHYCR); | ||
144 | goto out; | ||
145 | } | ||
146 | |||
147 | /* Assert the cr_write signal */ | ||
148 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); | ||
149 | if (ret) | ||
150 | return ret; | ||
151 | |||
152 | /* Deassert cr_write */ | ||
153 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); | ||
154 | if (ret) | ||
155 | return ret; | ||
156 | |||
157 | out: | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int imx_phy_reg_read(u16 *val, void __iomem *mmio) | ||
162 | { | ||
163 | int ret; | ||
164 | |||
165 | /* Assert the cr_read signal */ | ||
166 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); | ||
167 | if (ret) | ||
168 | return ret; | ||
169 | |||
170 | /* Capture the data from cr_data_out[] */ | ||
171 | *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; | ||
172 | |||
173 | /* Deassert cr_read */ | ||
174 | ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); | ||
175 | if (ret) | ||
176 | return ret; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) | ||
182 | { | ||
183 | void __iomem *mmio = hpriv->mmio; | ||
184 | int timeout = 10; | ||
185 | u16 val; | ||
186 | int ret; | ||
187 | |||
188 | /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ | ||
189 | ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); | ||
190 | if (ret) | ||
191 | return ret; | ||
192 | ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); | ||
193 | if (ret) | ||
194 | return ret; | ||
195 | |||
196 | /* Wait for PHY RX_PLL to be stable */ | ||
197 | do { | ||
198 | usleep_range(100, 200); | ||
199 | ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | ret = imx_phy_reg_read(&val, mmio); | ||
203 | if (ret) | ||
204 | return ret; | ||
205 | if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) | ||
206 | break; | ||
207 | } while (--timeout); | ||
208 | |||
209 | return timeout ? 0 : -ETIMEDOUT; | ||
210 | } | ||
211 | |||
57 | static int imx_sata_enable(struct ahci_host_priv *hpriv) | 212 | static int imx_sata_enable(struct ahci_host_priv *hpriv) |
58 | { | 213 | { |
59 | struct imx_ahci_priv *imxpriv = hpriv->plat_data; | 214 | struct imx_ahci_priv *imxpriv = hpriv->plat_data; |
215 | struct device *dev = &imxpriv->ahci_pdev->dev; | ||
60 | int ret; | 216 | int ret; |
61 | 217 | ||
62 | if (imxpriv->no_device) | 218 | if (imxpriv->no_device) |
@@ -101,6 +257,14 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) | |||
101 | regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, | 257 | regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, |
102 | IMX6Q_GPR13_SATA_MPLL_CLK_EN, | 258 | IMX6Q_GPR13_SATA_MPLL_CLK_EN, |
103 | IMX6Q_GPR13_SATA_MPLL_CLK_EN); | 259 | IMX6Q_GPR13_SATA_MPLL_CLK_EN); |
260 | |||
261 | usleep_range(100, 200); | ||
262 | |||
263 | ret = imx_sata_phy_reset(hpriv); | ||
264 | if (ret) { | ||
265 | dev_err(dev, "failed to reset phy: %d\n", ret); | ||
266 | goto disable_regulator; | ||
267 | } | ||
104 | } | 268 | } |
105 | 269 | ||
106 | usleep_range(1000, 2000); | 270 | usleep_range(1000, 2000); |
@@ -156,8 +320,8 @@ static void ahci_imx_error_handler(struct ata_port *ap) | |||
156 | * without full reset once the pddq mode is enabled making it | 320 | * without full reset once the pddq mode is enabled making it |
157 | * impossible to use as part of libata LPM. | 321 | * impossible to use as part of libata LPM. |
158 | */ | 322 | */ |
159 | reg_val = readl(mmio + PORT_PHY_CTL); | 323 | reg_val = readl(mmio + IMX_P0PHYCR); |
160 | writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL); | 324 | writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR); |
161 | imx_sata_disable(hpriv); | 325 | imx_sata_disable(hpriv); |
162 | imxpriv->no_device = true; | 326 | imxpriv->no_device = true; |
163 | } | 327 | } |
@@ -217,6 +381,7 @@ static int imx_ahci_probe(struct platform_device *pdev) | |||
217 | if (!imxpriv) | 381 | if (!imxpriv) |
218 | return -ENOMEM; | 382 | return -ENOMEM; |
219 | 383 | ||
384 | imxpriv->ahci_pdev = pdev; | ||
220 | imxpriv->no_device = false; | 385 | imxpriv->no_device = false; |
221 | imxpriv->first_time = true; | 386 | imxpriv->first_time = true; |
222 | imxpriv->type = (enum ahci_imx_type)of_id->data; | 387 | imxpriv->type = (enum ahci_imx_type)of_id->data; |
@@ -248,7 +413,7 @@ static int imx_ahci_probe(struct platform_device *pdev) | |||
248 | 413 | ||
249 | /* | 414 | /* |
250 | * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, | 415 | * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, |
251 | * and IP vendor specific register HOST_TIMER1MS. | 416 | * and IP vendor specific register IMX_TIMER1MS. |
252 | * Configure CAP_SSS (support stagered spin up). | 417 | * Configure CAP_SSS (support stagered spin up). |
253 | * Implement the port0. | 418 | * Implement the port0. |
254 | * Get the ahb clock rate, and configure the TIMER1MS register. | 419 | * Get the ahb clock rate, and configure the TIMER1MS register. |
@@ -265,7 +430,7 @@ static int imx_ahci_probe(struct platform_device *pdev) | |||
265 | } | 430 | } |
266 | 431 | ||
267 | reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; | 432 | reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; |
268 | writel(reg_val, hpriv->mmio + HOST_TIMER1MS); | 433 | writel(reg_val, hpriv->mmio + IMX_TIMER1MS); |
269 | 434 | ||
270 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0); | 435 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0); |
271 | if (ret) | 436 | if (ret) |