imx_ahcisata.c revision 1.1.2.2 1 1.1.2.2 thorpej /* $NetBSD: imx_ahcisata.c,v 1.1.2.2 2021/01/03 16:34:52 thorpej Exp $ */
2 1.1.2.2 thorpej
3 1.1.2.2 thorpej /*-
4 1.1.2.2 thorpej * Copyright (c) 2019 Genetec Corporation. All rights reserved.
5 1.1.2.2 thorpej * Written by Hashimoto Kenichi for Genetec Corporation.
6 1.1.2.2 thorpej *
7 1.1.2.2 thorpej * Redistribution and use in source and binary forms, with or without
8 1.1.2.2 thorpej * modification, are permitted provided that the following conditions
9 1.1.2.2 thorpej * are met:
10 1.1.2.2 thorpej * 1. Redistributions of source code must retain the above copyright
11 1.1.2.2 thorpej * notice, this list of conditions and the following disclaimer.
12 1.1.2.2 thorpej * 2. Redistributions in binary form must reproduce the above copyright
13 1.1.2.2 thorpej * notice, this list of conditions and the following disclaimer in the
14 1.1.2.2 thorpej * documentation and/or other materials provided with the distribution.
15 1.1.2.2 thorpej *
16 1.1.2.2 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1.2.2 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1.2.2 thorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1.2.2 thorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1.2.2 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 1.1.2.2 thorpej * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 1.1.2.2 thorpej * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 1.1.2.2 thorpej * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 1.1.2.2 thorpej * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1.2.2 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1.2.2 thorpej * SUCH DAMAGE.
27 1.1.2.2 thorpej */
28 1.1.2.2 thorpej
29 1.1.2.2 thorpej #include <sys/cdefs.h>
30 1.1.2.2 thorpej __KERNEL_RCSID(0, "$NetBSD: imx_ahcisata.c,v 1.1.2.2 2021/01/03 16:34:52 thorpej Exp $");
31 1.1.2.2 thorpej
32 1.1.2.2 thorpej #include <sys/param.h>
33 1.1.2.2 thorpej #include <sys/bus.h>
34 1.1.2.2 thorpej #include <sys/device.h>
35 1.1.2.2 thorpej #include <sys/intr.h>
36 1.1.2.2 thorpej #include <sys/systm.h>
37 1.1.2.2 thorpej #include <sys/kernel.h>
38 1.1.2.2 thorpej
39 1.1.2.2 thorpej #include <dev/ata/atavar.h>
40 1.1.2.2 thorpej #include <dev/ic/ahcisatavar.h>
41 1.1.2.2 thorpej
42 1.1.2.2 thorpej #include <arm/nxp/imx_ahcisatareg.h>
43 1.1.2.2 thorpej #include <arm/nxp/imx6_iomuxreg.h>
44 1.1.2.2 thorpej #include <arm/nxp/imx6_ccmreg.h>
45 1.1.2.2 thorpej #include <arm/nxp/imx6_ccmvar.h>
46 1.1.2.2 thorpej
47 1.1.2.2 thorpej #include <dev/fdt/fdtvar.h>
48 1.1.2.2 thorpej
49 1.1.2.2 thorpej static int imx_ahcisata_match(device_t, cfdata_t, void *);
50 1.1.2.2 thorpej static void imx_ahcisata_attach(device_t, device_t, void *);
51 1.1.2.2 thorpej
52 1.1.2.2 thorpej struct imx_ahcisata_softc {
53 1.1.2.2 thorpej struct ahci_softc sc;
54 1.1.2.2 thorpej
55 1.1.2.2 thorpej device_t sc_dev;
56 1.1.2.2 thorpej bus_space_tag_t sc_iot;
57 1.1.2.2 thorpej bus_space_handle_t sc_ioh;
58 1.1.2.2 thorpej bus_space_handle_t sc_gpr_ioh;
59 1.1.2.2 thorpej void *sc_ih;
60 1.1.2.2 thorpej
61 1.1.2.2 thorpej u_int sc_tx_level;
62 1.1.2.2 thorpej u_int sc_tx_boost;
63 1.1.2.2 thorpej u_int sc_tx_atten;
64 1.1.2.2 thorpej u_int sc_rx_eq;
65 1.1.2.2 thorpej u_int sc_ss;
66 1.1.2.2 thorpej
67 1.1.2.2 thorpej struct clk *sc_clk_sata;
68 1.1.2.2 thorpej struct clk *sc_clk_sata_ref;
69 1.1.2.2 thorpej struct clk *sc_clk_ahb;
70 1.1.2.2 thorpej };
71 1.1.2.2 thorpej
72 1.1.2.2 thorpej static int imx_ahcisata_init(struct imx_ahcisata_softc *);
73 1.1.2.2 thorpej static int imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc *, uint32_t, int);
74 1.1.2.2 thorpej static int imx_ahcisata_phy_addr(struct imx_ahcisata_softc *, uint32_t);
75 1.1.2.2 thorpej static int imx_ahcisata_phy_write(struct imx_ahcisata_softc *, uint32_t, uint16_t);
76 1.1.2.2 thorpej static int imx_ahcisata_phy_read(struct imx_ahcisata_softc *, uint32_t);
77 1.1.2.2 thorpej static int imx_ahcisata_init_clocks(struct imx_ahcisata_softc *);
78 1.1.2.2 thorpej
79 1.1.2.2 thorpej CFATTACH_DECL_NEW(imx_ahcisata, sizeof(struct imx_ahcisata_softc),
80 1.1.2.2 thorpej imx_ahcisata_match, imx_ahcisata_attach, NULL, NULL);
81 1.1.2.2 thorpej
82 1.1.2.2 thorpej static int
83 1.1.2.2 thorpej imx_ahcisata_match(device_t parent, cfdata_t cf, void *aux)
84 1.1.2.2 thorpej {
85 1.1.2.2 thorpej const char * const compatible[] = { "fsl,imx6q-ahci", NULL };
86 1.1.2.2 thorpej struct fdt_attach_args * const faa = aux;
87 1.1.2.2 thorpej
88 1.1.2.2 thorpej return of_match_compatible(faa->faa_phandle, compatible);
89 1.1.2.2 thorpej }
90 1.1.2.2 thorpej
91 1.1.2.2 thorpej static void
92 1.1.2.2 thorpej imx_ahcisata_attach(device_t parent, device_t self, void *aux)
93 1.1.2.2 thorpej {
94 1.1.2.2 thorpej struct imx_ahcisata_softc * const sc = device_private(self);
95 1.1.2.2 thorpej struct fdt_attach_args * const faa = aux;
96 1.1.2.2 thorpej const int phandle = faa->faa_phandle;
97 1.1.2.2 thorpej bus_addr_t ahci_addr;
98 1.1.2.2 thorpej bus_size_t ahci_size;
99 1.1.2.2 thorpej bus_addr_t addr;
100 1.1.2.2 thorpej bus_size_t size;
101 1.1.2.2 thorpej char intrstr[128];
102 1.1.2.2 thorpej int error;
103 1.1.2.2 thorpej
104 1.1.2.2 thorpej if (fdtbus_get_reg(phandle, 0, &ahci_addr, &ahci_size) != 0) {
105 1.1.2.2 thorpej aprint_error(": couldn't get ahci registers\n");
106 1.1.2.2 thorpej return;
107 1.1.2.2 thorpej }
108 1.1.2.2 thorpej
109 1.1.2.2 thorpej if (of_getprop_uint32(phandle, "fsl,transmit-level-mV", &sc->sc_tx_level) != 0)
110 1.1.2.2 thorpej sc->sc_tx_level = 1104;
111 1.1.2.2 thorpej if (of_getprop_uint32(phandle, "fsl,transmit-boost-mdB", &sc->sc_tx_boost) != 0)
112 1.1.2.2 thorpej sc->sc_tx_boost = 3330;
113 1.1.2.2 thorpej if (of_getprop_uint32(phandle, "fsl,transmit-atten-16ths", &sc->sc_tx_atten) != 0)
114 1.1.2.2 thorpej sc->sc_tx_atten = 9;
115 1.1.2.2 thorpej if (of_getprop_uint32(phandle, "fsl,receive-eq-mdB", &sc->sc_rx_eq) != 0)
116 1.1.2.2 thorpej sc->sc_rx_eq = 3000;
117 1.1.2.2 thorpej if (of_getprop_bool(phandle, "fsl,no-spread-spectrum") == false)
118 1.1.2.2 thorpej sc->sc_ss = 1;
119 1.1.2.2 thorpej else
120 1.1.2.2 thorpej sc->sc_ss = 0;
121 1.1.2.2 thorpej
122 1.1.2.2 thorpej sc->sc_clk_sata = fdtbus_clock_get(phandle, "sata");
123 1.1.2.2 thorpej if (sc->sc_clk_sata == NULL) {
124 1.1.2.2 thorpej aprint_error(": couldn't get clock sata\n");
125 1.1.2.2 thorpej return;
126 1.1.2.2 thorpej }
127 1.1.2.2 thorpej sc->sc_clk_sata_ref = fdtbus_clock_get(phandle, "sata_ref");
128 1.1.2.2 thorpej if (sc->sc_clk_sata_ref == NULL) {
129 1.1.2.2 thorpej aprint_error(": couldn't get clock sata_ref\n");
130 1.1.2.2 thorpej return;
131 1.1.2.2 thorpej }
132 1.1.2.2 thorpej sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb");
133 1.1.2.2 thorpej if (sc->sc_clk_ahb == NULL) {
134 1.1.2.2 thorpej aprint_error(": couldn't get clock ahb\n");
135 1.1.2.2 thorpej return;
136 1.1.2.2 thorpej }
137 1.1.2.2 thorpej
138 1.1.2.2 thorpej aprint_naive("\n");
139 1.1.2.2 thorpej aprint_normal(": AHCI Controller\n");
140 1.1.2.2 thorpej
141 1.1.2.2 thorpej aprint_debug_dev(self, "tx level %d [mV]\n", sc->sc_tx_level);
142 1.1.2.2 thorpej aprint_debug_dev(self, "tx boost %d [mdB]\n", sc->sc_tx_boost);
143 1.1.2.2 thorpej aprint_debug_dev(self, "tx atten %d [16ths]\n", sc->sc_tx_atten);
144 1.1.2.2 thorpej aprint_debug_dev(self, "rx eq %d [mdB]\n", sc->sc_rx_eq);
145 1.1.2.2 thorpej aprint_debug_dev(self, "ss %d\n", sc->sc_ss);
146 1.1.2.2 thorpej
147 1.1.2.2 thorpej sc->sc_dev = self;
148 1.1.2.2 thorpej
149 1.1.2.2 thorpej sc->sc.sc_atac.atac_dev = self;
150 1.1.2.2 thorpej sc->sc.sc_ahci_ports = 1;
151 1.1.2.2 thorpej sc->sc.sc_dmat = faa->faa_dmat;
152 1.1.2.2 thorpej sc->sc.sc_ahcit = faa->faa_bst;
153 1.1.2.2 thorpej sc->sc.sc_ahcis = ahci_size;
154 1.1.2.2 thorpej error = bus_space_map(sc->sc.sc_ahcit, ahci_addr, ahci_size, 0,
155 1.1.2.2 thorpej &sc->sc.sc_ahcih);
156 1.1.2.2 thorpej if (error) {
157 1.1.2.2 thorpej aprint_error(": couldn't map ahci registers: %d\n", error);
158 1.1.2.2 thorpej return;
159 1.1.2.2 thorpej }
160 1.1.2.2 thorpej
161 1.1.2.2 thorpej sc->sc_iot = sc->sc.sc_ahcit;
162 1.1.2.2 thorpej sc->sc_ioh = sc->sc.sc_ahcih;
163 1.1.2.2 thorpej
164 1.1.2.2 thorpej const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr");
165 1.1.2.2 thorpej fdtbus_get_reg(gpr_phandle, 0, &addr, &size);
166 1.1.2.2 thorpej if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) {
167 1.1.2.2 thorpej aprint_error_dev(self, "Cannot map registers\n");
168 1.1.2.2 thorpej return;
169 1.1.2.2 thorpej }
170 1.1.2.2 thorpej
171 1.1.2.2 thorpej if (imx_ahcisata_init_clocks(sc) != 0) {
172 1.1.2.2 thorpej aprint_error_dev(self, "couldn't init clocks\n");
173 1.1.2.2 thorpej return;
174 1.1.2.2 thorpej }
175 1.1.2.2 thorpej
176 1.1.2.2 thorpej if (imx_ahcisata_init(sc) != 0) {
177 1.1.2.2 thorpej aprint_error_dev(self, "couldn't init ahci\n");
178 1.1.2.2 thorpej return;
179 1.1.2.2 thorpej }
180 1.1.2.2 thorpej
181 1.1.2.2 thorpej if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
182 1.1.2.2 thorpej aprint_error_dev(self, "failed to decode interrupt\n");
183 1.1.2.2 thorpej return;
184 1.1.2.2 thorpej }
185 1.1.2.2 thorpej
186 1.1.2.2 thorpej sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_BIO, 0,
187 1.1.2.2 thorpej ahci_intr, &sc->sc);
188 1.1.2.2 thorpej if (sc->sc_ih == NULL) {
189 1.1.2.2 thorpej aprint_error_dev(self, "failed to establish interrupt on %s\n",
190 1.1.2.2 thorpej intrstr);
191 1.1.2.2 thorpej return;
192 1.1.2.2 thorpej }
193 1.1.2.2 thorpej aprint_normal_dev(self, "interrupting on %s\n", intrstr);
194 1.1.2.2 thorpej
195 1.1.2.2 thorpej ahci_attach(&sc->sc);
196 1.1.2.2 thorpej }
197 1.1.2.2 thorpej
198 1.1.2.2 thorpej static int
199 1.1.2.2 thorpej imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc *sc, uint32_t bitmask, int on)
200 1.1.2.2 thorpej {
201 1.1.2.2 thorpej uint32_t v;
202 1.1.2.2 thorpej int timeout;
203 1.1.2.2 thorpej
204 1.1.2.2 thorpej v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR);
205 1.1.2.2 thorpej if (on)
206 1.1.2.2 thorpej v |= bitmask;
207 1.1.2.2 thorpej else
208 1.1.2.2 thorpej v &= ~bitmask;
209 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, v);
210 1.1.2.2 thorpej
211 1.1.2.2 thorpej for (timeout = 5000; timeout > 0; --timeout) {
212 1.1.2.2 thorpej v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
213 1.1.2.2 thorpej if (!!(v & SATA_P0PHYSR_CR_ACK) == !!on)
214 1.1.2.2 thorpej break;
215 1.1.2.2 thorpej delay(100);
216 1.1.2.2 thorpej }
217 1.1.2.2 thorpej
218 1.1.2.2 thorpej if (timeout > 0)
219 1.1.2.2 thorpej return 0;
220 1.1.2.2 thorpej
221 1.1.2.2 thorpej return -1;
222 1.1.2.2 thorpej }
223 1.1.2.2 thorpej
224 1.1.2.2 thorpej static int
225 1.1.2.2 thorpej imx_ahcisata_phy_addr(struct imx_ahcisata_softc *sc, uint32_t addr)
226 1.1.2.2 thorpej {
227 1.1.2.2 thorpej delay(100);
228 1.1.2.2 thorpej
229 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, addr);
230 1.1.2.2 thorpej
231 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 1) != 0)
232 1.1.2.2 thorpej return -1;
233 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 0) != 0)
234 1.1.2.2 thorpej return -1;
235 1.1.2.2 thorpej
236 1.1.2.2 thorpej return 0;
237 1.1.2.2 thorpej }
238 1.1.2.2 thorpej
239 1.1.2.2 thorpej static int
240 1.1.2.2 thorpej imx_ahcisata_phy_write(struct imx_ahcisata_softc *sc, uint32_t addr,
241 1.1.2.2 thorpej uint16_t data)
242 1.1.2.2 thorpej {
243 1.1.2.2 thorpej if (imx_ahcisata_phy_addr(sc, addr) != 0)
244 1.1.2.2 thorpej return -1;
245 1.1.2.2 thorpej
246 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, data);
247 1.1.2.2 thorpej
248 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 1) != 0)
249 1.1.2.2 thorpej return -1;
250 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 0) != 0)
251 1.1.2.2 thorpej return -1;
252 1.1.2.2 thorpej
253 1.1.2.2 thorpej if ((addr == SATA_PHY_CLOCK_RESET) && data) {
254 1.1.2.2 thorpej /* we can't check ACK after RESET */
255 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
256 1.1.2.2 thorpej data | SATA_P0PHYCR_CR_WRITE);
257 1.1.2.2 thorpej return 0;
258 1.1.2.2 thorpej }
259 1.1.2.2 thorpej
260 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 1) != 0)
261 1.1.2.2 thorpej return -1;
262 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 0) != 0)
263 1.1.2.2 thorpej return -1;
264 1.1.2.2 thorpej
265 1.1.2.2 thorpej return 0;
266 1.1.2.2 thorpej }
267 1.1.2.2 thorpej
268 1.1.2.2 thorpej static int
269 1.1.2.2 thorpej imx_ahcisata_phy_read(struct imx_ahcisata_softc *sc, uint32_t addr)
270 1.1.2.2 thorpej {
271 1.1.2.2 thorpej uint32_t v;
272 1.1.2.2 thorpej
273 1.1.2.2 thorpej if (imx_ahcisata_phy_addr(sc, addr) != 0)
274 1.1.2.2 thorpej return -1;
275 1.1.2.2 thorpej
276 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 1) != 0)
277 1.1.2.2 thorpej return -1;
278 1.1.2.2 thorpej
279 1.1.2.2 thorpej v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
280 1.1.2.2 thorpej
281 1.1.2.2 thorpej if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 0) != 0)
282 1.1.2.2 thorpej return -1;
283 1.1.2.2 thorpej
284 1.1.2.2 thorpej return SATA_P0PHYSR_CR_DATA_OUT(v);
285 1.1.2.2 thorpej }
286 1.1.2.2 thorpej
287 1.1.2.2 thorpej const static int tx_level[] = {
288 1.1.2.2 thorpej 937,
289 1.1.2.2 thorpej 947,
290 1.1.2.2 thorpej 957,
291 1.1.2.2 thorpej 966,
292 1.1.2.2 thorpej 976,
293 1.1.2.2 thorpej 986,
294 1.1.2.2 thorpej 996,
295 1.1.2.2 thorpej 1005,
296 1.1.2.2 thorpej 1015,
297 1.1.2.2 thorpej 1025,
298 1.1.2.2 thorpej 1035,
299 1.1.2.2 thorpej 1045,
300 1.1.2.2 thorpej 1054,
301 1.1.2.2 thorpej 1064,
302 1.1.2.2 thorpej 1074,
303 1.1.2.2 thorpej 1084,
304 1.1.2.2 thorpej 1094,
305 1.1.2.2 thorpej 1104,
306 1.1.2.2 thorpej 1113,
307 1.1.2.2 thorpej 1123,
308 1.1.2.2 thorpej 1133,
309 1.1.2.2 thorpej 1143,
310 1.1.2.2 thorpej 1152,
311 1.1.2.2 thorpej 1162,
312 1.1.2.2 thorpej 1172,
313 1.1.2.2 thorpej 1182,
314 1.1.2.2 thorpej 1191,
315 1.1.2.2 thorpej 1201,
316 1.1.2.2 thorpej 1211,
317 1.1.2.2 thorpej 1221,
318 1.1.2.2 thorpej 1230,
319 1.1.2.2 thorpej 1240,
320 1.1.2.2 thorpej };
321 1.1.2.2 thorpej
322 1.1.2.2 thorpej const static int tx_boots[] = {
323 1.1.2.2 thorpej 0,
324 1.1.2.2 thorpej 370,
325 1.1.2.2 thorpej 740,
326 1.1.2.2 thorpej 1110,
327 1.1.2.2 thorpej 1480,
328 1.1.2.2 thorpej 1850,
329 1.1.2.2 thorpej 2220,
330 1.1.2.2 thorpej 2590,
331 1.1.2.2 thorpej 2960,
332 1.1.2.2 thorpej 3330,
333 1.1.2.2 thorpej 3700,
334 1.1.2.2 thorpej 4070,
335 1.1.2.2 thorpej 4440,
336 1.1.2.2 thorpej 4810,
337 1.1.2.2 thorpej 5280,
338 1.1.2.2 thorpej 5750,
339 1.1.2.2 thorpej };
340 1.1.2.2 thorpej
341 1.1.2.2 thorpej const static int tx_atten[] = {
342 1.1.2.2 thorpej 16,
343 1.1.2.2 thorpej 14,
344 1.1.2.2 thorpej 12,
345 1.1.2.2 thorpej 10,
346 1.1.2.2 thorpej 9,
347 1.1.2.2 thorpej 8,
348 1.1.2.2 thorpej };
349 1.1.2.2 thorpej
350 1.1.2.2 thorpej const static int rx_eq[] = {
351 1.1.2.2 thorpej 500,
352 1.1.2.2 thorpej 1000,
353 1.1.2.2 thorpej 1500,
354 1.1.2.2 thorpej 2000,
355 1.1.2.2 thorpej 2500,
356 1.1.2.2 thorpej 3000,
357 1.1.2.2 thorpej 3500,
358 1.1.2.2 thorpej 4000,
359 1.1.2.2 thorpej };
360 1.1.2.2 thorpej
361 1.1.2.2 thorpej static int
362 1.1.2.2 thorpej imx_ahcisata_search_regval(const int *values, int count, int val)
363 1.1.2.2 thorpej {
364 1.1.2.2 thorpej for (int i = 0; i < count; i++)
365 1.1.2.2 thorpej if (values[i] == val)
366 1.1.2.2 thorpej return i;
367 1.1.2.2 thorpej
368 1.1.2.2 thorpej return -1;
369 1.1.2.2 thorpej }
370 1.1.2.2 thorpej
371 1.1.2.2 thorpej static int
372 1.1.2.2 thorpej imx_ahcisata_init(struct imx_ahcisata_softc *sc)
373 1.1.2.2 thorpej {
374 1.1.2.2 thorpej uint32_t v;
375 1.1.2.2 thorpej int timeout;
376 1.1.2.2 thorpej int pllstat;
377 1.1.2.2 thorpej
378 1.1.2.2 thorpej v = bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13);
379 1.1.2.2 thorpej /* clear */
380 1.1.2.2 thorpej v &= ~(IOMUX_GPR13_SATA_PHY_8 |
381 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_7 |
382 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_6 |
383 1.1.2.2 thorpej IOMUX_GPR13_SATA_SPEED |
384 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_5 |
385 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_4 |
386 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_3 |
387 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_2 |
388 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_1 |
389 1.1.2.2 thorpej IOMUX_GPR13_SATA_PHY_0);
390 1.1.2.2 thorpej /* setting */
391 1.1.2.2 thorpej struct {
392 1.1.2.2 thorpej const int *array;
393 1.1.2.2 thorpej int count;
394 1.1.2.2 thorpej int val;
395 1.1.2.2 thorpej int def_val;
396 1.1.2.2 thorpej int mask;
397 1.1.2.2 thorpej } gpr13_sata_phy_settings[] = {
398 1.1.2.2 thorpej { tx_level, __arraycount(tx_level), sc->sc_tx_level,
399 1.1.2.2 thorpej 0x11, IOMUX_GPR13_SATA_PHY_2 },
400 1.1.2.2 thorpej { tx_boots, __arraycount(tx_boots), sc->sc_tx_boost,
401 1.1.2.2 thorpej 0x09, IOMUX_GPR13_SATA_PHY_3 },
402 1.1.2.2 thorpej { tx_atten, __arraycount(tx_atten), sc->sc_tx_atten,
403 1.1.2.2 thorpej 0x04, IOMUX_GPR13_SATA_PHY_4 },
404 1.1.2.2 thorpej { rx_eq, __arraycount(rx_eq), sc->sc_rx_eq,
405 1.1.2.2 thorpej 0x05, IOMUX_GPR13_SATA_PHY_8 }
406 1.1.2.2 thorpej };
407 1.1.2.2 thorpej for (int i = 0; i < __arraycount(gpr13_sata_phy_settings); i++) {
408 1.1.2.2 thorpej int val;
409 1.1.2.2 thorpej val = imx_ahcisata_search_regval(
410 1.1.2.2 thorpej gpr13_sata_phy_settings[i].array,
411 1.1.2.2 thorpej gpr13_sata_phy_settings[i].count,
412 1.1.2.2 thorpej gpr13_sata_phy_settings[i].val);
413 1.1.2.2 thorpej if (val == -1)
414 1.1.2.2 thorpej val = gpr13_sata_phy_settings[i].def_val;
415 1.1.2.2 thorpej v |= __SHIFTIN(val, gpr13_sata_phy_settings[i].mask);
416 1.1.2.2 thorpej }
417 1.1.2.2 thorpej v |= __SHIFTIN(0x12, IOMUX_GPR13_SATA_PHY_7); /* Rx SATA2m */
418 1.1.2.2 thorpej v |= __SHIFTIN(3, IOMUX_GPR13_SATA_PHY_6); /* Rx DPLL mode */
419 1.1.2.2 thorpej v |= __SHIFTIN(1, IOMUX_GPR13_SATA_SPEED); /* 3.0GHz */
420 1.1.2.2 thorpej v |= __SHIFTIN(sc->sc_ss, IOMUX_GPR13_SATA_PHY_5);
421 1.1.2.2 thorpej v |= __SHIFTIN(1, IOMUX_GPR13_SATA_PHY_1); /* PLL clock enable */
422 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13, v);
423 1.1.2.2 thorpej
424 1.1.2.2 thorpej /* phy reset */
425 1.1.2.2 thorpej if (imx_ahcisata_phy_write(sc, SATA_PHY_CLOCK_RESET,
426 1.1.2.2 thorpej SATA_PHY_CLOCK_RESET_RST) < 0) {
427 1.1.2.2 thorpej aprint_error_dev(sc->sc_dev, "cannot reset PHY\n");
428 1.1.2.2 thorpej return -1;
429 1.1.2.2 thorpej }
430 1.1.2.2 thorpej
431 1.1.2.2 thorpej for (timeout = 50; timeout > 0; --timeout) {
432 1.1.2.2 thorpej delay(100);
433 1.1.2.2 thorpej pllstat = imx_ahcisata_phy_read(sc, SATA_PHY_LANE0_OUT_STAT);
434 1.1.2.2 thorpej if (pllstat < 0) {
435 1.1.2.2 thorpej aprint_error_dev(sc->sc_dev,
436 1.1.2.2 thorpej "cannot read LANE0 status\n");
437 1.1.2.2 thorpej break;
438 1.1.2.2 thorpej }
439 1.1.2.2 thorpej if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE)
440 1.1.2.2 thorpej break;
441 1.1.2.2 thorpej }
442 1.1.2.2 thorpej if (timeout <= 0)
443 1.1.2.2 thorpej return -1;
444 1.1.2.2 thorpej
445 1.1.2.2 thorpej /* Support Staggered Spin-up */
446 1.1.2.2 thorpej v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP);
447 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP, v | SATA_CAP_SSS);
448 1.1.2.2 thorpej
449 1.1.2.2 thorpej /* Ports Implmented. must set 1 */
450 1.1.2.2 thorpej v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_PI);
451 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, v | SATA_PI_PI);
452 1.1.2.2 thorpej
453 1.1.2.2 thorpej /* set 1ms-timer = AHB clock / 1000 */
454 1.1.2.2 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS,
455 1.1.2.2 thorpej clk_get_rate(sc->sc_clk_ahb) / 1000);
456 1.1.2.2 thorpej
457 1.1.2.2 thorpej return 0;
458 1.1.2.2 thorpej }
459 1.1.2.2 thorpej
460 1.1.2.2 thorpej static int
461 1.1.2.2 thorpej imx_ahcisata_init_clocks(struct imx_ahcisata_softc *sc)
462 1.1.2.2 thorpej {
463 1.1.2.2 thorpej int error;
464 1.1.2.2 thorpej
465 1.1.2.2 thorpej error = clk_enable(sc->sc_clk_sata);
466 1.1.2.2 thorpej if (error) {
467 1.1.2.2 thorpej aprint_error_dev(sc->sc_dev, "couldn't enable sata: %d\n", error);
468 1.1.2.2 thorpej return error;
469 1.1.2.2 thorpej }
470 1.1.2.2 thorpej error = clk_enable(sc->sc_clk_sata_ref);
471 1.1.2.2 thorpej if (error) {
472 1.1.2.2 thorpej aprint_error_dev(sc->sc_dev, "couldn't enable sata-ref: %d\n", error);
473 1.1.2.2 thorpej return error;
474 1.1.2.2 thorpej }
475 1.1.2.2 thorpej error = clk_enable(sc->sc_clk_ahb);
476 1.1.2.2 thorpej if (error) {
477 1.1.2.2 thorpej aprint_error_dev(sc->sc_dev, "couldn't enable anb: %d\n", error);
478 1.1.2.2 thorpej return error;
479 1.1.2.2 thorpej }
480 1.1.2.2 thorpej
481 1.1.2.2 thorpej return 0;
482 1.1.2.2 thorpej }
483