Home | History | Annotate | Line # | Download | only in nxp
imx_ahcisata.c revision 1.1.2.3
      1  1.1.2.3  thorpej /*	$NetBSD: imx_ahcisata.c,v 1.1.2.3 2021/04/03 22:28:17 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.3  thorpej __KERNEL_RCSID(0, "$NetBSD: imx_ahcisata.c,v 1.1.2.3 2021/04/03 22:28:17 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.3  thorpej static const struct device_compatible_entry compat_data[] = {
     83  1.1.2.3  thorpej 	{ .compat = "fsl,imx6q-ahci" },
     84  1.1.2.3  thorpej 	DEVICE_COMPAT_EOL
     85  1.1.2.3  thorpej };
     86  1.1.2.3  thorpej 
     87  1.1.2.2  thorpej static int
     88  1.1.2.2  thorpej imx_ahcisata_match(device_t parent, cfdata_t cf, void *aux)
     89  1.1.2.2  thorpej {
     90  1.1.2.2  thorpej 	struct fdt_attach_args * const faa = aux;
     91  1.1.2.2  thorpej 
     92  1.1.2.3  thorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
     93  1.1.2.2  thorpej }
     94  1.1.2.2  thorpej 
     95  1.1.2.2  thorpej static void
     96  1.1.2.2  thorpej imx_ahcisata_attach(device_t parent, device_t self, void *aux)
     97  1.1.2.2  thorpej {
     98  1.1.2.2  thorpej 	struct imx_ahcisata_softc * const sc = device_private(self);
     99  1.1.2.2  thorpej 	struct fdt_attach_args * const faa = aux;
    100  1.1.2.2  thorpej 	const int phandle = faa->faa_phandle;
    101  1.1.2.2  thorpej 	bus_addr_t ahci_addr;
    102  1.1.2.2  thorpej 	bus_size_t ahci_size;
    103  1.1.2.2  thorpej 	bus_addr_t addr;
    104  1.1.2.2  thorpej 	bus_size_t size;
    105  1.1.2.2  thorpej 	char intrstr[128];
    106  1.1.2.2  thorpej 	int error;
    107  1.1.2.2  thorpej 
    108  1.1.2.2  thorpej 	if (fdtbus_get_reg(phandle, 0, &ahci_addr, &ahci_size) != 0) {
    109  1.1.2.2  thorpej 		aprint_error(": couldn't get ahci registers\n");
    110  1.1.2.2  thorpej 		return;
    111  1.1.2.2  thorpej 	}
    112  1.1.2.2  thorpej 
    113  1.1.2.2  thorpej 	if (of_getprop_uint32(phandle, "fsl,transmit-level-mV", &sc->sc_tx_level) != 0)
    114  1.1.2.2  thorpej 		sc->sc_tx_level = 1104;
    115  1.1.2.2  thorpej 	if (of_getprop_uint32(phandle, "fsl,transmit-boost-mdB", &sc->sc_tx_boost) != 0)
    116  1.1.2.2  thorpej 		sc->sc_tx_boost = 3330;
    117  1.1.2.2  thorpej 	if (of_getprop_uint32(phandle, "fsl,transmit-atten-16ths", &sc->sc_tx_atten) != 0)
    118  1.1.2.2  thorpej 		sc->sc_tx_atten = 9;
    119  1.1.2.2  thorpej 	if (of_getprop_uint32(phandle, "fsl,receive-eq-mdB", &sc->sc_rx_eq) != 0)
    120  1.1.2.2  thorpej 		sc->sc_rx_eq = 3000;
    121  1.1.2.2  thorpej 	if (of_getprop_bool(phandle, "fsl,no-spread-spectrum") == false)
    122  1.1.2.2  thorpej 		sc->sc_ss = 1;
    123  1.1.2.2  thorpej 	else
    124  1.1.2.2  thorpej 		sc->sc_ss = 0;
    125  1.1.2.2  thorpej 
    126  1.1.2.2  thorpej 	sc->sc_clk_sata = fdtbus_clock_get(phandle, "sata");
    127  1.1.2.2  thorpej 	if (sc->sc_clk_sata == NULL) {
    128  1.1.2.2  thorpej 		aprint_error(": couldn't get clock sata\n");
    129  1.1.2.2  thorpej 		return;
    130  1.1.2.2  thorpej 	}
    131  1.1.2.2  thorpej 	sc->sc_clk_sata_ref = fdtbus_clock_get(phandle, "sata_ref");
    132  1.1.2.2  thorpej 	if (sc->sc_clk_sata_ref == NULL) {
    133  1.1.2.2  thorpej 		aprint_error(": couldn't get clock sata_ref\n");
    134  1.1.2.2  thorpej 		return;
    135  1.1.2.2  thorpej 	}
    136  1.1.2.2  thorpej 	sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb");
    137  1.1.2.2  thorpej 	if (sc->sc_clk_ahb == NULL) {
    138  1.1.2.2  thorpej 		aprint_error(": couldn't get clock ahb\n");
    139  1.1.2.2  thorpej 		return;
    140  1.1.2.2  thorpej 	}
    141  1.1.2.2  thorpej 
    142  1.1.2.2  thorpej 	aprint_naive("\n");
    143  1.1.2.2  thorpej 	aprint_normal(": AHCI Controller\n");
    144  1.1.2.2  thorpej 
    145  1.1.2.2  thorpej 	aprint_debug_dev(self, "tx level %d [mV]\n", sc->sc_tx_level);
    146  1.1.2.2  thorpej 	aprint_debug_dev(self, "tx boost %d [mdB]\n", sc->sc_tx_boost);
    147  1.1.2.2  thorpej 	aprint_debug_dev(self, "tx atten %d [16ths]\n", sc->sc_tx_atten);
    148  1.1.2.2  thorpej 	aprint_debug_dev(self, "rx eq    %d [mdB]\n", sc->sc_rx_eq);
    149  1.1.2.2  thorpej 	aprint_debug_dev(self, "ss       %d\n", sc->sc_ss);
    150  1.1.2.2  thorpej 
    151  1.1.2.2  thorpej 	sc->sc_dev = self;
    152  1.1.2.2  thorpej 
    153  1.1.2.2  thorpej 	sc->sc.sc_atac.atac_dev = self;
    154  1.1.2.2  thorpej 	sc->sc.sc_ahci_ports = 1;
    155  1.1.2.2  thorpej 	sc->sc.sc_dmat = faa->faa_dmat;
    156  1.1.2.2  thorpej 	sc->sc.sc_ahcit = faa->faa_bst;
    157  1.1.2.2  thorpej 	sc->sc.sc_ahcis = ahci_size;
    158  1.1.2.2  thorpej 	error = bus_space_map(sc->sc.sc_ahcit, ahci_addr, ahci_size, 0,
    159  1.1.2.2  thorpej 	    &sc->sc.sc_ahcih);
    160  1.1.2.2  thorpej 	if (error) {
    161  1.1.2.2  thorpej 		aprint_error(": couldn't map ahci registers: %d\n", error);
    162  1.1.2.2  thorpej 		return;
    163  1.1.2.2  thorpej 	}
    164  1.1.2.2  thorpej 
    165  1.1.2.2  thorpej 	sc->sc_iot = sc->sc.sc_ahcit;
    166  1.1.2.2  thorpej 	sc->sc_ioh = sc->sc.sc_ahcih;
    167  1.1.2.2  thorpej 
    168  1.1.2.2  thorpej 	const int gpr_phandle = OF_finddevice("/soc/aips-bus/iomuxc-gpr");
    169  1.1.2.2  thorpej 	fdtbus_get_reg(gpr_phandle, 0, &addr, &size);
    170  1.1.2.2  thorpej 	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_gpr_ioh)) {
    171  1.1.2.2  thorpej 		aprint_error_dev(self, "Cannot map registers\n");
    172  1.1.2.2  thorpej 		return;
    173  1.1.2.2  thorpej 	}
    174  1.1.2.2  thorpej 
    175  1.1.2.2  thorpej 	if (imx_ahcisata_init_clocks(sc) != 0) {
    176  1.1.2.2  thorpej 		aprint_error_dev(self, "couldn't init clocks\n");
    177  1.1.2.2  thorpej 		return;
    178  1.1.2.2  thorpej 	}
    179  1.1.2.2  thorpej 
    180  1.1.2.2  thorpej 	if (imx_ahcisata_init(sc) != 0) {
    181  1.1.2.2  thorpej 		aprint_error_dev(self, "couldn't init ahci\n");
    182  1.1.2.2  thorpej 		return;
    183  1.1.2.2  thorpej 	}
    184  1.1.2.2  thorpej 
    185  1.1.2.2  thorpej 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
    186  1.1.2.2  thorpej 		aprint_error_dev(self, "failed to decode interrupt\n");
    187  1.1.2.2  thorpej 		return;
    188  1.1.2.2  thorpej 	}
    189  1.1.2.2  thorpej 
    190  1.1.2.3  thorpej 	sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_BIO, 0,
    191  1.1.2.3  thorpej 	    ahci_intr, &sc->sc, device_xname(self));
    192  1.1.2.2  thorpej 	if (sc->sc_ih == NULL) {
    193  1.1.2.2  thorpej 		aprint_error_dev(self, "failed to establish interrupt on %s\n",
    194  1.1.2.2  thorpej 		    intrstr);
    195  1.1.2.2  thorpej 		return;
    196  1.1.2.2  thorpej 	}
    197  1.1.2.2  thorpej 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
    198  1.1.2.2  thorpej 
    199  1.1.2.2  thorpej 	ahci_attach(&sc->sc);
    200  1.1.2.2  thorpej }
    201  1.1.2.2  thorpej 
    202  1.1.2.2  thorpej static int
    203  1.1.2.2  thorpej imx_ahcisata_phy_ctrl(struct imx_ahcisata_softc *sc, uint32_t bitmask, int on)
    204  1.1.2.2  thorpej {
    205  1.1.2.2  thorpej 	uint32_t v;
    206  1.1.2.2  thorpej 	int timeout;
    207  1.1.2.2  thorpej 
    208  1.1.2.2  thorpej 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR);
    209  1.1.2.2  thorpej 	if (on)
    210  1.1.2.2  thorpej 		v |= bitmask;
    211  1.1.2.2  thorpej 	else
    212  1.1.2.2  thorpej 		v &= ~bitmask;
    213  1.1.2.2  thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, v);
    214  1.1.2.2  thorpej 
    215  1.1.2.2  thorpej 	for (timeout = 5000; timeout > 0; --timeout) {
    216  1.1.2.2  thorpej 		v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
    217  1.1.2.2  thorpej 		if (!!(v & SATA_P0PHYSR_CR_ACK) == !!on)
    218  1.1.2.2  thorpej 			break;
    219  1.1.2.2  thorpej 		delay(100);
    220  1.1.2.2  thorpej 	}
    221  1.1.2.2  thorpej 
    222  1.1.2.2  thorpej 	if (timeout > 0)
    223  1.1.2.2  thorpej 		return 0;
    224  1.1.2.2  thorpej 
    225  1.1.2.2  thorpej 	return -1;
    226  1.1.2.2  thorpej }
    227  1.1.2.2  thorpej 
    228  1.1.2.2  thorpej static int
    229  1.1.2.2  thorpej imx_ahcisata_phy_addr(struct imx_ahcisata_softc *sc, uint32_t addr)
    230  1.1.2.2  thorpej {
    231  1.1.2.2  thorpej 	delay(100);
    232  1.1.2.2  thorpej 
    233  1.1.2.2  thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, addr);
    234  1.1.2.2  thorpej 
    235  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 1) != 0)
    236  1.1.2.2  thorpej 		return -1;
    237  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_ADDR, 0) != 0)
    238  1.1.2.2  thorpej 		return -1;
    239  1.1.2.2  thorpej 
    240  1.1.2.2  thorpej 	return 0;
    241  1.1.2.2  thorpej }
    242  1.1.2.2  thorpej 
    243  1.1.2.2  thorpej static int
    244  1.1.2.2  thorpej imx_ahcisata_phy_write(struct imx_ahcisata_softc *sc, uint32_t addr,
    245  1.1.2.2  thorpej                         uint16_t data)
    246  1.1.2.2  thorpej {
    247  1.1.2.2  thorpej 	if (imx_ahcisata_phy_addr(sc, addr) != 0)
    248  1.1.2.2  thorpej 		return -1;
    249  1.1.2.2  thorpej 
    250  1.1.2.2  thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, data);
    251  1.1.2.2  thorpej 
    252  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 1) != 0)
    253  1.1.2.2  thorpej 		return -1;
    254  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_CAP_DATA, 0) != 0)
    255  1.1.2.2  thorpej 		return -1;
    256  1.1.2.2  thorpej 
    257  1.1.2.2  thorpej 	if ((addr == SATA_PHY_CLOCK_RESET) && data) {
    258  1.1.2.2  thorpej 		/* we can't check ACK after RESET */
    259  1.1.2.2  thorpej 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
    260  1.1.2.2  thorpej 		    data | SATA_P0PHYCR_CR_WRITE);
    261  1.1.2.2  thorpej 		return 0;
    262  1.1.2.2  thorpej 	}
    263  1.1.2.2  thorpej 
    264  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 1) != 0)
    265  1.1.2.2  thorpej 		return -1;
    266  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_WRITE, 0) != 0)
    267  1.1.2.2  thorpej 		return -1;
    268  1.1.2.2  thorpej 
    269  1.1.2.2  thorpej 	return 0;
    270  1.1.2.2  thorpej }
    271  1.1.2.2  thorpej 
    272  1.1.2.2  thorpej static int
    273  1.1.2.2  thorpej imx_ahcisata_phy_read(struct imx_ahcisata_softc *sc, uint32_t addr)
    274  1.1.2.2  thorpej {
    275  1.1.2.2  thorpej 	uint32_t v;
    276  1.1.2.2  thorpej 
    277  1.1.2.2  thorpej 	if (imx_ahcisata_phy_addr(sc, addr) != 0)
    278  1.1.2.2  thorpej 		return -1;
    279  1.1.2.2  thorpej 
    280  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 1) != 0)
    281  1.1.2.2  thorpej 		return -1;
    282  1.1.2.2  thorpej 
    283  1.1.2.2  thorpej 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYSR);
    284  1.1.2.2  thorpej 
    285  1.1.2.2  thorpej 	if (imx_ahcisata_phy_ctrl(sc, SATA_P0PHYCR_CR_READ, 0) != 0)
    286  1.1.2.2  thorpej 		return -1;
    287  1.1.2.2  thorpej 
    288  1.1.2.2  thorpej 	return SATA_P0PHYSR_CR_DATA_OUT(v);
    289  1.1.2.2  thorpej }
    290  1.1.2.2  thorpej 
    291  1.1.2.2  thorpej const static int tx_level[] = {
    292  1.1.2.2  thorpej 	 937,
    293  1.1.2.2  thorpej 	 947,
    294  1.1.2.2  thorpej 	 957,
    295  1.1.2.2  thorpej 	 966,
    296  1.1.2.2  thorpej 	 976,
    297  1.1.2.2  thorpej 	 986,
    298  1.1.2.2  thorpej 	 996,
    299  1.1.2.2  thorpej 	1005,
    300  1.1.2.2  thorpej 	1015,
    301  1.1.2.2  thorpej 	1025,
    302  1.1.2.2  thorpej 	1035,
    303  1.1.2.2  thorpej 	1045,
    304  1.1.2.2  thorpej 	1054,
    305  1.1.2.2  thorpej 	1064,
    306  1.1.2.2  thorpej 	1074,
    307  1.1.2.2  thorpej 	1084,
    308  1.1.2.2  thorpej 	1094,
    309  1.1.2.2  thorpej 	1104,
    310  1.1.2.2  thorpej 	1113,
    311  1.1.2.2  thorpej 	1123,
    312  1.1.2.2  thorpej 	1133,
    313  1.1.2.2  thorpej 	1143,
    314  1.1.2.2  thorpej 	1152,
    315  1.1.2.2  thorpej 	1162,
    316  1.1.2.2  thorpej 	1172,
    317  1.1.2.2  thorpej 	1182,
    318  1.1.2.2  thorpej 	1191,
    319  1.1.2.2  thorpej 	1201,
    320  1.1.2.2  thorpej 	1211,
    321  1.1.2.2  thorpej 	1221,
    322  1.1.2.2  thorpej 	1230,
    323  1.1.2.2  thorpej 	1240,
    324  1.1.2.2  thorpej };
    325  1.1.2.2  thorpej 
    326  1.1.2.2  thorpej const static int tx_boots[] = {
    327  1.1.2.2  thorpej 	   0,
    328  1.1.2.2  thorpej 	 370,
    329  1.1.2.2  thorpej 	 740,
    330  1.1.2.2  thorpej 	1110,
    331  1.1.2.2  thorpej 	1480,
    332  1.1.2.2  thorpej 	1850,
    333  1.1.2.2  thorpej 	2220,
    334  1.1.2.2  thorpej 	2590,
    335  1.1.2.2  thorpej 	2960,
    336  1.1.2.2  thorpej 	3330,
    337  1.1.2.2  thorpej 	3700,
    338  1.1.2.2  thorpej 	4070,
    339  1.1.2.2  thorpej 	4440,
    340  1.1.2.2  thorpej 	4810,
    341  1.1.2.2  thorpej 	5280,
    342  1.1.2.2  thorpej 	5750,
    343  1.1.2.2  thorpej };
    344  1.1.2.2  thorpej 
    345  1.1.2.2  thorpej const static int tx_atten[] = {
    346  1.1.2.2  thorpej 	  16,
    347  1.1.2.2  thorpej 	  14,
    348  1.1.2.2  thorpej 	  12,
    349  1.1.2.2  thorpej 	  10,
    350  1.1.2.2  thorpej 	   9,
    351  1.1.2.2  thorpej 	   8,
    352  1.1.2.2  thorpej };
    353  1.1.2.2  thorpej 
    354  1.1.2.2  thorpej const static int rx_eq[] = {
    355  1.1.2.2  thorpej 	 500,
    356  1.1.2.2  thorpej 	1000,
    357  1.1.2.2  thorpej 	1500,
    358  1.1.2.2  thorpej 	2000,
    359  1.1.2.2  thorpej 	2500,
    360  1.1.2.2  thorpej 	3000,
    361  1.1.2.2  thorpej 	3500,
    362  1.1.2.2  thorpej 	4000,
    363  1.1.2.2  thorpej };
    364  1.1.2.2  thorpej 
    365  1.1.2.2  thorpej static int
    366  1.1.2.2  thorpej imx_ahcisata_search_regval(const int *values, int count, int val)
    367  1.1.2.2  thorpej {
    368  1.1.2.2  thorpej 	for (int i = 0; i < count; i++)
    369  1.1.2.2  thorpej 		if (values[i] == val)
    370  1.1.2.2  thorpej 			return i;
    371  1.1.2.2  thorpej 
    372  1.1.2.2  thorpej 	return -1;
    373  1.1.2.2  thorpej }
    374  1.1.2.2  thorpej 
    375  1.1.2.2  thorpej static int
    376  1.1.2.2  thorpej imx_ahcisata_init(struct imx_ahcisata_softc *sc)
    377  1.1.2.2  thorpej {
    378  1.1.2.2  thorpej 	uint32_t v;
    379  1.1.2.2  thorpej 	int timeout;
    380  1.1.2.2  thorpej 	int pllstat;
    381  1.1.2.2  thorpej 
    382  1.1.2.2  thorpej 	v = bus_space_read_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13);
    383  1.1.2.2  thorpej 	/* clear */
    384  1.1.2.2  thorpej 	v &= ~(IOMUX_GPR13_SATA_PHY_8 |
    385  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_7 |
    386  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_6 |
    387  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_SPEED |
    388  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_5 |
    389  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_4 |
    390  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_3 |
    391  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_2 |
    392  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_1 |
    393  1.1.2.2  thorpej 	    IOMUX_GPR13_SATA_PHY_0);
    394  1.1.2.2  thorpej 	/* setting */
    395  1.1.2.2  thorpej 	struct {
    396  1.1.2.2  thorpej 		const int *array;
    397  1.1.2.2  thorpej 		int count;
    398  1.1.2.2  thorpej 		int val;
    399  1.1.2.2  thorpej 		int def_val;
    400  1.1.2.2  thorpej 		int mask;
    401  1.1.2.2  thorpej 	} gpr13_sata_phy_settings[] = {
    402  1.1.2.2  thorpej 		{ tx_level, __arraycount(tx_level), sc->sc_tx_level,
    403  1.1.2.2  thorpej 		  0x11, IOMUX_GPR13_SATA_PHY_2 },
    404  1.1.2.2  thorpej 		{ tx_boots, __arraycount(tx_boots), sc->sc_tx_boost,
    405  1.1.2.2  thorpej 		  0x09, IOMUX_GPR13_SATA_PHY_3 },
    406  1.1.2.2  thorpej 		{ tx_atten, __arraycount(tx_atten), sc->sc_tx_atten,
    407  1.1.2.2  thorpej 		  0x04, IOMUX_GPR13_SATA_PHY_4 },
    408  1.1.2.2  thorpej 		{ rx_eq, __arraycount(rx_eq), sc->sc_rx_eq,
    409  1.1.2.2  thorpej 		  0x05, IOMUX_GPR13_SATA_PHY_8 }
    410  1.1.2.2  thorpej 	};
    411  1.1.2.2  thorpej 	for (int i = 0; i < __arraycount(gpr13_sata_phy_settings); i++) {
    412  1.1.2.2  thorpej 		int val;
    413  1.1.2.2  thorpej 		val = imx_ahcisata_search_regval(
    414  1.1.2.2  thorpej 			gpr13_sata_phy_settings[i].array,
    415  1.1.2.2  thorpej 			gpr13_sata_phy_settings[i].count,
    416  1.1.2.2  thorpej 			gpr13_sata_phy_settings[i].val);
    417  1.1.2.2  thorpej 		if (val == -1)
    418  1.1.2.2  thorpej 			val = gpr13_sata_phy_settings[i].def_val;
    419  1.1.2.2  thorpej 		v |= __SHIFTIN(val, gpr13_sata_phy_settings[i].mask);
    420  1.1.2.2  thorpej 	}
    421  1.1.2.2  thorpej 	v |= __SHIFTIN(0x12, IOMUX_GPR13_SATA_PHY_7);	/* Rx SATA2m */
    422  1.1.2.2  thorpej 	v |= __SHIFTIN(3, IOMUX_GPR13_SATA_PHY_6);	/* Rx DPLL mode */
    423  1.1.2.2  thorpej 	v |= __SHIFTIN(1, IOMUX_GPR13_SATA_SPEED);	/* 3.0GHz */
    424  1.1.2.2  thorpej 	v |= __SHIFTIN(sc->sc_ss, IOMUX_GPR13_SATA_PHY_5);
    425  1.1.2.2  thorpej 	v |= __SHIFTIN(1, IOMUX_GPR13_SATA_PHY_1);	/* PLL clock enable */
    426  1.1.2.2  thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_gpr_ioh, IOMUX_GPR13, v);
    427  1.1.2.2  thorpej 
    428  1.1.2.2  thorpej 	/* phy reset */
    429  1.1.2.2  thorpej 	if (imx_ahcisata_phy_write(sc, SATA_PHY_CLOCK_RESET,
    430  1.1.2.2  thorpej 	    SATA_PHY_CLOCK_RESET_RST) < 0) {
    431  1.1.2.2  thorpej 		aprint_error_dev(sc->sc_dev, "cannot reset PHY\n");
    432  1.1.2.2  thorpej 		return -1;
    433  1.1.2.2  thorpej 	}
    434  1.1.2.2  thorpej 
    435  1.1.2.2  thorpej 	for (timeout = 50; timeout > 0; --timeout) {
    436  1.1.2.2  thorpej 		delay(100);
    437  1.1.2.2  thorpej 		pllstat = imx_ahcisata_phy_read(sc, SATA_PHY_LANE0_OUT_STAT);
    438  1.1.2.2  thorpej 		if (pllstat < 0) {
    439  1.1.2.2  thorpej 			aprint_error_dev(sc->sc_dev,
    440  1.1.2.2  thorpej 			    "cannot read LANE0 status\n");
    441  1.1.2.2  thorpej 			break;
    442  1.1.2.2  thorpej 		}
    443  1.1.2.2  thorpej 		if (pllstat & SATA_PHY_LANE0_OUT_STAT_RX_PLL_STATE)
    444  1.1.2.2  thorpej 			break;
    445  1.1.2.2  thorpej 	}
    446  1.1.2.2  thorpej 	if (timeout <= 0)
    447  1.1.2.2  thorpej 		return -1;
    448  1.1.2.2  thorpej 
    449  1.1.2.2  thorpej 	/* Support Staggered Spin-up */
    450  1.1.2.2  thorpej 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP);
    451  1.1.2.2  thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP, v | SATA_CAP_SSS);
    452  1.1.2.2  thorpej 
    453  1.1.2.2  thorpej 	/* Ports Implmented. must set 1 */
    454  1.1.2.2  thorpej 	v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_PI);
    455  1.1.2.2  thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, v | SATA_PI_PI);
    456  1.1.2.2  thorpej 
    457  1.1.2.2  thorpej 	/* set 1ms-timer = AHB clock / 1000 */
    458  1.1.2.2  thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS,
    459  1.1.2.2  thorpej 	    clk_get_rate(sc->sc_clk_ahb) / 1000);
    460  1.1.2.2  thorpej 
    461  1.1.2.2  thorpej 	return 0;
    462  1.1.2.2  thorpej }
    463  1.1.2.2  thorpej 
    464  1.1.2.2  thorpej static int
    465  1.1.2.2  thorpej imx_ahcisata_init_clocks(struct imx_ahcisata_softc *sc)
    466  1.1.2.2  thorpej {
    467  1.1.2.2  thorpej 	int error;
    468  1.1.2.2  thorpej 
    469  1.1.2.2  thorpej 	error = clk_enable(sc->sc_clk_sata);
    470  1.1.2.2  thorpej 	if (error) {
    471  1.1.2.2  thorpej 		aprint_error_dev(sc->sc_dev, "couldn't enable sata: %d\n", error);
    472  1.1.2.2  thorpej 		return error;
    473  1.1.2.2  thorpej 	}
    474  1.1.2.2  thorpej 	error = clk_enable(sc->sc_clk_sata_ref);
    475  1.1.2.2  thorpej 	if (error) {
    476  1.1.2.2  thorpej 		aprint_error_dev(sc->sc_dev, "couldn't enable sata-ref: %d\n", error);
    477  1.1.2.2  thorpej 		return error;
    478  1.1.2.2  thorpej 	}
    479  1.1.2.2  thorpej 	error = clk_enable(sc->sc_clk_ahb);
    480  1.1.2.2  thorpej 	if (error) {
    481  1.1.2.2  thorpej 		aprint_error_dev(sc->sc_dev, "couldn't enable anb: %d\n", error);
    482  1.1.2.2  thorpej 		return error;
    483  1.1.2.2  thorpej 	}
    484  1.1.2.2  thorpej 
    485  1.1.2.2  thorpej 	return 0;
    486  1.1.2.2  thorpej }
    487