Home | History | Annotate | Line # | Download | only in nxp
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