sa11xx_pcic.c revision 1.1 1 /* $NetBSD: sa11xx_pcic.c,v 1.1 2001/07/08 23:37:54 rjs Exp $ */
2
3 /*
4 * Copyright (c) 2001 IWAMOTO Toshihiro. All rights reserved.
5 * Copyright (c) 1997 Marc Horowitz. 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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Marc Horowitz.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Common code for SA11x0 based PCMCIA modules
35 */
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/callout.h>
42 #include <sys/kernel.h>
43 #include <sys/kthread.h>
44 #include <sys/malloc.h>
45 #include <uvm/uvm.h>
46
47 #include <machine/bus.h>
48 #include <machine/intr.h>
49
50 #include <dev/pcmcia/pcmciareg.h>
51 #include <dev/pcmcia/pcmciavar.h>
52 #include <dev/pcmcia/pcmciachip.h>
53
54 #include <arm/sa11x0/sa11x0_reg.h>
55 #include <arm/sa11x0/sa11x0_var.h>
56 #include <arm/sa11x0/sa11xx_pcicreg.h>
57 #include <arm/sa11x0/sa11xx_pcicvar.h>
58
59 static int sapcic_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
60 struct pcmcia_mem_handle *);
61 static void sapcic_mem_free(pcmcia_chipset_handle_t,
62 struct pcmcia_mem_handle *);
63 static int sapcic_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
64 bus_size_t, struct pcmcia_mem_handle *,
65 bus_addr_t *, int *);
66 static void sapcic_mem_unmap(pcmcia_chipset_handle_t, int);
67 static int sapcic_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
68 bus_size_t, bus_size_t,
69 struct pcmcia_io_handle *);
70 static void sapcic_io_free(pcmcia_chipset_handle_t,
71 struct pcmcia_io_handle *);
72 static int sapcic_io_map(pcmcia_chipset_handle_t, int,
73 bus_addr_t, bus_size_t,
74 struct pcmcia_io_handle *, int *);
75 static void sapcic_io_unmap(pcmcia_chipset_handle_t, int);
76 static void *sapcic_intr_establish(pcmcia_chipset_handle_t,
77 struct pcmcia_function *, int,
78 int (*)(void *), void *);
79 static void sapcic_intr_disestablish(pcmcia_chipset_handle_t,
80 void *);
81 static void sapcic_socket_enable(pcmcia_chipset_handle_t);
82 static void sapcic_socket_disable(pcmcia_chipset_handle_t);
83
84 static void sapcic_event_thread(void *);
85
86 static void sapcic_delay(int, const char *);
87
88 #ifdef DEBUG
89 #define DPRINTF(arg) printf arg
90 #else
91 #define DPRINTF(arg)
92 #endif
93
94 struct pcmcia_chip_functions sa11x0_pcmcia_functions = {
95 sapcic_mem_alloc,
96 sapcic_mem_free,
97 sapcic_mem_map,
98 sapcic_mem_unmap,
99
100 sapcic_io_alloc,
101 sapcic_io_free,
102 sapcic_io_map,
103 sapcic_io_unmap,
104
105 sapcic_intr_establish,
106 sapcic_intr_disestablish,
107
108 sapcic_socket_enable,
109 sapcic_socket_disable,
110 };
111
112
113 void
114 sapcic_kthread_create(arg)
115 void *arg;
116 {
117 struct sapcic_socket *so = arg;
118
119 /* XXX attach card if already present */
120
121 so->laststatus =(so->pcictag->read)(so, SAPCIC_STATUS_CARD);
122 if (so->laststatus == SAPCIC_CARD_VALID) {
123 printf("%s: card present\n",
124 so->sc->sc_dev.dv_xname);
125
126 pcmcia_card_attach(so->pcmcia);
127 }
128
129 if (kthread_create1(sapcic_event_thread, so, &so->event_thread,
130 "%s,%d", so->sc->sc_dev.dv_xname, so->socket)) {
131 printf("%s: unable to create event thread for socket %d\n",
132 so->sc->sc_dev.dv_xname, so->socket);
133 panic("sapcic_kthread_create");
134 }
135 }
136
137 static void
138 sapcic_event_thread(arg)
139 void *arg;
140 {
141 struct sapcic_socket *so = arg;
142 int newstatus, s;
143
144 while (so->shutdown == 0) {
145 /*
146 * Serialize event processing on the PCIC. We may
147 * sleep while we hold this lock.
148 */
149 (void) lockmgr(&so->sc->sc_lock, LK_EXCLUSIVE, NULL);
150
151 /* sleep .25s to be enqueued chatterling interrupts */
152 (void) tsleep((caddr_t)sapcic_event_thread, PWAIT,
153 "pcicss", hz/4);
154
155 s = splhigh();
156 so->event = 0;
157
158 /* we don't rely on interrupt type */
159 newstatus = (so->pcictag->read)(so, SAPCIC_STATUS_CARD);
160 splx(s);
161
162 if (so->laststatus == newstatus) {
163 /*
164 * No events to process; release the PCIC lock.
165 */
166 (void) lockmgr(&so->sc->sc_lock, LK_RELEASE, NULL);
167 (void) tsleep(&so->event, PWAIT, "pcicev", hz);
168 continue;
169 }
170
171 so->laststatus = newstatus;
172 switch (newstatus) {
173 case SAPCIC_CARD_VALID:
174 printf("%s: insertion event\n",
175 so->sc->sc_dev.dv_xname);
176
177 pcmcia_card_attach(so->pcmcia);
178 break;
179
180 case SAPCIC_CARD_INVALID:
181 printf("%s: removal event\n",
182 so->sc->sc_dev.dv_xname);
183
184 pcmcia_card_detach(so->pcmcia, DETACH_FORCE);
185 break;
186
187 default:
188 panic("sapcic_event_thread: unknown status %d",
189 newstatus);
190 }
191
192 (void) lockmgr(&so->sc->sc_lock, LK_RELEASE, NULL);
193 }
194
195 so->event_thread = NULL;
196
197 /* In case parent is waiting for us to exit. */
198 wakeup(so->sc);
199
200 kthread_exit(0);
201 }
202
203 static void
204 sapcic_delay(timo, wmesg)
205 int timo; /* in milliseconds */
206 const char *wmesg;
207 {
208 #ifdef DIAGNOSTIC
209 if (curproc == NULL)
210 panic("sapcic_delay: called in interrupt context\n");
211 #endif
212
213 tsleep(sapcic_delay, PWAIT, wmesg, roundup(timo * hz, 1000) / 1000);
214 }
215
216 int
217 sapcic_intr(arg)
218 void *arg;
219 {
220 struct sapcic_socket *so = arg;
221
222 so->event++;
223 (so->pcictag->clear_intr)(so->socket);
224 wakeup(&so->event);
225 return 1;
226 }
227
228 static int
229 sapcic_mem_alloc(pch, size, pmh)
230 pcmcia_chipset_handle_t pch;
231 bus_size_t size;
232 struct pcmcia_mem_handle *pmh;
233 {
234 struct sapcic_socket *so = pch;
235
236 /* All we need is bus space tag */
237 memset(pmh, 0, sizeof(*pmh));
238 pmh->memt = so->sc->sc_iot;
239 return (0);
240 }
241
242
243 static void
244 sapcic_mem_free(pch, pmh)
245 pcmcia_chipset_handle_t pch;
246 struct pcmcia_mem_handle *pmh;
247 {
248 }
249
250 static int
251 sapcic_mem_map(pch, kind, card_addr, size, pmh, offsetp, windowp)
252 pcmcia_chipset_handle_t pch;
253 int kind;
254 bus_addr_t card_addr;
255 bus_size_t size;
256 struct pcmcia_mem_handle *pmh;
257 bus_addr_t *offsetp;
258 int *windowp;
259 {
260 struct sapcic_socket *so = pch;
261 int error;
262 bus_addr_t pa;
263
264 pa = trunc_page(card_addr);
265 *offsetp = card_addr - pa;
266 size = round_page(card_addr + size) - pa;
267 pmh->realsize = size;
268
269 pa += SAPCIC_BASE_OFFSET;
270 pa += SAPCIC_SOCKET_OFFSET * so->socket;
271
272 switch (kind & ~PCMCIA_WIDTH_MEM_MASK) {
273 case PCMCIA_MEM_ATTR:
274 pa += SAPCIC_ATTR_OFFSET;
275 break;
276 case PCMCIA_MEM_COMMON:
277 pa += SAPCIC_COMMON_OFFSET;
278 break;
279 default:
280 panic("sapcic_mem_map: bogus kind\n");
281 }
282
283 error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pmh->memh);
284 if (! error)
285 *windowp = (int)pmh->memh;
286 return (error);
287 }
288
289 static void
290 sapcic_mem_unmap(pch, window)
291 pcmcia_chipset_handle_t pch;
292 int window;
293 {
294 struct sapcic_socket *so = pch;
295
296 bus_space_unmap(so->sc->sc_iot, (bus_addr_t)window, 4096); /* XXX */
297 }
298
299 static int
300 sapcic_io_alloc(pch, start, size, align, pih)
301 pcmcia_chipset_handle_t pch;
302 bus_addr_t start;
303 bus_size_t size;
304 bus_size_t align;
305 struct pcmcia_io_handle *pih;
306 {
307 struct sapcic_socket *so = pch;
308 int error;
309 bus_addr_t pa;
310
311 memset(pih, 0, sizeof(*pih));
312 pih->iot = so->sc->sc_iot;
313 pih->addr = start;
314 pih->size = size;
315
316 pa = pih->addr;
317 pa += SAPCIC_BASE_OFFSET;
318 pa += SAPCIC_SOCKET_OFFSET * so->socket;
319
320 DPRINTF(("sapcic_io_alloc: %x %x\n", (unsigned int)pa,
321 (unsigned int)size));
322 /* XXX Are we ignoring alignment constraints? */
323 error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pih->ioh);
324
325 return (error);
326 }
327
328 static void
329 sapcic_io_free(pch, pih)
330 pcmcia_chipset_handle_t pch;
331 struct pcmcia_io_handle *pih;
332 {
333 struct sapcic_socket *so = pch;
334
335 bus_space_unmap(so->sc->sc_iot, pih->ioh, pih->size);
336 }
337
338 static int
339 sapcic_io_map(pch, width, offset, size, pih, windowp)
340 pcmcia_chipset_handle_t pch;
341 int width;
342 bus_addr_t offset;
343 bus_size_t size;
344 struct pcmcia_io_handle *pih;
345 int *windowp;
346 {
347 return (0);
348 }
349
350 static void sapcic_io_unmap(pch, window)
351 pcmcia_chipset_handle_t pch;
352 int window;
353 {
354 }
355
356 static void *
357 sapcic_intr_establish(pch, pf, ipl, fct, arg)
358 pcmcia_chipset_handle_t pch;
359 struct pcmcia_function *pf;
360 int ipl;
361 int (*fct)(void *);
362 void *arg;
363 {
364 struct sapcic_socket *so = pch;
365
366 /* XXX need to check if something should be done here */
367
368 return ((so->pcictag->intr_establish)(so, ipl, fct, arg));
369 }
370
371 static void
372 sapcic_intr_disestablish(pch, ih)
373 pcmcia_chipset_handle_t pch;
374 void *ih;
375 {
376 struct sapcic_socket *so = pch;
377
378 ((so->pcictag->intr_disestablish)(so, ih));
379 }
380
381 static void
382 sapcic_socket_enable(pch)
383 pcmcia_chipset_handle_t pch;
384 {
385 struct sapcic_socket *so = pch;
386 int i;
387
388 #if defined(DIAGNOSTIC) && defined(notyet)
389 if (so->flags & PCIC_FLAG_ENABLED)
390 printf("sapcic_socket_enable: enabling twice\n");
391 #endif
392
393 /* disable interrupts */
394
395 /* power down the socket to reset it, clear the card reset pin */
396 (so->pcictag->set_power)(so, SAPCIC_POWER_OFF);
397
398 /*
399 * wait 300ms until power fails (Tpf). Then, wait 100ms since
400 * we are changing Vcc (Toff).
401 */
402 sapcic_delay(300 + 100, "pccen0");
403
404 /* power up the socket */
405 /* XXX voltage selection should be done in PCMCIA code */
406 if (so->power_capability & SAPCIC_POWER_5V) {
407 (so->pcictag->set_power)(so, SAPCIC_POWER_5V);
408 (so->pcictag->write)(so, SAPCIC_CONTROL_POWERSELECT,
409 SAPCIC_POWER_5V);
410 } else {
411 (so->pcictag->set_power)(so, SAPCIC_POWER_3V);
412 (so->pcictag->write)(so, SAPCIC_CONTROL_POWERSELECT,
413 SAPCIC_POWER_3V);
414 }
415
416 /* enable PCMCIA control lines */
417 (so->pcictag->write)(so, SAPCIC_CONTROL_LINEENABLE, 1);
418
419 /*
420 * wait 100ms until power raise (Tpr) and 20ms to become
421 * stable (Tsu(Vcc)).
422 *
423 * some machines require some more time to be settled
424 * (300ms is added here).
425 */
426 sapcic_delay(100 + 20 + 300, "pccen1");
427
428 /* honor nWAIT signal */
429 (so->pcictag->write)(so, SAPCIC_CONTROL_WAITENABLE, 1);
430 /* now make sure we have reset# active */
431 (so->pcictag->write)(so, SAPCIC_CONTROL_RESET, 1);
432
433 /*
434 * hold RESET at least 10us, this is a min allow for slop in
435 * delay routine.
436 */
437 delay(20);
438
439 /* clear the reset flag */
440 (so->pcictag->write)(so, SAPCIC_CONTROL_RESET, 0);
441
442 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
443 sapcic_delay(20, "pccen2");
444
445 /* wait for the chip to finish initializing */
446 sapcic_delay(10, "pccen3");
447 for(i = 100; i; i--) {
448 if ((so->pcictag->read)(so, SAPCIC_STATUS_READY))
449 break;
450 sapcic_delay(100, "pccen4");
451 }
452 DPRINTF(("sapcic_socket_enable: wait ready %d\n", 100 - i));
453
454 /* finally enable the interrupt */
455
456 }
457
458 static void
459 sapcic_socket_disable(pch)
460 pcmcia_chipset_handle_t pch;
461 {
462 struct sapcic_socket *so = pch;
463
464 /* XXX mask card interrupts */
465
466 /* power down the card */
467 (so->pcictag->set_power)(so, SAPCIC_POWER_OFF);
468
469 /* float controller lines */
470 (so->pcictag->write)(so, SAPCIC_CONTROL_LINEENABLE, 0);
471 }
472