1 /* $OpenBSD: mvpxa.c,v 1.4 2022/01/18 11:36:21 patrick Exp $ */
2 /*
3 * Copyright (c) 2017 Mark Kettenis
4 * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/systm.h>
21
22 #include <machine/bus.h>
23 #include <machine/fdt.h>
24 #include <machine/intr.h>
25
26 #include <armv7/marvell/mvmbusvar.h>
27
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/ofw_clock.h>
30 #include <dev/ofw/ofw_pinctrl.h>
31 #include <dev/ofw/fdt.h>
32
33 #include <dev/sdmmc/sdhcreg.h>
34 #include <dev/sdmmc/sdhcvar.h>
35
36 #define MVPXA_READ(sc, reg) \
37 bus_space_read_4((sc)->sc_iot, (sc)->mbus_ioh, (reg))
38 #define MVPXA_WRITE(sc, reg, val) \
39 bus_space_write_4((sc)->sc_iot, (sc)->mbus_ioh, (reg), (val))
40
41 #define MVPXA_NWINDOW 8
42 #define MVPXA_CTRL(x) (0x80 + ((x) << 3))
43 #define MVPXA_BASE(x) (0x84 + ((x) << 3))
44
45 #define MVPXA_TARGET(target) (((target) & 0xf) << 4)
46 #define MVPXA_ATTR(attr) (((attr) & 0xff) << 8)
47 #define MVPXA_SIZE(size) (((size) - 1) & 0xffff0000)
48 #define MVPXA_WINEN (1 << 0)
49
50 struct mvpxa_softc {
51 struct sdhc_softc sc;
52 bus_space_tag_t sc_iot;
53 bus_space_handle_t sc_ioh;
54 bus_space_handle_t mbus_ioh;
55 bus_space_handle_t conf_ioh;
56 bus_size_t sc_size;
57 void *sc_ih;
58
59 struct sdhc_host *sc_host;
60 };
61
62 int mvpxa_match(struct device *, void *, void *);
63 void mvpxa_attach(struct device *, struct device *, void *);
64
65 struct cfdriver mvpxa_cd = {
66 NULL, "mvpxa", DV_DULL
67 };
68
69 const struct cfattach mvpxa_ca = {
70 sizeof(struct mvpxa_softc), mvpxa_match, mvpxa_attach
71 };
72
73 void mvpxa_wininit(struct mvpxa_softc *);
74
75 void
mvpxa_wininit(struct mvpxa_softc * sc)76 mvpxa_wininit(struct mvpxa_softc *sc)
77 {
78 int i;
79
80 if (mvmbus_dram_info == NULL)
81 panic("%s: mbus dram information not set up", __func__);
82
83 for (i = 0; i < MVPXA_NWINDOW; i++) {
84 MVPXA_WRITE(sc, MVPXA_CTRL(i), 0);
85 MVPXA_WRITE(sc, MVPXA_BASE(i), 0);
86 }
87
88 for (i = 0; i < mvmbus_dram_info->numcs; i++) {
89 struct mbus_dram_window *win = &mvmbus_dram_info->cs[i];
90
91 MVPXA_WRITE(sc, MVPXA_CTRL(i),
92 MVPXA_WINEN |
93 MVPXA_TARGET(mvmbus_dram_info->targetid) |
94 MVPXA_ATTR(win->attr) |
95 MVPXA_SIZE(win->size));
96 MVPXA_WRITE(sc, MVPXA_BASE(i), win->base);
97 }
98 }
99
100
101 int
mvpxa_match(struct device * parent,void * match,void * aux)102 mvpxa_match(struct device *parent, void *match, void *aux)
103 {
104 struct fdt_attach_args *faa = aux;
105
106 return OF_is_compatible(faa->fa_node, "marvell,armada-380-sdhci");
107 }
108
109 void
mvpxa_attach(struct device * parent,struct device * self,void * aux)110 mvpxa_attach(struct device *parent, struct device *self, void *aux)
111 {
112 struct mvpxa_softc *sc = (struct mvpxa_softc *)self;
113 struct fdt_attach_args *faa = aux;
114 uint64_t capmask = 0, capset = 0;
115
116 if (faa->fa_nreg < 3) {
117 printf(": not enough registers\n");
118 return;
119 }
120
121 sc->sc_iot = faa->fa_iot;
122 sc->sc_size = faa->fa_reg[0].size;
123
124 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
125 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
126 printf(": can't map registers\n");
127 return;
128 }
129
130 if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
131 faa->fa_reg[1].size, 0, &sc->mbus_ioh)) {
132 printf(": can't map registers\n");
133 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
134 return;
135 }
136
137 if (bus_space_map(sc->sc_iot, faa->fa_reg[2].addr,
138 faa->fa_reg[2].size, 0, &sc->conf_ioh)) {
139 printf(": can't map registers\n");
140 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
141 bus_space_unmap(sc->sc_iot, sc->mbus_ioh, faa->fa_reg[1].size);
142 return;
143 }
144
145 pinctrl_byname(faa->fa_node, "default");
146
147 clock_enable_all(faa->fa_node);
148 reset_deassert_all(faa->fa_node);
149
150 /* Set up MBUS windows. */
151 mvpxa_wininit(sc);
152
153 sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
154 sdhc_intr, sc, sc->sc.sc_dev.dv_xname);
155 if (sc->sc_ih == NULL) {
156 printf(": can't establish interrupt\n");
157 goto unmap;
158 }
159
160 printf("\n");
161
162 sc->sc.sc_host = &sc->sc_host;
163 sc->sc.sc_dmat = faa->fa_dmat;
164
165 if (OF_getproplen(faa->fa_node, "no-1-8-v") >= 0)
166 capmask |= SDHC_VOLTAGE_SUPP_1_8V;
167
168 sdhc_host_found(&sc->sc, sc->sc_iot, sc->sc_ioh, sc->sc_size, 1,
169 capmask, capset);
170 return;
171
172 unmap:
173 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
174 bus_space_unmap(sc->sc_iot, sc->mbus_ioh, faa->fa_reg[1].size);
175 bus_space_unmap(sc->sc_iot, sc->conf_ioh, faa->fa_reg[2].size);
176 }
177