Line data Source code
1 : /* $OpenBSD: sdhc_pci.c,v 1.20 2016/04/30 11:32:23 kettenis Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
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/device.h>
21 : #include <sys/systm.h>
22 : #include <sys/malloc.h>
23 :
24 : #include <dev/pci/pcivar.h>
25 : #include <dev/pci/pcidevs.h>
26 : #include <dev/sdmmc/sdhcreg.h>
27 : #include <dev/sdmmc/sdhcvar.h>
28 : #include <dev/sdmmc/sdmmcvar.h>
29 :
30 : /*
31 : * 8-bit PCI configuration register that tells us how many slots there
32 : * are and which BAR entry corresponds to the first slot.
33 : */
34 : #define SDHC_PCI_CONF_SLOT_INFO 0x40
35 : #define SDHC_PCI_NUM_SLOTS(info) ((((info) >> 4) & 0x7) + 1)
36 : #define SDHC_PCI_FIRST_BAR(info) ((info) & 0x7)
37 :
38 : /* TI specific register */
39 : #define SDHC_PCI_GENERAL_CTL 0x4c
40 : #define MMC_SD_DIS 0x02
41 :
42 : /* RICOH specific registers */
43 : #define SDHC_PCI_MODE_KEY 0xf9
44 : #define SDHC_PCI_MODE 0x150
45 : #define SDHC_PCI_MODE_SD20 0x10
46 : #define SDHC_PCI_BASE_FREQ_KEY 0xfc
47 : #define SDHC_PCI_BASE_FREQ 0xe1
48 :
49 : struct sdhc_pci_softc {
50 : struct sdhc_softc sc;
51 : pci_chipset_tag_t sc_pc;
52 : pcitag_t sc_tag;
53 : pcireg_t sc_id;
54 : void *sc_ih;
55 : };
56 :
57 : int sdhc_pci_match(struct device *, void *, void *);
58 : void sdhc_pci_attach(struct device *, struct device *, void *);
59 : int sdhc_pci_activate(struct device *, int);
60 :
61 : void sdhc_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, uint8_t);
62 : void sdhc_takecontroller(struct pci_attach_args *);
63 : void sdhc_ricohfix(struct sdhc_pci_softc *);
64 :
65 : struct cfattach sdhc_pci_ca = {
66 : sizeof(struct sdhc_pci_softc), sdhc_pci_match, sdhc_pci_attach,
67 : NULL, sdhc_pci_activate
68 : };
69 :
70 : int
71 0 : sdhc_pci_match(struct device *parent, void *match, void *aux)
72 : {
73 0 : struct pci_attach_args *pa = aux;
74 :
75 : /*
76 : * The Realtek RTS5209 is supported by rtsx(4). Usually the device
77 : * class for these is UNDEFINED but there are RTS5209 devices which
78 : * are advertising an SYSTEM/SDHC device class in addition to a
79 : * separate device advertising the UNDEFINED class. Such devices are
80 : * not compatible with sdhc(4), so ignore them.
81 : */
82 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_REALTEK &&
83 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_REALTEK_RTS5209)
84 0 : return 0;
85 :
86 0 : if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM &&
87 0 : PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC)
88 0 : return 1;
89 :
90 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RICOH &&
91 0 : (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U822 ||
92 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U823))
93 0 : return 1;
94 :
95 0 : return 0;
96 0 : }
97 :
98 : void
99 0 : sdhc_pci_attach(struct device *parent, struct device *self, void *aux)
100 : {
101 0 : struct sdhc_pci_softc *sc = (struct sdhc_pci_softc *)self;
102 0 : struct pci_attach_args *pa = aux;
103 0 : pci_intr_handle_t ih;
104 : char const *intrstr;
105 : int slotinfo;
106 : int nslots;
107 : int usedma;
108 : int reg;
109 0 : pcireg_t type;
110 0 : bus_space_tag_t iot;
111 0 : bus_space_handle_t ioh;
112 0 : bus_size_t size;
113 : u_int32_t caps = 0;
114 :
115 0 : sc->sc_pc = pa->pa_pc;
116 0 : sc->sc_tag = pa->pa_tag;
117 0 : sc->sc_id = pa->pa_id;
118 :
119 : /* Some TI controllers needs special treatment. */
120 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI &&
121 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TI_PCI7XX1_SD &&
122 0 : pa->pa_function == 4)
123 0 : sdhc_takecontroller(pa);
124 :
125 : /* ENE controllers break if set to 0V bus power. */
126 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ENE &&
127 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENE_SDCARD)
128 0 : sc->sc.sc_flags |= SDHC_F_NOPWR0;
129 :
130 : /* Some RICOH controllers need to be bumped into the right mode. */
131 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RICOH &&
132 0 : (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U822 ||
133 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RICOH_R5U823))
134 0 : sdhc_ricohfix(sc);
135 :
136 0 : if (pci_intr_map(pa, &ih)) {
137 0 : printf(": can't map interrupt\n");
138 0 : return;
139 : }
140 :
141 0 : intrstr = pci_intr_string(pa->pa_pc, ih);
142 0 : sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SDMMC,
143 0 : sdhc_intr, sc, sc->sc.sc_dev.dv_xname);
144 0 : if (sc->sc_ih == NULL) {
145 0 : printf(": can't establish interrupt\n");
146 0 : return;
147 : }
148 0 : printf(": %s\n", intrstr);
149 :
150 : /* Enable use of DMA if supported by the interface. */
151 0 : usedma = PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA;
152 0 : sc->sc.sc_dmat = pa->pa_dmat;
153 :
154 : /*
155 : * Map and attach all hosts supported by the host controller.
156 : */
157 0 : slotinfo = pci_conf_read(pa->pa_pc, pa->pa_tag,
158 : SDHC_PCI_CONF_SLOT_INFO);
159 0 : nslots = SDHC_PCI_NUM_SLOTS(slotinfo);
160 :
161 : /* Allocate an array big enough to hold all the possible hosts */
162 0 : sc->sc.sc_host = mallocarray(nslots, sizeof(struct sdhc_host *),
163 : M_DEVBUF, M_WAITOK);
164 :
165 0 : for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) * 4;
166 0 : reg < SDHC_PCI_BAR_END && nslots > 0;
167 0 : reg += 4, nslots--) {
168 0 : if (!pci_mapreg_probe(pa->pa_pc, pa->pa_tag, reg, &type))
169 : break;
170 :
171 0 : if (type == PCI_MAPREG_TYPE_IO || pci_mapreg_map(pa, reg,
172 : type, 0, &iot, &ioh, NULL, &size, 0)) {
173 0 : printf("%s at 0x%x: can't map registers\n",
174 : sc->sc.sc_dev.dv_xname, reg);
175 0 : break;
176 : }
177 :
178 0 : if (sdhc_host_found(&sc->sc, iot, ioh, size, usedma, caps) != 0)
179 0 : printf("%s at 0x%x: can't initialize host\n",
180 : sc->sc.sc_dev.dv_xname, reg);
181 :
182 0 : if (type & PCI_MAPREG_MEM_TYPE_64BIT)
183 0 : reg += 4;
184 : }
185 0 : }
186 :
187 : int
188 0 : sdhc_pci_activate(struct device *self, int act)
189 : {
190 0 : struct sdhc_pci_softc *sc = (struct sdhc_pci_softc *)self;
191 : int rv;
192 :
193 0 : switch (act) {
194 : case DVACT_SUSPEND:
195 0 : rv = sdhc_activate(self, act);
196 0 : break;
197 : case DVACT_RESUME:
198 : /* Some RICOH controllers need to be bumped into the right mode. */
199 0 : if (PCI_VENDOR(sc->sc_id) == PCI_VENDOR_RICOH &&
200 0 : (PCI_PRODUCT(sc->sc_id) == PCI_PRODUCT_RICOH_R5U822 ||
201 0 : PCI_PRODUCT(sc->sc_id) == PCI_PRODUCT_RICOH_R5U823))
202 0 : sdhc_ricohfix(sc);
203 0 : rv = sdhc_activate(self, act);
204 0 : break;
205 : default:
206 0 : rv = sdhc_activate(self, act);
207 0 : break;
208 : }
209 0 : return (rv);
210 : }
211 :
212 : void
213 0 : sdhc_takecontroller(struct pci_attach_args *pa)
214 : {
215 : pcitag_t tag;
216 : pcireg_t id, reg;
217 :
218 : /* Look at func 3 for the flash device */
219 0 : tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 3);
220 0 : id = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG);
221 0 : if (PCI_PRODUCT(id) != PCI_PRODUCT_TI_PCI7XX1_FLASH)
222 0 : return;
223 :
224 : /*
225 : * Disable MMC/SD on the flash media controller so the
226 : * SD host takes over.
227 : */
228 0 : reg = pci_conf_read(pa->pa_pc, tag, SDHC_PCI_GENERAL_CTL);
229 0 : reg |= MMC_SD_DIS;
230 0 : pci_conf_write(pa->pa_pc, tag, SDHC_PCI_GENERAL_CTL, reg);
231 0 : }
232 :
233 : void
234 0 : sdhc_ricohfix(struct sdhc_pci_softc *sc)
235 : {
236 : /* Enable SD2.0 mode. */
237 0 : sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_MODE_KEY, 0xfc);
238 0 : sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20);
239 0 : sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_MODE_KEY, 0x00);
240 :
241 : /*
242 : * Some SD/MMC cards don't work with the default base
243 : * clock frequency of 200MHz. Lower it to 50Hz.
244 : */
245 0 : sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_BASE_FREQ_KEY, 0x01);
246 0 : sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_BASE_FREQ, 50);
247 0 : sdhc_pci_conf_write(sc->sc_pc, sc->sc_tag, SDHC_PCI_BASE_FREQ_KEY, 0x00);
248 0 : }
249 :
250 : void
251 0 : sdhc_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, uint8_t val)
252 : {
253 : pcireg_t tmp;
254 :
255 0 : tmp = pci_conf_read(pc, tag, reg & ~0x3);
256 0 : tmp &= ~(0xff << ((reg & 0x3) * 8));
257 0 : tmp |= (val << ((reg & 0x3) * 8));
258 0 : pci_conf_write(pc, tag, reg & ~0x3, tmp);
259 0 : }
|