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