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