1/* $OpenBSD: imxahci.c,v 1.13 2021/10/24 17:52:27 mpi Exp $ */ 2/* 3 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/param.h> 19#include <sys/systm.h> 20#include <sys/device.h> 21 22#include <machine/bus.h> 23#include <machine/fdt.h> 24 25#include <dev/ic/ahcireg.h> 26#include <dev/ic/ahcivar.h> 27 28#include <dev/ofw/openfirm.h> 29#include <dev/ofw/ofw_clock.h> 30#include <dev/ofw/ofw_misc.h> 31#include <dev/ofw/fdt.h> 32 33/* registers */ 34#define SATA_CAP 0x000 35#define SATA_GHC 0x004 36#define SATA_IS 0x008 37#define SATA_PI 0x00C 38#define SATA_VS 0x010 39#define SATA_CCC_CTL 0x014 40#define SATA_CCC_PORTS 0x018 41#define SATA_CAP2 0x024 42#define SATA_BISTAFR 0x0A0 43#define SATA_BISTCR 0x0A4 44#define SATA_BISTFCTR 0x0A8 45#define SATA_BSTSR 0x0AC 46#define SATA_OOBR 0x0BC 47#define SATA_GPCR 0x0D0 48#define SATA_GPSR 0x0D4 49#define SATA_TIMER1MS 0x0E0 50#define SATA_TESTR 0x0F4 51#define SATA_VERSIONR 0x0F8 52#define SATA_P0CLB 0x100 53#define SATA_P0FB 0x108 54#define SATA_P0IS 0x110 55#define SATA_P0IE 0x114 56#define SATA_P0CMD 0x118 57#define SATA_P0TFD 0x120 58#define SATA_P0SIG 0x124 59#define SATA_P0SSTS 0x128 60#define SATA_P0SCTL 0x12C 61#define SATA_P0SERR 0x130 62#define SATA_P0SACT 0x134 63#define SATA_P0CI 0x138 64#define SATA_P0SNTF 0x13C 65#define SATA_P0DMACR 0x170 66#define SATA_P0PHYCR 0x178 67#define SATA_P0PHYSR 0x17C 68 69#define SATA_CAP_SSS (1 << 27) 70#define SATA_GHC_HR (1 << 0) 71#define SATA_P0PHYCR_TEST_PDDQ (1 << 20) 72 73/* iomuxc */ 74#define IOMUXC_GPR13 0x034 75#define IOMUXC_GPR13_SATA_PHY_1_TX_EDGE_RATE (1 << 0) 76#define IOMUXC_GPR13_SATA_PHY_1_MPLL_CLK_EN (1 << 1) 77#define IOMUXC_GPR13_SATA_PHY_2_1104V (0x11 << 2) 78#define IOMUXC_GPR13_SATA_PHY_3_333DB (0x00 << 7) 79#define IOMUXC_GPR13_SATA_PHY_4_9_16 (0x04 << 11) 80#define IOMUXC_GPR13_SATA_PHY_5_SS (0x01 << 14) 81#define IOMUXC_GPR13_SATA_SPEED_3G (0x01 << 15) 82#define IOMUXC_GPR13_SATA_PHY_6 (0x03 << 16) 83#define IOMUXC_GPR13_SATA_PHY_7_SATA2M (0x12 << 19) 84#define IOMUXC_GPR13_SATA_PHY_8_30DB (0x05 << 24) 85#define IOMUXC_GPR13_SATA_MASK 0x07FFFFFF 86 87int imxahci_match(struct device *, void *, void *); 88void imxahci_attach(struct device *, struct device *, void *); 89int imxahci_detach(struct device *, int); 90int imxahci_activate(struct device *, int); 91 92extern int ahci_intr(void *); 93 94struct imxahci_softc { 95 struct ahci_softc sc; 96}; 97 98const struct cfattach imxahci_ca = { 99 sizeof(struct imxahci_softc), 100 imxahci_match, 101 imxahci_attach, 102 imxahci_detach, 103 imxahci_activate 104}; 105 106struct cfdriver imxahci_cd = { 107 NULL, "imxahci", DV_DULL 108}; 109 110int 111imxahci_match(struct device *parent, void *match, void *aux) 112{ 113 struct fdt_attach_args *faa = aux; 114 115 return OF_is_compatible(faa->fa_node, "fsl,imx6q-ahci"); 116} 117 118void 119imxahci_attach(struct device *parent, struct device *self, void *aux) 120{ 121 struct imxahci_softc *imxsc = (struct imxahci_softc *) self; 122 struct ahci_softc *sc = &imxsc->sc; 123 struct fdt_attach_args *faa = aux; 124 uint32_t timeout = 0x100000; 125 struct regmap *rm; 126 uint32_t reg; 127 128 if (faa->fa_nreg < 1) 129 return; 130 131 sc->sc_iot = faa->fa_iot; 132 sc->sc_ios = faa->fa_reg[0].size; 133 sc->sc_dmat = faa->fa_dmat; 134 135 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 136 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 137 panic("imxahci_attach: bus_space_map failed!"); 138 139 sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO, 140 ahci_intr, sc, sc->sc_dev.dv_xname); 141 if (sc->sc_ih == NULL) { 142 printf(": unable to establish interrupt\n"); 143 goto unmap; 144 } 145 146 /* power it up */ 147 clock_enable(faa->fa_node, "sata_ref"); 148 clock_enable(faa->fa_node, "sata"); 149 delay(100); 150 151 /* power phy up */ 152 rm = regmap_bycompatible("fsl,imx6q-iomuxc-gpr"); 153 if (rm != NULL) { 154 reg = regmap_read_4(rm, IOMUXC_GPR13); 155 reg &= ~IOMUXC_GPR13_SATA_MASK; 156 reg |= IOMUXC_GPR13_SATA_PHY_2_1104V | 157 IOMUXC_GPR13_SATA_PHY_3_333DB | 158 IOMUXC_GPR13_SATA_PHY_4_9_16 | 159 IOMUXC_GPR13_SATA_SPEED_3G | 160 IOMUXC_GPR13_SATA_PHY_6 | 161 IOMUXC_GPR13_SATA_PHY_7_SATA2M | 162 IOMUXC_GPR13_SATA_PHY_8_30DB; 163 regmap_write_4(rm, IOMUXC_GPR13, reg); 164 reg = regmap_read_4(rm, IOMUXC_GPR13); 165 reg |= IOMUXC_GPR13_SATA_PHY_1_MPLL_CLK_EN; 166 regmap_write_4(rm, IOMUXC_GPR13, reg); 167 } 168 169 /* setup */ 170 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR, 171 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR) & ~SATA_P0PHYCR_TEST_PDDQ); 172 173 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_GHC, SATA_GHC_HR); 174 175 while (!bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_VERSIONR)); 176 177 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP, 178 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP) | SATA_CAP_SSS); 179 180 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, 1); 181 182 bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS, 183 clock_get_frequency(faa->fa_node, "ahb")); 184 185 while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0SSTS) & 0xF) && timeout--); 186 187 printf(":"); 188 189 if (ahci_attach(sc) != 0) { 190 /* error printed by ahci_attach */ 191 goto irq; 192 } 193 194 return; 195irq: 196 arm_intr_disestablish(sc->sc_ih); 197unmap: 198 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 199} 200 201int 202imxahci_detach(struct device *self, int flags) 203{ 204 struct imxahci_softc *imxsc = (struct imxahci_softc *) self; 205 struct ahci_softc *sc = &imxsc->sc; 206 207 ahci_detach(sc, flags); 208 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 209 return 0; 210} 211 212int 213imxahci_activate(struct device *self, int act) 214{ 215 struct imxahci_softc *imxsc = (struct imxahci_softc *) self; 216 struct ahci_softc *sc = &imxsc->sc; 217 218 return ahci_activate((struct device *)sc, act); 219} 220