Commit c206ca62ec4e3a04af24c668d2394b81142b6ec4
1 parent
7a3ac31ccd
Exists in
smarc_8mm-imx_v2019.04_4.19.35_1.1.0
and in
1 other branch
MLK-22293-2 ata: Add iMX AHCI driver
Add new iMX AHCI driver which is ported from kernel and support imx6q/qp/imx8qm. The new driver adapt to SCSI through common AHCI interfaces in ahci.c So after enabling it, we will use SCSI commands to access the SATA disk device. Signed-off-by: Ye Li <ye.li@nxp.com>
Showing 3 changed files with 866 additions and 0 deletions Side-by-side Diff
drivers/ata/Kconfig
... | ... | @@ -59,6 +59,15 @@ |
59 | 59 | Enable this driver to support Sata devices through |
60 | 60 | Synopsys DWC AHCI module. |
61 | 61 | |
62 | +config IMX_AHCI | |
63 | + bool "Enable IMX AHCI driver support" | |
64 | + select SCSI_AHCI | |
65 | + depends on AHCI | |
66 | + depends on DM_SCSI | |
67 | + help | |
68 | + Enable this driver to support Sata devices through | |
69 | + i.MX AHCI module. | |
70 | + | |
62 | 71 | config DWC_AHSATA |
63 | 72 | bool "Enable DWC AHSATA driver support" |
64 | 73 | select LIBATA |
drivers/ata/Makefile
... | ... | @@ -13,6 +13,7 @@ |
13 | 13 | obj-$(CONFIG_MVSATA_IDE) += mvsata_ide.o |
14 | 14 | obj-$(CONFIG_SATA) += sata.o |
15 | 15 | obj-$(CONFIG_SATA_CEVA) += sata_ceva.o |
16 | +obj-$(CONFIG_IMX_AHCI) += imx_ahci.o | |
16 | 17 | obj-$(CONFIG_SATA_MV) += sata_mv.o |
17 | 18 | obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o |
18 | 19 | obj-$(CONFIG_SATA_SIL) += sata_sil.o |
drivers/ata/imx_ahci.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * Copyright 2019 NXP | |
4 | + */ | |
5 | + | |
6 | +#include <common.h> | |
7 | +#include <dm.h> | |
8 | +#include <ahci.h> | |
9 | +#include <scsi.h> | |
10 | +#include <sata.h> | |
11 | +#include <asm/io.h> | |
12 | +#if CONFIG_IS_ENABLED(CLK) | |
13 | +#include <clk.h> | |
14 | +#else | |
15 | +#include <asm/arch/clock.h> | |
16 | +#include <asm/arch/sys_proto.h> | |
17 | +#endif | |
18 | +#include <asm/arch-mx6/iomux.h> | |
19 | +#include <syscon.h> | |
20 | +#include <regmap.h> | |
21 | +#include <asm-generic/gpio.h> | |
22 | + | |
23 | +enum { | |
24 | + /* Timer 1-ms Register */ | |
25 | + IMX_TIMER1MS = 0x00e0, | |
26 | + /* Port0 PHY Control Register */ | |
27 | + IMX_P0PHYCR = 0x0178, | |
28 | + IMX_P0PHYCR_TEST_PDDQ = 1 << 20, | |
29 | + IMX_P0PHYCR_CR_READ = 1 << 19, | |
30 | + IMX_P0PHYCR_CR_WRITE = 1 << 18, | |
31 | + IMX_P0PHYCR_CR_CAP_DATA = 1 << 17, | |
32 | + IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16, | |
33 | + /* Port0 PHY Status Register */ | |
34 | + IMX_P0PHYSR = 0x017c, | |
35 | + IMX_P0PHYSR_CR_ACK = 1 << 18, | |
36 | + IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0, | |
37 | + /* Lane0 Output Status Register */ | |
38 | + IMX_LANE0_OUT_STAT = 0x2003, | |
39 | + IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1, | |
40 | + /* Clock Reset Register */ | |
41 | + IMX_CLOCK_RESET = 0x7f3f, | |
42 | + IMX_CLOCK_RESET_RESET = 1 << 0, | |
43 | + /* IMX8QM HSIO AHCI definitions */ | |
44 | + IMX8QM_SATA_PHY_REG03_RX_IMPED_RATIO = 0x03, | |
45 | + IMX8QM_SATA_PHY_REG09_TX_IMPED_RATIO = 0x09, | |
46 | + IMX8QM_SATA_PHY_REG10_TX_POST_CURSOR_RATIO = 0x0a, | |
47 | + IMX8QM_SATA_PHY_GEN1_TX_POST_CURSOR_RATIO = 0x15, | |
48 | + IMX8QM_SATA_PHY_IMPED_RATIO_85OHM = 0x6c, | |
49 | + IMX8QM_SATA_PHY_REG22_TX_POST_CURSOR_RATIO = 0x16, | |
50 | + IMX8QM_SATA_PHY_GEN2_TX_POST_CURSOR_RATIO = 0x00, | |
51 | + IMX8QM_SATA_PHY_REG24_TX_AMP_RATIO_MARGIN0 = 0x18, | |
52 | + IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN0 = 0x64, | |
53 | + IMX8QM_SATA_PHY_REG25_TX_AMP_RATIO_MARGIN1 = 0x19, | |
54 | + IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN1 = 0x70, | |
55 | + IMX8QM_SATA_PHY_REG26_TX_AMP_RATIO_MARGIN2 = 0x1a, | |
56 | + IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN2 = 0x69, | |
57 | + IMX8QM_SATA_PHY_REG48_PMA_STATUS = 0x30, | |
58 | + IMX8QM_SATA_PHY_REG48_PMA_RDY = BIT(7), | |
59 | + IMX8QM_SATA_PHY_REG128_UPDATE_SETTING = 0x80, | |
60 | + IMX8QM_SATA_PHY_UPDATE_SETTING = 0x01, | |
61 | + IMX8QM_LPCG_PHYX2_OFFSET = 0x00000, | |
62 | + IMX8QM_CSR_PHYX2_OFFSET = 0x90000, | |
63 | + IMX8QM_CSR_PHYX1_OFFSET = 0xa0000, | |
64 | + IMX8QM_CSR_PHYX_STTS0_OFFSET = 0x4, | |
65 | + IMX8QM_CSR_PCIEA_OFFSET = 0xb0000, | |
66 | + IMX8QM_CSR_PCIEB_OFFSET = 0xc0000, | |
67 | + IMX8QM_CSR_SATA_OFFSET = 0xd0000, | |
68 | + IMX8QM_CSR_PCIE_CTRL2_OFFSET = 0x8, | |
69 | + IMX8QM_CSR_MISC_OFFSET = 0xe0000, | |
70 | + /* IMX8QM SATA specific control registers */ | |
71 | + IMX8QM_SATA_PPCFG_OFFSET = 0xa8, | |
72 | + IMX8QM_SATA_PPCFG_FORCE_PHY_RDY = BIT(20), | |
73 | + IMX8QM_SATA_PPCFG_BIST_PATTERN_MASK = 0x7 << 21, | |
74 | + IMX8QM_SATA_PPCFG_BIST_PATTERN_OFFSET = 21, | |
75 | + IMX8QM_SATA_PPCFG_BIST_PATTERN_EN = BIT(24), | |
76 | + IMX8QM_SATA_PPCFG_BIST_PATTERN_NOALIGNS = BIT(26), | |
77 | + IMX8QM_SATA_PP2CFG_OFFSET = 0xac, | |
78 | + IMX8QM_SATA_PP2CFG_COMINIT_NEGATE_MIN = 0x28 << 24, | |
79 | + IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP = 0x18 << 16, | |
80 | + IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MAX = 0x2b << 8, | |
81 | + IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MIN = 0x1b << 0, | |
82 | + IMX8QM_SATA_PP3CFG_OFFSET = 0xb0, | |
83 | + IMX8QM_SATA_PP3CFG_COMWAKE_NEGATE_MIN = 0x0e << 24, | |
84 | + IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP = 0x08 << 16, | |
85 | + IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MAX = 0x0f << 8, | |
86 | + IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MIN = 0x01 << 0, | |
87 | + | |
88 | + IMX8QM_LPCG_PHYX2_PCLK0_MASK = (0x3 << 16), | |
89 | + IMX8QM_LPCG_PHYX2_PCLK1_MASK = (0x3 << 20), | |
90 | + IMX8QM_PHY_APB_RSTN_0 = BIT(0), | |
91 | + IMX8QM_PHY_MODE_SATA = BIT(19), | |
92 | + IMX8QM_PHY_MODE_MASK = (0xf << 17), | |
93 | + IMX8QM_PHY_PIPE_RSTN_0 = BIT(24), | |
94 | + IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0 = BIT(25), | |
95 | + IMX8QM_PHY_PIPE_RSTN_1 = BIT(26), | |
96 | + IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1 = BIT(27), | |
97 | + IMX8QM_STTS0_LANE0_TX_PLL_LOCK = BIT(4), | |
98 | + IMX8QM_MISC_IOB_RXENA = BIT(0), | |
99 | + IMX8QM_MISC_IOB_TXENA = BIT(1), | |
100 | + IMX8QM_MISC_PHYX1_EPCS_SEL = BIT(12), | |
101 | + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 = BIT(24), | |
102 | + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 = BIT(25), | |
103 | + IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 = BIT(28), | |
104 | + IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0 = BIT(29), | |
105 | + IMX8QM_SATA_CTRL_RESET_N = BIT(12), | |
106 | + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N = BIT(7), | |
107 | + IMX8QM_SATA_CTRL_EPCS_TXDEEMP_SEL = BIT(6), | |
108 | + IMX8QM_SATA_CTRL_EPCS_TXDEEMP = BIT(5), | |
109 | + IMX8QM_CTRL_BUTTON_RST_N = BIT(21), | |
110 | + IMX8QM_CTRL_POWER_UP_RST_N = BIT(23), | |
111 | + IMX8QM_CTRL_LTSSM_ENABLE = BIT(4), | |
112 | +}; | |
113 | + | |
114 | +enum ahci_imx_type { | |
115 | + AHCI_IMX6Q, | |
116 | + AHCI_IMX6QP, | |
117 | + AHCI_IMX8QM, | |
118 | +}; | |
119 | + | |
120 | +struct imx_ahci_priv { | |
121 | +#if CONFIG_IS_ENABLED(CLK) | |
122 | + struct clk sata_clk; | |
123 | + struct clk sata_ref_clk; | |
124 | + struct clk ahb_clk; | |
125 | + struct clk epcs_tx_clk; | |
126 | + struct clk epcs_rx_clk; | |
127 | + struct clk phy_apbclk; | |
128 | + struct clk phy_pclk0; | |
129 | + struct clk phy_pclk1; | |
130 | +#endif | |
131 | + enum ahci_imx_type type; | |
132 | + void __iomem *phy_base; | |
133 | + void __iomem *mmio; | |
134 | + struct regmap *gpr; | |
135 | + struct gpio_desc clkreq_gpio; | |
136 | + u32 phy_params; | |
137 | + u32 imped_ratio; | |
138 | + u32 ext_osc; | |
139 | +}; | |
140 | + | |
141 | +static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert) | |
142 | +{ | |
143 | + int timeout = 10; | |
144 | + u32 crval; | |
145 | + u32 srval; | |
146 | + | |
147 | + /* Assert or deassert the bit */ | |
148 | + crval = readl(mmio + IMX_P0PHYCR); | |
149 | + if (assert) | |
150 | + crval |= bit; | |
151 | + else | |
152 | + crval &= ~bit; | |
153 | + writel(crval, mmio + IMX_P0PHYCR); | |
154 | + | |
155 | + /* Wait for the cr_ack signal */ | |
156 | + do { | |
157 | + srval = readl(mmio + IMX_P0PHYSR); | |
158 | + if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) | |
159 | + break; | |
160 | + udelay(100); | |
161 | + } while (--timeout); | |
162 | + | |
163 | + return timeout ? 0 : -ETIMEDOUT; | |
164 | +} | |
165 | + | |
166 | +static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) | |
167 | +{ | |
168 | + u32 crval = addr; | |
169 | + int ret; | |
170 | + | |
171 | + /* Supply the address on cr_data_in */ | |
172 | + writel(crval, mmio + IMX_P0PHYCR); | |
173 | + | |
174 | + /* Assert the cr_cap_addr signal */ | |
175 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); | |
176 | + if (ret) | |
177 | + return ret; | |
178 | + | |
179 | + /* Deassert cr_cap_addr */ | |
180 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); | |
181 | + if (ret) | |
182 | + return ret; | |
183 | + | |
184 | + return 0; | |
185 | +} | |
186 | + | |
187 | +static int imx_phy_reg_write(u16 val, void __iomem *mmio) | |
188 | +{ | |
189 | + u32 crval = val; | |
190 | + int ret; | |
191 | + | |
192 | + /* Supply the data on cr_data_in */ | |
193 | + writel(crval, mmio + IMX_P0PHYCR); | |
194 | + | |
195 | + /* Assert the cr_cap_data signal */ | |
196 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); | |
197 | + if (ret) | |
198 | + return ret; | |
199 | + | |
200 | + /* Deassert cr_cap_data */ | |
201 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); | |
202 | + if (ret) | |
203 | + return ret; | |
204 | + | |
205 | + if (val & IMX_CLOCK_RESET_RESET) { | |
206 | + /* | |
207 | + * In case we're resetting the phy, it's unable to acknowledge, | |
208 | + * so we return immediately here. | |
209 | + */ | |
210 | + crval |= IMX_P0PHYCR_CR_WRITE; | |
211 | + writel(crval, mmio + IMX_P0PHYCR); | |
212 | + goto out; | |
213 | + } | |
214 | + | |
215 | + /* Assert the cr_write signal */ | |
216 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); | |
217 | + if (ret) | |
218 | + return ret; | |
219 | + | |
220 | + /* Deassert cr_write */ | |
221 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); | |
222 | + if (ret) | |
223 | + return ret; | |
224 | + | |
225 | +out: | |
226 | + return 0; | |
227 | +} | |
228 | + | |
229 | +static int imx_phy_reg_read(u16 *val, void __iomem *mmio) | |
230 | +{ | |
231 | + int ret; | |
232 | + | |
233 | + /* Assert the cr_read signal */ | |
234 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); | |
235 | + if (ret) | |
236 | + return ret; | |
237 | + | |
238 | + /* Capture the data from cr_data_out[] */ | |
239 | + *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; | |
240 | + | |
241 | + /* Deassert cr_read */ | |
242 | + ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); | |
243 | + if (ret) | |
244 | + return ret; | |
245 | + | |
246 | + return 0; | |
247 | +} | |
248 | + | |
249 | +static int imx_sata_phy_reset(struct imx_ahci_priv *priv) | |
250 | +{ | |
251 | + void __iomem *mmio = priv->mmio; | |
252 | + int timeout = 10; | |
253 | + u16 val; | |
254 | + int ret; | |
255 | + | |
256 | + /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ | |
257 | + ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); | |
258 | + if (ret) | |
259 | + return ret; | |
260 | + ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); | |
261 | + if (ret) | |
262 | + return ret; | |
263 | + | |
264 | + /* Wait for PHY RX_PLL to be stable */ | |
265 | + do { | |
266 | + udelay(100); | |
267 | + ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); | |
268 | + if (ret) | |
269 | + return ret; | |
270 | + ret = imx_phy_reg_read(&val, mmio); | |
271 | + if (ret) | |
272 | + return ret; | |
273 | + if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) | |
274 | + break; | |
275 | + } while (--timeout); | |
276 | + | |
277 | + return timeout ? 0 : -ETIMEDOUT; | |
278 | +} | |
279 | + | |
280 | +static int imx8_sata_enable(struct udevice *dev) | |
281 | +{ | |
282 | + u32 val, reg; | |
283 | + int i, ret; | |
284 | + struct imx_ahci_priv *imxpriv = dev_get_priv(dev); | |
285 | + | |
286 | +#if CONFIG_IS_ENABLED(CLK) | |
287 | + /* configure the hsio for sata */ | |
288 | + ret = clk_enable(&imxpriv->phy_pclk0); | |
289 | + if (ret < 0) { | |
290 | + dev_err(dev, "can't enable phy pclk0.\n"); | |
291 | + return ret; | |
292 | + } | |
293 | + ret = clk_enable(&imxpriv->phy_pclk1); | |
294 | + if (ret < 0) { | |
295 | + dev_err(dev, "can't enable phy pclk1.\n"); | |
296 | + goto disable_phy_pclk0; | |
297 | + } | |
298 | + ret = clk_enable(&imxpriv->epcs_tx_clk); | |
299 | + if (ret < 0) { | |
300 | + dev_err(dev, "can't enable epcs tx clk.\n"); | |
301 | + goto disable_phy_pclk1; | |
302 | + } | |
303 | + ret = clk_enable(&imxpriv->epcs_rx_clk); | |
304 | + if (ret < 0) { | |
305 | + dev_err(dev, "can't enable epcs rx clk.\n"); | |
306 | + goto disable_epcs_tx_clk; | |
307 | + } | |
308 | + ret = clk_enable(&imxpriv->phy_apbclk); | |
309 | + if (ret < 0) { | |
310 | + dev_err(dev, "can't enable phy pclk1.\n"); | |
311 | + goto disable_epcs_rx_clk; | |
312 | + } | |
313 | +#endif | |
314 | + | |
315 | + /* Configure PHYx2 PIPE_RSTN */ | |
316 | + regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEA_OFFSET | |
317 | + + IMX8QM_CSR_PCIE_CTRL2_OFFSET, &val); | |
318 | + if ((val & IMX8QM_CTRL_LTSSM_ENABLE) == 0) { | |
319 | + /* PCIEA of HSIO is down too */ | |
320 | + regmap_update_bits(imxpriv->gpr, | |
321 | + IMX8QM_CSR_PHYX2_OFFSET, | |
322 | + IMX8QM_PHY_PIPE_RSTN_0 | |
323 | + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0, | |
324 | + IMX8QM_PHY_PIPE_RSTN_0 | |
325 | + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0); | |
326 | + } | |
327 | + regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEB_OFFSET | |
328 | + + IMX8QM_CSR_PCIE_CTRL2_OFFSET, ®); | |
329 | + if ((reg & IMX8QM_CTRL_LTSSM_ENABLE) == 0) { | |
330 | + /* PCIEB of HSIO is down */ | |
331 | + regmap_update_bits(imxpriv->gpr, | |
332 | + IMX8QM_CSR_PHYX2_OFFSET, | |
333 | + IMX8QM_PHY_PIPE_RSTN_1 | |
334 | + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1, | |
335 | + IMX8QM_PHY_PIPE_RSTN_1 | |
336 | + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1); | |
337 | + } | |
338 | + | |
339 | + /* set PWR_RST and BT_RST of csr_pciea */ | |
340 | + val = IMX8QM_CSR_PCIEA_OFFSET + IMX8QM_CSR_PCIE_CTRL2_OFFSET; | |
341 | + regmap_update_bits(imxpriv->gpr, | |
342 | + val, | |
343 | + IMX8QM_CTRL_BUTTON_RST_N, | |
344 | + IMX8QM_CTRL_BUTTON_RST_N); | |
345 | + regmap_update_bits(imxpriv->gpr, | |
346 | + val, | |
347 | + IMX8QM_CTRL_POWER_UP_RST_N, | |
348 | + IMX8QM_CTRL_POWER_UP_RST_N); | |
349 | + | |
350 | + /* PHYX1_MODE to SATA */ | |
351 | + regmap_update_bits(imxpriv->gpr, | |
352 | + IMX8QM_CSR_PHYX1_OFFSET, | |
353 | + IMX8QM_PHY_MODE_MASK, | |
354 | + IMX8QM_PHY_MODE_SATA); | |
355 | + | |
356 | + if (imxpriv->ext_osc) { | |
357 | + dev_info(dev, "external osc is used.\n"); | |
358 | + /* | |
359 | + * bit0 rx ena 1, bit1 tx ena 0 | |
360 | + * bit12 PHY_X1_EPCS_SEL 1. | |
361 | + */ | |
362 | + regmap_update_bits(imxpriv->gpr, | |
363 | + IMX8QM_CSR_MISC_OFFSET, | |
364 | + IMX8QM_MISC_IOB_RXENA, | |
365 | + IMX8QM_MISC_IOB_RXENA); | |
366 | + regmap_update_bits(imxpriv->gpr, | |
367 | + IMX8QM_CSR_MISC_OFFSET, | |
368 | + IMX8QM_MISC_IOB_TXENA, | |
369 | + 0); | |
370 | + } else { | |
371 | + dev_info(dev, "internal pll is used.\n"); | |
372 | + regmap_update_bits(imxpriv->gpr, | |
373 | + IMX8QM_CSR_MISC_OFFSET, | |
374 | + IMX8QM_MISC_IOB_RXENA, | |
375 | + 0); | |
376 | + regmap_update_bits(imxpriv->gpr, | |
377 | + IMX8QM_CSR_MISC_OFFSET, | |
378 | + IMX8QM_MISC_IOB_TXENA, | |
379 | + IMX8QM_MISC_IOB_TXENA); | |
380 | + | |
381 | + } | |
382 | + regmap_update_bits(imxpriv->gpr, | |
383 | + IMX8QM_CSR_MISC_OFFSET, | |
384 | + IMX8QM_MISC_PHYX1_EPCS_SEL, | |
385 | + IMX8QM_MISC_PHYX1_EPCS_SEL); | |
386 | + /* | |
387 | + * It is possible, for PCIe and SATA are sharing | |
388 | + * the same clock source, HPLL or external oscillator. | |
389 | + * When PCIe is in low power modes (L1.X or L2 etc), | |
390 | + * the clock source can be turned off. In this case, | |
391 | + * if this clock source is required to be toggling by | |
392 | + * SATA, then SATA functions will be abnormal. | |
393 | + */ | |
394 | + regmap_update_bits(imxpriv->gpr, | |
395 | + IMX8QM_CSR_MISC_OFFSET, | |
396 | + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 | |
397 | + | IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 | |
398 | + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 | |
399 | + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0, | |
400 | + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 | |
401 | + | IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 | |
402 | + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 | |
403 | + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0); | |
404 | + | |
405 | + /* clear PHY RST, then set it */ | |
406 | + regmap_update_bits(imxpriv->gpr, | |
407 | + IMX8QM_CSR_SATA_OFFSET, | |
408 | + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N, | |
409 | + 0); | |
410 | + | |
411 | + regmap_update_bits(imxpriv->gpr, | |
412 | + IMX8QM_CSR_SATA_OFFSET, | |
413 | + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N, | |
414 | + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N); | |
415 | + regmap_update_bits(imxpriv->gpr, | |
416 | + IMX8QM_CSR_SATA_OFFSET, | |
417 | + IMX8QM_SATA_CTRL_EPCS_TXDEEMP, | |
418 | + IMX8QM_SATA_CTRL_EPCS_TXDEEMP); | |
419 | + regmap_update_bits(imxpriv->gpr, | |
420 | + IMX8QM_CSR_SATA_OFFSET, | |
421 | + IMX8QM_SATA_CTRL_EPCS_TXDEEMP_SEL, | |
422 | + IMX8QM_SATA_CTRL_EPCS_TXDEEMP_SEL); | |
423 | + | |
424 | + /* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */ | |
425 | + regmap_update_bits(imxpriv->gpr, | |
426 | + IMX8QM_CSR_SATA_OFFSET, | |
427 | + IMX8QM_SATA_CTRL_RESET_N, | |
428 | + IMX8QM_SATA_CTRL_RESET_N); | |
429 | + udelay(1); | |
430 | + regmap_update_bits(imxpriv->gpr, | |
431 | + IMX8QM_CSR_SATA_OFFSET, | |
432 | + IMX8QM_SATA_CTRL_RESET_N, | |
433 | + 0); | |
434 | + regmap_update_bits(imxpriv->gpr, | |
435 | + IMX8QM_CSR_SATA_OFFSET, | |
436 | + IMX8QM_SATA_CTRL_RESET_N, | |
437 | + IMX8QM_SATA_CTRL_RESET_N); | |
438 | + | |
439 | + /* APB reset */ | |
440 | + regmap_update_bits(imxpriv->gpr, | |
441 | + IMX8QM_CSR_PHYX1_OFFSET, | |
442 | + IMX8QM_PHY_APB_RSTN_0, | |
443 | + IMX8QM_PHY_APB_RSTN_0); | |
444 | + | |
445 | + for (i = 0; i < 100; i++) { | |
446 | + reg = IMX8QM_CSR_PHYX1_OFFSET | |
447 | + + IMX8QM_CSR_PHYX_STTS0_OFFSET; | |
448 | + regmap_read(imxpriv->gpr, reg, &val); | |
449 | + val &= IMX8QM_STTS0_LANE0_TX_PLL_LOCK; | |
450 | + if (val == IMX8QM_STTS0_LANE0_TX_PLL_LOCK) | |
451 | + break; | |
452 | + udelay(1); | |
453 | + } | |
454 | + | |
455 | + if (val != IMX8QM_STTS0_LANE0_TX_PLL_LOCK) { | |
456 | + dev_err(dev, "TX PLL of the PHY is not locked\n"); | |
457 | + ret = -ENODEV; | |
458 | + } else { | |
459 | + for (i = 0; i < 1000; i++) { | |
460 | + reg = readb(imxpriv->phy_base + | |
461 | + IMX8QM_SATA_PHY_REG48_PMA_STATUS); | |
462 | + if (reg & IMX8QM_SATA_PHY_REG48_PMA_RDY) | |
463 | + break; | |
464 | + udelay(10); | |
465 | + } | |
466 | + if ((reg & IMX8QM_SATA_PHY_REG48_PMA_RDY) == 0) { | |
467 | + dev_err(dev, "Calibration is NOT finished.\n"); | |
468 | + ret = -ENODEV; | |
469 | + goto err_out; | |
470 | + } | |
471 | + | |
472 | + writeb(imxpriv->imped_ratio, imxpriv->phy_base | |
473 | + + IMX8QM_SATA_PHY_REG03_RX_IMPED_RATIO); | |
474 | + writeb(imxpriv->imped_ratio, imxpriv->phy_base | |
475 | + + IMX8QM_SATA_PHY_REG09_TX_IMPED_RATIO); | |
476 | + reg = readb(imxpriv->phy_base | |
477 | + + IMX8QM_SATA_PHY_REG03_RX_IMPED_RATIO); | |
478 | + if (unlikely(reg != imxpriv->imped_ratio)) | |
479 | + dev_info(dev, "Can't set PHY RX impedance ratio.\n"); | |
480 | + reg = readb(imxpriv->phy_base | |
481 | + + IMX8QM_SATA_PHY_REG09_TX_IMPED_RATIO); | |
482 | + if (unlikely(reg != imxpriv->imped_ratio)) | |
483 | + dev_info(dev, "Can't set PHY TX impedance ratio.\n"); | |
484 | + | |
485 | + /* Configure the tx_amplitude to pass the tests. */ | |
486 | + writeb(IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN0, imxpriv->phy_base + | |
487 | + IMX8QM_SATA_PHY_REG24_TX_AMP_RATIO_MARGIN0); | |
488 | + writeb(IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN1, imxpriv->phy_base + | |
489 | + IMX8QM_SATA_PHY_REG25_TX_AMP_RATIO_MARGIN1); | |
490 | + writeb(IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN2, imxpriv->phy_base + | |
491 | + IMX8QM_SATA_PHY_REG26_TX_AMP_RATIO_MARGIN2); | |
492 | + | |
493 | + /* Adjust the OOB COMINIT/COMWAKE to pass the tests. */ | |
494 | + writeb(IMX8QM_SATA_PHY_GEN1_TX_POST_CURSOR_RATIO, | |
495 | + imxpriv->phy_base + | |
496 | + IMX8QM_SATA_PHY_REG10_TX_POST_CURSOR_RATIO); | |
497 | + writeb(IMX8QM_SATA_PHY_GEN2_TX_POST_CURSOR_RATIO, | |
498 | + imxpriv->phy_base + | |
499 | + IMX8QM_SATA_PHY_REG22_TX_POST_CURSOR_RATIO); | |
500 | + | |
501 | + writeb(IMX8QM_SATA_PHY_UPDATE_SETTING, imxpriv->phy_base + | |
502 | + IMX8QM_SATA_PHY_REG128_UPDATE_SETTING); | |
503 | + | |
504 | + reg = IMX8QM_SATA_PP2CFG_COMINIT_NEGATE_MIN | | |
505 | + IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP | | |
506 | + IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MAX | | |
507 | + IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MIN; | |
508 | + writel(reg, imxpriv->mmio + IMX8QM_SATA_PP2CFG_OFFSET); | |
509 | + reg = IMX8QM_SATA_PP3CFG_COMWAKE_NEGATE_MIN | | |
510 | + IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP | | |
511 | + IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MAX | | |
512 | + IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MIN; | |
513 | + writel(reg, imxpriv->mmio + IMX8QM_SATA_PP3CFG_OFFSET); | |
514 | + | |
515 | + udelay(100); | |
516 | + | |
517 | + /* | |
518 | + * To reduce the power consumption, gate off | |
519 | + * the PHY clks | |
520 | + */ | |
521 | +#if CONFIG_IS_ENABLED(CLK) | |
522 | + clk_disable(&imxpriv->phy_apbclk); | |
523 | + clk_disable(&imxpriv->phy_pclk1); | |
524 | + clk_disable(&imxpriv->phy_pclk0); | |
525 | +#endif | |
526 | + return ret; | |
527 | + } | |
528 | + | |
529 | +err_out: | |
530 | +#if CONFIG_IS_ENABLED(CLK) | |
531 | + clk_disable(&imxpriv->phy_apbclk); | |
532 | +disable_epcs_rx_clk: | |
533 | + clk_disable(&imxpriv->epcs_rx_clk); | |
534 | +disable_epcs_tx_clk: | |
535 | + clk_disable(&imxpriv->epcs_tx_clk); | |
536 | +disable_phy_pclk1: | |
537 | + clk_disable(&imxpriv->phy_pclk1); | |
538 | +disable_phy_pclk0: | |
539 | + clk_disable(&imxpriv->phy_pclk0); | |
540 | +#endif | |
541 | + return ret; | |
542 | +} | |
543 | + | |
544 | +static int imx8_sata_probe(struct udevice *dev, struct imx_ahci_priv *imxpriv) | |
545 | +{ | |
546 | + int ret = 0; | |
547 | + fdt_addr_t addr; | |
548 | + | |
549 | + if (dev_read_u32u(dev, "ext_osc", &imxpriv->ext_osc)) { | |
550 | + dev_info(dev, "ext_osc is not specified.\n"); | |
551 | + /* Use the external osc as ref clk defaultly. */ | |
552 | + imxpriv->ext_osc = 1; | |
553 | + } | |
554 | + | |
555 | + if (dev_read_u32u(dev, "fsl,phy-imp", &imxpriv->imped_ratio)) { | |
556 | + /* | |
557 | + * Regarding to the differnet Hw designs, | |
558 | + * Set the impedance ratio to 0x6c when 85OHM is used. | |
559 | + * Keep it to default value 0x80, when 100OHM is used. | |
560 | + */ | |
561 | + dev_info(dev, "phy impedance ratio is not specified.\n"); | |
562 | + imxpriv->imped_ratio = IMX8QM_SATA_PHY_IMPED_RATIO_85OHM; | |
563 | + } | |
564 | + | |
565 | + addr = dev_read_addr_name(dev, "phy"); | |
566 | + if (addr == FDT_ADDR_T_NONE){ | |
567 | + dev_err(dev, "no phy space\n"); | |
568 | + return -ENOMEM; | |
569 | + } | |
570 | + | |
571 | + imxpriv->phy_base = (void __iomem *)addr; | |
572 | + | |
573 | + imxpriv->gpr = | |
574 | + syscon_regmap_lookup_by_phandle(dev, "hsio"); | |
575 | + if (IS_ERR(imxpriv->gpr)) { | |
576 | + dev_err(dev, "unable to find gpr registers\n"); | |
577 | + return PTR_ERR(imxpriv->gpr); | |
578 | + } | |
579 | + | |
580 | +#if CONFIG_IS_ENABLED(CLK) | |
581 | + ret = clk_get_by_name(dev, "epcs_tx", &imxpriv->epcs_tx_clk); | |
582 | + if (ret) { | |
583 | + dev_err(dev, "can't get sata_epcs tx clock.\n"); | |
584 | + return ret; | |
585 | + } | |
586 | + | |
587 | + ret = clk_get_by_name(dev, "epcs_rx", &imxpriv->epcs_rx_clk); | |
588 | + if (ret) { | |
589 | + dev_err(dev, "can't get sata_epcs rx clock.\n"); | |
590 | + return ret; | |
591 | + } | |
592 | + | |
593 | + ret = clk_get_by_name(dev, "phy_pclk0", &imxpriv->phy_pclk0); | |
594 | + if (ret) { | |
595 | + dev_err(dev, "can't get sata_phy_pclk0 clock.\n"); | |
596 | + return ret; | |
597 | + } | |
598 | + | |
599 | + ret = clk_get_by_name(dev, "phy_pclk1", &imxpriv->phy_pclk1); | |
600 | + if (ret) { | |
601 | + dev_err(dev, "can't get sata_phy_pclk1 clock.\n"); | |
602 | + return ret; | |
603 | + } | |
604 | + | |
605 | + ret = clk_get_by_name(dev, "phy_apbclk", &imxpriv->phy_apbclk); | |
606 | + if (ret) { | |
607 | + dev_err(dev, "can't get sata_phy_apbclk clock.\n"); | |
608 | + return ret; | |
609 | + } | |
610 | +#endif | |
611 | + | |
612 | + /* Fetch GPIO, then enable the external OSC */ | |
613 | + ret = gpio_request_by_name(dev, "clkreq-gpio", 0, &imxpriv->clkreq_gpio, | |
614 | + (GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE)); | |
615 | + if (ret) { | |
616 | + dev_err(dev, "%d unable to get clkreq.\n", ret); | |
617 | + return ret; | |
618 | + } | |
619 | + | |
620 | + return 0; | |
621 | +} | |
622 | + | |
623 | + | |
624 | +static int imx_sata_enable(struct udevice *dev) | |
625 | +{ | |
626 | + struct imx_ahci_priv *imxpriv = dev_get_priv(dev); | |
627 | + int ret = 0; | |
628 | + | |
629 | + if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) { | |
630 | + /* | |
631 | + * set PHY Paremeters, two steps to configure the GPR13, | |
632 | + * one write for rest of parameters, mask of first write | |
633 | + * is 0x07ffffff, and the other one write for setting | |
634 | + * the mpll_clk_en. | |
635 | + */ | |
636 | + regmap_update_bits(imxpriv->gpr, 0x34, | |
637 | + IOMUXC_GPR13_SATA_MASK, | |
638 | + imxpriv->phy_params); | |
639 | + regmap_update_bits(imxpriv->gpr, 0x34, | |
640 | + IOMUXC_GPR13_SATA_PHY_1_MASK, | |
641 | + IOMUXC_GPR13_SATA_PHY_1_SLOW); | |
642 | + | |
643 | + udelay(200); | |
644 | + } | |
645 | + | |
646 | + if (imxpriv->type == AHCI_IMX6Q) { | |
647 | + ret = imx_sata_phy_reset(imxpriv); | |
648 | + } else if (imxpriv->type == AHCI_IMX6QP) { | |
649 | + /* 6qp adds the sata reset mechanism, use it for 6qp sata */ | |
650 | + regmap_update_bits(imxpriv->gpr, 0x14, | |
651 | + BIT(10), 0); | |
652 | + | |
653 | + regmap_update_bits(imxpriv->gpr, 0x14, | |
654 | + BIT(11), 0); | |
655 | + udelay(50); | |
656 | + regmap_update_bits(imxpriv->gpr, 0x14, | |
657 | + BIT(11), BIT(11)); | |
658 | + } else if (imxpriv->type == AHCI_IMX8QM) { | |
659 | + ret = imx8_sata_enable(dev); | |
660 | + } | |
661 | + | |
662 | + if (ret) { | |
663 | + dev_err(dev, "failed to reset phy: %d\n", ret); | |
664 | + return ret; | |
665 | + } | |
666 | + | |
667 | + udelay(2000); | |
668 | + | |
669 | + return 0; | |
670 | +} | |
671 | + | |
672 | +static void imx_sata_disable(struct udevice *dev) | |
673 | +{ | |
674 | + struct imx_ahci_priv *imxpriv = dev_get_priv(dev); | |
675 | + | |
676 | + if (imxpriv->type == AHCI_IMX6QP) | |
677 | + regmap_update_bits(imxpriv->gpr, 0x14, | |
678 | + BIT(10), BIT(10)); | |
679 | + | |
680 | + if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) { | |
681 | + regmap_update_bits(imxpriv->gpr, 0x34, | |
682 | + IOMUXC_GPR13_SATA_PHY_1_MASK, | |
683 | + 0); | |
684 | + } | |
685 | + | |
686 | + if (imxpriv->type == AHCI_IMX8QM) { | |
687 | +#if CONFIG_IS_ENABLED(CLK) | |
688 | + clk_disable(&imxpriv->epcs_rx_clk); | |
689 | + clk_disable(&imxpriv->epcs_tx_clk); | |
690 | +#endif | |
691 | + } | |
692 | +} | |
693 | + | |
694 | + | |
695 | +static int imx_ahci_bind(struct udevice *dev) | |
696 | +{ | |
697 | + struct udevice *scsi_dev; | |
698 | + | |
699 | + return ahci_bind_scsi(dev, &scsi_dev); | |
700 | +} | |
701 | + | |
702 | +static int imx_ahci_probe(struct udevice *dev) | |
703 | +{ | |
704 | + int ret = 0; | |
705 | + struct imx_ahci_priv *priv = dev_get_priv(dev); | |
706 | + fdt_addr_t addr; | |
707 | + unsigned int reg_val; | |
708 | + | |
709 | + priv->type = (enum ahci_imx_type)dev_get_driver_data(dev); | |
710 | + | |
711 | +#if CONFIG_IS_ENABLED(CLK) | |
712 | + ret = clk_get_by_name(dev, "sata", &priv->sata_clk); | |
713 | + if (ret) { | |
714 | + printf("Failed to get sata clk\n"); | |
715 | + return ret; | |
716 | + } | |
717 | + | |
718 | + ret = clk_get_by_name(dev, "sata_ref", &priv->sata_ref_clk); | |
719 | + if (ret) { | |
720 | + printf("Failed to get sata_ref clk\n"); | |
721 | + return ret; | |
722 | + } | |
723 | +#endif | |
724 | + | |
725 | + addr = dev_read_addr(dev); | |
726 | + if (addr == FDT_ADDR_T_NONE) { | |
727 | + dev_err(dev, "no mmio space\n"); | |
728 | + return -EINVAL; | |
729 | + } | |
730 | + | |
731 | + priv->mmio = (void __iomem *)addr; | |
732 | + | |
733 | + if (priv->type == AHCI_IMX6Q || priv->type == AHCI_IMX6QP) { | |
734 | + priv->gpr = syscon_regmap_lookup_by_phandle(dev, "gpr"); | |
735 | + if (IS_ERR(priv->gpr)) { | |
736 | + dev_err(dev, | |
737 | + "failed to find fsl,imx6q-iomux-gpr regmap\n"); | |
738 | + return PTR_ERR(priv->gpr); | |
739 | + } | |
740 | + | |
741 | + priv->phy_params = | |
742 | + IOMUXC_GPR13_SATA_PHY_7_SATA2M | | |
743 | + (3 << IOMUXC_GPR13_SATA_PHY_6_SHIFT) | | |
744 | + IOMUXC_GPR13_SATA_SPEED_3G | | |
745 | + IOMUXC_GPR13_SATA_PHY_2_TX_1P025V | | |
746 | + IOMUXC_GPR13_SATA_PHY_3_TXBOOST_3P33_DB | | |
747 | + IOMUXC_GPR13_SATA_SATA_PHY_4_ATTEN_9_16 | | |
748 | + IOMUXC_GPR13_SATA_PHY_8_RXEQ_3P0DB | | |
749 | + IOMUXC_GPR13_SATA_SATA_PHY_5_SS_DISABLED; | |
750 | + } else if (priv->type == AHCI_IMX8QM) { | |
751 | + ret = imx8_sata_probe(dev, priv); | |
752 | + if (ret) | |
753 | + return ret; | |
754 | + } | |
755 | + | |
756 | +#if CONFIG_IS_ENABLED(CLK) | |
757 | + ret = clk_enable(&priv->sata_clk); | |
758 | + if (ret) | |
759 | + return ret; | |
760 | + | |
761 | + ret = clk_enable(&priv->sata_ref_clk); | |
762 | + if (ret) | |
763 | + return ret; | |
764 | +#else | |
765 | + enable_sata_clock(); | |
766 | +#endif | |
767 | + | |
768 | + ret = imx_sata_enable(dev); | |
769 | + if (ret) | |
770 | + goto disable_clk; | |
771 | + | |
772 | + /* | |
773 | + * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, | |
774 | + * and IP vendor specific register IMX_TIMER1MS. | |
775 | + * Configure CAP_SSS (support stagered spin up). | |
776 | + * Implement the port0. | |
777 | + * Get the ahb clock rate, and configure the TIMER1MS register. | |
778 | + */ | |
779 | + reg_val = readl(priv->mmio + HOST_CAP); | |
780 | + if (!(reg_val & (1 << 27))) { | |
781 | + reg_val |= (1 << 27); | |
782 | + writel(reg_val, priv->mmio + HOST_CAP); | |
783 | + } | |
784 | + reg_val = readl(priv->mmio + HOST_PORTS_IMPL); | |
785 | + if (!(reg_val & 0x1)) { | |
786 | + reg_val |= 0x1; | |
787 | + writel(reg_val, priv->mmio + HOST_PORTS_IMPL); | |
788 | + } | |
789 | + | |
790 | +#if CONFIG_IS_ENABLED(CLK) | |
791 | + ret = clk_get_by_name(dev, "ahb", &priv->ahb_clk); | |
792 | + if (ret) { | |
793 | + dev_info(dev, "no ahb clock.\n"); | |
794 | + } else { | |
795 | + /* | |
796 | + * AHB clock is only used to configure the vendor specified | |
797 | + * TIMER1MS register. Set it if the AHB clock is defined. | |
798 | + */ | |
799 | + reg_val = clk_get_rate(&priv->ahb_clk) / 1000; | |
800 | + writel(reg_val, priv->mmio + IMX_TIMER1MS); | |
801 | + } | |
802 | +#else | |
803 | + reg_val = mxc_get_clock(MXC_AHB_CLK) / 1000; | |
804 | + writel(reg_val, priv->mmio + IMX_TIMER1MS); | |
805 | +#endif | |
806 | + | |
807 | + ret = ahci_probe_scsi(dev, (ulong)priv->mmio); | |
808 | + if (ret) | |
809 | + goto disable_sata; | |
810 | + | |
811 | + return ret; | |
812 | + | |
813 | +disable_sata: | |
814 | + imx_sata_disable(dev); | |
815 | +disable_clk: | |
816 | +#if CONFIG_IS_ENABLED(CLK) | |
817 | + clk_disable(&priv->sata_ref_clk); | |
818 | + clk_disable(&priv->sata_clk); | |
819 | +#else | |
820 | + disable_sata_clock(); | |
821 | +#endif | |
822 | + return ret; | |
823 | +} | |
824 | + | |
825 | +static int imx_ahci_remove(struct udevice *dev) | |
826 | +{ | |
827 | + imx_sata_disable(dev); | |
828 | + | |
829 | +#if CONFIG_IS_ENABLED(CLK) | |
830 | + struct imx_ahci_priv *priv = dev_get_priv(dev); | |
831 | + clk_disable(&priv->sata_ref_clk); | |
832 | + clk_disable(&priv->sata_clk); | |
833 | +#else | |
834 | + disable_sata_clock(); | |
835 | +#endif | |
836 | + | |
837 | + return 0; | |
838 | +} | |
839 | + | |
840 | + | |
841 | +static const struct udevice_id imx_ahci_ids[] = { | |
842 | + { .compatible = "fsl,imx6q-ahci", .data = (ulong)AHCI_IMX6Q }, | |
843 | + { .compatible = "fsl,imx6qp-ahci", .data = (ulong)AHCI_IMX6QP }, | |
844 | + { .compatible = "fsl,imx8qm-ahci", .data = (ulong)AHCI_IMX8QM }, | |
845 | + { } | |
846 | +}; | |
847 | + | |
848 | +U_BOOT_DRIVER(imx_ahci) = { | |
849 | + .name = "imx_ahci", | |
850 | + .id = UCLASS_AHCI, | |
851 | + .of_match = imx_ahci_ids, | |
852 | + .bind = imx_ahci_bind, | |
853 | + .probe = imx_ahci_probe, | |
854 | + .remove = imx_ahci_remove, | |
855 | + .priv_auto_alloc_size = sizeof(struct imx_ahci_priv), | |
856 | +}; |
-
mentioned in commit d49b65
-
mentioned in commit d49b65
-
mentioned in commit d49b65
-
mentioned in commit d49b65
-
mentioned in commit 1a74c7
-
mentioned in commit 1a74c7
-
mentioned in commit d49b65
-
mentioned in commit 1a74c7
-
mentioned in commit 1a74c7
-
mentioned in commit 1a74c7
-
mentioned in commit 1a74c7
-
mentioned in commit 4f7732