1*9fdf0c62Smpi /* $OpenBSD: sxiahci.c,v 1.17 2021/10/24 17:52:28 mpi Exp $ */
219606781Sjasper /*
319606781Sjasper * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
493c0f120Sjsg * Copyright (c) 2013,2014 Artturi Alm
519606781Sjasper *
619606781Sjasper * Permission to use, copy, modify, and distribute this software for any
719606781Sjasper * purpose with or without fee is hereby granted, provided that the above
819606781Sjasper * copyright notice and this permission notice appear in all copies.
919606781Sjasper *
1019606781Sjasper * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1119606781Sjasper * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1219606781Sjasper * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1319606781Sjasper * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1419606781Sjasper * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1519606781Sjasper * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1619606781Sjasper * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1719606781Sjasper */
1819606781Sjasper
1919606781Sjasper #include <sys/param.h>
2019606781Sjasper #include <sys/systm.h>
2119606781Sjasper #include <sys/device.h>
2219606781Sjasper
2319606781Sjasper #include <machine/bus.h>
24411a93efSkettenis #include <machine/fdt.h>
2519606781Sjasper
2619606781Sjasper #include <dev/ic/ahcireg.h>
2706133b5aSdlg #include <dev/ic/ahcivar.h>
2819606781Sjasper
290ea1c705Spatrick #include <dev/fdt/sunxireg.h>
3019606781Sjasper
31411a93efSkettenis #include <dev/ofw/openfirm.h>
32e904db79Skettenis #include <dev/ofw/ofw_clock.h>
335cae81a0Skettenis #include <dev/ofw/ofw_regulator.h>
34411a93efSkettenis #include <dev/ofw/fdt.h>
35411a93efSkettenis
364e64f0a4Sjasper #define SXIAHCI_CAP 0x0000
374e64f0a4Sjasper #define SXIAHCI_GHC 0x0004
384e64f0a4Sjasper #define SXIAHCI_PI 0x000c
394e64f0a4Sjasper #define SXIAHCI_PHYCS0 0x00c0
404e64f0a4Sjasper #define SXIAHCI_PHYCS1 0x00c4
414e64f0a4Sjasper #define SXIAHCI_PHYCS2 0x00c8
424e64f0a4Sjasper #define SXIAHCI_TIMER1MS 0x00e0
434e64f0a4Sjasper #define SXIAHCI_RWC 0x00fc
444e64f0a4Sjasper #define SXIAHCI_TIMEOUT 0x100000
454e64f0a4Sjasper #define SXIAHCI_PWRPIN 40
4619606781Sjasper
4793c0f120Sjsg #define SXIAHCI_PREG_DMA 0x70
4893c0f120Sjsg #define SXIAHCI_PREG_DMA_MASK (0xff<<8)
4993c0f120Sjsg #define SXIAHCI_PREG_DMA_INIT (0x44<<8)
5093c0f120Sjsg
51411a93efSkettenis int sxiahci_match(struct device *, void *, void *);
5219606781Sjasper void sxiahci_attach(struct device *, struct device *, void *);
5319606781Sjasper int sxiahci_detach(struct device *, int);
5419606781Sjasper int sxiahci_activate(struct device *, int);
5593c0f120Sjsg int sxiahci_port_start(struct ahci_port *, int);
5619606781Sjasper
5719606781Sjasper extern int ahci_intr(void *);
5819606781Sjasper extern u_int32_t ahci_read(struct ahci_softc *, bus_size_t);
5919606781Sjasper extern void ahci_write(struct ahci_softc *, bus_size_t, u_int32_t);
6093c0f120Sjsg extern u_int32_t ahci_pread(struct ahci_port *, bus_size_t);
6193c0f120Sjsg extern void ahci_pwrite(struct ahci_port *, bus_size_t, u_int32_t);
6293c0f120Sjsg extern int ahci_default_port_start(struct ahci_port *, int);
6319606781Sjasper
6419606781Sjasper struct sxiahci_softc {
6519606781Sjasper struct ahci_softc sc;
6619606781Sjasper
6719606781Sjasper };
6819606781Sjasper
69*9fdf0c62Smpi const struct cfattach sxiahci_ca = {
7019606781Sjasper sizeof(struct sxiahci_softc),
71411a93efSkettenis sxiahci_match,
7219606781Sjasper sxiahci_attach,
7319606781Sjasper sxiahci_detach,
7419606781Sjasper sxiahci_activate
7519606781Sjasper };
7619606781Sjasper
7719606781Sjasper struct cfdriver sxiahci_cd = {
78411a93efSkettenis NULL, "sxiahci", DV_DULL
7919606781Sjasper };
8019606781Sjasper
81411a93efSkettenis int
sxiahci_match(struct device * parent,void * match,void * aux)82411a93efSkettenis sxiahci_match(struct device *parent, void *match, void *aux)
8319606781Sjasper {
84411a93efSkettenis struct fdt_attach_args *faa = aux;
85411a93efSkettenis
8685b8fad3Sjsg return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ahci") ||
8785b8fad3Sjsg OF_is_compatible(faa->fa_node, "allwinner,sun8i-r40-ahci");
88411a93efSkettenis }
89411a93efSkettenis
90411a93efSkettenis void
sxiahci_attach(struct device * parent,struct device * self,void * aux)91411a93efSkettenis sxiahci_attach(struct device *parent, struct device *self, void *aux)
92411a93efSkettenis {
9319606781Sjasper struct sxiahci_softc *sxisc = (struct sxiahci_softc *)self;
9419606781Sjasper struct ahci_softc *sc = &sxisc->sc;
95411a93efSkettenis struct fdt_attach_args *faa = aux;
965cae81a0Skettenis uint32_t target_supply;
9719606781Sjasper uint32_t timo;
9819606781Sjasper
99411a93efSkettenis if (faa->fa_nreg < 1)
100411a93efSkettenis return;
10119606781Sjasper
102411a93efSkettenis sc->sc_iot = faa->fa_iot;
103411a93efSkettenis sc->sc_ios = faa->fa_reg[0].size;
104411a93efSkettenis sc->sc_dmat = faa->fa_dmat;
105411a93efSkettenis
106411a93efSkettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
107411a93efSkettenis faa->fa_reg[0].size, 0, &sc->sc_ioh))
10819606781Sjasper panic("sxiahci_attach: bus_space_map failed!");
10919606781Sjasper
110e904db79Skettenis /* enable clocks */
111e904db79Skettenis clock_enable_all(faa->fa_node);
11219606781Sjasper delay(5000);
11319606781Sjasper
114f22f0821Skettenis reset_deassert_all(faa->fa_node);
115f22f0821Skettenis
11619606781Sjasper /* XXX setup magix */
1174e64f0a4Sjasper SXIWRITE4(sc, SXIAHCI_RWC, 0);
11819606781Sjasper delay(10);
11919606781Sjasper
1204e64f0a4Sjasper SXISET4(sc, SXIAHCI_PHYCS1, 1 << 19);
12119606781Sjasper delay(10);
12219606781Sjasper
12393c0f120Sjsg SXICMS4(sc, SXIAHCI_PHYCS0, 7 << 24,
12493c0f120Sjsg 1 << 23 | 5 << 24 | 1 << 18);
12519606781Sjasper delay(10);
12619606781Sjasper
1274e64f0a4Sjasper SXICMS4(sc, SXIAHCI_PHYCS1,
12893c0f120Sjsg 3 << 16 | 0x1f << 8 | 3 << 6,
12993c0f120Sjsg 2 << 16 | 0x06 << 8 | 2 << 6);
13019606781Sjasper delay(10);
13119606781Sjasper
1324e64f0a4Sjasper SXISET4(sc, SXIAHCI_PHYCS1, 1 << 28 | 1 << 15);
13319606781Sjasper delay(10);
13419606781Sjasper
1354e64f0a4Sjasper SXICLR4(sc, SXIAHCI_PHYCS1, 1 << 19);
13619606781Sjasper delay(10);
13719606781Sjasper
13893c0f120Sjsg SXICMS4(sc, SXIAHCI_PHYCS0, 0x07 << 20, 0x03 << 20);
13993c0f120Sjsg SXICMS4(sc, SXIAHCI_PHYCS2, 0x1f << 5, 0x19 << 5);
14019606781Sjasper delay(5000);
14119606781Sjasper
1424e64f0a4Sjasper SXISET4(sc, SXIAHCI_PHYCS0, 1 << 19);
14319606781Sjasper delay(20);
14419606781Sjasper
1454e64f0a4Sjasper timo = SXIAHCI_TIMEOUT;
14693c0f120Sjsg while ((SXIREAD4(sc, SXIAHCI_PHYCS0) >> 28 & 7) != 2 && --timo)
14719606781Sjasper delay(10);
148c2f7ab5fSjasper if (!timo) {
149c2f7ab5fSjasper printf(": AHCI phy power up failed.\n");
150c2f7ab5fSjasper goto dismod;
151c2f7ab5fSjasper }
15219606781Sjasper
1534e64f0a4Sjasper SXISET4(sc, SXIAHCI_PHYCS2, 1 << 24);
15419606781Sjasper
1554e64f0a4Sjasper timo = SXIAHCI_TIMEOUT;
1564e64f0a4Sjasper while ((SXIREAD4(sc, SXIAHCI_PHYCS2) & (1 << 24)) && --timo)
15719606781Sjasper delay(10);
158c2f7ab5fSjasper if (!timo) {
159c2f7ab5fSjasper printf(": AHCI phy calibration failed.\n");
160c2f7ab5fSjasper goto dismod;
161c2f7ab5fSjasper }
16219606781Sjasper
16319606781Sjasper delay(15000);
1644e64f0a4Sjasper SXIWRITE4(sc, SXIAHCI_RWC, 7);
16519606781Sjasper
16619606781Sjasper /* power up phy */
1675cae81a0Skettenis target_supply = OF_getpropint(faa->fa_node, "target-supply", 0);
1685cae81a0Skettenis if (target_supply)
1695cae81a0Skettenis regulator_enable(target_supply);
17019606781Sjasper
171411a93efSkettenis sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
17219606781Sjasper ahci_intr, sc, sc->sc_dev.dv_xname);
17319606781Sjasper if (sc->sc_ih == NULL) {
17419606781Sjasper printf(": unable to establish interrupt\n");
175c2f7ab5fSjasper goto clrpwr;
17619606781Sjasper }
17719606781Sjasper
178411a93efSkettenis printf(":");
179411a93efSkettenis
1804e64f0a4Sjasper SXIWRITE4(sc, SXIAHCI_PI, 1);
1814e64f0a4Sjasper SXICLR4(sc, SXIAHCI_CAP, AHCI_REG_CAP_SPM);
18293c0f120Sjsg sc->sc_flags |= AHCI_F_NO_PMP;
18393c0f120Sjsg sc->sc_port_start = sxiahci_port_start;
18419606781Sjasper if (ahci_attach(sc) != 0) {
18519606781Sjasper /* error printed by ahci_attach */
18619606781Sjasper goto irq;
18719606781Sjasper }
18819606781Sjasper
18919606781Sjasper return;
19019606781Sjasper irq:
19119606781Sjasper arm_intr_disestablish(sc->sc_ih);
192c2f7ab5fSjasper clrpwr:
1935cae81a0Skettenis if (target_supply)
1945cae81a0Skettenis regulator_disable(target_supply);
195c2f7ab5fSjasper dismod:
196e904db79Skettenis clock_disable_all(faa->fa_node);
19719606781Sjasper bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
19819606781Sjasper }
19919606781Sjasper
20019606781Sjasper int
sxiahci_detach(struct device * self,int flags)20119606781Sjasper sxiahci_detach(struct device *self, int flags)
20219606781Sjasper {
20319606781Sjasper struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
20419606781Sjasper struct ahci_softc *sc = &sxisc->sc;
20519606781Sjasper
20619606781Sjasper ahci_detach(sc, flags);
20719606781Sjasper bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
20819606781Sjasper return 0;
20919606781Sjasper }
21019606781Sjasper
21119606781Sjasper int
sxiahci_activate(struct device * self,int act)21219606781Sjasper sxiahci_activate(struct device *self, int act)
21319606781Sjasper {
21419606781Sjasper struct sxiahci_softc *sxisc = (struct sxiahci_softc *) self;
21519606781Sjasper struct ahci_softc *sc = &sxisc->sc;
21619606781Sjasper
21719606781Sjasper return ahci_activate((struct device *)sc, act);
21819606781Sjasper }
21993c0f120Sjsg
22093c0f120Sjsg int
sxiahci_port_start(struct ahci_port * ap,int fre_only)22193c0f120Sjsg sxiahci_port_start(struct ahci_port *ap, int fre_only)
22293c0f120Sjsg {
223e904db79Skettenis uint32_t r;
22493c0f120Sjsg
22593c0f120Sjsg /* Setup DMA */
22693c0f120Sjsg r = ahci_pread(ap, SXIAHCI_PREG_DMA);
22793c0f120Sjsg r &= ~SXIAHCI_PREG_DMA_MASK;
22893c0f120Sjsg r |= SXIAHCI_PREG_DMA_INIT; /* XXX if fre_only? */
22993c0f120Sjsg ahci_pwrite(ap, SXIAHCI_PREG_DMA, r);
23093c0f120Sjsg
23193c0f120Sjsg return (ahci_default_port_start(ap, fre_only));
23293c0f120Sjsg }
233