xref: /netbsd-src/sys/arch/arm/nxp/imx_ahcisata.c (revision 183889cba7f5563a43fd45def3b2e1a8611f85dc)
1*183889cbSandvar /*	$NetBSD: imx_ahcisata.c,v 1.4 2022/02/06 20:20:19 andvar Exp $	*/
28644267aSskrll 
38644267aSskrll /*-
48644267aSskrll  * Copyright (c) 2019 Genetec Corporation.  All rights reserved.
58644267aSskrll  * Written by Hashimoto Kenichi for Genetec Corporation.
68644267aSskrll  *
78644267aSskrll  * Redistribution and use in source and binary forms, with or without
88644267aSskrll  * modification, are permitted provided that the following conditions
98644267aSskrll  * are met:
108644267aSskrll  * 1. Redistributions of source code must retain the above copyright
118644267aSskrll  *    notice, this list of conditions and the following disclaimer.
128644267aSskrll  * 2. Redistributions in binary form must reproduce the above copyright
138644267aSskrll  *    notice, this list of conditions and the following disclaimer in the
148644267aSskrll  *    documentation and/or other materials provided with the distribution.
158644267aSskrll  *
168644267aSskrll  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
178644267aSskrll  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
188644267aSskrll  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
198644267aSskrll  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
208644267aSskrll  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
218644267aSskrll  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
228644267aSskrll  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
238644267aSskrll  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
248644267aSskrll  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258644267aSskrll  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268644267aSskrll  * SUCH DAMAGE.
278644267aSskrll  */
288644267aSskrll 
298644267aSskrll #include <sys/cdefs.h>
30*183889cbSandvar __KERNEL_RCSID(0, "$NetBSD: imx_ahcisata.c,v 1.4 2022/02/06 20:20:19 andvar Exp $");
318644267aSskrll 
328644267aSskrll #include <sys/param.h>
338644267aSskrll #include <sys/bus.h>
348644267aSskrll #include <sys/device.h>
358644267aSskrll #include <sys/intr.h>
368644267aSskrll #include <sys/systm.h>
378644267aSskrll #include <sys/kernel.h>
388644267aSskrll 
398644267aSskrll #include <dev/ata/atavar.h>
408644267aSskrll #include <dev/ic/ahcisatavar.h>
418644267aSskrll 
428644267aSskrll #include <arm/nxp/imx_ahcisatareg.h>
438644267aSskrll #include <arm/nxp/imx6_iomuxreg.h>
448644267aSskrll #include <arm/nxp/imx6_ccmreg.h>
458644267aSskrll #include <arm/nxp/imx6_ccmvar.h>
468644267aSskrll 
478644267aSskrll #include <dev/fdt/fdtvar.h>
488644267aSskrll 
498644267aSskrll static int imx_ahcisata_match(device_t, cfdata_t, void *);
508644267aSskrll static void imx_ahcisata_attach(device_t, device_t, void *);
518644267aSskrll 
528644267aSskrll struct imx_ahcisata_softc {
538644267aSskrll 	struct ahci_softc sc;
548644267aSskrll 
558644267aSskrll 	device_t sc_dev;
568644267aSskrll 	bus_space_tag_t sc_iot;
578644267aSskrll 	bus_space_handle_t sc_ioh;
588644267aSskrll 	bus_space_handle_t sc_gpr_ioh;
598644267aSskrll 	void *sc_ih;
608644267aSskrll 
618644267aSskrll 	u_int sc_tx_level;
628644267aSskrll 	u_int sc_tx_boost;
638644267aSskrll 	u_int sc_tx_atten;
648644267aSskrll 	u_int sc_rx_eq;
658644267aSskrll 	u_int sc_ss;
668644267aSskrll 
678644267aSskrll 	struct clk *sc_clk_sata;
688644267aSskrll 	struct clk *sc_clk_sata_ref;
698644267aSskrll 	struct clk *sc_clk_ahb;
708644267aSskrll };
718644267aSskrll 
728644267aSskrll static int imx_ahcisata_init(struct imx_ahcisata_softc *);
738644267aSskrll static int imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc *, uint32_t, int);
748644267aSskrll static int imx_ahcisata_phy_addr(struct imx_ahcisata_softc *, uint32_t);
758644267aSskrll static int imx_ahcisata_phy_write(struct imx_ahcisata_softc *, uint32_t, uint16_t);
768644267aSskrll static int imx_ahcisata_phy_read(struct imx_ahcisata_softc *, uint32_t);
778644267aSskrll static int imx_ahcisata_init_clocks(struct imx_ahcisata_softc *);
788644267aSskrll 
798644267aSskrll CFATTACH_DECL_NEW(imx_ahcisata, sizeof(struct imx_ahcisata_softc),
808644267aSskrll 	imx_ahcisata_match, imx_ahcisata_attach, NULL, NULL);
818644267aSskrll 
826e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
836e54367aSthorpej 	{ .compat = "fsl,imx6q-ahci" },
846e54367aSthorpej 	DEVICE_COMPAT_EOL
856e54367aSthorpej };
866e54367aSthorpej 
878644267aSskrll static int
imx_ahcisata_match(device_t parent,cfdata_t cf,void * aux)888644267aSskrll imx_ahcisata_match(device_t parent, cfdata_t cf, void *aux)
898644267aSskrll {
908644267aSskrll 	struct fdt_attach_args * const faa = aux;
918644267aSskrll 
926e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
938644267aSskrll }
948644267aSskrll 
958644267aSskrll static void
imx_ahcisata_attach(device_t parent,device_t self,void * aux)968644267aSskrll imx_ahcisata_attach(device_t parent, device_t self, void *aux)
978644267aSskrll {
988644267aSskrll 	struct imx_ahcisata_softc * const sc = device_private(self);
998644267aSskrll 	struct fdt_attach_args * const faa = aux;
1008644267aSskrll 	const int phandle = faa->faa_phandle;
1018644267aSskrll 	bus_addr_t ahci_addr;
1028644267aSskrll 	bus_size_t ahci_size;
1038644267aSskrll 	bus_addr_t addr;
1048644267aSskrll 	bus_size_t size;
1058644267aSskrll 	char intrstr[128];
1068644267aSskrll 	int error;
1078644267aSskrll 
1088644267aSskrll 	if (fdtbus_get_reg(phandle, 0, &ahci_addr, &ahci_size) != 0) {
1098644267aSskrll 		aprint_error(": couldn't get ahci registers\n");
1108644267aSskrll 		return;
1118644267aSskrll 	}
1128644267aSskrll 
1138644267aSskrll 	if (of_getprop_uint32(phandle, "fsl,transmit-level-mV", &sc->sc_tx_level) != 0)
1148644267aSskrll 		sc->sc_tx_level = 1104;
1158644267aSskrll 	if (of_getprop_uint32(phandle, "fsl,transmit-boost-mdB", &sc->sc_tx_boost) != 0)
1168644267aSskrll 		sc->sc_tx_boost = 3330;
1178644267aSskrll 	if (of_getprop_uint32(phandle, "fsl,transmit-atten-16ths", &sc->sc_tx_atten) != 0)
1188644267aSskrll 		sc->sc_tx_atten = 9;
1198644267aSskrll 	if (of_getprop_uint32(phandle, "fsl,receive-eq-mdB", &sc->sc_rx_eq) != 0)
1208644267aSskrll 		sc->sc_rx_eq = 3000;
1218644267aSskrll 	if (of_getprop_bool(phandle, "fsl,no-spread-spectrum") == false)
1228644267aSskrll 		sc->sc_ss = 1;
1238644267aSskrll 	else
1248644267aSskrll 		sc->sc_ss = 0;
1258644267aSskrll 
1268644267aSskrll 	sc->sc_clk_sata = fdtbus_clock_get(phandle, "sata");
1278644267aSskrll 	if (sc->sc_clk_sata == NULL) {
1288644267aSskrll 		aprint_error(": couldn't get clock sata\n");
1298644267aSskrll 		return;
1308644267aSskrll 	}
1318644267aSskrll 	sc->sc_clk_sata_ref = fdtbus_clock_get(phandle, "sata_ref");
1328644267aSskrll 	if (sc->sc_clk_sata_ref == NULL) {
1338644267aSskrll 		aprint_error(": couldn't get clock sata_ref\n");
1348644267aSskrll 		return;
1358644267aSskrll 	}
1368644267aSskrll 	sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb");
1378644267aSskrll 	if (sc->sc_clk_ahb == NULL) {
1388644267aSskrll 		aprint_error(": couldn't get clock ahb\n");
1398644267aSskrll 		return;
1408644267aSskrll 	}
1418644267aSskrll 
1428644267aSskrll 	aprint_naive("\n");
1438644267aSskrll 	aprint_normal(": AHCI Controller\n");
1448644267aSskrll 
1458644267aSskrll 	aprint_debug_dev(self, "tx level %d [mV]\n", sc->sc_tx_level);
1468644267aSskrll 	aprint_debug_dev(self, "tx boost %d [mdB]\n", sc->sc_tx_boost);
1478644267aSskrll 	aprint_debug_dev(self, "tx atten %d [16ths]\n", sc->sc_tx_atten);
1488644267aSskrll 	aprint_debug_dev(self, "rx eq    %d [mdB]\n", sc->sc_rx_eq);
1498644267aSskrll 	aprint_debug_dev(self, "ss       %d\n", sc->sc_ss);
1508644267aSskrll 
1518644267aSskrll 	sc->sc_dev = self;
1528644267aSskrll 
1538644267aSskrll 	sc->sc.sc_atac.atac_dev = self;
1548644267aSskrll 	sc->sc.sc_ahci_ports = 1;
1558644267aSskrll 	sc->sc.sc_dmat = faa->faa_dmat;
1568644267aSskrll 	sc->sc.sc_ahcit = faa->faa_bst;
1578644267aSskrll 	sc->sc.sc_ahcis = ahci_size;
1588644267aSskrll 	error = bus_space_map(sc->sc.sc_ahcit, ahci_addr, ahci_size, 0,
1598644267aSskrll 	    &sc->sc.sc_ahcih);
1608644267aSskrll 	if (error) {
1618644267aSskrll 		aprint_error(": couldn't map ahci registers: %d\n", error);
1628644267aSskrll 		return;
1638644267aSskrll 	}
1648644267aSskrll 
1658644267aSskrll 	sc->sc_iot = sc->sc.sc_ahcit;
1668644267aSskrll 	sc->sc_ioh = sc->sc.sc_ahcih;
1678644267aSskrll 
1688644267aSskrll 	const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr");
1698644267aSskrll 	fdtbus_get_reg(gpr_phandle, 0, &addr, &size);
1708644267aSskrll 	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) {
1718644267aSskrll 		aprint_error_dev(self, "Cannot map registers\n");
1728644267aSskrll 		return;
1738644267aSskrll 	}
1748644267aSskrll 
1758644267aSskrll 	if (imx_ahcisata_init_clocks(sc) != 0) {
1768644267aSskrll 		aprint_error_dev(self, "couldn't init clocks\n");
1778644267aSskrll 		return;
1788644267aSskrll 	}
1798644267aSskrll 
1808644267aSskrll 	if (imx_ahcisata_init(sc) != 0) {
1818644267aSskrll 		aprint_error_dev(self, "couldn't init ahci\n");
1828644267aSskrll 		return;
1838644267aSskrll 	}
1848644267aSskrll 
1858644267aSskrll 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
1868644267aSskrll 		aprint_error_dev(self, "failed to decode interrupt\n");
1878644267aSskrll 		return;
1888644267aSskrll 	}
1898644267aSskrll 
19082b8374aSjmcneill 	sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_BIO, 0,
19182b8374aSjmcneill 	    ahci_intr, &sc->sc, device_xname(self));
1928644267aSskrll 	if (sc->sc_ih == NULL) {
1938644267aSskrll 		aprint_error_dev(self, "failed to establish interrupt on %s\n",
1948644267aSskrll 		    intrstr);
1958644267aSskrll 		return;
1968644267aSskrll 	}
1978644267aSskrll 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
1988644267aSskrll 
1998644267aSskrll 	ahci_attach(&sc->sc);
2008644267aSskrll }
2018644267aSskrll 
2028644267aSskrll static int
imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc * sc,uint32_t bitmask,int on)2038644267aSskrll imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc *sc, uint32_t bitmask, int on)
2048644267aSskrll {
2058644267aSskrll 	uint32_t v;
2068644267aSskrll 	int timeout;
2078644267aSskrll 
2088644267aSskrll 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR);
2098644267aSskrll 	if (on)
2108644267aSskrll 		v |= bitmask;
2118644267aSskrll 	else
2128644267aSskrll 		v &= ~bitmask;
2138644267aSskrll 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, v);
2148644267aSskrll 
2158644267aSskrll 	for (timeout = 5000; timeout > 0; --timeout) {
2168644267aSskrll 		v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
2178644267aSskrll 		if (!!(v & SATA_P0PHYSR_CR_ACK) == !!on)
2188644267aSskrll 			break;
2198644267aSskrll 		delay(100);
2208644267aSskrll 	}
2218644267aSskrll 
2228644267aSskrll 	if (timeout > 0)
2238644267aSskrll 		return 0;
2248644267aSskrll 
2258644267aSskrll 	return -1;
2268644267aSskrll }
2278644267aSskrll 
2288644267aSskrll static int
imx_ahcisata_phy_addr(struct imx_ahcisata_softc * sc,uint32_t addr)2298644267aSskrll imx_ahcisata_phy_addr(struct imx_ahcisata_softc *sc, uint32_t addr)
2308644267aSskrll {
2318644267aSskrll 	delay(100);
2328644267aSskrll 
2338644267aSskrll 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, addr);
2348644267aSskrll 
2358644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 1) != 0)
2368644267aSskrll 		return -1;
2378644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 0) != 0)
2388644267aSskrll 		return -1;
2398644267aSskrll 
2408644267aSskrll 	return 0;
2418644267aSskrll }
2428644267aSskrll 
2438644267aSskrll static int
imx_ahcisata_phy_write(struct imx_ahcisata_softc * sc,uint32_t addr,uint16_t data)2448644267aSskrll imx_ahcisata_phy_write(struct imx_ahcisata_softc *sc, uint32_t addr,
2458644267aSskrll                         uint16_t data)
2468644267aSskrll {
2478644267aSskrll 	if (imx_ahcisata_phy_addr(sc, addr) != 0)
2488644267aSskrll 		return -1;
2498644267aSskrll 
2508644267aSskrll 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, data);
2518644267aSskrll 
2528644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 1) != 0)
2538644267aSskrll 		return -1;
2548644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 0) != 0)
2558644267aSskrll 		return -1;
2568644267aSskrll 
2578644267aSskrll 	if ((addr == SATA_PHY_CLOCK_RESET) && data) {
2588644267aSskrll 		/* we can't check ACK after RESET */
2598644267aSskrll 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
2608644267aSskrll 		    data | SATA_P0PHYCR_CR_WRITE);
2618644267aSskrll 		return 0;
2628644267aSskrll 	}
2638644267aSskrll 
2648644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 1) != 0)
2658644267aSskrll 		return -1;
2668644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 0) != 0)
2678644267aSskrll 		return -1;
2688644267aSskrll 
2698644267aSskrll 	return 0;
2708644267aSskrll }
2718644267aSskrll 
2728644267aSskrll static int
imx_ahcisata_phy_read(struct imx_ahcisata_softc * sc,uint32_t addr)2738644267aSskrll imx_ahcisata_phy_read(struct imx_ahcisata_softc *sc, uint32_t addr)
2748644267aSskrll {
2758644267aSskrll 	uint32_t v;
2768644267aSskrll 
2778644267aSskrll 	if (imx_ahcisata_phy_addr(sc, addr) != 0)
2788644267aSskrll 		return -1;
2798644267aSskrll 
2808644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 1) != 0)
2818644267aSskrll 		return -1;
2828644267aSskrll 
2838644267aSskrll 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
2848644267aSskrll 
2858644267aSskrll 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 0) != 0)
2868644267aSskrll 		return -1;
2878644267aSskrll 
2888644267aSskrll 	return SATA_P0PHYSR_CR_DATA_OUT(v);
2898644267aSskrll }
2908644267aSskrll 
2918644267aSskrll const static int tx_level[] = {
2928644267aSskrll 	 937,
2938644267aSskrll 	 947,
2948644267aSskrll 	 957,
2958644267aSskrll 	 966,
2968644267aSskrll 	 976,
2978644267aSskrll 	 986,
2988644267aSskrll 	 996,
2998644267aSskrll 	1005,
3008644267aSskrll 	1015,
3018644267aSskrll 	1025,
3028644267aSskrll 	1035,
3038644267aSskrll 	1045,
3048644267aSskrll 	1054,
3058644267aSskrll 	1064,
3068644267aSskrll 	1074,
3078644267aSskrll 	1084,
3088644267aSskrll 	1094,
3098644267aSskrll 	1104,
3108644267aSskrll 	1113,
3118644267aSskrll 	1123,
3128644267aSskrll 	1133,
3138644267aSskrll 	1143,
3148644267aSskrll 	1152,
3158644267aSskrll 	1162,
3168644267aSskrll 	1172,
3178644267aSskrll 	1182,
3188644267aSskrll 	1191,
3198644267aSskrll 	1201,
3208644267aSskrll 	1211,
3218644267aSskrll 	1221,
3228644267aSskrll 	1230,
3238644267aSskrll 	1240,
3248644267aSskrll };
3258644267aSskrll 
3268644267aSskrll const static int tx_boots[] = {
3278644267aSskrll 	   0,
3288644267aSskrll 	 370,
3298644267aSskrll 	 740,
3308644267aSskrll 	1110,
3318644267aSskrll 	1480,
3328644267aSskrll 	1850,
3338644267aSskrll 	2220,
3348644267aSskrll 	2590,
3358644267aSskrll 	2960,
3368644267aSskrll 	3330,
3378644267aSskrll 	3700,
3388644267aSskrll 	4070,
3398644267aSskrll 	4440,
3408644267aSskrll 	4810,
3418644267aSskrll 	5280,
3428644267aSskrll 	5750,
3438644267aSskrll };
3448644267aSskrll 
3458644267aSskrll const static int tx_atten[] = {
3468644267aSskrll 	  16,
3478644267aSskrll 	  14,
3488644267aSskrll 	  12,
3498644267aSskrll 	  10,
3508644267aSskrll 	   9,
3518644267aSskrll 	   8,
3528644267aSskrll };
3538644267aSskrll 
3548644267aSskrll const static int rx_eq[] = {
3558644267aSskrll 	 500,
3568644267aSskrll 	1000,
3578644267aSskrll 	1500,
3588644267aSskrll 	2000,
3598644267aSskrll 	2500,
3608644267aSskrll 	3000,
3618644267aSskrll 	3500,
3628644267aSskrll 	4000,
3638644267aSskrll };
3648644267aSskrll 
3658644267aSskrll static int
imx_ahcisata_search_regval(const int * values,int count,int val)3668644267aSskrll imx_ahcisata_search_regval(const int *values, int count, int val)
3678644267aSskrll {
3688644267aSskrll 	for (int i = 0; i < count; i++)
3698644267aSskrll 		if (values[i] == val)
3708644267aSskrll 			return i;
3718644267aSskrll 
3728644267aSskrll 	return -1;
3738644267aSskrll }
3748644267aSskrll 
3758644267aSskrll static int
imx_ahcisata_init(struct imx_ahcisata_softc * sc)3768644267aSskrll imx_ahcisata_init(struct imx_ahcisata_softc *sc)
3778644267aSskrll {
3788644267aSskrll 	uint32_t v;
3798644267aSskrll 	int timeout;
3808644267aSskrll 	int pllstat;
3818644267aSskrll 
3828644267aSskrll 	v = bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13);
3838644267aSskrll 	/* clear */
3848644267aSskrll 	v &= ~(IOMUX_GPR13_SATA_PHY_8 |
3858644267aSskrll 	    IOMUX_GPR13_SATA_PHY_7 |
3868644267aSskrll 	    IOMUX_GPR13_SATA_PHY_6 |
3878644267aSskrll 	    IOMUX_GPR13_SATA_SPEED |
3888644267aSskrll 	    IOMUX_GPR13_SATA_PHY_5 |
3898644267aSskrll 	    IOMUX_GPR13_SATA_PHY_4 |
3908644267aSskrll 	    IOMUX_GPR13_SATA_PHY_3 |
3918644267aSskrll 	    IOMUX_GPR13_SATA_PHY_2 |
3928644267aSskrll 	    IOMUX_GPR13_SATA_PHY_1 |
3938644267aSskrll 	    IOMUX_GPR13_SATA_PHY_0);
3948644267aSskrll 	/* setting */
3958644267aSskrll 	struct {
3968644267aSskrll 		const int *array;
3978644267aSskrll 		int count;
3988644267aSskrll 		int val;
3998644267aSskrll 		int def_val;
4008644267aSskrll 		int mask;
4018644267aSskrll 	} gpr13_sata_phy_settings[] = {
4028644267aSskrll 		{ tx_level, __arraycount(tx_level), sc->sc_tx_level,
4038644267aSskrll 		  0x11, IOMUX_GPR13_SATA_PHY_2 },
4048644267aSskrll 		{ tx_boots, __arraycount(tx_boots), sc->sc_tx_boost,
4058644267aSskrll 		  0x09, IOMUX_GPR13_SATA_PHY_3 },
4068644267aSskrll 		{ tx_atten, __arraycount(tx_atten), sc->sc_tx_atten,
4078644267aSskrll 		  0x04, IOMUX_GPR13_SATA_PHY_4 },
4088644267aSskrll 		{ rx_eq, __arraycount(rx_eq), sc->sc_rx_eq,
4098644267aSskrll 		  0x05, IOMUX_GPR13_SATA_PHY_8 }
4108644267aSskrll 	};
4118644267aSskrll 	for (int i = 0; i < __arraycount(gpr13_sata_phy_settings); i++) {
4128644267aSskrll 		int val;
4138644267aSskrll 		val = imx_ahcisata_search_regval(
4148644267aSskrll 			gpr13_sata_phy_settings[i].array,
4158644267aSskrll 			gpr13_sata_phy_settings[i].count,
4168644267aSskrll 			gpr13_sata_phy_settings[i].val);
4178644267aSskrll 		if (val == -1)
4188644267aSskrll 			val = gpr13_sata_phy_settings[i].def_val;
4198644267aSskrll 		v |= __SHIFTIN(val, gpr13_sata_phy_settings[i].mask);
4208644267aSskrll 	}
4218644267aSskrll 	v |= __SHIFTIN(0x12, IOMUX_GPR13_SATA_PHY_7);	/* Rx SATA2m */
4228644267aSskrll 	v |= __SHIFTIN(3, IOMUX_GPR13_SATA_PHY_6);	/* Rx DPLL mode */
4238644267aSskrll 	v |= __SHIFTIN(1, IOMUX_GPR13_SATA_SPEED);	/* 3.0GHz */
4248644267aSskrll 	v |= __SHIFTIN(sc->sc_ss, IOMUX_GPR13_SATA_PHY_5);
4258644267aSskrll 	v |= __SHIFTIN(1, IOMUX_GPR13_SATA_PHY_1);	/* PLL clock enable */
4268644267aSskrll 	bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13, v);
4278644267aSskrll 
4288644267aSskrll 	/* phy reset */
4298644267aSskrll 	if (imx_ahcisata_phy_write(sc, SATA_PHY_CLOCK_RESET,
4308644267aSskrll 	    SATA_PHY_CLOCK_RESET_RST) < 0) {
4318644267aSskrll 		aprint_error_dev(sc->sc_dev, "cannot reset PHY\n");
4328644267aSskrll 		return -1;
4338644267aSskrll 	}
4348644267aSskrll 
4358644267aSskrll 	for (timeout = 50; timeout > 0; --timeout) {
4368644267aSskrll 		delay(100);
4378644267aSskrll 		pllstat = imx_ahcisata_phy_read(sc, SATA_PHY_LANE0_OUT_STAT);
4388644267aSskrll 		if (pllstat < 0) {
4398644267aSskrll 			aprint_error_dev(sc->sc_dev,
4408644267aSskrll 			    "cannot read LANE0 status\n");
4418644267aSskrll 			break;
4428644267aSskrll 		}
4438644267aSskrll 		if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE)
4448644267aSskrll 			break;
4458644267aSskrll 	}
4468644267aSskrll 	if (timeout <= 0)
4478644267aSskrll 		return -1;
4488644267aSskrll 
4498644267aSskrll 	/* Support Staggered Spin-up */
4508644267aSskrll 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP);
4518644267aSskrll 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP, v | SATA_CAP_SSS);
4528644267aSskrll 
453*183889cbSandvar 	/* Ports Implemented. must set 1 */
4548644267aSskrll 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_PI);
4558644267aSskrll 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, v | SATA_PI_PI);
4568644267aSskrll 
4578644267aSskrll 	/* set 1ms-timer = AHB clock / 1000 */
4588644267aSskrll 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS,
4598644267aSskrll 	    clk_get_rate(sc->sc_clk_ahb) / 1000);
4608644267aSskrll 
4618644267aSskrll 	return 0;
4628644267aSskrll }
4638644267aSskrll 
4648644267aSskrll static int
imx_ahcisata_init_clocks(struct imx_ahcisata_softc * sc)4658644267aSskrll imx_ahcisata_init_clocks(struct imx_ahcisata_softc *sc)
4668644267aSskrll {
4678644267aSskrll 	int error;
4688644267aSskrll 
4698644267aSskrll 	error = clk_enable(sc->sc_clk_sata);
4708644267aSskrll 	if (error) {
4718644267aSskrll 		aprint_error_dev(sc->sc_dev, "couldn't enable sata: %d\n", error);
4728644267aSskrll 		return error;
4738644267aSskrll 	}
4748644267aSskrll 	error = clk_enable(sc->sc_clk_sata_ref);
4758644267aSskrll 	if (error) {
4768644267aSskrll 		aprint_error_dev(sc->sc_dev, "couldn't enable sata-ref: %d\n", error);
4778644267aSskrll 		return error;
4788644267aSskrll 	}
4798644267aSskrll 	error = clk_enable(sc->sc_clk_ahb);
4808644267aSskrll 	if (error) {
4818644267aSskrll 		aprint_error_dev(sc->sc_dev, "couldn't enable anb: %d\n", error);
4828644267aSskrll 		return error;
4838644267aSskrll 	}
4848644267aSskrll 
4858644267aSskrll 	return 0;
4868644267aSskrll }
487