1 /* $NetBSD: gayle_pcmcia.c,v 1.21.12.1 2007/10/03 19:22:22 garbled Exp $ */
6 __KERNEL_RCSID(0, "$NetBSD: gayle_pcmcia.c,v 1.21.12.1 2007/10/03 19:22:22 garbled Exp $");
8 /* PCMCIA front-end driver for A1200's and A600's. */
10 #include <sys/param.h>
11 #include <sys/device.h>
12 #include <sys/kernel.h>
13 #include <sys/kthread.h>
14 #include <sys/systm.h>
18 #include <dev/pcmcia/pcmciareg.h>
19 #include <dev/pcmcia/pcmciavar.h>
21 #include <machine/cpu.h>
22 #include <amiga/amiga/custom.h>
23 #include <amiga/amiga/device.h>
24 #include <amiga/amiga/gayle.h>
25 #include <amiga/amiga/isr.h>
28 /* There is one of these for each slot. And yes, there is only one slot. */
30 struct pccard_softc
*sc
; /* refer to `parent' */
31 int (*intr_func
)(void *);
35 #define SLOT_OCCUPIED 0x01
36 #define SLOT_NEW_CARD_EVENT 0x02
41 struct bus_space_tag io_space
;
42 struct bus_space_tag attr_space
;
43 struct bus_space_tag mem_space
;
44 struct pccard_slot devs
[1];
49 static int pccard_probe(struct device
*, struct cfdata
*, void *);
50 static void pccard_attach(struct device
*, struct device
*, void *);
51 static void pccard_attach_slot(struct pccard_slot
*);
52 static int pccard_intr6(void *);
53 static int pccard_intr2(void *);
54 static void pccard_kthread(void *);
56 static int pcf_mem_alloc(pcmcia_chipset_handle_t
, bus_size_t
,
57 struct pcmcia_mem_handle
*);
58 static void pcf_mem_free(pcmcia_chipset_handle_t
, struct pcmcia_mem_handle
*);
59 static int pcf_mem_map(pcmcia_chipset_handle_t
, int, bus_addr_t
, bus_size_t
,
60 struct pcmcia_mem_handle
*, bus_addr_t
*, int *);
61 static void pcf_mem_unmap(pcmcia_chipset_handle_t
, int);
62 static int pcf_io_alloc(pcmcia_chipset_handle_t
, bus_addr_t
, bus_size_t
,
63 bus_size_t
, struct pcmcia_io_handle
*);
64 static void pcf_io_free(pcmcia_chipset_handle_t
, struct pcmcia_io_handle
*);
65 static int pcf_io_map(pcmcia_chipset_handle_t
, int, bus_addr_t
, bus_size_t
,
66 struct pcmcia_io_handle
*, int *);
67 static void pcf_io_unmap(pcmcia_chipset_handle_t
, int);
68 static void *pcf_intr_establish(pcmcia_chipset_handle_t
,
69 struct pcmcia_function
*, int, int (*)(void *), void *);
70 static void pcf_intr_disestablish(pcmcia_chipset_handle_t
, void *);
71 static void pcf_socket_enable(pcmcia_chipset_handle_t
);
72 static void pcf_socket_disable(pcmcia_chipset_handle_t
);
73 static void pcf_socket_settype(pcmcia_chipset_handle_t
, int);
75 static bsr(pcmio_bsr1
, u_int8_t
);
76 static bsw(pcmio_bsw1
, u_int8_t
);
77 static bsrm(pcmio_bsrm1
, u_int8_t
);
78 static bswm(pcmio_bswm1
, u_int8_t
);
79 static bsrm(pcmio_bsrr1
, u_int8_t
);
80 static bswm(pcmio_bswr1
, u_int8_t
);
81 static bssr(pcmio_bssr1
, u_int8_t
);
82 static bscr(pcmio_bscr1
, u_int8_t
);
84 CFATTACH_DECL(pccard
, sizeof(struct pccard_softc
),
85 pccard_probe
, pccard_attach
, NULL
, NULL
);
87 static struct pcmcia_chip_functions chip_functions
= {
88 pcf_mem_alloc
, pcf_mem_free
,
89 pcf_mem_map
, pcf_mem_unmap
,
90 pcf_io_alloc
, pcf_io_free
,
91 pcf_io_map
, pcf_io_unmap
,
92 pcf_intr_establish
, pcf_intr_disestablish
,
93 pcf_socket_enable
, pcf_socket_disable
,
97 static struct amiga_bus_space_methods pcmio_bs_methods
;
99 static u_int8_t
*reset_card_reg
;
102 pccard_probe(struct device
*dev
, struct cfdata
*cfd
, void *aux
)
105 return (/*is_a600() || */is_a1200()) && matchname(aux
, "pccard");
109 pccard_attach(struct device
*parent
, struct device
*myself
, void *aux
)
111 struct pccard_softc
*self
= (struct pccard_softc
*) myself
;
112 struct pcmciabus_attach_args paa
;
120 pcmcia_base
= uvm_km_alloc(kernel_map
,
121 GAYLE_PCMCIA_END
- GAYLE_PCMCIA_START
,
122 0, UVM_KMF_VAONLY
| UVM_KMF_NOWAIT
);
123 if (pcmcia_base
== 0) {
124 printf("attach failed (no virtual memory)\n");
128 for (i
= GAYLE_PCMCIA_START
; i
< GAYLE_PCMCIA_END
; i
+= PAGE_SIZE
)
129 pmap_enter(vm_map_pmap(kernel_map
),
130 i
- GAYLE_PCMCIA_START
+ pcmcia_base
, i
,
131 VM_PROT_READ
| VM_PROT_WRITE
, true);
132 pmap_update(vm_map_pmap(kernel_map
));
134 /* override the one-byte access methods for I/O space */
135 pcmio_bs_methods
= amiga_bus_stride_1
;
136 pcmio_bs_methods
.bsr1
= pcmio_bsr1
;
137 pcmio_bs_methods
.bsw1
= pcmio_bsw1
;
138 pcmio_bs_methods
.bsrm1
= pcmio_bsrm1
;
139 pcmio_bs_methods
.bswm1
= pcmio_bswm1
;
140 pcmio_bs_methods
.bsrr1
= pcmio_bsrr1
;
141 pcmio_bs_methods
.bswr1
= pcmio_bswr1
;
142 pcmio_bs_methods
.bssr1
= pcmio_bssr1
;
143 pcmio_bs_methods
.bscr1
= pcmio_bscr1
;
145 reset_card_reg
= (u_int8_t
*) pcmcia_base
+
146 (GAYLE_PCMCIA_RESET
- GAYLE_PCMCIA_START
);
148 self
->io_space
.base
= (bus_addr_t
) pcmcia_base
+
149 (GAYLE_PCMCIA_IO_START
- GAYLE_PCMCIA_START
);
150 self
->io_space
.absm
= &pcmio_bs_methods
;
152 self
->attr_space
.base
= (bus_addr_t
) pcmcia_base
+
153 (GAYLE_PCMCIA_ATTR_START
- GAYLE_PCMCIA_START
);
154 self
->attr_space
.absm
= &amiga_bus_stride_1
;
156 /* XXX we should check if the 4M of common memory are actually
157 * RAM or PCMCIA usable.
158 * For now, we just do as if the 4M were RAM and make common memory
159 * point to attribute memory, which is OK for some I/O cards.
161 self
->mem_space
.base
= (bus_addr_t
) pcmcia_base
;
162 self
->mem_space
.absm
= &amiga_bus_stride_1
;
164 self
->devs
[0].sc
= self
;
165 self
->devs
[0].intr_func
= NULL
;
166 self
->devs
[0].intr_arg
= NULL
;
167 self
->devs
[0].flags
= 0;
169 gayle
.pcc_status
= 0;
171 gayle
.pcc_config
= 0;
172 gayle
.intena
&= GAYLE_INT_IDE
;
174 paa
.paa_busname
= "pcmcia";
175 paa
.pct
= &chip_functions
;
176 paa
.pch
= &self
->devs
[0];
180 config_found(myself
, &paa
, simple_devprint
);
181 if (self
->devs
[0].card
== NULL
) {
182 printf("attach failed, config_found() returned NULL\n");
183 pmap_remove(kernel_map
->pmap
, pcmcia_base
,
184 pcmcia_base
+ (GAYLE_PCMCIA_END
- GAYLE_PCMCIA_START
));
185 pmap_update(kernel_map
->pmap
);
186 uvm_deallocate(kernel_map
, pcmcia_base
,
187 GAYLE_PCMCIA_END
- GAYLE_PCMCIA_START
);
191 self
->intr6
.isr_intr
= pccard_intr6
;
192 self
->intr6
.isr_arg
= self
;
193 self
->intr6
.isr_ipl
= 6;
194 add_isr(&self
->intr6
);
196 self
->intr2
.isr_intr
= pccard_intr2
;
197 self
->intr2
.isr_arg
= self
;
198 self
->intr2
.isr_ipl
= 2;
199 add_isr(&self
->intr2
);
201 if (kthread_create(PRI_NONE
, 0, NULL
, pccard_kthread
, self
,
203 printf("%s: can't create kernel thread\n",
204 self
->sc_dev
.dv_xname
);
205 panic("pccard kthread_create() failed");
208 gayle
.intena
|= GAYLE_INT_DETECT
| GAYLE_INT_IREQ
;
210 /* reset the card if it's already there */
211 if (gayle
.pcc_status
& GAYLE_CCMEM_DETECT
) {
213 *reset_card_reg
= 0x0;
216 gayle
.pcc_status
= GAYLE_CCMEM_WP
| GAYLE_CCIO_SPKR
;
219 pccard_attach_slot(&self
->devs
[0]);
223 pccard_intr6(void *arg
)
225 struct pccard_softc
*self
= arg
;
227 if (gayle
.intreq
& GAYLE_INT_DETECT
) {
228 gayle
.intreq
= GAYLE_INT_IDE
| GAYLE_INT_STSCHG
|
229 GAYLE_INT_SPKR
| GAYLE_INT_WP
| GAYLE_INT_IREQ
;
230 self
->devs
[0].flags
|= SLOT_NEW_CARD_EVENT
;
237 pccard_intr2(void *arg
)
239 struct pccard_softc
*self
= arg
;
240 struct pccard_slot
*slot
= &self
->devs
[0];
242 if (slot
->flags
& SLOT_NEW_CARD_EVENT
) {
243 slot
->flags
&= ~SLOT_NEW_CARD_EVENT
;
245 /* reset the registers */
246 gayle
.intreq
= GAYLE_INT_IDE
| GAYLE_INT_DETECT
;
247 gayle
.pcc_status
= GAYLE_CCMEM_WP
| GAYLE_CCIO_SPKR
;
248 gayle
.pcc_config
= 0;
249 pccard_attach_slot(&self
->devs
[0]);
251 int intreq
= gayle
.intreq
&
252 (GAYLE_INT_STSCHG
| GAYLE_INT_WP
| GAYLE_INT_IREQ
);
254 gayle
.intreq
= (intreq
^ 0x2c) | 0xc0;
256 return slot
->flags
& SLOT_OCCUPIED
&&
257 slot
->intr_func
!= NULL
&&
258 slot
->intr_func(slot
->intr_arg
);
265 pccard_kthread(void *arg
)
267 struct pccard_softc
*self
= arg
;
268 struct pccard_slot
*slot
= &self
->devs
[0];
273 if (slot
->flags
& SLOT_NEW_CARD_EVENT
) {
274 slot
->flags
&= ~SLOT_NEW_CARD_EVENT
;
277 /* reset the registers */
278 gayle
.intreq
= GAYLE_INT_IDE
| GAYLE_INT_DETECT
;
279 gayle
.pcc_status
= GAYLE_CCMEM_WP
| GAYLE_CCIO_SPKR
;
280 gayle
.pcc_config
= 0;
281 pccard_attach_slot(&self
->devs
[0]);
285 tsleep(slot
, PWAIT
, "pccthread", hz
);
290 pccard_attach_slot(struct pccard_slot
*slot
)
293 if (!(slot
->flags
& SLOT_OCCUPIED
) &&
294 gayle
.pcc_status
& GAYLE_CCMEM_DETECT
) {
295 if (pcmcia_card_attach(slot
->card
) == 0)
296 slot
->flags
|= SLOT_OCCUPIED
;
301 pcf_mem_alloc(pcmcia_chipset_handle_t pch
, bus_size_t bsz
,
302 struct pcmcia_mem_handle
*pcmh
)
304 struct pccard_slot
*slot
= (struct pccard_slot
*) pch
;
306 pcmh
->memt
= &slot
->sc
->attr_space
;
307 pcmh
->memh
= pcmh
->memt
->base
;
312 pcf_mem_free(pcmcia_chipset_handle_t pch
, struct pcmcia_mem_handle
*memh
)
317 pcf_mem_map(pcmcia_chipset_handle_t pch
, int kind
, bus_addr_t addr
,
318 bus_size_t size
, struct pcmcia_mem_handle
*pcmh
,
319 bus_addr_t
*offsetp
, int *windowp
)
321 struct pccard_slot
*slot
= (struct pccard_slot
*) pch
;
323 /* Ignore width requirements */
324 kind
&= ~PCMCIA_WIDTH_MEM_MASK
;
327 case PCMCIA_MEM_ATTR
:
328 pcmh
->memt
= &slot
->sc
->attr_space
;
330 case PCMCIA_MEM_COMMON
:
331 pcmh
->memt
= &slot
->sc
->mem_space
;
334 /* This means that this code needs an update/a bugfix */
335 printf(__FILE__
": unknown kind %d of PCMCIA memory\n", kind
);
339 bus_space_map(pcmh
->memt
, addr
, size
, 0, &pcmh
->memh
);
341 *windowp
= 0; /* unused */
347 pcf_mem_unmap(pcmcia_chipset_handle_t pch
, int win
)
352 pcf_io_alloc(pcmcia_chipset_handle_t pch
, bus_addr_t start
, bus_size_t size
,
353 bus_size_t align
, struct pcmcia_io_handle
*pcihp
)
355 struct pccard_slot
*slot
= (struct pccard_slot
*) pch
;
357 pcihp
->iot
= &slot
->sc
->io_space
;
358 pcihp
->ioh
= pcihp
->iot
->base
;
363 pcf_io_free(pcmcia_chipset_handle_t pch
, struct pcmcia_io_handle
*pcihp
)
368 pcf_io_map(pcmcia_chipset_handle_t pch
, int width
, bus_addr_t offset
,
369 bus_size_t size
, struct pcmcia_io_handle
*pcihp
, int *windowp
)
371 struct pccard_slot
*slot
= (struct pccard_slot
*) pch
;
373 pcihp
->iot
= &slot
->sc
->io_space
;
374 bus_space_map(pcihp
->iot
, offset
, size
, 0, &pcihp
->ioh
);
376 *windowp
= 0; /* unused */
381 pcf_io_unmap(pcmcia_chipset_handle_t pch
, int win
)
386 pcf_intr_establish(pcmcia_chipset_handle_t pch
, struct pcmcia_function
*pf
,
387 int ipl
, int (*func
)(void *), void *arg
)
389 struct pccard_slot
*slot
= (struct pccard_slot
*) pch
;
393 if (slot
->intr_func
== NULL
) {
394 slot
->intr_func
= func
;
395 slot
->intr_arg
= arg
;
397 /* if we are here, we need to put intrs into a list */
398 printf("ARGH! see " __FILE__
"\n");
407 pcf_intr_disestablish(pcmcia_chipset_handle_t pch
, void *intr_handler
)
409 struct pccard_slot
*slot
= (struct pccard_slot
*) intr_handler
;
412 slot
->intr_func
= NULL
;
413 slot
->intr_arg
= NULL
;
418 pcf_socket_enable(pcmcia_chipset_handle_t pch
)
423 pcf_socket_disable(pcmcia_chipset_handle_t pch
)
428 pcf_socket_settype(pcmcia_chipset_handle_t pch
, int type
) {
432 pcmio_bsr1(bus_space_handle_t h
, bus_size_t o
)
435 return *((volatile u_int8_t
*) h
+ o
+ (o
& 1 ? 0xffff : 0));
439 pcmio_bsw1(bus_space_handle_t h
, bus_size_t o
, unsigned v
)
442 *((volatile u_int8_t
*) h
+ o
+ (o
& 1 ? 0xffff : 0)) = v
;
446 pcmio_bsrm1(bus_space_handle_t h
, bus_size_t o
, u_int8_t
*p
, bus_size_t c
)
448 volatile u_int8_t
*src
= (volatile u_int8_t
*)
449 (h
+ o
+ (o
& 1 ? 0xffff : 0));
452 /* XXX we can (should, must) optimize this if c >= 4 */
459 pcmio_bswm1(bus_space_handle_t h
, bus_size_t o
, const u_int8_t
*p
, bus_size_t c
)
461 volatile u_int8_t
*dst
= (volatile u_int8_t
*)
462 (h
+ o
+ (o
& 1 ? 0xffff : 0));
465 /* XXX we can (should, must) optimize this if c >= 4 */
471 pcmio_bsrr1(bus_space_handle_t h
, bus_size_t o
, u_int8_t
*p
, bus_size_t c
)
473 volatile u_int8_t
*cp1
;
474 volatile u_int8_t
*cp2
;
475 volatile u_int8_t
*temp
;
478 cp1
= (volatile u_int8_t
*) h
+ o
+ 0x10000;
479 cp2
= (volatile u_int8_t
*) h
+ o
;
481 cp1
= (volatile u_int8_t
*) h
+ o
;
482 cp2
= (volatile u_int8_t
*) h
+ o
+ 0x10000 + 2;
485 /* XXX we can (should, must) optimize this if c >= 4 */
490 /* swap pointers - hope gcc generates exg for this ;) */
499 pcmio_bswr1(bus_space_handle_t h
, bus_size_t o
, const u_int8_t
*p
, bus_size_t c
)
501 volatile u_int8_t
*cp1
;
502 volatile u_int8_t
*cp2
;
503 volatile u_int8_t
*temp
;
506 cp1
= (volatile u_int8_t
*) h
+ o
+ 0x10000;
507 cp2
= (volatile u_int8_t
*) h
+ o
;
509 cp1
= (volatile u_int8_t
*) h
+ o
;
510 cp2
= (volatile u_int8_t
*) h
+ o
+ 0x10000 + 2;
513 /* XXX we can (should, must) optimize this if c >= 4 */
518 /* swap pointers - hope gcc generates exg for this ;) */
526 pcmio_bssr1(bus_space_handle_t h
, bus_size_t o
, unsigned v
, bus_size_t c
)
529 panic("pcmio_bssr1 is not defined (" __FILE__
")");
533 pcmio_bscr1(bus_space_handle_t h
, bus_size_t o
, bus_space_handle_t g
,
534 bus_size_t q
, bus_size_t c
)
537 panic("pcmio_bscr1 is not defined (" __FILE__
")");