1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org> |
---|
5 | * All rights reserved. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms, with or without |
---|
8 | * modification, are permitted provided that the following conditions |
---|
9 | * are met: |
---|
10 | * 1. Redistributions of source code must retain the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer. |
---|
12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer in the |
---|
14 | * documentation and/or other materials provided with the distribution. |
---|
15 | * |
---|
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
26 | */ |
---|
27 | |
---|
28 | #include <sys/cdefs.h> |
---|
29 | __FBSDID("$FreeBSD$"); |
---|
30 | |
---|
31 | #include <rtems/bsd/sys/param.h> |
---|
32 | #include <sys/systm.h> |
---|
33 | #include <sys/bus.h> |
---|
34 | #include <sys/conf.h> |
---|
35 | #include <sys/kernel.h> |
---|
36 | #include <rtems/bsd/sys/lock.h> |
---|
37 | #include <sys/module.h> |
---|
38 | #include <sys/mutex.h> |
---|
39 | #include <sys/resource.h> |
---|
40 | #include <sys/rman.h> |
---|
41 | #include <sys/sysctl.h> |
---|
42 | #include <sys/taskqueue.h> |
---|
43 | |
---|
44 | #include <dev/pci/pcireg.h> |
---|
45 | #include <dev/pci/pcivar.h> |
---|
46 | |
---|
47 | #include <machine/bus.h> |
---|
48 | #include <machine/resource.h> |
---|
49 | #include <machine/stdarg.h> |
---|
50 | |
---|
51 | #include <dev/mmc/bridge.h> |
---|
52 | #include <dev/mmc/mmcreg.h> |
---|
53 | #include <dev/mmc/mmcbrvar.h> |
---|
54 | |
---|
55 | #include <rtems/bsd/local/mmcbr_if.h> |
---|
56 | #ifndef __rtems__ |
---|
57 | #include <rtems/bsd/local/sdhci.h> |
---|
58 | #else /* __rtems__ */ |
---|
59 | #include <dev/sdhci/sdhci.h> |
---|
60 | #endif /* __rtems__ */ |
---|
61 | #ifdef __rtems__ |
---|
62 | #include <bsp.h> |
---|
63 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
64 | #include <bsp/qoriq.h> |
---|
65 | #include <bsp/utility.h> |
---|
66 | #include <bsp/irq.h> |
---|
67 | #define RTEMS_BSD_SDHCI_QUIRK_NO_BUSY_IRQ |
---|
68 | #define RTEMS_BSD_SDHCI_QUIRK_32_BIT_REGS |
---|
69 | #endif |
---|
70 | #endif /* __rtems__ */ |
---|
71 | |
---|
72 | #ifndef __rtems__ |
---|
73 | #define DMA_BLOCK_SIZE 4096 |
---|
74 | #else /* __rtems__ */ |
---|
75 | #define DMA_BLOCK_SIZE 512 |
---|
76 | #endif /* __rtems__ */ |
---|
77 | #define DMA_BOUNDARY 0 /* DMA reload every 4K */ |
---|
78 | |
---|
79 | /* Controller doesn't honor resets unless we touch the clock register */ |
---|
80 | #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) |
---|
81 | /* Controller really supports DMA */ |
---|
82 | #define SDHCI_QUIRK_FORCE_DMA (1<<1) |
---|
83 | /* Controller has unusable DMA engine */ |
---|
84 | #define SDHCI_QUIRK_BROKEN_DMA (1<<2) |
---|
85 | /* Controller doesn't like to be reset when there is no card inserted. */ |
---|
86 | #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<3) |
---|
87 | /* Controller has flaky internal state so reset it on each ios change */ |
---|
88 | #define SDHCI_QUIRK_RESET_ON_IOS (1<<4) |
---|
89 | /* Controller can only DMA chunk sizes that are a multiple of 32 bits */ |
---|
90 | #define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<5) |
---|
91 | /* Controller needs to be reset after each request to stay stable */ |
---|
92 | #define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<6) |
---|
93 | /* Controller has an off-by-one issue with timeout value */ |
---|
94 | #define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<7) |
---|
95 | /* Controller has broken read timings */ |
---|
96 | #define SDHCI_QUIRK_BROKEN_TIMINGS (1<<8) |
---|
97 | |
---|
98 | #ifndef __rtems__ |
---|
99 | static const struct sdhci_device { |
---|
100 | uint32_t model; |
---|
101 | uint16_t subvendor; |
---|
102 | char *desc; |
---|
103 | u_int quirks; |
---|
104 | } sdhci_devices[] = { |
---|
105 | { 0x08221180, 0xffff, "RICOH R5C822 SD", |
---|
106 | SDHCI_QUIRK_FORCE_DMA }, |
---|
107 | { 0x8034104c, 0xffff, "TI XX21/XX11 SD", |
---|
108 | SDHCI_QUIRK_FORCE_DMA }, |
---|
109 | { 0x05501524, 0xffff, "ENE CB712 SD", |
---|
110 | SDHCI_QUIRK_BROKEN_TIMINGS }, |
---|
111 | { 0x05511524, 0xffff, "ENE CB712 SD 2", |
---|
112 | SDHCI_QUIRK_BROKEN_TIMINGS }, |
---|
113 | { 0x07501524, 0xffff, "ENE CB714 SD", |
---|
114 | SDHCI_QUIRK_RESET_ON_IOS | |
---|
115 | SDHCI_QUIRK_BROKEN_TIMINGS }, |
---|
116 | { 0x07511524, 0xffff, "ENE CB714 SD 2", |
---|
117 | SDHCI_QUIRK_RESET_ON_IOS | |
---|
118 | SDHCI_QUIRK_BROKEN_TIMINGS }, |
---|
119 | { 0x410111ab, 0xffff, "Marvell CaFe SD", |
---|
120 | SDHCI_QUIRK_INCR_TIMEOUT_CONTROL }, |
---|
121 | { 0x2381197B, 0xffff, "JMicron JMB38X SD", |
---|
122 | SDHCI_QUIRK_32BIT_DMA_SIZE | |
---|
123 | SDHCI_QUIRK_RESET_AFTER_REQUEST }, |
---|
124 | { 0, 0xffff, NULL, |
---|
125 | 0 } |
---|
126 | }; |
---|
127 | #endif /* __rtems__ */ |
---|
128 | |
---|
129 | struct sdhci_softc; |
---|
130 | |
---|
131 | struct sdhci_slot { |
---|
132 | struct sdhci_softc *sc; |
---|
133 | device_t dev; /* Slot device */ |
---|
134 | u_char num; /* Slot number */ |
---|
135 | u_char opt; /* Slot options */ |
---|
136 | #define SDHCI_HAVE_DMA 1 |
---|
137 | uint32_t max_clk; /* Max possible freq */ |
---|
138 | uint32_t timeout_clk; /* Timeout freq */ |
---|
139 | #ifndef __rtems__ |
---|
140 | struct resource *mem_res; /* Memory resource */ |
---|
141 | int mem_rid; |
---|
142 | #else /* __rtems__ */ |
---|
143 | struct resource mem_res [1]; /* Memory resource */ |
---|
144 | #endif /* __rtems__ */ |
---|
145 | #ifndef __rtems__ |
---|
146 | bus_dma_tag_t dmatag; |
---|
147 | bus_dmamap_t dmamap; |
---|
148 | u_char *dmamem; |
---|
149 | bus_addr_t paddr; /* DMA buffer address */ |
---|
150 | struct task card_task; /* Card presence check task */ |
---|
151 | #endif /* __rtems__ */ |
---|
152 | struct callout card_callout; /* Card insert delay callout */ |
---|
153 | struct mmc_host host; /* Host parameters */ |
---|
154 | struct mmc_request *req; /* Current request */ |
---|
155 | struct mmc_command *curcmd; /* Current command of current request */ |
---|
156 | |
---|
157 | uint32_t intmask; /* Current interrupt mask */ |
---|
158 | uint32_t clock; /* Current clock freq. */ |
---|
159 | size_t offset; /* Data buffer offset */ |
---|
160 | uint8_t hostctrl; /* Current host control register */ |
---|
161 | u_char power; /* Current power */ |
---|
162 | u_char bus_busy; /* Bus busy status */ |
---|
163 | u_char cmd_done; /* CMD command part done flag */ |
---|
164 | u_char data_done; /* DAT command part done flag */ |
---|
165 | u_char flags; /* Request execution flags */ |
---|
166 | #define CMD_STARTED 1 |
---|
167 | #define STOP_STARTED 2 |
---|
168 | #define SDHCI_USE_DMA 4 /* Use DMA for this req. */ |
---|
169 | struct mtx mtx; /* Slot mutex */ |
---|
170 | }; |
---|
171 | |
---|
172 | struct sdhci_softc { |
---|
173 | device_t dev; /* Controller device */ |
---|
174 | u_int quirks; /* Chip specific quirks */ |
---|
175 | #ifndef __rtems__ |
---|
176 | struct resource *irq_res; /* IRQ resource */ |
---|
177 | int irq_rid; |
---|
178 | void *intrhand; /* Interrupt handle */ |
---|
179 | #endif /* __rtems__ */ |
---|
180 | |
---|
181 | int num_slots; /* Number of slots on this controller */ |
---|
182 | struct sdhci_slot slots[6]; |
---|
183 | }; |
---|
184 | |
---|
185 | SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver"); |
---|
186 | |
---|
187 | int sdhci_debug; |
---|
188 | TUNABLE_INT("hw.sdhci.debug", &sdhci_debug); |
---|
189 | SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RW, &sdhci_debug, 0, "Debug level"); |
---|
190 | |
---|
191 | static inline uint8_t |
---|
192 | RD1(struct sdhci_slot *slot, bus_size_t off) |
---|
193 | { |
---|
194 | bus_barrier(slot->mem_res, 0, 0xFF, |
---|
195 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
---|
196 | #ifndef __rtems__ |
---|
197 | return bus_read_1(slot->mem_res, off); |
---|
198 | #else /* __rtems__ */ |
---|
199 | /* FIXME */ |
---|
200 | bus_size_t aligned_off = off & ~0x3; |
---|
201 | bus_size_t shift = (off & 0x3) * 8; |
---|
202 | uint32_t val = bus_read_4(slot->mem_res, aligned_off); |
---|
203 | return val >> shift; |
---|
204 | #endif /* __rtems__ */ |
---|
205 | } |
---|
206 | |
---|
207 | static inline void |
---|
208 | WR1(struct sdhci_slot *slot, bus_size_t off, uint8_t val) |
---|
209 | { |
---|
210 | bus_barrier(slot->mem_res, 0, 0xFF, |
---|
211 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
---|
212 | #ifndef __rtems__ |
---|
213 | bus_write_1(slot->mem_res, off, val); |
---|
214 | #else /* __rtems__ */ |
---|
215 | /* FIXME */ |
---|
216 | if (off != SDHCI_POWER_CONTROL) { |
---|
217 | bus_size_t aligned_off = off & ~0x3; |
---|
218 | bus_size_t shift = (off & 0x3) * 8; |
---|
219 | uint32_t reg = bus_read_4(slot->mem_res, aligned_off); |
---|
220 | reg &= ~(0xff << shift); |
---|
221 | reg |= val << shift; |
---|
222 | bus_write_4(slot->mem_res, aligned_off, reg); |
---|
223 | } |
---|
224 | #endif /* __rtems__ */ |
---|
225 | } |
---|
226 | |
---|
227 | static inline uint16_t |
---|
228 | RD2(struct sdhci_slot *slot, bus_size_t off) |
---|
229 | { |
---|
230 | bus_barrier(slot->mem_res, 0, 0xFF, |
---|
231 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
---|
232 | #ifndef __rtems__ |
---|
233 | return bus_read_2(slot->mem_res, off); |
---|
234 | #else /* __rtems__ */ |
---|
235 | /* FIXME */ |
---|
236 | bus_size_t aligned_off = off & ~0x3; |
---|
237 | bus_size_t shift = (off & 0x2) * 8; |
---|
238 | uint32_t val = bus_read_4(slot->mem_res, aligned_off); |
---|
239 | return val >> shift; |
---|
240 | #endif /* __rtems__ */ |
---|
241 | } |
---|
242 | |
---|
243 | static inline void |
---|
244 | WR2(struct sdhci_slot *slot, bus_size_t off, uint16_t val) |
---|
245 | { |
---|
246 | bus_barrier(slot->mem_res, 0, 0xFF, |
---|
247 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
---|
248 | #ifndef __rtems__ |
---|
249 | bus_write_2(slot->mem_res, off, val); |
---|
250 | #else /* __rtems__ */ |
---|
251 | /* FIXME */ |
---|
252 | bus_size_t aligned_off = off & ~0x3; |
---|
253 | bus_size_t shift = (off & 0x2) * 8; |
---|
254 | uint32_t reg = bus_read_4(slot->mem_res, aligned_off); |
---|
255 | reg &= ~(0xffff << shift); |
---|
256 | reg |= val << shift; |
---|
257 | bus_write_4(slot->mem_res, aligned_off, reg); |
---|
258 | #endif /* __rtems__ */ |
---|
259 | } |
---|
260 | |
---|
261 | static inline uint32_t |
---|
262 | RD4(struct sdhci_slot *slot, bus_size_t off) |
---|
263 | { |
---|
264 | bus_barrier(slot->mem_res, 0, 0xFF, |
---|
265 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
---|
266 | #if defined(__rtems__) && defined(LIBBSP_POWERPC_QORIQ_BSP_H) |
---|
267 | uint32_t val = bus_read_4(slot->mem_res, off); |
---|
268 | if (off == SDHCI_BUFFER) { |
---|
269 | /* The DATPORT register use little-endian order */ |
---|
270 | val = CPU_swap_u32(val); |
---|
271 | } |
---|
272 | return val; |
---|
273 | #else /* __rtems__ */ |
---|
274 | return bus_read_4(slot->mem_res, off); |
---|
275 | #endif /* __rtems__ */ |
---|
276 | } |
---|
277 | |
---|
278 | static inline void |
---|
279 | WR4(struct sdhci_slot *slot, bus_size_t off, uint32_t val) |
---|
280 | { |
---|
281 | bus_barrier(slot->mem_res, 0, 0xFF, |
---|
282 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
---|
283 | #if defined(__rtems__) && defined(LIBBSP_POWERPC_QORIQ_BSP_H) |
---|
284 | if (off == SDHCI_BUFFER) { |
---|
285 | /* The DATPORT register use little-endian order */ |
---|
286 | val = CPU_swap_u32(val); |
---|
287 | } |
---|
288 | #endif /* __rtems__ */ |
---|
289 | bus_write_4(slot->mem_res, off, val); |
---|
290 | } |
---|
291 | |
---|
292 | /* bus entry points */ |
---|
293 | static int sdhci_probe(device_t dev); |
---|
294 | static int sdhci_attach(device_t dev); |
---|
295 | static int sdhci_detach(device_t dev); |
---|
296 | static void sdhci_intr(void *); |
---|
297 | |
---|
298 | static void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock); |
---|
299 | static void sdhci_start(struct sdhci_slot *slot); |
---|
300 | static void sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data); |
---|
301 | |
---|
302 | static void sdhci_card_task(void *, int); |
---|
303 | |
---|
304 | /* helper routines */ |
---|
305 | #define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx) |
---|
306 | #define SDHCI_UNLOCK(_slot) mtx_unlock(&(_slot)->mtx) |
---|
307 | #define SDHCI_LOCK_INIT(_slot) \ |
---|
308 | mtx_init(&_slot->mtx, "SD slot mtx", "sdhci", MTX_DEF) |
---|
309 | #define SDHCI_LOCK_DESTROY(_slot) mtx_destroy(&_slot->mtx); |
---|
310 | #define SDHCI_ASSERT_LOCKED(_slot) mtx_assert(&_slot->mtx, MA_OWNED); |
---|
311 | #define SDHCI_ASSERT_UNLOCKED(_slot) mtx_assert(&_slot->mtx, MA_NOTOWNED); |
---|
312 | |
---|
313 | static int |
---|
314 | slot_printf(struct sdhci_slot *slot, const char * fmt, ...) |
---|
315 | { |
---|
316 | va_list ap; |
---|
317 | int retval; |
---|
318 | |
---|
319 | retval = printf("%s-slot%d: ", |
---|
320 | device_get_nameunit(slot->sc->dev), slot->num); |
---|
321 | |
---|
322 | va_start(ap, fmt); |
---|
323 | retval += vprintf(fmt, ap); |
---|
324 | va_end(ap); |
---|
325 | return (retval); |
---|
326 | } |
---|
327 | |
---|
328 | #ifndef __rtems__ |
---|
329 | static void |
---|
330 | sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) |
---|
331 | { |
---|
332 | if (error != 0) { |
---|
333 | printf("getaddr: error %d\n", error); |
---|
334 | return; |
---|
335 | } |
---|
336 | *(bus_addr_t *)arg = segs[0].ds_addr; |
---|
337 | } |
---|
338 | #endif /* __rtems__ */ |
---|
339 | |
---|
340 | static void |
---|
341 | sdhci_dumpregs(struct sdhci_slot *slot) |
---|
342 | { |
---|
343 | slot_printf(slot, |
---|
344 | "============== REGISTER DUMP ==============\n"); |
---|
345 | |
---|
346 | slot_printf(slot, "Sys addr: 0x%08x | Version: 0x%08x\n", |
---|
347 | RD4(slot, SDHCI_DMA_ADDRESS), RD2(slot, SDHCI_HOST_VERSION)); |
---|
348 | slot_printf(slot, "Blk size: 0x%08x | Blk cnt: 0x%08x\n", |
---|
349 | RD2(slot, SDHCI_BLOCK_SIZE), RD2(slot, SDHCI_BLOCK_COUNT)); |
---|
350 | slot_printf(slot, "Argument: 0x%08x | Trn mode: 0x%08x\n", |
---|
351 | RD4(slot, SDHCI_ARGUMENT), RD2(slot, SDHCI_TRANSFER_MODE)); |
---|
352 | slot_printf(slot, "Present: 0x%08x | Host ctl: 0x%08x\n", |
---|
353 | RD4(slot, SDHCI_PRESENT_STATE), RD1(slot, SDHCI_HOST_CONTROL)); |
---|
354 | slot_printf(slot, "Power: 0x%08x | Blk gap: 0x%08x\n", |
---|
355 | RD1(slot, SDHCI_POWER_CONTROL), RD1(slot, SDHCI_BLOCK_GAP_CONTROL)); |
---|
356 | slot_printf(slot, "Wake-up: 0x%08x | Clock: 0x%08x\n", |
---|
357 | RD1(slot, SDHCI_WAKE_UP_CONTROL), RD2(slot, SDHCI_CLOCK_CONTROL)); |
---|
358 | slot_printf(slot, "Timeout: 0x%08x | Int stat: 0x%08x\n", |
---|
359 | RD1(slot, SDHCI_TIMEOUT_CONTROL), RD4(slot, SDHCI_INT_STATUS)); |
---|
360 | slot_printf(slot, "Int enab: 0x%08x | Sig enab: 0x%08x\n", |
---|
361 | RD4(slot, SDHCI_INT_ENABLE), RD4(slot, SDHCI_SIGNAL_ENABLE)); |
---|
362 | slot_printf(slot, "AC12 err: 0x%08x | Slot int: 0x%08x\n", |
---|
363 | RD2(slot, SDHCI_ACMD12_ERR), RD2(slot, SDHCI_SLOT_INT_STATUS)); |
---|
364 | slot_printf(slot, "Caps: 0x%08x | Max curr: 0x%08x\n", |
---|
365 | RD4(slot, SDHCI_CAPABILITIES), RD4(slot, SDHCI_MAX_CURRENT)); |
---|
366 | |
---|
367 | slot_printf(slot, |
---|
368 | "===========================================\n"); |
---|
369 | } |
---|
370 | |
---|
371 | static void |
---|
372 | sdhci_reset(struct sdhci_slot *slot, uint8_t mask) |
---|
373 | { |
---|
374 | int timeout; |
---|
375 | uint8_t res; |
---|
376 | |
---|
377 | if (slot->sc->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { |
---|
378 | if (!(RD4(slot, SDHCI_PRESENT_STATE) & |
---|
379 | SDHCI_CARD_PRESENT)) |
---|
380 | return; |
---|
381 | } |
---|
382 | |
---|
383 | /* Some controllers need this kick or reset won't work. */ |
---|
384 | if ((mask & SDHCI_RESET_ALL) == 0 && |
---|
385 | (slot->sc->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) { |
---|
386 | uint32_t clock; |
---|
387 | |
---|
388 | /* This is to force an update */ |
---|
389 | clock = slot->clock; |
---|
390 | slot->clock = 0; |
---|
391 | sdhci_set_clock(slot, clock); |
---|
392 | } |
---|
393 | |
---|
394 | WR1(slot, SDHCI_SOFTWARE_RESET, mask); |
---|
395 | |
---|
396 | if (mask & SDHCI_RESET_ALL) { |
---|
397 | slot->clock = 0; |
---|
398 | slot->power = 0; |
---|
399 | } |
---|
400 | |
---|
401 | /* Wait max 100 ms */ |
---|
402 | timeout = 100; |
---|
403 | /* Controller clears the bits when it's done */ |
---|
404 | while ((res = RD1(slot, SDHCI_SOFTWARE_RESET)) & mask) { |
---|
405 | if (timeout == 0) { |
---|
406 | slot_printf(slot, |
---|
407 | "Reset 0x%x never completed - 0x%x.\n", |
---|
408 | (int)mask, (int)res); |
---|
409 | sdhci_dumpregs(slot); |
---|
410 | return; |
---|
411 | } |
---|
412 | timeout--; |
---|
413 | DELAY(1000); |
---|
414 | } |
---|
415 | |
---|
416 | #ifdef __rtems__ |
---|
417 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
418 | WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); |
---|
419 | #endif |
---|
420 | #endif /* __rtems__ */ |
---|
421 | } |
---|
422 | |
---|
423 | static void |
---|
424 | sdhci_init(struct sdhci_slot *slot) |
---|
425 | { |
---|
426 | |
---|
427 | sdhci_reset(slot, SDHCI_RESET_ALL); |
---|
428 | |
---|
429 | /* Enable interrupts. */ |
---|
430 | slot->intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | |
---|
431 | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | |
---|
432 | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | |
---|
433 | #ifndef __rtems__ |
---|
434 | SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT | |
---|
435 | #endif /* __rtems__ */ |
---|
436 | SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | |
---|
437 | SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | |
---|
438 | SDHCI_INT_ACMD12ERR; |
---|
439 | WR4(slot, SDHCI_INT_ENABLE, slot->intmask); |
---|
440 | WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); |
---|
441 | } |
---|
442 | |
---|
443 | static void |
---|
444 | sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock) |
---|
445 | { |
---|
446 | #ifndef __rtems__ |
---|
447 | uint32_t res; |
---|
448 | uint16_t clk; |
---|
449 | int timeout; |
---|
450 | #endif /* __rtems__ */ |
---|
451 | |
---|
452 | if (clock == slot->clock) |
---|
453 | return; |
---|
454 | slot->clock = clock; |
---|
455 | |
---|
456 | #ifndef __rtems__ |
---|
457 | /* Turn off the clock. */ |
---|
458 | WR2(slot, SDHCI_CLOCK_CONTROL, 0); |
---|
459 | /* If no clock requested - left it so. */ |
---|
460 | if (clock == 0) |
---|
461 | return; |
---|
462 | /* Looking for highest freq <= clock. */ |
---|
463 | res = slot->max_clk; |
---|
464 | for (clk = 1; clk < 256; clk <<= 1) { |
---|
465 | if (res <= clock) |
---|
466 | break; |
---|
467 | res >>= 1; |
---|
468 | } |
---|
469 | /* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */ |
---|
470 | clk >>= 1; |
---|
471 | /* Now we have got divider, set it. */ |
---|
472 | clk <<= SDHCI_DIVIDER_SHIFT; |
---|
473 | WR2(slot, SDHCI_CLOCK_CONTROL, clk); |
---|
474 | /* Enable clock. */ |
---|
475 | clk |= SDHCI_CLOCK_INT_EN; |
---|
476 | WR2(slot, SDHCI_CLOCK_CONTROL, clk); |
---|
477 | /* Wait up to 10 ms until it stabilize. */ |
---|
478 | timeout = 10; |
---|
479 | while (!((clk = RD2(slot, SDHCI_CLOCK_CONTROL)) |
---|
480 | & SDHCI_CLOCK_INT_STABLE)) { |
---|
481 | if (timeout == 0) { |
---|
482 | slot_printf(slot, |
---|
483 | "Internal clock never stabilised.\n"); |
---|
484 | sdhci_dumpregs(slot); |
---|
485 | return; |
---|
486 | } |
---|
487 | timeout--; |
---|
488 | DELAY(1000); |
---|
489 | } |
---|
490 | /* Pass clock signal to the bus. */ |
---|
491 | clk |= SDHCI_CLOCK_CARD_EN; |
---|
492 | WR2(slot, SDHCI_CLOCK_CONTROL, clk); |
---|
493 | #else /* __rtems__ */ |
---|
494 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
495 | |
---|
496 | #define SYSCTL_CLOCK_DISABLE_MASK BSP_BMSK32(28, 31) |
---|
497 | #define SYSCTL_CLOCK_MASK BSP_BMSK32(16, 31) |
---|
498 | #define SYSCTL_SDCLKFS(val) BSP_BFLD32(val, 16, 23) |
---|
499 | #define SYSCTL_DVS(val) BSP_BFLD32(val, 24, 27) |
---|
500 | #define SYSCTL_SDCLKEN BSP_BBIT32(28) |
---|
501 | #define SYSCTL_PEREN BSP_BBIT32(29) |
---|
502 | #define SYSCTL_HCKEN BSP_BBIT32(30) |
---|
503 | #define SYSCTL_IPGEN BSP_BBIT32(31) |
---|
504 | |
---|
505 | uint32_t sysctl = RD4(slot, SDHCI_CLOCK_CONTROL); |
---|
506 | sysctl &= ~SYSCTL_CLOCK_DISABLE_MASK; |
---|
507 | WR4(slot, SDHCI_CLOCK_CONTROL, sysctl); |
---|
508 | |
---|
509 | if (clock != 0) { |
---|
510 | uint32_t sdclkfs_2 = 2; |
---|
511 | uint32_t dvs_p1 = 1; |
---|
512 | uint32_t base_clock = slot->max_clk; |
---|
513 | |
---|
514 | while (base_clock / sdclkfs_2 / 16 > clock && sdclkfs_2 < 256) { |
---|
515 | sdclkfs_2 *= 2; |
---|
516 | } |
---|
517 | |
---|
518 | while (base_clock / sdclkfs_2 / dvs_p1 > clock && dvs_p1 < 16) { |
---|
519 | dvs_p1++; |
---|
520 | } |
---|
521 | |
---|
522 | slot_printf( |
---|
523 | slot, |
---|
524 | "desired SD clock: %u, actual: %u\n", |
---|
525 | clock, |
---|
526 | base_clock / sdclkfs_2 / dvs_p1 |
---|
527 | ); |
---|
528 | |
---|
529 | sysctl &= ~SYSCTL_CLOCK_MASK; |
---|
530 | sysctl |= SYSCTL_SDCLKFS(sdclkfs_2 / 2) | SYSCTL_DVS(dvs_p1 - 1) | SYSCTL_SDCLKEN | SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN; |
---|
531 | WR4(slot, SDHCI_CLOCK_CONTROL, sysctl); |
---|
532 | |
---|
533 | DELAY(10000); |
---|
534 | } |
---|
535 | #else |
---|
536 | panic("FIXME"); |
---|
537 | #endif |
---|
538 | #endif /* __rtems__ */ |
---|
539 | } |
---|
540 | |
---|
541 | static void |
---|
542 | sdhci_set_power(struct sdhci_slot *slot, u_char power) |
---|
543 | { |
---|
544 | uint8_t pwr; |
---|
545 | |
---|
546 | if (slot->power == power) |
---|
547 | return; |
---|
548 | slot->power = power; |
---|
549 | |
---|
550 | /* Turn off the power. */ |
---|
551 | pwr = 0; |
---|
552 | WR1(slot, SDHCI_POWER_CONTROL, pwr); |
---|
553 | /* If power down requested - left it so. */ |
---|
554 | if (power == 0) |
---|
555 | return; |
---|
556 | /* Set voltage. */ |
---|
557 | switch (1 << power) { |
---|
558 | case MMC_OCR_LOW_VOLTAGE: |
---|
559 | pwr |= SDHCI_POWER_180; |
---|
560 | break; |
---|
561 | case MMC_OCR_290_300: |
---|
562 | case MMC_OCR_300_310: |
---|
563 | pwr |= SDHCI_POWER_300; |
---|
564 | break; |
---|
565 | case MMC_OCR_320_330: |
---|
566 | case MMC_OCR_330_340: |
---|
567 | pwr |= SDHCI_POWER_330; |
---|
568 | break; |
---|
569 | } |
---|
570 | WR1(slot, SDHCI_POWER_CONTROL, pwr); |
---|
571 | /* Turn on the power. */ |
---|
572 | pwr |= SDHCI_POWER_ON; |
---|
573 | WR1(slot, SDHCI_POWER_CONTROL, pwr); |
---|
574 | } |
---|
575 | |
---|
576 | static void |
---|
577 | sdhci_read_block_pio(struct sdhci_slot *slot) |
---|
578 | { |
---|
579 | uint32_t data; |
---|
580 | char *buffer; |
---|
581 | size_t left; |
---|
582 | |
---|
583 | buffer = slot->curcmd->data->data; |
---|
584 | buffer += slot->offset; |
---|
585 | /* Transfer one block at a time. */ |
---|
586 | left = min(512, slot->curcmd->data->len - slot->offset); |
---|
587 | slot->offset += left; |
---|
588 | |
---|
589 | /* If we are too fast, broken controllers return zeroes. */ |
---|
590 | if (slot->sc->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) |
---|
591 | DELAY(10); |
---|
592 | /* Handle unalligned and alligned buffer cases. */ |
---|
593 | if ((intptr_t)buffer & 3) { |
---|
594 | while (left > 3) { |
---|
595 | data = RD4(slot, SDHCI_BUFFER); |
---|
596 | buffer[0] = data; |
---|
597 | buffer[1] = (data >> 8); |
---|
598 | buffer[2] = (data >> 16); |
---|
599 | buffer[3] = (data >> 24); |
---|
600 | buffer += 4; |
---|
601 | left -= 4; |
---|
602 | } |
---|
603 | } else { |
---|
604 | #if defined(__rtems__) && defined(LIBBSP_POWERPC_QORIQ_BSP_H) |
---|
605 | /* The DATPORT register use little-endian order */ |
---|
606 | uint32_t *in = (uint32_t *) buffer; |
---|
607 | while (left > 3) { |
---|
608 | *in = RD4(slot, SDHCI_BUFFER); |
---|
609 | ++in; |
---|
610 | left -= 4; |
---|
611 | } |
---|
612 | #else /* __rtems__ */ |
---|
613 | bus_read_multi_stream_4(slot->mem_res, SDHCI_BUFFER, |
---|
614 | (uint32_t *)buffer, left >> 2); |
---|
615 | left &= 3; |
---|
616 | #endif /* __rtems__ */ |
---|
617 | } |
---|
618 | /* Handle uneven size case. */ |
---|
619 | if (left > 0) { |
---|
620 | data = RD4(slot, SDHCI_BUFFER); |
---|
621 | while (left > 0) { |
---|
622 | *(buffer++) = data; |
---|
623 | data >>= 8; |
---|
624 | left--; |
---|
625 | } |
---|
626 | } |
---|
627 | } |
---|
628 | |
---|
629 | static void |
---|
630 | sdhci_write_block_pio(struct sdhci_slot *slot) |
---|
631 | { |
---|
632 | uint32_t data = 0; |
---|
633 | char *buffer; |
---|
634 | size_t left; |
---|
635 | |
---|
636 | buffer = slot->curcmd->data->data; |
---|
637 | buffer += slot->offset; |
---|
638 | /* Transfer one block at a time. */ |
---|
639 | left = min(512, slot->curcmd->data->len - slot->offset); |
---|
640 | slot->offset += left; |
---|
641 | |
---|
642 | /* Handle unalligned and alligned buffer cases. */ |
---|
643 | if ((intptr_t)buffer & 3) { |
---|
644 | while (left > 3) { |
---|
645 | data = buffer[0] + |
---|
646 | (buffer[1] << 8) + |
---|
647 | (buffer[2] << 16) + |
---|
648 | (buffer[3] << 24); |
---|
649 | left -= 4; |
---|
650 | buffer += 4; |
---|
651 | WR4(slot, SDHCI_BUFFER, data); |
---|
652 | } |
---|
653 | } else { |
---|
654 | #if defined(__rtems__) && defined(LIBBSP_POWERPC_QORIQ_BSP_H) |
---|
655 | /* The DATPORT register use little-endian order */ |
---|
656 | uint32_t *out = (uint32_t *) buffer; |
---|
657 | while (left > 3) { |
---|
658 | WR4(slot, SDHCI_BUFFER, *out); |
---|
659 | ++out; |
---|
660 | left -= 4; |
---|
661 | } |
---|
662 | #else /* __rtems__ */ |
---|
663 | bus_write_multi_stream_4(slot->mem_res, SDHCI_BUFFER, |
---|
664 | (uint32_t *)buffer, left >> 2); |
---|
665 | left &= 3; |
---|
666 | #endif /* __rtems__ */ |
---|
667 | } |
---|
668 | /* Handle uneven size case. */ |
---|
669 | if (left > 0) { |
---|
670 | while (left > 0) { |
---|
671 | data <<= 8; |
---|
672 | data += *(buffer++); |
---|
673 | left--; |
---|
674 | } |
---|
675 | WR4(slot, SDHCI_BUFFER, data); |
---|
676 | } |
---|
677 | } |
---|
678 | |
---|
679 | static void |
---|
680 | sdhci_transfer_pio(struct sdhci_slot *slot) |
---|
681 | { |
---|
682 | |
---|
683 | /* Read as many blocks as possible. */ |
---|
684 | if (slot->curcmd->data->flags & MMC_DATA_READ) { |
---|
685 | while (RD4(slot, SDHCI_PRESENT_STATE) & |
---|
686 | SDHCI_DATA_AVAILABLE) { |
---|
687 | sdhci_read_block_pio(slot); |
---|
688 | if (slot->offset >= slot->curcmd->data->len) |
---|
689 | break; |
---|
690 | } |
---|
691 | } else { |
---|
692 | while (RD4(slot, SDHCI_PRESENT_STATE) & |
---|
693 | SDHCI_SPACE_AVAILABLE) { |
---|
694 | sdhci_write_block_pio(slot); |
---|
695 | if (slot->offset >= slot->curcmd->data->len) |
---|
696 | break; |
---|
697 | } |
---|
698 | } |
---|
699 | } |
---|
700 | |
---|
701 | static void |
---|
702 | sdhci_card_delay(void *arg) |
---|
703 | { |
---|
704 | #ifndef __rtems__ |
---|
705 | struct sdhci_slot *slot = arg; |
---|
706 | |
---|
707 | taskqueue_enqueue(taskqueue_swi_giant, &slot->card_task); |
---|
708 | #else /* __rtems__ */ |
---|
709 | sdhci_card_task(arg, 0); |
---|
710 | #endif /* __rtems__ */ |
---|
711 | } |
---|
712 | |
---|
713 | static void |
---|
714 | sdhci_card_task(void *arg, int pending) |
---|
715 | { |
---|
716 | struct sdhci_slot *slot = arg; |
---|
717 | |
---|
718 | SDHCI_LOCK(slot); |
---|
719 | if (RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT) { |
---|
720 | if (slot->dev == NULL) { |
---|
721 | /* If card is present - attach mmc bus. */ |
---|
722 | slot->dev = device_add_child(slot->sc->dev, "mmc", -1); |
---|
723 | device_set_ivars(slot->dev, slot); |
---|
724 | SDHCI_UNLOCK(slot); |
---|
725 | device_probe_and_attach(slot->dev); |
---|
726 | } else |
---|
727 | SDHCI_UNLOCK(slot); |
---|
728 | } else { |
---|
729 | if (slot->dev != NULL) { |
---|
730 | /* If no card present - detach mmc bus. */ |
---|
731 | device_t d = slot->dev; |
---|
732 | slot->dev = NULL; |
---|
733 | SDHCI_UNLOCK(slot); |
---|
734 | device_delete_child(slot->sc->dev, d); |
---|
735 | } else |
---|
736 | SDHCI_UNLOCK(slot); |
---|
737 | } |
---|
738 | } |
---|
739 | |
---|
740 | static int |
---|
741 | sdhci_probe(device_t dev) |
---|
742 | { |
---|
743 | #ifndef __rtems__ |
---|
744 | uint32_t model; |
---|
745 | uint16_t subvendor; |
---|
746 | uint8_t class, subclass; |
---|
747 | int i, result; |
---|
748 | |
---|
749 | model = (uint32_t)pci_get_device(dev) << 16; |
---|
750 | model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; |
---|
751 | subvendor = pci_get_subvendor(dev); |
---|
752 | class = pci_get_class(dev); |
---|
753 | subclass = pci_get_subclass(dev); |
---|
754 | |
---|
755 | result = ENXIO; |
---|
756 | for (i = 0; sdhci_devices[i].model != 0; i++) { |
---|
757 | if (sdhci_devices[i].model == model && |
---|
758 | (sdhci_devices[i].subvendor == 0xffff || |
---|
759 | sdhci_devices[i].subvendor == subvendor)) { |
---|
760 | device_set_desc(dev, sdhci_devices[i].desc); |
---|
761 | result = BUS_PROBE_DEFAULT; |
---|
762 | break; |
---|
763 | } |
---|
764 | } |
---|
765 | if (result == ENXIO && class == PCIC_BASEPERIPH && |
---|
766 | subclass == PCIS_BASEPERIPH_SDHC) { |
---|
767 | device_set_desc(dev, "Generic SD HCI"); |
---|
768 | result = BUS_PROBE_GENERIC; |
---|
769 | } |
---|
770 | |
---|
771 | return (result); |
---|
772 | #else /* __rtems__ */ |
---|
773 | return (0); |
---|
774 | #endif /* __rtems__ */ |
---|
775 | } |
---|
776 | |
---|
777 | static int |
---|
778 | sdhci_attach(device_t dev) |
---|
779 | { |
---|
780 | struct sdhci_softc *sc = device_get_softc(dev); |
---|
781 | #ifndef __rtems__ |
---|
782 | uint32_t model; |
---|
783 | uint16_t subvendor; |
---|
784 | uint8_t class, subclass, progif; |
---|
785 | int err, slots, bar, i; |
---|
786 | #else /* __rtems__ */ |
---|
787 | int slots, i; |
---|
788 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
789 | rtems_status_code status_code; |
---|
790 | #endif |
---|
791 | #endif /* __rtems__ */ |
---|
792 | |
---|
793 | sc->dev = dev; |
---|
794 | #ifndef __rtems__ |
---|
795 | model = (uint32_t)pci_get_device(dev) << 16; |
---|
796 | model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff; |
---|
797 | subvendor = pci_get_subvendor(dev); |
---|
798 | class = pci_get_class(dev); |
---|
799 | subclass = pci_get_subclass(dev); |
---|
800 | progif = pci_get_progif(dev); |
---|
801 | /* Apply chip specific quirks. */ |
---|
802 | for (i = 0; sdhci_devices[i].model != 0; i++) { |
---|
803 | if (sdhci_devices[i].model == model && |
---|
804 | (sdhci_devices[i].subvendor == 0xffff || |
---|
805 | sdhci_devices[i].subvendor == subvendor)) { |
---|
806 | sc->quirks = sdhci_devices[i].quirks; |
---|
807 | break; |
---|
808 | } |
---|
809 | } |
---|
810 | /* Read slots info from PCI registers. */ |
---|
811 | slots = pci_read_config(dev, PCI_SLOT_INFO, 1); |
---|
812 | bar = PCI_SLOT_INFO_FIRST_BAR(slots); |
---|
813 | slots = PCI_SLOT_INFO_SLOTS(slots); |
---|
814 | if (slots > 6 || bar > 5) { |
---|
815 | device_printf(dev, "Incorrect slots information (%d, %d).\n", |
---|
816 | slots, bar); |
---|
817 | return (EINVAL); |
---|
818 | } |
---|
819 | #else /* __rtems__ */ |
---|
820 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
821 | /* FIXME */ |
---|
822 | qoriq.esdhc.dcr = BSP_BBIT32(25); |
---|
823 | sc->quirks = SDHCI_QUIRK_BROKEN_TIMINGS |
---|
824 | | SDHCI_QUIRK_32BIT_DMA_SIZE; |
---|
825 | slots = 1; |
---|
826 | #else |
---|
827 | slots = 0; |
---|
828 | #endif |
---|
829 | #endif /* __rtems__ */ |
---|
830 | #ifndef __rtems__ |
---|
831 | /* Allocate IRQ. */ |
---|
832 | sc->irq_rid = 0; |
---|
833 | sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, |
---|
834 | RF_SHAREABLE | RF_ACTIVE); |
---|
835 | if (sc->irq_res == NULL) { |
---|
836 | device_printf(dev, "Can't allocate IRQ\n"); |
---|
837 | return (ENOMEM); |
---|
838 | } |
---|
839 | #endif /* __rtems__ */ |
---|
840 | /* Scan all slots. */ |
---|
841 | for (i = 0; i < slots; i++) { |
---|
842 | struct sdhci_slot *slot = &sc->slots[sc->num_slots]; |
---|
843 | uint32_t caps; |
---|
844 | |
---|
845 | SDHCI_LOCK_INIT(slot); |
---|
846 | slot->sc = sc; |
---|
847 | slot->num = sc->num_slots; |
---|
848 | #ifndef __rtems__ |
---|
849 | /* Allocate memory. */ |
---|
850 | slot->mem_rid = PCIR_BAR(bar + i); |
---|
851 | slot->mem_res = bus_alloc_resource(dev, |
---|
852 | SYS_RES_MEMORY, &slot->mem_rid, 0ul, ~0ul, 0x100, RF_ACTIVE); |
---|
853 | if (slot->mem_res == NULL) { |
---|
854 | device_printf(dev, "Can't allocate memory\n"); |
---|
855 | SDHCI_LOCK_DESTROY(slot); |
---|
856 | continue; |
---|
857 | } |
---|
858 | #else /* __rtems__ */ |
---|
859 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
860 | slot->mem_res [0].r_bustag = 0; |
---|
861 | slot->mem_res [0].r_bushandle = &qoriq.esdhc; |
---|
862 | #endif |
---|
863 | #endif /* __rtems__ */ |
---|
864 | #ifndef __rtems__ |
---|
865 | /* Allocate DMA tag. */ |
---|
866 | err = bus_dma_tag_create(bus_get_dma_tag(dev), |
---|
867 | DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, |
---|
868 | BUS_SPACE_MAXADDR, NULL, NULL, |
---|
869 | DMA_BLOCK_SIZE, 1, DMA_BLOCK_SIZE, |
---|
870 | BUS_DMA_ALLOCNOW, NULL, NULL, |
---|
871 | &slot->dmatag); |
---|
872 | if (err != 0) { |
---|
873 | device_printf(dev, "Can't create DMA tag\n"); |
---|
874 | SDHCI_LOCK_DESTROY(slot); |
---|
875 | continue; |
---|
876 | } |
---|
877 | /* Allocate DMA memory. */ |
---|
878 | err = bus_dmamem_alloc(slot->dmatag, (void **)&slot->dmamem, |
---|
879 | BUS_DMA_NOWAIT, &slot->dmamap); |
---|
880 | if (err != 0) { |
---|
881 | device_printf(dev, "Can't alloc DMA memory\n"); |
---|
882 | SDHCI_LOCK_DESTROY(slot); |
---|
883 | continue; |
---|
884 | } |
---|
885 | /* Map the memory. */ |
---|
886 | err = bus_dmamap_load(slot->dmatag, slot->dmamap, |
---|
887 | (void *)slot->dmamem, DMA_BLOCK_SIZE, |
---|
888 | sdhci_getaddr, &slot->paddr, 0); |
---|
889 | if (err != 0 || slot->paddr == 0) { |
---|
890 | device_printf(dev, "Can't load DMA memory\n"); |
---|
891 | SDHCI_LOCK_DESTROY(slot); |
---|
892 | continue; |
---|
893 | } |
---|
894 | #endif /* __rtems__ */ |
---|
895 | /* Initialize slot. */ |
---|
896 | sdhci_init(slot); |
---|
897 | caps = RD4(slot, SDHCI_CAPABILITIES); |
---|
898 | /* Calculate base clock frequency. */ |
---|
899 | #ifndef __rtems__ |
---|
900 | slot->max_clk = |
---|
901 | (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; |
---|
902 | if (slot->max_clk == 0) { |
---|
903 | device_printf(dev, "Hardware doesn't specify base clock " |
---|
904 | "frequency.\n"); |
---|
905 | } |
---|
906 | slot->max_clk *= 1000000; |
---|
907 | #else /* __rtems__ */ |
---|
908 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
909 | slot->max_clk = BSP_bus_frequency / 2; |
---|
910 | #else |
---|
911 | panic("FIXME"); |
---|
912 | #endif |
---|
913 | #endif /* __rtems__ */ |
---|
914 | /* Calculate timeout clock frequency. */ |
---|
915 | #ifndef __rtems__ |
---|
916 | slot->timeout_clk = |
---|
917 | (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; |
---|
918 | #else /* __rtems__ */ |
---|
919 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
920 | slot->timeout_clk = slot->max_clk / 1000; |
---|
921 | #else |
---|
922 | panic("FIXME"); |
---|
923 | #endif |
---|
924 | #endif /* __rtems__ */ |
---|
925 | if (slot->timeout_clk == 0) { |
---|
926 | device_printf(dev, "Hardware doesn't specify timeout clock " |
---|
927 | "frequency.\n"); |
---|
928 | } |
---|
929 | if (caps & SDHCI_TIMEOUT_CLK_UNIT) |
---|
930 | slot->timeout_clk *= 1000; |
---|
931 | |
---|
932 | #ifndef __rtems__ |
---|
933 | slot->host.f_min = slot->max_clk / 256; |
---|
934 | #else /* __rtems__ */ |
---|
935 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
936 | slot->host.f_min = 400000; |
---|
937 | #else |
---|
938 | panic("FIXME"); |
---|
939 | #endif |
---|
940 | #endif /* __rtems__ */ |
---|
941 | slot->host.f_max = slot->max_clk; |
---|
942 | slot->host.host_ocr = 0; |
---|
943 | if (caps & SDHCI_CAN_VDD_330) |
---|
944 | slot->host.host_ocr |= MMC_OCR_320_330 | MMC_OCR_330_340; |
---|
945 | if (caps & SDHCI_CAN_VDD_300) |
---|
946 | slot->host.host_ocr |= MMC_OCR_290_300 | MMC_OCR_300_310; |
---|
947 | if (caps & SDHCI_CAN_VDD_180) |
---|
948 | slot->host.host_ocr |= MMC_OCR_LOW_VOLTAGE; |
---|
949 | if (slot->host.host_ocr == 0) { |
---|
950 | device_printf(dev, "Hardware doesn't report any " |
---|
951 | "support voltages.\n"); |
---|
952 | } |
---|
953 | slot->host.caps = MMC_CAP_4_BIT_DATA; |
---|
954 | if (caps & SDHCI_CAN_DO_HISPD) |
---|
955 | slot->host.caps |= MMC_CAP_HSPEED; |
---|
956 | /* Decide if we have usable DMA. */ |
---|
957 | if (caps & SDHCI_CAN_DO_DMA) |
---|
958 | slot->opt |= SDHCI_HAVE_DMA; |
---|
959 | #ifndef __rtems__ |
---|
960 | if (class == PCIC_BASEPERIPH && |
---|
961 | subclass == PCIS_BASEPERIPH_SDHC && |
---|
962 | progif != PCI_SDHCI_IFDMA) |
---|
963 | slot->opt &= ~SDHCI_HAVE_DMA; |
---|
964 | if (sc->quirks & SDHCI_QUIRK_BROKEN_DMA) |
---|
965 | slot->opt &= ~SDHCI_HAVE_DMA; |
---|
966 | if (sc->quirks & SDHCI_QUIRK_FORCE_DMA) |
---|
967 | slot->opt |= SDHCI_HAVE_DMA; |
---|
968 | #endif /* __rtems__ */ |
---|
969 | |
---|
970 | if (bootverbose || sdhci_debug) { |
---|
971 | slot_printf(slot, "%uMHz%s 4bits%s%s%s %s\n", |
---|
972 | slot->max_clk / 1000000, |
---|
973 | (caps & SDHCI_CAN_DO_HISPD) ? " HS" : "", |
---|
974 | (caps & SDHCI_CAN_VDD_330) ? " 3.3V" : "", |
---|
975 | (caps & SDHCI_CAN_VDD_300) ? " 3.0V" : "", |
---|
976 | (caps & SDHCI_CAN_VDD_180) ? " 1.8V" : "", |
---|
977 | (slot->opt & SDHCI_HAVE_DMA) ? "DMA" : "PIO"); |
---|
978 | sdhci_dumpregs(slot); |
---|
979 | } |
---|
980 | |
---|
981 | #ifndef __rtems__ |
---|
982 | TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot); |
---|
983 | #endif /* __rtems__ */ |
---|
984 | callout_init(&slot->card_callout, 1); |
---|
985 | sc->num_slots++; |
---|
986 | } |
---|
987 | device_printf(dev, "%d slot(s) allocated\n", sc->num_slots); |
---|
988 | /* Activate the interrupt */ |
---|
989 | #ifndef __rtems__ |
---|
990 | err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, |
---|
991 | NULL, sdhci_intr, sc, &sc->intrhand); |
---|
992 | if (err) |
---|
993 | device_printf(dev, "Can't setup IRQ\n"); |
---|
994 | pci_enable_busmaster(dev); |
---|
995 | #else /* __rtems__ */ |
---|
996 | #ifdef LIBBSP_POWERPC_QORIQ_BSP_H |
---|
997 | status_code = rtems_interrupt_server_handler_install( |
---|
998 | RTEMS_ID_NONE, |
---|
999 | QORIQ_IRQ_ESDHC, |
---|
1000 | "eSDHC", |
---|
1001 | RTEMS_INTERRUPT_UNIQUE, |
---|
1002 | sdhci_intr, |
---|
1003 | sc |
---|
1004 | ); |
---|
1005 | BSD_ASSERT(status_code == RTEMS_SUCCESSFUL); |
---|
1006 | #endif |
---|
1007 | #endif /* __rtems__ */ |
---|
1008 | /* Process cards detection. */ |
---|
1009 | for (i = 0; i < sc->num_slots; i++) { |
---|
1010 | struct sdhci_slot *slot = &sc->slots[i]; |
---|
1011 | |
---|
1012 | sdhci_card_task(slot, 0); |
---|
1013 | } |
---|
1014 | |
---|
1015 | return (0); |
---|
1016 | } |
---|
1017 | |
---|
1018 | static int |
---|
1019 | sdhci_detach(device_t dev) |
---|
1020 | { |
---|
1021 | #ifndef __rtems__ |
---|
1022 | struct sdhci_softc *sc = device_get_softc(dev); |
---|
1023 | int i; |
---|
1024 | |
---|
1025 | bus_teardown_intr(dev, sc->irq_res, sc->intrhand); |
---|
1026 | bus_release_resource(dev, SYS_RES_IRQ, |
---|
1027 | sc->irq_rid, sc->irq_res); |
---|
1028 | |
---|
1029 | for (i = 0; i < sc->num_slots; i++) { |
---|
1030 | struct sdhci_slot *slot = &sc->slots[i]; |
---|
1031 | device_t d; |
---|
1032 | |
---|
1033 | callout_drain(&slot->card_callout); |
---|
1034 | taskqueue_drain(taskqueue_swi_giant, &slot->card_task); |
---|
1035 | |
---|
1036 | SDHCI_LOCK(slot); |
---|
1037 | d = slot->dev; |
---|
1038 | slot->dev = NULL; |
---|
1039 | SDHCI_UNLOCK(slot); |
---|
1040 | if (d != NULL) |
---|
1041 | device_delete_child(dev, d); |
---|
1042 | |
---|
1043 | SDHCI_LOCK(slot); |
---|
1044 | sdhci_reset(slot, SDHCI_RESET_ALL); |
---|
1045 | SDHCI_UNLOCK(slot); |
---|
1046 | bus_dmamap_unload(slot->dmatag, slot->dmamap); |
---|
1047 | bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap); |
---|
1048 | bus_dma_tag_destroy(slot->dmatag); |
---|
1049 | bus_release_resource(dev, SYS_RES_MEMORY, |
---|
1050 | slot->mem_rid, slot->mem_res); |
---|
1051 | SDHCI_LOCK_DESTROY(slot); |
---|
1052 | } |
---|
1053 | #else /* __rtems__ */ |
---|
1054 | panic("FIXME"); |
---|
1055 | #endif /* __rtems__ */ |
---|
1056 | return (0); |
---|
1057 | } |
---|
1058 | |
---|
1059 | static int |
---|
1060 | sdhci_suspend(device_t dev) |
---|
1061 | { |
---|
1062 | struct sdhci_softc *sc = device_get_softc(dev); |
---|
1063 | int i, err; |
---|
1064 | |
---|
1065 | err = bus_generic_suspend(dev); |
---|
1066 | if (err) |
---|
1067 | return (err); |
---|
1068 | for (i = 0; i < sc->num_slots; i++) |
---|
1069 | sdhci_reset(&sc->slots[i], SDHCI_RESET_ALL); |
---|
1070 | return (0); |
---|
1071 | } |
---|
1072 | |
---|
1073 | static int |
---|
1074 | sdhci_resume(device_t dev) |
---|
1075 | { |
---|
1076 | struct sdhci_softc *sc = device_get_softc(dev); |
---|
1077 | int i; |
---|
1078 | |
---|
1079 | for (i = 0; i < sc->num_slots; i++) |
---|
1080 | sdhci_init(&sc->slots[i]); |
---|
1081 | return (bus_generic_resume(dev)); |
---|
1082 | } |
---|
1083 | |
---|
1084 | static int |
---|
1085 | sdhci_update_ios(device_t brdev, device_t reqdev) |
---|
1086 | { |
---|
1087 | struct sdhci_slot *slot = device_get_ivars(reqdev); |
---|
1088 | struct mmc_ios *ios = &slot->host.ios; |
---|
1089 | |
---|
1090 | SDHCI_LOCK(slot); |
---|
1091 | /* Do full reset on bus power down to clear from any state. */ |
---|
1092 | if (ios->power_mode == power_off) { |
---|
1093 | WR4(slot, SDHCI_SIGNAL_ENABLE, 0); |
---|
1094 | sdhci_init(slot); |
---|
1095 | } |
---|
1096 | /* Configure the bus. */ |
---|
1097 | sdhci_set_clock(slot, ios->clock); |
---|
1098 | sdhci_set_power(slot, (ios->power_mode == power_off)?0:ios->vdd); |
---|
1099 | if (ios->bus_width == bus_width_4) |
---|
1100 | slot->hostctrl |= SDHCI_CTRL_4BITBUS; |
---|
1101 | else |
---|
1102 | slot->hostctrl &= ~SDHCI_CTRL_4BITBUS; |
---|
1103 | if (ios->timing == bus_timing_hs) |
---|
1104 | slot->hostctrl |= SDHCI_CTRL_HISPD; |
---|
1105 | else |
---|
1106 | slot->hostctrl &= ~SDHCI_CTRL_HISPD; |
---|
1107 | #if defined(__rtems__) && defined(LIBBSP_POWERPC_QORIQ_BSP_H) |
---|
1108 | slot->hostctrl &= ~BSP_MSK8(2, 5); |
---|
1109 | slot->hostctrl |= BSP_FLD8(0x4, 2, 5); |
---|
1110 | #endif /* __rtems__ */ |
---|
1111 | WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl); |
---|
1112 | /* Some controllers like reset after bus changes. */ |
---|
1113 | if(slot->sc->quirks & SDHCI_QUIRK_RESET_ON_IOS) |
---|
1114 | sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA); |
---|
1115 | |
---|
1116 | SDHCI_UNLOCK(slot); |
---|
1117 | return (0); |
---|
1118 | } |
---|
1119 | |
---|
1120 | #if !defined(__rtems__) || !defined(RTEMS_BSD_SDHCI_QUIRK_32_BIT_REGS) |
---|
1121 | static void |
---|
1122 | sdhci_set_transfer_mode(struct sdhci_slot *slot, |
---|
1123 | struct mmc_data *data) |
---|
1124 | #else /* __rtems__ */ |
---|
1125 | static uint16_t |
---|
1126 | sdhci_get_transfer_mode(struct sdhci_slot *slot, |
---|
1127 | struct mmc_data *data) |
---|
1128 | #endif /* __rtems__ */ |
---|
1129 | { |
---|
1130 | uint16_t mode; |
---|
1131 | |
---|
1132 | if (data == NULL) |
---|
1133 | #if !defined(__rtems__) || !defined(RTEMS_BSD_SDHCI_QUIRK_32_BIT_REGS) |
---|
1134 | return; |
---|
1135 | #else /* __rtems__ */ |
---|
1136 | return 0; |
---|
1137 | #endif /* __rtems__ */ |
---|
1138 | |
---|
1139 | #if !defined(__rtems__) || !defined(LIBBSP_POWERPC_QORIQ_BSP_H) |
---|
1140 | mode = SDHCI_TRNS_BLK_CNT_EN; |
---|
1141 | if (data->len > 512) |
---|
1142 | mode |= SDHCI_TRNS_MULTI; |
---|
1143 | #else /* __rtems__ */ |
---|
1144 | mode = 0; |
---|
1145 | if (data->len > 512) |
---|
1146 | mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN; |
---|
1147 | #endif /* __rtems__ */ |
---|
1148 | if (data->flags & MMC_DATA_READ) |
---|
1149 | mode |= SDHCI_TRNS_READ; |
---|
1150 | if (slot->req->stop) |
---|
1151 | mode |= SDHCI_TRNS_ACMD12; |
---|
1152 | if (slot->flags & SDHCI_USE_DMA) |
---|
1153 | mode |= SDHCI_TRNS_DMA; |
---|
1154 | |
---|
1155 | #if !defined(__rtems__) || !defined(RTEMS_BSD_SDHCI_QUIRK_32_BIT_REGS) |
---|
1156 | WR2(slot, SDHCI_TRANSFER_MODE, mode); |
---|
1157 | #else /* __rtems__ */ |
---|
1158 | return mode; |
---|
1159 | #endif /* __rtems__ */ |
---|
1160 | } |
---|
1161 | |
---|
1162 | static void |
---|
1163 | sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd) |
---|
1164 | { |
---|
1165 | struct mmc_request *req = slot->req; |
---|
1166 | int flags, timeout; |
---|
1167 | uint32_t mask, state; |
---|
1168 | |
---|
1169 | slot->curcmd = cmd; |
---|
1170 | slot->cmd_done = 0; |
---|
1171 | |
---|
1172 | cmd->error = MMC_ERR_NONE; |
---|
1173 | |
---|
1174 | /* This flags combination is not supported by controller. */ |
---|
1175 | if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { |
---|
1176 | slot_printf(slot, "Unsupported response type!\n"); |
---|
1177 | cmd->error = MMC_ERR_FAILED; |
---|
1178 | slot->req = NULL; |
---|
1179 | slot->curcmd = NULL; |
---|
1180 | req->done(req); |
---|
1181 | return; |
---|
1182 | } |
---|
1183 | |
---|
1184 | /* Read controller present state. */ |
---|
1185 | state = RD4(slot, SDHCI_PRESENT_STATE); |
---|
1186 | /* Do not issue command if there is no card, clock or power. |
---|
1187 | * Controller will not detect timeout without clock active. */ |
---|
1188 | if ((state & SDHCI_CARD_PRESENT) == 0 || |
---|
1189 | slot->power == 0 || |
---|
1190 | slot->clock == 0) { |
---|
1191 | cmd->error = MMC_ERR_FAILED; |
---|
1192 | slot->req = NULL; |
---|
1193 | slot->curcmd = NULL; |
---|
1194 | req->done(req); |
---|
1195 | return; |
---|
1196 | } |
---|
1197 | /* Always wait for free CMD bus. */ |
---|
1198 | mask = SDHCI_CMD_INHIBIT; |
---|
1199 | /* Wait for free DAT if we have data or busy signal. */ |
---|
1200 | if (cmd->data || (cmd->flags & MMC_RSP_BUSY)) |
---|
1201 | mask |= SDHCI_DAT_INHIBIT; |
---|
1202 | /* We shouldn't wait for DAT for stop commands. */ |
---|
1203 | if (cmd == slot->req->stop) |
---|
1204 | mask &= ~SDHCI_DAT_INHIBIT; |
---|
1205 | /* Wait for bus no more then 10 ms. */ |
---|
1206 | timeout = 10; |
---|
1207 | while (state & mask) { |
---|
1208 | if (timeout == 0) { |
---|
1209 | slot_printf(slot, "Controller never released " |
---|
1210 | "inhibit bit(s).\n"); |
---|
1211 | sdhci_dumpregs(slot); |
---|
1212 | cmd->error = MMC_ERR_FAILED; |
---|
1213 | slot->req = NULL; |
---|
1214 | slot->curcmd = NULL; |
---|
1215 | req->done(req); |
---|
1216 | return; |
---|
1217 | } |
---|
1218 | timeout--; |
---|
1219 | DELAY(1000); |
---|
1220 | state = RD4(slot, SDHCI_PRESENT_STATE); |
---|
1221 | } |
---|
1222 | |
---|
1223 | /* Prepare command flags. */ |
---|
1224 | if (!(cmd->flags & MMC_RSP_PRESENT)) |
---|
1225 | flags = SDHCI_CMD_RESP_NONE; |
---|
1226 | else if (cmd->flags & MMC_RSP_136) |
---|
1227 | flags = SDHCI_CMD_RESP_LONG; |
---|
1228 | else if (cmd->flags & MMC_RSP_BUSY) |
---|
1229 | flags = SDHCI_CMD_RESP_SHORT_BUSY; |
---|
1230 | else |
---|
1231 | flags = SDHCI_CMD_RESP_SHORT; |
---|
1232 | if (cmd->flags & MMC_RSP_CRC) |
---|
1233 | flags |= SDHCI_CMD_CRC; |
---|
1234 | if (cmd->flags & MMC_RSP_OPCODE) |
---|
1235 | flags |= SDHCI_CMD_INDEX; |
---|
1236 | if (cmd->data) |
---|
1237 | flags |= SDHCI_CMD_DATA; |
---|
1238 | if (cmd->opcode == MMC_STOP_TRANSMISSION) |
---|
1239 | flags |= SDHCI_CMD_TYPE_ABORT; |
---|
1240 | /* Prepare data. */ |
---|
1241 | sdhci_start_data(slot, cmd->data); |
---|
1242 | /* |
---|
1243 | * Interrupt aggregation: To reduce total number of interrupts |
---|
1244 | * group response interrupt with data interrupt when possible. |
---|
1245 | * If there going to be data interrupt, mask response one. |
---|
1246 | */ |
---|
1247 | if (slot->data_done == 0) { |
---|
1248 | #if !defined(__rtems__) || !defined(RTEMS_BSD_SDHCI_QUIRK_NO_BUSY_IRQ) |
---|
1249 | WR4(slot, SDHCI_SIGNAL_ENABLE, |
---|
1250 | slot->intmask &= ~SDHCI_INT_RESPONSE); |
---|
1251 | #endif /* __rtems__ */ |
---|
1252 | } |
---|
1253 | /* Set command argument. */ |
---|
1254 | WR4(slot, SDHCI_ARGUMENT, cmd->arg); |
---|
1255 | /* Set data transfer mode. */ |
---|
1256 | #if !defined(__rtems__) || !defined(RTEMS_BSD_SDHCI_QUIRK_32_BIT_REGS) |
---|
1257 | sdhci_set_transfer_mode(slot, cmd->data); |
---|
1258 | /* Set command flags. */ |
---|
1259 | WR1(slot, SDHCI_COMMAND_FLAGS, flags); |
---|
1260 | /* Start command. */ |
---|
1261 | WR1(slot, SDHCI_COMMAND, cmd->opcode); |
---|
1262 | #else /* __rtems__ */ |
---|
1263 | uint16_t mode = sdhci_get_transfer_mode(slot, cmd->data); |
---|
1264 | WR4(slot, SDHCI_TRANSFER_MODE, (cmd->opcode << 24) | (flags << 16) | mode); |
---|
1265 | #endif /* __rtems__ */ |
---|
1266 | } |
---|
1267 | |
---|
1268 | static void |
---|
1269 | sdhci_finish_command(struct sdhci_slot *slot) |
---|
1270 | { |
---|
1271 | int i; |
---|
1272 | |
---|
1273 | slot->cmd_done = 1; |
---|
1274 | /* Interrupt aggregation: Restore command interrupt. |
---|
1275 | * Main restore point for the case when command interrupt |
---|
1276 | * happened first. */ |
---|
1277 | WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |= SDHCI_INT_RESPONSE); |
---|
1278 | /* In case of error - reset host and return. */ |
---|
1279 | if (slot->curcmd->error) { |
---|
1280 | sdhci_reset(slot, SDHCI_RESET_CMD); |
---|
1281 | sdhci_reset(slot, SDHCI_RESET_DATA); |
---|
1282 | sdhci_start(slot); |
---|
1283 | return; |
---|
1284 | } |
---|
1285 | /* If command has response - fetch it. */ |
---|
1286 | if (slot->curcmd->flags & MMC_RSP_PRESENT) { |
---|
1287 | if (slot->curcmd->flags & MMC_RSP_136) { |
---|
1288 | /* CRC is stripped so we need one byte shift. */ |
---|
1289 | uint8_t extra = 0; |
---|
1290 | for (i = 0; i < 4; i++) { |
---|
1291 | uint32_t val = RD4(slot, SDHCI_RESPONSE + i * 4); |
---|
1292 | slot->curcmd->resp[3 - i] = (val << 8) + extra; |
---|
1293 | extra = val >> 24; |
---|
1294 | } |
---|
1295 | } else |
---|
1296 | slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE); |
---|
1297 | } |
---|
1298 | /* If data ready - finish. */ |
---|
1299 | if (slot->data_done) |
---|
1300 | sdhci_start(slot); |
---|
1301 | } |
---|
1302 | |
---|
1303 | static void |
---|
1304 | sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data) |
---|
1305 | { |
---|
1306 | uint32_t target_timeout, current_timeout; |
---|
1307 | uint8_t div; |
---|
1308 | |
---|
1309 | #if defined(__rtems__) && defined(RTEMS_BSD_SDHCI_QUIRK_NO_BUSY_IRQ) |
---|
1310 | if (data == NULL) { |
---|
1311 | #else /* __rtems__ */ |
---|
1312 | if (data == NULL && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) { |
---|
1313 | #endif /* __rtems__ */ |
---|
1314 | slot->data_done = 1; |
---|
1315 | return; |
---|
1316 | } |
---|
1317 | |
---|
1318 | slot->data_done = 0; |
---|
1319 | |
---|
1320 | /* Calculate and set data timeout.*/ |
---|
1321 | /* XXX: We should have this from mmc layer, now assume 1 sec. */ |
---|
1322 | target_timeout = 1000000; |
---|
1323 | div = 0; |
---|
1324 | current_timeout = (1 << 13) * 1000 / slot->timeout_clk; |
---|
1325 | while (current_timeout < target_timeout) { |
---|
1326 | div++; |
---|
1327 | current_timeout <<= 1; |
---|
1328 | if (div >= 0xF) |
---|
1329 | break; |
---|
1330 | } |
---|
1331 | /* Compensate for an off-by-one error in the CaFe chip.*/ |
---|
1332 | if (slot->sc->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL) |
---|
1333 | div++; |
---|
1334 | if (div >= 0xF) { |
---|
1335 | #ifndef __rtems__ |
---|
1336 | slot_printf(slot, "Timeout too large!\n"); |
---|
1337 | #endif /* __rtems__ */ |
---|
1338 | div = 0xE; |
---|
1339 | } |
---|
1340 | WR1(slot, SDHCI_TIMEOUT_CONTROL, div); |
---|
1341 | |
---|
1342 | if (data == NULL) |
---|
1343 | return; |
---|
1344 | |
---|
1345 | /* Use DMA if possible. */ |
---|
1346 | if ((slot->opt & SDHCI_HAVE_DMA)) |
---|
1347 | slot->flags |= SDHCI_USE_DMA; |
---|
1348 | /* If data is small, broken DMA may return zeroes instead of data, */ |
---|
1349 | #ifndef __rtems__ |
---|
1350 | if ((slot->sc->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) && |
---|
1351 | (data->len <= 512)) |
---|
1352 | #else /* __rtems__ */ |
---|
1353 | if ((slot->sc->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) && |
---|
1354 | (data->len < 512)) |
---|
1355 | #endif /* __rtems__ */ |
---|
1356 | slot->flags &= ~SDHCI_USE_DMA; |
---|
1357 | /* Some controllers require even block sizes. */ |
---|
1358 | if ((slot->sc->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && |
---|
1359 | ((data->len) & 0x3)) |
---|
1360 | slot->flags &= ~SDHCI_USE_DMA; |
---|
1361 | /* Load DMA buffer. */ |
---|
1362 | if (slot->flags & SDHCI_USE_DMA) { |
---|
1363 | #ifndef __rtems__ |
---|
1364 | if (data->flags & MMC_DATA_READ) |
---|
1365 | bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREREAD); |
---|
1366 | else { |
---|
1367 | memcpy(slot->dmamem, data->data, |
---|
1368 | (data->len < DMA_BLOCK_SIZE)?data->len:DMA_BLOCK_SIZE); |
---|
1369 | bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_PREWRITE); |
---|
1370 | } |
---|
1371 | WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); |
---|
1372 | /* Interrupt aggregation: Mask border interrupt |
---|
1373 | * for the last page and unmask else. */ |
---|
1374 | if (data->len == DMA_BLOCK_SIZE) |
---|
1375 | #else /* __rtems__ */ |
---|
1376 | WR4(slot, SDHCI_DMA_ADDRESS, (uint32_t) data->data); |
---|
1377 | if (data->len <= DMA_BLOCK_SIZE) |
---|
1378 | #endif /* __rtems__ */ |
---|
1379 | slot->intmask &= ~SDHCI_INT_DMA_END; |
---|
1380 | else |
---|
1381 | slot->intmask |= SDHCI_INT_DMA_END; |
---|
1382 | #ifndef __rtems__ |
---|
1383 | WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); |
---|
1384 | } |
---|
1385 | #else /* __rtems__ */ |
---|
1386 | slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL); |
---|
1387 | } else { |
---|
1388 | slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL; |
---|
1389 | } |
---|
1390 | WR4(slot, SDHCI_INT_ENABLE, slot->intmask); |
---|
1391 | WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); |
---|
1392 | #endif /* __rtems__ */ |
---|
1393 | /* Current data offset for both PIO and DMA. */ |
---|
1394 | slot->offset = 0; |
---|
1395 | /* Set block size and request IRQ on 4K border. */ |
---|
1396 | WR2(slot, SDHCI_BLOCK_SIZE, |
---|
1397 | SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512)?data->len:512)); |
---|
1398 | /* Set block count. */ |
---|
1399 | WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512); |
---|
1400 | } |
---|
1401 | |
---|
1402 | static void |
---|
1403 | sdhci_finish_data(struct sdhci_slot *slot) |
---|
1404 | { |
---|
1405 | #ifndef __rtems__ |
---|
1406 | struct mmc_data *data = slot->curcmd->data; |
---|
1407 | #endif /* __rtems__ */ |
---|
1408 | |
---|
1409 | slot->data_done = 1; |
---|
1410 | /* Interrupt aggregation: Restore command interrupt. |
---|
1411 | * Auxillary restore point for the case when data interrupt |
---|
1412 | * happened first. */ |
---|
1413 | if (!slot->cmd_done) { |
---|
1414 | WR4(slot, SDHCI_SIGNAL_ENABLE, |
---|
1415 | slot->intmask |= SDHCI_INT_RESPONSE); |
---|
1416 | } |
---|
1417 | #ifndef __rtems__ |
---|
1418 | /* Unload rest of data from DMA buffer. */ |
---|
1419 | if (slot->flags & SDHCI_USE_DMA) { |
---|
1420 | if (data->flags & MMC_DATA_READ) { |
---|
1421 | size_t left = data->len - slot->offset; |
---|
1422 | bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTREAD); |
---|
1423 | memcpy((u_char*)data->data + slot->offset, slot->dmamem, |
---|
1424 | (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); |
---|
1425 | } else |
---|
1426 | bus_dmamap_sync(slot->dmatag, slot->dmamap, BUS_DMASYNC_POSTWRITE); |
---|
1427 | } |
---|
1428 | #endif /* __rtems__ */ |
---|
1429 | /* If there was error - reset the host. */ |
---|
1430 | if (slot->curcmd->error) { |
---|
1431 | sdhci_reset(slot, SDHCI_RESET_CMD); |
---|
1432 | sdhci_reset(slot, SDHCI_RESET_DATA); |
---|
1433 | sdhci_start(slot); |
---|
1434 | return; |
---|
1435 | } |
---|
1436 | /* If we already have command response - finish. */ |
---|
1437 | if (slot->cmd_done) |
---|
1438 | sdhci_start(slot); |
---|
1439 | } |
---|
1440 | |
---|
1441 | static void |
---|
1442 | sdhci_start(struct sdhci_slot *slot) |
---|
1443 | { |
---|
1444 | struct mmc_request *req; |
---|
1445 | |
---|
1446 | req = slot->req; |
---|
1447 | if (req == NULL) |
---|
1448 | return; |
---|
1449 | |
---|
1450 | if (!(slot->flags & CMD_STARTED)) { |
---|
1451 | slot->flags |= CMD_STARTED; |
---|
1452 | sdhci_start_command(slot, req->cmd); |
---|
1453 | return; |
---|
1454 | } |
---|
1455 | /* We don't need this until using Auto-CMD12 feature |
---|
1456 | if (!(slot->flags & STOP_STARTED) && req->stop) { |
---|
1457 | slot->flags |= STOP_STARTED; |
---|
1458 | sdhci_start_command(slot, req->stop); |
---|
1459 | return; |
---|
1460 | } |
---|
1461 | */ |
---|
1462 | if (sdhci_debug > 1) |
---|
1463 | slot_printf(slot, "result: %d\n", req->cmd->error); |
---|
1464 | if (!req->cmd->error && |
---|
1465 | (slot->sc->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) { |
---|
1466 | sdhci_reset(slot, SDHCI_RESET_CMD); |
---|
1467 | sdhci_reset(slot, SDHCI_RESET_DATA); |
---|
1468 | } |
---|
1469 | |
---|
1470 | /* We must be done -- bad idea to do this while locked? */ |
---|
1471 | slot->req = NULL; |
---|
1472 | slot->curcmd = NULL; |
---|
1473 | req->done(req); |
---|
1474 | } |
---|
1475 | |
---|
1476 | static int |
---|
1477 | sdhci_request(device_t brdev, device_t reqdev, struct mmc_request *req) |
---|
1478 | { |
---|
1479 | struct sdhci_slot *slot = device_get_ivars(reqdev); |
---|
1480 | |
---|
1481 | SDHCI_LOCK(slot); |
---|
1482 | if (slot->req != NULL) { |
---|
1483 | SDHCI_UNLOCK(slot); |
---|
1484 | return (EBUSY); |
---|
1485 | } |
---|
1486 | if (sdhci_debug > 1) { |
---|
1487 | slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", |
---|
1488 | req->cmd->opcode, req->cmd->arg, req->cmd->flags, |
---|
1489 | (req->cmd->data)?(u_int)req->cmd->data->len:0, |
---|
1490 | (req->cmd->data)?req->cmd->data->flags:0); |
---|
1491 | } |
---|
1492 | slot->req = req; |
---|
1493 | slot->flags = 0; |
---|
1494 | sdhci_start(slot); |
---|
1495 | SDHCI_UNLOCK(slot); |
---|
1496 | #ifndef __rtems__ |
---|
1497 | if (dumping) { |
---|
1498 | while (slot->req != NULL) { |
---|
1499 | sdhci_intr(slot->sc); |
---|
1500 | DELAY(10); |
---|
1501 | } |
---|
1502 | } |
---|
1503 | #endif /* __rtems__ */ |
---|
1504 | return (0); |
---|
1505 | } |
---|
1506 | |
---|
1507 | static int |
---|
1508 | sdhci_get_ro(device_t brdev, device_t reqdev) |
---|
1509 | { |
---|
1510 | struct sdhci_slot *slot = device_get_ivars(reqdev); |
---|
1511 | uint32_t val; |
---|
1512 | |
---|
1513 | SDHCI_LOCK(slot); |
---|
1514 | val = RD4(slot, SDHCI_PRESENT_STATE); |
---|
1515 | SDHCI_UNLOCK(slot); |
---|
1516 | return (!(val & SDHCI_WRITE_PROTECT)); |
---|
1517 | } |
---|
1518 | |
---|
1519 | static int |
---|
1520 | sdhci_acquire_host(device_t brdev, device_t reqdev) |
---|
1521 | { |
---|
1522 | #ifndef __rtems__ |
---|
1523 | struct sdhci_slot *slot = device_get_ivars(reqdev); |
---|
1524 | int err = 0; |
---|
1525 | |
---|
1526 | SDHCI_LOCK(slot); |
---|
1527 | while (slot->bus_busy) |
---|
1528 | msleep(slot, &slot->mtx, 0, "sdhciah", 0); |
---|
1529 | slot->bus_busy++; |
---|
1530 | /* Activate led. */ |
---|
1531 | WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl |= SDHCI_CTRL_LED); |
---|
1532 | SDHCI_UNLOCK(slot); |
---|
1533 | return (err); |
---|
1534 | #else /* __rtems__ */ |
---|
1535 | return (0); |
---|
1536 | #endif /* __rtems__ */ |
---|
1537 | } |
---|
1538 | |
---|
1539 | static int |
---|
1540 | sdhci_release_host(device_t brdev, device_t reqdev) |
---|
1541 | { |
---|
1542 | #ifndef __rtems__ |
---|
1543 | struct sdhci_slot *slot = device_get_ivars(reqdev); |
---|
1544 | |
---|
1545 | SDHCI_LOCK(slot); |
---|
1546 | /* Deactivate led. */ |
---|
1547 | WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl &= ~SDHCI_CTRL_LED); |
---|
1548 | slot->bus_busy--; |
---|
1549 | SDHCI_UNLOCK(slot); |
---|
1550 | wakeup(slot); |
---|
1551 | #endif /* __rtems__ */ |
---|
1552 | return (0); |
---|
1553 | } |
---|
1554 | |
---|
1555 | static void |
---|
1556 | sdhci_cmd_irq(struct sdhci_slot *slot, uint32_t intmask) |
---|
1557 | { |
---|
1558 | |
---|
1559 | if (!slot->curcmd) { |
---|
1560 | slot_printf(slot, "Got command interrupt 0x%08x, but " |
---|
1561 | "there is no active command.\n", intmask); |
---|
1562 | sdhci_dumpregs(slot); |
---|
1563 | return; |
---|
1564 | } |
---|
1565 | if (intmask & SDHCI_INT_TIMEOUT) |
---|
1566 | slot->curcmd->error = MMC_ERR_TIMEOUT; |
---|
1567 | else if (intmask & SDHCI_INT_CRC) |
---|
1568 | slot->curcmd->error = MMC_ERR_BADCRC; |
---|
1569 | else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) |
---|
1570 | slot->curcmd->error = MMC_ERR_FIFO; |
---|
1571 | |
---|
1572 | sdhci_finish_command(slot); |
---|
1573 | } |
---|
1574 | |
---|
1575 | static void |
---|
1576 | sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask) |
---|
1577 | { |
---|
1578 | |
---|
1579 | if (!slot->curcmd) { |
---|
1580 | slot_printf(slot, "Got data interrupt 0x%08x, but " |
---|
1581 | "there is no active command.\n", intmask); |
---|
1582 | sdhci_dumpregs(slot); |
---|
1583 | return; |
---|
1584 | } |
---|
1585 | if (slot->curcmd->data == NULL && |
---|
1586 | (slot->curcmd->flags & MMC_RSP_BUSY) == 0) { |
---|
1587 | slot_printf(slot, "Got data interrupt 0x%08x, but " |
---|
1588 | "there is no active data operation.\n", |
---|
1589 | intmask); |
---|
1590 | sdhci_dumpregs(slot); |
---|
1591 | return; |
---|
1592 | } |
---|
1593 | if (intmask & SDHCI_INT_DATA_TIMEOUT) |
---|
1594 | slot->curcmd->error = MMC_ERR_TIMEOUT; |
---|
1595 | else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) |
---|
1596 | slot->curcmd->error = MMC_ERR_BADCRC; |
---|
1597 | if (slot->curcmd->data == NULL && |
---|
1598 | (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | |
---|
1599 | SDHCI_INT_DMA_END))) { |
---|
1600 | slot_printf(slot, "Got data interrupt 0x%08x, but " |
---|
1601 | "there is busy-only command.\n", intmask); |
---|
1602 | sdhci_dumpregs(slot); |
---|
1603 | slot->curcmd->error = MMC_ERR_INVALID; |
---|
1604 | } |
---|
1605 | if (slot->curcmd->error) { |
---|
1606 | /* No need to continue after any error. */ |
---|
1607 | sdhci_finish_data(slot); |
---|
1608 | return; |
---|
1609 | } |
---|
1610 | |
---|
1611 | /* Handle PIO interrupt. */ |
---|
1612 | if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) |
---|
1613 | sdhci_transfer_pio(slot); |
---|
1614 | /* Handle DMA border. */ |
---|
1615 | if (intmask & SDHCI_INT_DMA_END) { |
---|
1616 | struct mmc_data *data = slot->curcmd->data; |
---|
1617 | size_t left; |
---|
1618 | |
---|
1619 | /* Unload DMA buffer... */ |
---|
1620 | left = data->len - slot->offset; |
---|
1621 | #ifndef __rtems__ |
---|
1622 | if (data->flags & MMC_DATA_READ) { |
---|
1623 | bus_dmamap_sync(slot->dmatag, slot->dmamap, |
---|
1624 | BUS_DMASYNC_POSTREAD); |
---|
1625 | memcpy((u_char*)data->data + slot->offset, slot->dmamem, |
---|
1626 | (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); |
---|
1627 | } else { |
---|
1628 | bus_dmamap_sync(slot->dmatag, slot->dmamap, |
---|
1629 | BUS_DMASYNC_POSTWRITE); |
---|
1630 | } |
---|
1631 | #endif /* __rtems__ */ |
---|
1632 | /* ... and reload it again. */ |
---|
1633 | slot->offset += DMA_BLOCK_SIZE; |
---|
1634 | left = data->len - slot->offset; |
---|
1635 | #ifndef __rtems__ |
---|
1636 | if (data->flags & MMC_DATA_READ) { |
---|
1637 | bus_dmamap_sync(slot->dmatag, slot->dmamap, |
---|
1638 | BUS_DMASYNC_PREREAD); |
---|
1639 | } else { |
---|
1640 | memcpy(slot->dmamem, (u_char*)data->data + slot->offset, |
---|
1641 | (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE); |
---|
1642 | bus_dmamap_sync(slot->dmatag, slot->dmamap, |
---|
1643 | BUS_DMASYNC_PREWRITE); |
---|
1644 | } |
---|
1645 | #endif /* __rtems__ */ |
---|
1646 | /* Interrupt aggregation: Mask border interrupt |
---|
1647 | * for the last page. */ |
---|
1648 | if (left == DMA_BLOCK_SIZE) { |
---|
1649 | slot->intmask &= ~SDHCI_INT_DMA_END; |
---|
1650 | WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask); |
---|
1651 | } |
---|
1652 | /* Restart DMA. */ |
---|
1653 | #ifndef __rtems__ |
---|
1654 | WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr); |
---|
1655 | #else /* __rtems__ */ |
---|
1656 | WR4(slot, SDHCI_DMA_ADDRESS, (uint32_t) ((u_char*)data->data + slot->offset)); |
---|
1657 | #endif /* __rtems__ */ |
---|
1658 | } |
---|
1659 | /* We have got all data. */ |
---|
1660 | if (intmask & SDHCI_INT_DATA_END) |
---|
1661 | sdhci_finish_data(slot); |
---|
1662 | } |
---|
1663 | |
---|
1664 | static void |
---|
1665 | sdhci_acmd_irq(struct sdhci_slot *slot) |
---|
1666 | { |
---|
1667 | uint16_t err; |
---|
1668 | |
---|
1669 | err = RD4(slot, SDHCI_ACMD12_ERR); |
---|
1670 | if (!slot->curcmd) { |
---|
1671 | slot_printf(slot, "Got AutoCMD12 error 0x%04x, but " |
---|
1672 | "there is no active command.\n", err); |
---|
1673 | sdhci_dumpregs(slot); |
---|
1674 | return; |
---|
1675 | } |
---|
1676 | slot_printf(slot, "Got AutoCMD12 error 0x%04x\n", err); |
---|
1677 | sdhci_reset(slot, SDHCI_RESET_CMD); |
---|
1678 | } |
---|
1679 | |
---|
1680 | static void |
---|
1681 | sdhci_intr(void *arg) |
---|
1682 | { |
---|
1683 | struct sdhci_softc *sc = (struct sdhci_softc *)arg; |
---|
1684 | int i; |
---|
1685 | |
---|
1686 | for (i = 0; i < sc->num_slots; i++) { |
---|
1687 | struct sdhci_slot *slot = &sc->slots[i]; |
---|
1688 | uint32_t intmask; |
---|
1689 | |
---|
1690 | SDHCI_LOCK(slot); |
---|
1691 | /* Read slot interrupt status. */ |
---|
1692 | intmask = RD4(slot, SDHCI_INT_STATUS); |
---|
1693 | if (intmask == 0 || intmask == 0xffffffff) { |
---|
1694 | SDHCI_UNLOCK(slot); |
---|
1695 | continue; |
---|
1696 | } |
---|
1697 | if (sdhci_debug > 2) |
---|
1698 | slot_printf(slot, "Interrupt %#x\n", intmask); |
---|
1699 | |
---|
1700 | /* Handle card presence interrupts. */ |
---|
1701 | if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { |
---|
1702 | WR4(slot, SDHCI_INT_STATUS, intmask & |
---|
1703 | (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)); |
---|
1704 | |
---|
1705 | if (intmask & SDHCI_INT_CARD_REMOVE) { |
---|
1706 | if (bootverbose || sdhci_debug) |
---|
1707 | slot_printf(slot, "Card removed\n"); |
---|
1708 | callout_stop(&slot->card_callout); |
---|
1709 | #ifndef __rtems__ |
---|
1710 | taskqueue_enqueue(taskqueue_swi_giant, |
---|
1711 | &slot->card_task); |
---|
1712 | #endif /* __rtems__ */ |
---|
1713 | } |
---|
1714 | if (intmask & SDHCI_INT_CARD_INSERT) { |
---|
1715 | if (bootverbose || sdhci_debug) |
---|
1716 | slot_printf(slot, "Card inserted\n"); |
---|
1717 | callout_reset(&slot->card_callout, hz / 2, |
---|
1718 | sdhci_card_delay, slot); |
---|
1719 | } |
---|
1720 | intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); |
---|
1721 | } |
---|
1722 | /* Handle command interrupts. */ |
---|
1723 | if (intmask & SDHCI_INT_CMD_MASK) { |
---|
1724 | WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_CMD_MASK); |
---|
1725 | sdhci_cmd_irq(slot, intmask & SDHCI_INT_CMD_MASK); |
---|
1726 | } |
---|
1727 | /* Handle data interrupts. */ |
---|
1728 | if (intmask & SDHCI_INT_DATA_MASK) { |
---|
1729 | WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_DATA_MASK); |
---|
1730 | sdhci_data_irq(slot, intmask & SDHCI_INT_DATA_MASK); |
---|
1731 | } |
---|
1732 | /* Handle AutoCMD12 error interrupt. */ |
---|
1733 | if (intmask & SDHCI_INT_ACMD12ERR) { |
---|
1734 | WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_ACMD12ERR); |
---|
1735 | sdhci_acmd_irq(slot); |
---|
1736 | } |
---|
1737 | intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); |
---|
1738 | intmask &= ~SDHCI_INT_ACMD12ERR; |
---|
1739 | intmask &= ~SDHCI_INT_ERROR; |
---|
1740 | /* Handle bus power interrupt. */ |
---|
1741 | if (intmask & SDHCI_INT_BUS_POWER) { |
---|
1742 | WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_BUS_POWER); |
---|
1743 | slot_printf(slot, |
---|
1744 | "Card is consuming too much power!\n"); |
---|
1745 | intmask &= ~SDHCI_INT_BUS_POWER; |
---|
1746 | } |
---|
1747 | /* The rest is unknown. */ |
---|
1748 | if (intmask) { |
---|
1749 | WR4(slot, SDHCI_INT_STATUS, intmask); |
---|
1750 | slot_printf(slot, "Unexpected interrupt 0x%08x.\n", |
---|
1751 | intmask); |
---|
1752 | sdhci_dumpregs(slot); |
---|
1753 | } |
---|
1754 | |
---|
1755 | SDHCI_UNLOCK(slot); |
---|
1756 | } |
---|
1757 | } |
---|
1758 | |
---|
1759 | static int |
---|
1760 | sdhci_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) |
---|
1761 | { |
---|
1762 | struct sdhci_slot *slot = device_get_ivars(child); |
---|
1763 | |
---|
1764 | switch (which) { |
---|
1765 | default: |
---|
1766 | return (EINVAL); |
---|
1767 | case MMCBR_IVAR_BUS_MODE: |
---|
1768 | *(int *)result = slot->host.ios.bus_mode; |
---|
1769 | break; |
---|
1770 | case MMCBR_IVAR_BUS_WIDTH: |
---|
1771 | *(int *)result = slot->host.ios.bus_width; |
---|
1772 | break; |
---|
1773 | case MMCBR_IVAR_CHIP_SELECT: |
---|
1774 | *(int *)result = slot->host.ios.chip_select; |
---|
1775 | break; |
---|
1776 | case MMCBR_IVAR_CLOCK: |
---|
1777 | *(int *)result = slot->host.ios.clock; |
---|
1778 | break; |
---|
1779 | case MMCBR_IVAR_F_MIN: |
---|
1780 | *(int *)result = slot->host.f_min; |
---|
1781 | break; |
---|
1782 | case MMCBR_IVAR_F_MAX: |
---|
1783 | *(int *)result = slot->host.f_max; |
---|
1784 | break; |
---|
1785 | case MMCBR_IVAR_HOST_OCR: |
---|
1786 | *(int *)result = slot->host.host_ocr; |
---|
1787 | break; |
---|
1788 | case MMCBR_IVAR_MODE: |
---|
1789 | *(int *)result = slot->host.mode; |
---|
1790 | break; |
---|
1791 | case MMCBR_IVAR_OCR: |
---|
1792 | *(int *)result = slot->host.ocr; |
---|
1793 | break; |
---|
1794 | case MMCBR_IVAR_POWER_MODE: |
---|
1795 | *(int *)result = slot->host.ios.power_mode; |
---|
1796 | break; |
---|
1797 | case MMCBR_IVAR_VDD: |
---|
1798 | *(int *)result = slot->host.ios.vdd; |
---|
1799 | break; |
---|
1800 | case MMCBR_IVAR_CAPS: |
---|
1801 | *(int *)result = slot->host.caps; |
---|
1802 | break; |
---|
1803 | case MMCBR_IVAR_TIMING: |
---|
1804 | *(int *)result = slot->host.ios.timing; |
---|
1805 | break; |
---|
1806 | case MMCBR_IVAR_MAX_DATA: |
---|
1807 | *(int *)result = 65535; |
---|
1808 | break; |
---|
1809 | } |
---|
1810 | return (0); |
---|
1811 | } |
---|
1812 | |
---|
1813 | static int |
---|
1814 | sdhci_write_ivar(device_t bus, device_t child, int which, uintptr_t value) |
---|
1815 | { |
---|
1816 | struct sdhci_slot *slot = device_get_ivars(child); |
---|
1817 | |
---|
1818 | switch (which) { |
---|
1819 | default: |
---|
1820 | return (EINVAL); |
---|
1821 | case MMCBR_IVAR_BUS_MODE: |
---|
1822 | slot->host.ios.bus_mode = value; |
---|
1823 | break; |
---|
1824 | case MMCBR_IVAR_BUS_WIDTH: |
---|
1825 | slot->host.ios.bus_width = value; |
---|
1826 | break; |
---|
1827 | case MMCBR_IVAR_CHIP_SELECT: |
---|
1828 | slot->host.ios.chip_select = value; |
---|
1829 | break; |
---|
1830 | case MMCBR_IVAR_CLOCK: |
---|
1831 | if (value > 0) { |
---|
1832 | #ifndef __rtems__ |
---|
1833 | uint32_t clock = slot->max_clk; |
---|
1834 | int i; |
---|
1835 | |
---|
1836 | for (i = 0; i < 8; i++) { |
---|
1837 | if (clock <= value) |
---|
1838 | break; |
---|
1839 | clock >>= 1; |
---|
1840 | } |
---|
1841 | slot->host.ios.clock = clock; |
---|
1842 | #else /* __rtems__ */ |
---|
1843 | slot->host.ios.clock = value; |
---|
1844 | #endif /* __rtems__ */ |
---|
1845 | } else |
---|
1846 | slot->host.ios.clock = 0; |
---|
1847 | break; |
---|
1848 | case MMCBR_IVAR_MODE: |
---|
1849 | slot->host.mode = value; |
---|
1850 | break; |
---|
1851 | case MMCBR_IVAR_OCR: |
---|
1852 | slot->host.ocr = value; |
---|
1853 | break; |
---|
1854 | case MMCBR_IVAR_POWER_MODE: |
---|
1855 | slot->host.ios.power_mode = value; |
---|
1856 | break; |
---|
1857 | case MMCBR_IVAR_VDD: |
---|
1858 | slot->host.ios.vdd = value; |
---|
1859 | break; |
---|
1860 | case MMCBR_IVAR_TIMING: |
---|
1861 | slot->host.ios.timing = value; |
---|
1862 | break; |
---|
1863 | case MMCBR_IVAR_CAPS: |
---|
1864 | case MMCBR_IVAR_HOST_OCR: |
---|
1865 | case MMCBR_IVAR_F_MIN: |
---|
1866 | case MMCBR_IVAR_F_MAX: |
---|
1867 | case MMCBR_IVAR_MAX_DATA: |
---|
1868 | return (EINVAL); |
---|
1869 | } |
---|
1870 | return (0); |
---|
1871 | } |
---|
1872 | |
---|
1873 | static device_method_t sdhci_methods[] = { |
---|
1874 | /* device_if */ |
---|
1875 | DEVMETHOD(device_probe, sdhci_probe), |
---|
1876 | DEVMETHOD(device_attach, sdhci_attach), |
---|
1877 | DEVMETHOD(device_detach, sdhci_detach), |
---|
1878 | DEVMETHOD(device_suspend, sdhci_suspend), |
---|
1879 | DEVMETHOD(device_resume, sdhci_resume), |
---|
1880 | |
---|
1881 | /* Bus interface */ |
---|
1882 | DEVMETHOD(bus_read_ivar, sdhci_read_ivar), |
---|
1883 | DEVMETHOD(bus_write_ivar, sdhci_write_ivar), |
---|
1884 | |
---|
1885 | /* mmcbr_if */ |
---|
1886 | DEVMETHOD(mmcbr_update_ios, sdhci_update_ios), |
---|
1887 | DEVMETHOD(mmcbr_request, sdhci_request), |
---|
1888 | DEVMETHOD(mmcbr_get_ro, sdhci_get_ro), |
---|
1889 | DEVMETHOD(mmcbr_acquire_host, sdhci_acquire_host), |
---|
1890 | DEVMETHOD(mmcbr_release_host, sdhci_release_host), |
---|
1891 | |
---|
1892 | {0, 0}, |
---|
1893 | }; |
---|
1894 | |
---|
1895 | static driver_t sdhci_driver = { |
---|
1896 | "sdhci", |
---|
1897 | sdhci_methods, |
---|
1898 | sizeof(struct sdhci_softc), |
---|
1899 | }; |
---|
1900 | static devclass_t sdhci_devclass; |
---|
1901 | |
---|
1902 | |
---|
1903 | #ifndef __rtems__ |
---|
1904 | DRIVER_MODULE(sdhci, pci, sdhci_driver, sdhci_devclass, 0, 0); |
---|
1905 | #else /* __rtems__ */ |
---|
1906 | DRIVER_MODULE(sdhci, nexus, sdhci_driver, sdhci_devclass, 0, 0); |
---|
1907 | #endif /* __rtems__ */ |
---|