1 /* $NetBSD: stp4020.c,v 1.63 2009/09/18 12:23:16 tsutsui Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.63 2009/09/18 12:23:16 tsutsui Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/malloc.h>
43 #include <sys/extent.h>
45 #include <sys/kernel.h>
46 #include <sys/kthread.h>
47 #include <sys/device.h>
50 #include <dev/pcmcia/pcmciareg.h>
51 #include <dev/pcmcia/pcmciavar.h>
52 #include <dev/pcmcia/pcmciachip.h>
56 #include <dev/sbus/sbusvar.h>
57 #include <dev/sbus/stp4020reg.h>
59 #define STP4020_DEBUG 1 /* XXX-temp */
62 * We use the three available windows per socket in a simple, fixed
63 * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
64 * spaces into sbus space.
66 #define STP_WIN_ATTR 0 /* index of the attribute memory space window */
67 #define STP_WIN_MEM 1 /* index of the common memory space window */
68 #define STP_WIN_IO 2 /* index of the io space window */
71 #if defined(STP4020_DEBUG)
72 int stp4020_debug
= 0;
73 #define DPRINTF(x) do { if (stp4020_debug) printf x; } while(0)
79 * Event queue; events detected in an interrupt context go here
80 * awaiting attention from our event handling thread.
82 struct stp4020_event
{
83 SIMPLEQ_ENTRY(stp4020_event
) se_q
;
87 /* Defined event types */
88 #define STP4020_EVENT_INSERTION 0
89 #define STP4020_EVENT_REMOVAL 1
94 struct stp4020_socket
{
95 struct stp4020_softc
*sc
; /* Back link */
97 #define STP4020_SOCKET_BUSY 0x0001
98 int sock
; /* Socket number (0 or 1) */
99 int sbus_intno
; /* Do we use first (0) or second (1)
102 int int_enable
; /* ICR0 value for interrupt enabled */
103 int int_disable
; /* ICR0 value for interrupt disabled */
105 bus_space_tag_t tag
; /* socket control io */
106 bus_space_handle_t regs
; /* space */
107 bus_space_tag_t pcmciat
; /* io space for pcmcia */
108 struct device
*pcmcia
; /* Associated PCMCIA device */
109 int (*intrhandler
) /* Card driver interrupt handler */
111 void *intrarg
; /* Card interrupt handler argument */
113 void *softint
; /* cookie for the softintr */
117 bus_space_handle_t winaddr
;/* this window's address */
118 } windows
[STP4020_NWIN
];
122 struct stp4020_softc
{
123 struct device sc_dev
; /* Base device */
124 pcmcia_chipset_tag_t sc_pct
; /* Chipset methods */
126 struct lwp
*event_thread
; /* event handling thread */
127 SIMPLEQ_HEAD(, stp4020_event
) events
; /* Pending events for thread */
129 struct stp4020_socket sc_socks
[STP4020_NSOCK
];
136 static int stp4020print(void *, const char *);
137 static int stp4020match(device_t
, cfdata_t
, void *);
138 static void stp4020attach(device_t
, device_t
, void *);
139 static int stp4020_intr(void *);
140 static void stp4020_map_window(struct stp4020_socket
*h
, int win
, int speed
);
141 static void stp4020_calc_speed(int bus_speed
, int ns
, int *length
, int *cmd_delay
);
143 static void stp4020_intr_dispatch(void *arg
);
146 CFATTACH_DECL(nell
, sizeof(struct stp4020_softc
),
147 stp4020match
, stp4020attach
, NULL
, NULL
);
150 static void stp4020_dump_regs(struct stp4020_socket
*);
153 static int stp4020_rd_sockctl(struct stp4020_socket
*, int);
154 static void stp4020_wr_sockctl(struct stp4020_socket
*, int, int);
155 static int stp4020_rd_winctl(struct stp4020_socket
*, int, int);
156 static void stp4020_wr_winctl(struct stp4020_socket
*, int, int, int);
158 void stp4020_delay(struct stp4020_softc
*sc
, unsigned int);
159 void stp4020_attach_socket(struct stp4020_socket
*, int);
160 void stp4020_event_thread(void *);
161 void stp4020_queue_event(struct stp4020_softc
*, int, int);
163 int stp4020_chip_mem_alloc(pcmcia_chipset_handle_t
, bus_size_t
,
164 struct pcmcia_mem_handle
*);
165 void stp4020_chip_mem_free(pcmcia_chipset_handle_t
,
166 struct pcmcia_mem_handle
*);
167 int stp4020_chip_mem_map(pcmcia_chipset_handle_t
, int, bus_addr_t
,
168 bus_size_t
, struct pcmcia_mem_handle
*,
169 bus_size_t
*, int *);
170 void stp4020_chip_mem_unmap(pcmcia_chipset_handle_t
, int);
172 int stp4020_chip_io_alloc(pcmcia_chipset_handle_t
,
173 bus_addr_t
, bus_size_t
, bus_size_t
,
174 struct pcmcia_io_handle
*);
175 void stp4020_chip_io_free(pcmcia_chipset_handle_t
,
176 struct pcmcia_io_handle
*);
177 int stp4020_chip_io_map(pcmcia_chipset_handle_t
, int, bus_addr_t
,
178 bus_size_t
, struct pcmcia_io_handle
*, int *);
179 void stp4020_chip_io_unmap(pcmcia_chipset_handle_t
, int);
181 void stp4020_chip_socket_enable(pcmcia_chipset_handle_t
);
182 void stp4020_chip_socket_disable(pcmcia_chipset_handle_t
);
183 void stp4020_chip_socket_settype(pcmcia_chipset_handle_t
, int);
184 void *stp4020_chip_intr_establish(pcmcia_chipset_handle_t
,
185 struct pcmcia_function
*, int,
186 int (*)(void *), void *);
187 void stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t
, void *);
189 /* Our PCMCIA chipset methods */
190 static struct pcmcia_chip_functions stp4020_functions
= {
191 stp4020_chip_mem_alloc
,
192 stp4020_chip_mem_free
,
193 stp4020_chip_mem_map
,
194 stp4020_chip_mem_unmap
,
196 stp4020_chip_io_alloc
,
197 stp4020_chip_io_free
,
199 stp4020_chip_io_unmap
,
201 stp4020_chip_intr_establish
,
202 stp4020_chip_intr_disestablish
,
204 stp4020_chip_socket_enable
,
205 stp4020_chip_socket_disable
,
206 stp4020_chip_socket_settype
,
212 stp4020_rd_sockctl(struct stp4020_socket
*h
, int idx
)
214 int o
= ((STP4020_SOCKREGS_SIZE
* (h
->sock
)) + idx
);
215 return (bus_space_read_2(h
->tag
, h
->regs
, o
));
219 stp4020_wr_sockctl(struct stp4020_socket
*h
, int idx
, int v
)
221 int o
= (STP4020_SOCKREGS_SIZE
* (h
->sock
)) + idx
;
222 bus_space_write_2(h
->tag
, h
->regs
, o
, v
);
226 stp4020_rd_winctl(struct stp4020_socket
*h
, int win
, int idx
)
228 int o
= (STP4020_SOCKREGS_SIZE
* (h
->sock
)) +
229 (STP4020_WINREGS_SIZE
* win
) + idx
;
230 return (bus_space_read_2(h
->tag
, h
->regs
, o
));
234 stp4020_wr_winctl(struct stp4020_socket
*h
, int win
, int idx
, int v
)
236 int o
= (STP4020_SOCKREGS_SIZE
* (h
->sock
)) +
237 (STP4020_WINREGS_SIZE
* win
) + idx
;
239 bus_space_write_2(h
->tag
, h
->regs
, o
, v
);
242 #ifndef SUN4U /* XXX - move to SBUS machdep function? */
244 static uint16_t stp4020_read_2(bus_space_tag_t
,
247 static uint32_t stp4020_read_4(bus_space_tag_t
,
250 static uint64_t stp4020_read_8(bus_space_tag_t
,
253 static void stp4020_write_2(bus_space_tag_t
,
257 static void stp4020_write_4(bus_space_tag_t
,
261 static void stp4020_write_8(bus_space_tag_t
,
267 stp4020_read_2(bus_space_tag_t space
, bus_space_handle_t handle
, bus_size_t offset
)
269 return (le16toh(*(volatile uint16_t *)(handle
+ offset
)));
273 stp4020_read_4(bus_space_tag_t space
, bus_space_handle_t handle
, bus_size_t offset
)
275 return (le32toh(*(volatile uint32_t *)(handle
+ offset
)));
279 stp4020_read_8(bus_space_tag_t space
, bus_space_handle_t handle
, bus_size_t offset
)
281 return (le64toh(*(volatile uint64_t *)(handle
+ offset
)));
285 stp4020_write_2(bus_space_tag_t space
, bus_space_handle_t handle
, bus_size_t offset
, uint16_t value
)
287 (*(volatile uint16_t *)(handle
+ offset
)) = htole16(value
);
291 stp4020_write_4(bus_space_tag_t space
, bus_space_handle_t handle
, bus_size_t offset
, uint32_t value
)
293 (*(volatile uint32_t *)(handle
+ offset
)) = htole32(value
);
297 stp4020_write_8(bus_space_tag_t space
, bus_space_handle_t handle
, bus_size_t offset
, uint64_t value
)
299 (*(volatile uint64_t *)(handle
+ offset
)) = htole64(value
);
304 stp4020print(void *aux
, const char *busname
)
306 struct pcmciabus_attach_args
*paa
= aux
;
307 struct stp4020_socket
*h
= paa
->pch
;
309 aprint_normal(" socket %d", h
->sock
);
314 stp4020match(device_t parent
, cfdata_t cf
, void *aux
)
316 struct sbus_attach_args
*sa
= aux
;
318 return (strcmp("SUNW,pcmcia", sa
->sa_name
) == 0);
322 * Attach all the sub-devices we can find
325 stp4020attach(device_t parent
, device_t self
, void *aux
)
327 struct sbus_attach_args
*sa
= aux
;
328 struct stp4020_softc
*sc
= device_private(self
);
330 int rev
, i
, sbus_intno
, hw_ipl
;
331 bus_space_handle_t bh
;
333 /* Transfer bus tags */
337 tag
= bus_space_tag_alloc(sa
->sa_bustag
, sc
);
339 aprint_error_dev(self
, "attach: out of memory\n");
342 tag
->sparc_read_2
= stp4020_read_2
;
343 tag
->sparc_read_4
= stp4020_read_4
;
344 tag
->sparc_read_8
= stp4020_read_8
;
345 tag
->sparc_write_2
= stp4020_write_2
;
346 tag
->sparc_write_4
= stp4020_write_4
;
347 tag
->sparc_write_8
= stp4020_write_8
;
350 /* check interrupt options, decide if we need a softint */
353 * On sparc64 the hardware interrupt priority does not restrict
354 * the IPL we run our interrupt handler on, so we can always just
355 * use the first interrupt and reqest the handler to run at
362 * We need to check if one of the available interrupts has
363 * a priority that allows us to establish a handler at IPL_VM.
364 * If not (hard to imagine), use a soft interrupt.
367 for (i
= 0; i
< sa
->sa_nintr
; i
++) {
368 struct sbus_softc
*bus
=
369 (struct sbus_softc
*) sa
->sa_bustag
->cookie
;
370 int ipl
= bus
->sc_intr2ipl
[sa
->sa_intr
[i
].oi_pri
];
373 sc
->sc_use_softint
= false;
378 if (sbus_intno
== -1) {
380 * We have not found a usable hardware interrupt - so
381 * use a softint to bounce to the proper IPL.
383 printf("no usable HW interrupt found, using softint\n");
385 sc
->sc_use_softint
= true;
390 /* Set up per-socket static initialization */
391 sc
->sc_socks
[0].sc
= sc
->sc_socks
[1].sc
= sc
;
392 sc
->sc_socks
[0].tag
= sc
->sc_socks
[1].tag
= sa
->sa_bustag
;
394 * XXX we rely on "tag" accepting the same handle-domain
397 sc
->sc_socks
[0].pcmciat
= sc
->sc_socks
[1].pcmciat
= tag
;
398 sc
->sc_socks
[0].sbus_intno
=
399 sc
->sc_socks
[1].sbus_intno
= sbus_intno
;
401 if (sa
->sa_nreg
< 8) {
402 printf("%s: only %d register sets\n",
403 device_xname(self
), sa
->sa_nreg
);
407 if (sa
->sa_nintr
!= 2) {
408 printf("%s: expect 2 interrupt Sbus levels; got %d\n",
409 device_xname(self
), sa
->sa_nintr
);
413 #define STP4020_BANK_PROM 0
414 #define STP4020_BANK_CTRL 4
415 for (i
= 0; i
< 8; i
++) {
418 * STP4020 Register address map:
420 * banks 1-3: socket 0, windows 0-2
421 * bank 4: control registers
422 * banks 5-7: socket 1, windows 0-2
425 if (i
== STP4020_BANK_PROM
)
429 if (sbus_bus_map(sa
->sa_bustag
,
430 sa
->sa_reg
[i
].oa_space
,
431 sa
->sa_reg
[i
].oa_base
,
432 sa
->sa_reg
[i
].oa_size
,
434 aprint_error_dev(self
, "attach: cannot map registers\n");
438 if (i
== STP4020_BANK_CTRL
) {
440 * Copy tag and handle to both socket structures
441 * for easy access in control/status IO functions.
443 sc
->sc_socks
[0].regs
= sc
->sc_socks
[1].regs
= bh
;
444 } else if (i
< STP4020_BANK_CTRL
) {
446 sc
->sc_socks
[0].windows
[i
-1].winaddr
= bh
;
449 sc
->sc_socks
[1].windows
[i
-5].winaddr
= bh
;
453 /* We only use one interrupt level. */
454 if (sa
->sa_nintr
> sbus_intno
) {
455 bus_intr_establish(sa
->sa_bustag
,
456 sa
->sa_intr
[sbus_intno
].oi_pri
,
457 hw_ipl
, stp4020_intr
, sc
);
460 rev
= stp4020_rd_sockctl(&sc
->sc_socks
[0], STP4020_ISR1_IDX
) &
462 printf(": rev %x\n", rev
);
464 sc
->sc_pct
= (pcmcia_chipset_tag_t
)&stp4020_functions
;
466 SIMPLEQ_INIT(&sc
->events
);
468 for (i
= 0; i
< STP4020_NSOCK
; i
++) {
469 struct stp4020_socket
*h
= &sc
->sc_socks
[i
];
474 stp4020_dump_regs(h
);
476 stp4020_attach_socket(h
, sa
->sa_frequency
);
480 * Arrange that a kernel thread be created to handle
481 * insert/removal events.
483 if (kthread_create(PRI_NONE
, 0, NULL
, stp4020_event_thread
, sc
,
484 &sc
->event_thread
, "%s", device_xname(self
))) {
485 panic("%s: unable to create event thread", device_xname(self
));
490 stp4020_attach_socket(struct stp4020_socket
*h
, int speed
)
492 struct pcmciabus_attach_args paa
;
495 /* no interrupt handlers yet */
496 h
->intrhandler
= NULL
;
504 /* Map all three windows */
505 stp4020_map_window(h
, STP_WIN_ATTR
, speed
);
506 stp4020_map_window(h
, STP_WIN_MEM
, speed
);
507 stp4020_map_window(h
, STP_WIN_IO
, speed
);
509 /* Configure one pcmcia device per socket */
510 paa
.paa_busname
= "pcmcia";
511 paa
.pct
= (pcmcia_chipset_tag_t
)h
->sc
->sc_pct
;
512 paa
.pch
= (pcmcia_chipset_handle_t
)h
;
514 paa
.iosize
= STP4020_WINDOW_SIZE
;
516 h
->pcmcia
= config_found(&h
->sc
->sc_dev
, &paa
, stp4020print
);
518 if (h
->pcmcia
== NULL
)
522 * There's actually a pcmcia bus attached; initialize the slot.
526 * Clear things up before we enable status change interrupts.
527 * This seems to not be fully initialized by the PROM.
529 stp4020_wr_sockctl(h
, STP4020_ICR1_IDX
, 0);
530 stp4020_wr_sockctl(h
, STP4020_ICR0_IDX
, 0);
531 stp4020_wr_sockctl(h
, STP4020_ISR1_IDX
, 0x3fff);
532 stp4020_wr_sockctl(h
, STP4020_ISR0_IDX
, 0x3fff);
535 * Enable socket status change interrupts.
536 * We only use one common interrupt for status change
537 * and IO, to avoid locking issues.
539 v
= STP4020_ICR0_ALL_STATUS_IE
540 | (h
->sbus_intno
? STP4020_ICR0_SCILVL_SB1
541 : STP4020_ICR0_SCILVL_SB0
);
542 stp4020_wr_sockctl(h
, STP4020_ICR0_IDX
, v
);
544 /* Get live status bits from ISR0 and clear pending interrupts */
545 v
= stp4020_rd_sockctl(h
, STP4020_ISR0_IDX
);
546 stp4020_wr_sockctl(h
, STP4020_ISR0_IDX
, v
);
548 if ((v
& (STP4020_ISR0_CD1ST
|STP4020_ISR0_CD2ST
)) == 0)
551 pcmcia_card_attach(h
->pcmcia
);
552 h
->flags
|= STP4020_SOCKET_BUSY
;
556 * The actual event handling thread.
559 stp4020_event_thread(void *arg
)
561 struct stp4020_softc
*sc
= arg
;
562 struct stp4020_event
*e
;
566 struct stp4020_socket
*h
;
570 if ((e
= SIMPLEQ_FIRST(&sc
->events
)) == NULL
) {
572 (void)tsleep(&sc
->events
, PWAIT
, "nellevt", 0);
575 SIMPLEQ_REMOVE_HEAD(&sc
->events
, se_q
);
579 if (n
< 0 || n
>= STP4020_NSOCK
)
580 panic("stp4020_event_thread: wayward socket number %d",
583 h
= &sc
->sc_socks
[n
];
584 switch (e
->se_type
) {
585 case STP4020_EVENT_INSERTION
:
586 pcmcia_card_attach(h
->pcmcia
);
588 case STP4020_EVENT_REMOVAL
:
589 pcmcia_card_detach(h
->pcmcia
, DETACH_FORCE
);
592 panic("stp4020_event_thread: unknown event type %d",
600 stp4020_queue_event(struct stp4020_softc
*sc
, int sock
, int event
)
602 struct stp4020_event
*e
;
605 e
= malloc(sizeof(*e
), M_TEMP
, M_NOWAIT
);
607 panic("stp4020_queue_event: can't allocate event");
612 SIMPLEQ_INSERT_TAIL(&sc
->events
, e
, se_q
);
619 * Softinterrupt called to invoke the real driver interrupt handler.
622 stp4020_intr_dispatch(void *arg
)
624 struct stp4020_socket
*h
= arg
;
627 /* invoke driver handler */
628 h
->intrhandler(h
->intrarg
);
630 /* enable SBUS interrupts for pcmcia interrupts again */
632 stp4020_wr_sockctl(h
, STP4020_ICR0_IDX
, h
->int_enable
);
638 stp4020_intr(void *arg
)
640 struct stp4020_softc
*sc
= arg
;
644 int i
, r
= 0, cd_change
= 0;
648 /* protect hardware access by splhigh against softint */
653 * Check each socket for pending requests.
655 for (i
= 0 ; i
< STP4020_NSOCK
; i
++) {
656 struct stp4020_socket
*h
;
659 h
= &sc
->sc_socks
[i
];
661 v
= stp4020_rd_sockctl(h
, STP4020_ISR0_IDX
);
663 /* Ack all interrupts at once. */
664 stp4020_wr_sockctl(h
, STP4020_ISR0_IDX
, v
);
667 if (stp4020_debug
!= 0) {
669 snprintb(bits
, sizeof(bits
), STP4020_ISR0_IOBITS
, v
);
670 printf("stp4020_statintr: ISR0=%s\n", bits
);
674 if ((v
& STP4020_ISR0_CDCHG
) != 0) {
676 * Card status change detect
680 if ((v
& (STP4020_ISR0_CD1ST
|STP4020_ISR0_CD2ST
)) == (STP4020_ISR0_CD1ST
|STP4020_ISR0_CD2ST
)){
681 if ((h
->flags
& STP4020_SOCKET_BUSY
) == 0) {
682 stp4020_queue_event(sc
, i
,
683 STP4020_EVENT_INSERTION
);
684 h
->flags
|= STP4020_SOCKET_BUSY
;
687 if ((v
& (STP4020_ISR0_CD1ST
|STP4020_ISR0_CD2ST
)) == 0){
688 if ((h
->flags
& STP4020_SOCKET_BUSY
) != 0) {
689 stp4020_queue_event(sc
, i
,
690 STP4020_EVENT_REMOVAL
);
691 h
->flags
&= ~STP4020_SOCKET_BUSY
;
696 if ((v
& STP4020_ISR0_IOINT
) != 0) {
697 /* we can not deny this is ours, no matter what the
701 /* It's a card interrupt */
702 if ((h
->flags
& STP4020_SOCKET_BUSY
) == 0) {
703 printf("stp4020[%d]: spurious interrupt?\n",
710 * Schedule softint to invoke driver interrupt
713 if (h
->softint
!= NULL
)
714 sparc_softintr_schedule(h
->softint
);
716 * Disable this sbus interrupt, until the soft-int
717 * handler had a chance to run
719 stp4020_wr_sockctl(h
, STP4020_ICR0_IDX
, h
->int_disable
);
721 (*h
->intrhandler
)(h
->intrarg
);
725 /* informational messages */
726 if ((v
& STP4020_ISR0_BVD1CHG
) != 0) {
727 /* ignore if this is caused by insert or removal */
729 printf("stp4020[%d]: Battery change 1\n", h
->sock
);
733 if ((v
& STP4020_ISR0_BVD2CHG
) != 0) {
734 /* ignore if this is caused by insert or removal */
736 printf("stp4020[%d]: Battery change 2\n", h
->sock
);
740 if ((v
& STP4020_ISR0_SCINT
) != 0) {
741 DPRINTF(("stp4020[%d]: status change\n", h
->sock
));
745 if ((v
& STP4020_ISR0_RDYCHG
) != 0) {
746 DPRINTF(("stp4020[%d]: Ready/Busy change\n", h
->sock
));
750 if ((v
& STP4020_ISR0_WPCHG
) != 0) {
751 DPRINTF(("stp4020[%d]: Write protect change\n", h
->sock
));
755 if ((v
& STP4020_ISR0_PCTO
) != 0) {
756 DPRINTF(("stp4020[%d]: Card access timeout\n", h
->sock
));
760 if ((v
& ~STP4020_ISR0_LIVE
) && r
== 0)
761 printf("stp4020[%d]: unhandled interrupt: 0x%x\n", h
->sock
, v
);
772 * The function gets the sbus speed and a access time and calculates
773 * values for the CMDLNG and CMDDLAY registers.
776 stp4020_calc_speed(int bus_speed
, int ns
, int *length
, int *cmd_delay
)
780 if (ns
< STP4020_MEM_SPEED_MIN
)
781 ns
= STP4020_MEM_SPEED_MIN
;
782 else if (ns
> STP4020_MEM_SPEED_MAX
)
783 ns
= STP4020_MEM_SPEED_MAX
;
784 result
= ns
*(bus_speed
/1000);
785 if (result
% 1000000)
786 result
= result
/1000000 + 1;
791 /* the sbus frequency range is limited, so we can keep this simple */
792 *cmd_delay
= ns
<= STP4020_MEM_SPEED_MIN
? 1 : 2;
796 stp4020_map_window(struct stp4020_socket
*h
, int win
, int speed
)
798 int v
, length
, cmd_delay
;
801 * According to the PC Card standard 300ns access timing should be
802 * used for attribute memory access. Our pcmcia framework does not
803 * seem to propagate timing information, so we use that
806 stp4020_calc_speed(speed
, (win
==STP_WIN_ATTR
)? 300 : 100, &length
, &cmd_delay
);
809 * Fill in the Address Space Select and Base Address
810 * fields of this windows control register 0.
812 v
= ((cmd_delay
<< STP4020_WCR0_CMDDLY_S
)&STP4020_WCR0_CMDDLY_M
)
813 | ((length
<< STP4020_WCR0_CMDLNG_S
)&STP4020_WCR0_CMDLNG_M
);
816 v
|= STP4020_WCR0_ASPSEL_AM
;
819 v
|= STP4020_WCR0_ASPSEL_CM
;
822 v
|= STP4020_WCR0_ASPSEL_IO
;
825 v
|= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M
);
826 stp4020_wr_winctl(h
, win
, STP4020_WCR0_IDX
, v
);
827 stp4020_wr_winctl(h
, win
, STP4020_WCR1_IDX
, 1<<STP4020_WCR1_WAITREQ_S
);
831 stp4020_chip_mem_alloc(pcmcia_chipset_handle_t pch
, bus_size_t size
, struct pcmcia_mem_handle
*pcmhp
)
833 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
835 /* we can not do much here, defere work to _mem_map */
836 pcmhp
->memt
= h
->pcmciat
;
840 pcmhp
->realsize
= size
;
846 stp4020_chip_mem_free(pcmcia_chipset_handle_t pch
, struct pcmcia_mem_handle
*pcmhp
)
851 stp4020_chip_mem_map(pcmcia_chipset_handle_t pch
, int kind
, bus_addr_t card_addr
, bus_size_t size
, struct pcmcia_mem_handle
*pcmhp
, bus_size_t
*offsetp
, int *windowp
)
853 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
854 int win
= (kind
&PCMCIA_MEM_ATTR
)? STP_WIN_ATTR
: STP_WIN_MEM
;
856 pcmhp
->memt
= h
->pcmciat
;
857 bus_space_subregion(h
->pcmciat
, h
->windows
[win
].winaddr
, card_addr
, size
, &pcmhp
->memh
);
859 if ((uint8_t)pcmhp
->memh
._asi
== ASI_PHYS_NON_CACHED
)
860 pcmhp
->memh
._asi
= ASI_PHYS_NON_CACHED_LITTLE
;
861 else if ((uint8_t)pcmhp
->memh
._asi
== ASI_PRIMARY
)
862 pcmhp
->memh
._asi
= ASI_PRIMARY_LITTLE
;
865 pcmhp
->realsize
= STP4020_WINDOW_SIZE
- card_addr
;
873 stp4020_chip_mem_unmap(pcmcia_chipset_handle_t pch
, int win
)
878 stp4020_chip_io_alloc(pcmcia_chipset_handle_t pch
, bus_addr_t start
, bus_size_t size
, bus_size_t align
, struct pcmcia_io_handle
*pcihp
)
880 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
882 pcihp
->iot
= h
->pcmciat
;
883 pcihp
->ioh
= h
->windows
[STP_WIN_IO
].winaddr
;
888 stp4020_chip_io_free(pcmcia_chipset_handle_t pch
, struct pcmcia_io_handle
*pcihp
)
893 stp4020_chip_io_map(pcmcia_chipset_handle_t pch
, int width
, bus_addr_t offset
, bus_size_t size
, struct pcmcia_io_handle
*pcihp
, int *windowp
)
895 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
897 pcihp
->iot
= h
->pcmciat
;
898 bus_space_subregion(h
->pcmciat
, h
->windows
[STP_WIN_IO
].winaddr
, offset
, size
, &pcihp
->ioh
);
900 if ((uint8_t)pcihp
->ioh
._asi
== ASI_PHYS_NON_CACHED
)
901 pcihp
->ioh
._asi
= ASI_PHYS_NON_CACHED_LITTLE
;
902 else if ((uint8_t)pcihp
->ioh
._asi
== ASI_PRIMARY
)
903 pcihp
->ioh
._asi
= ASI_PRIMARY_LITTLE
;
910 stp4020_chip_io_unmap(pcmcia_chipset_handle_t pch
, int win
)
915 stp4020_chip_socket_enable(pcmcia_chipset_handle_t pch
)
917 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
920 /* this bit is mostly stolen from pcic_attach_card */
922 /* Power down the socket to reset it, clear the card reset pin */
923 stp4020_wr_sockctl(h
, STP4020_ICR1_IDX
, 0);
926 * wait 300ms until power fails (Tpf). Then, wait 100ms since
927 * we are changing Vcc (Toff).
929 stp4020_delay(h
->sc
, 300 + 100);
931 /* Power up the socket */
932 v
= STP4020_ICR1_MSTPWR
;
933 stp4020_wr_sockctl(h
, STP4020_ICR1_IDX
, v
);
936 * wait 100ms until power raise (Tpr) and 20ms to become
939 stp4020_delay(h
->sc
, 100 + 20);
941 v
|= STP4020_ICR1_PCIFOE
|STP4020_ICR1_VPP1_VCC
;
942 stp4020_wr_sockctl(h
, STP4020_ICR1_IDX
, v
);
945 * hold RESET at least 10us.
949 /* Clear reset flag, set to memory mode */
950 v
= stp4020_rd_sockctl(h
, STP4020_ICR0_IDX
);
951 v
&= ~(STP4020_ICR0_IOIE
| STP4020_ICR0_IOILVL
| STP4020_ICR0_IFTYPE
|
952 STP4020_ICR0_SPKREN
);
953 v
&= ~STP4020_ICR0_RESET
;
954 stp4020_wr_sockctl(h
, STP4020_ICR0_IDX
, v
);
956 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
957 stp4020_delay(h
->sc
, 20);
959 /* Wait for the chip to finish initializing (5 seconds max) */
960 for (i
= 10000; i
> 0; i
--) {
961 v
= stp4020_rd_sockctl(h
, STP4020_ISR0_IDX
);
962 if ((v
& STP4020_ISR0_RDYST
) != 0)
968 snprintb(bits
, sizeof(bits
),
970 stp4020_rd_sockctl(h
, STP4020_ISR0_IDX
));
971 printf("stp4020_chip_socket_enable: not ready: status %s\n",
978 stp4020_chip_socket_settype(pcmcia_chipset_handle_t pch
, int type
)
980 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
984 * Check the card type.
985 * Enable socket I/O interrupts for IO cards.
987 v
= stp4020_rd_sockctl(h
, STP4020_ICR0_IDX
);
988 v
&= ~(STP4020_ICR0_IOIE
| STP4020_ICR0_IOILVL
| STP4020_ICR0_IFTYPE
|
989 STP4020_ICR0_SPKREN
);
990 if (type
== PCMCIA_IFTYPE_IO
) {
991 v
|= STP4020_ICR0_IFTYPE_IO
|STP4020_ICR0_IOIE
992 |STP4020_ICR0_SPKREN
;
993 v
|= h
->sbus_intno
? STP4020_ICR0_IOILVL_SB1
994 : STP4020_ICR0_IOILVL_SB0
;
997 h
->int_disable
= v
& ~STP4020_ICR0_IOIE
;
999 DPRINTF(("%s: configuring card for IO useage\n", device_xname(&h
->sc
->sc_dev
)));
1001 v
|= STP4020_ICR0_IFTYPE_MEM
;
1003 h
->int_enable
= h
->int_disable
= v
;
1005 DPRINTF(("%s: configuring card for IO useage\n", device_xname(&h
->sc
->sc_dev
)));
1006 DPRINTF(("%s: configuring card for MEM ONLY useage\n", device_xname(&h
->sc
->sc_dev
)));
1008 stp4020_wr_sockctl(h
, STP4020_ICR0_IDX
, v
);
1012 stp4020_chip_socket_disable(pcmcia_chipset_handle_t pch
)
1014 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
1018 * Disable socket I/O interrupts.
1020 v
= stp4020_rd_sockctl(h
, STP4020_ICR0_IDX
);
1021 v
&= ~(STP4020_ICR0_IOIE
| STP4020_ICR0_IOILVL
| STP4020_ICR0_IFTYPE
|
1022 STP4020_ICR0_SPKREN
);
1023 stp4020_wr_sockctl(h
, STP4020_ICR0_IDX
, v
);
1025 /* Power down the socket */
1026 stp4020_wr_sockctl(h
, STP4020_ICR1_IDX
, 0);
1029 * wait 300ms until power fails (Tpf).
1031 stp4020_delay(h
->sc
, 300);
1035 stp4020_chip_intr_establish(pcmcia_chipset_handle_t pch
, struct pcmcia_function
*pf
, int ipl
, int (*handler
)(void *), void *arg
)
1037 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
1039 /* only one interrupt handler per slot */
1040 if (h
->intrhandler
!= NULL
) return NULL
;
1042 h
->intrhandler
= handler
;
1045 if (h
->sc
->sc_use_softint
) {
1046 h
->softint
= sparc_softintr_establish(ipl
, stp4020_intr_dispatch
, h
);
1054 stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t pch
, void *ih
)
1056 struct stp4020_socket
*h
= (struct stp4020_socket
*)pch
;
1058 h
->intrhandler
= NULL
;
1062 sparc_softintr_disestablish(h
->softint
);
1069 * Delay and possibly yield CPU.
1070 * XXX - assumes a context
1073 stp4020_delay(struct stp4020_softc
*sc
, unsigned int ms
)
1075 unsigned int ticks
= mstohz(ms
);
1077 if (cold
|| ticks
== 0) {
1084 panic("stp4020: preposterous delay: %u", ticks
);
1086 tsleep(sc
, 0, "nelldel", ticks
);
1089 #ifdef STP4020_DEBUG
1091 stp4020_dump_regs(struct stp4020_socket
*h
)
1095 * Dump control and status registers.
1097 printf("socket[%d] registers:\n", h
->sock
);
1098 snprintb(bits
, sizeof(bits
), STP4020_ICR0_BITS
,
1099 stp4020_rd_sockctl(h
, STP4020_ICR0_IDX
));
1100 printf("\tICR0=%s\n", bits
);
1102 snprintb(bits
, sizeof(bits
), STP4020_ICR1_BITS
,
1103 stp4020_rd_sockctl(h
, STP4020_ICR1_IDX
));
1104 printf("\tICR1=%s\n", bits
);
1106 snprintb(bits
, sizeof(bits
), STP4020_ISR0_IOBITS
,
1107 stp4020_rd_sockctl(h
, STP4020_ISR0_IDX
));
1108 printf("\tISR0=%s\n", bits
);
1110 snprintb(bits
, sizeof(bits
), STP4020_ISR1_BITS
,
1111 stp4020_rd_sockctl(h
, STP4020_ISR1_IDX
));
1112 printf("\tISR1=%s\n", bits
);
1114 #endif /* STP4020_DEBUG */