1 /* $NetBSD: scoop_pcic.c,v 1.2 2006/12/17 16:07:11 peter Exp $ */
2 /* $OpenBSD: scoop_pcic.c,v 1.1 2005/07/01 23:51:55 uwe Exp $ */
5 * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: scoop_pcic.c,v 1.2 2006/12/17 16:07:11 peter Exp $");
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
29 #include <arch/arm/xscale/pxa2x0var.h>
30 #include <arch/arm/xscale/pxa2x0_gpio.h>
31 #include <arch/arm/xscale/pxa2x0_pcic.h>
33 #include <zaurus/zaurus/zaurus_reg.h>
34 #include <zaurus/zaurus/zaurus_var.h>
36 #include <zaurus/dev/scoopreg.h>
38 static int scoop_pcic_match(device_t
, cfdata_t
, void *);
39 static void scoop_pcic_attach(device_t
, device_t
, void *);
41 CFATTACH_DECL_NEW(pxapcic_scoop
, sizeof(struct pxapcic_softc
),
42 scoop_pcic_match
, scoop_pcic_attach
, NULL
, NULL
);
44 static void scoop_pcic_socket_setup(struct pxapcic_socket
*);
45 static u_int
scoop_pcic_read(struct pxapcic_socket
*, int);
46 static void scoop_pcic_write(struct pxapcic_socket
*, int, u_int
);
47 static void scoop_pcic_set_power(struct pxapcic_socket
*, int);
48 static void scoop_pcic_clear_intr(struct pxapcic_socket
*);
49 static void *scoop_pcic_intr_establish(struct pxapcic_socket
*, int,
50 int (*)(void *), void *);
51 static void scoop_pcic_intr_disestablish(struct pxapcic_socket
*, void *);
53 static struct pxapcic_tag scoop_pcic_functions
= {
57 scoop_pcic_clear_intr
,
58 scoop_pcic_intr_establish
,
59 scoop_pcic_intr_disestablish
63 scoop_pcic_match(device_t parent
, cfdata_t cf
, void *aux
)
66 return (ZAURUS_ISC860
|| ZAURUS_ISC3000
);
70 scoop_pcic_attach(device_t parent
, device_t self
, void *aux
)
72 struct pxapcic_softc
*sc
= device_private(self
);
73 struct pxaip_attach_args
*pxa
= (struct pxaip_attach_args
*)aux
;
76 sc
->sc_iot
= pxa
->pxa_iot
;
80 sc
->sc_irqpin
[0] = C860_CF0_IRQ
;
81 sc
->sc_irqcfpin
[0] = C860_CF0_IRQ_PIN
;
82 } else if (ZAURUS_ISC3000
) {
84 sc
->sc_irqpin
[0] = C3000_CF0_IRQ
;
85 sc
->sc_irqcfpin
[0] = C3000_CF0_IRQ_PIN
;
86 sc
->sc_irqpin
[1] = C3000_CF1_IRQ
;
87 sc
->sc_irqcfpin
[1] = C3000_CF1_IRQ_PIN
;
89 sc
->sc_flags
|= PPF_REVERSE_ORDER
;
91 pxapcic_attach_common(sc
, &scoop_pcic_socket_setup
);
95 scoop_pcic_socket_setup(struct pxapcic_socket
*so
)
97 struct pxapcic_softc
*sc
;
99 bus_size_t size
= SCOOP_SIZE
;
101 bus_space_handle_t scooph
;
107 if (so
->socket
== 0) {
108 pa
= C3000_SCOOP0_BASE
;
109 } else if (so
->socket
== 1) {
110 pa
= C3000_SCOOP1_BASE
;
112 panic("%s: invalid CF slot %d", device_xname(sc
->sc_dev
),
116 error
= bus_space_map(iot
, trunc_page(pa
), round_page(size
),
119 panic("%s: failed to map memory %x for scoop",
120 device_xname(sc
->sc_dev
), (uint32_t)pa
);
122 scooph
+= pa
- trunc_page(pa
);
124 bus_space_write_2(iot
, scooph
, SCOOP_IMR
,
125 SCP_IMR_UNKN0
| SCP_IMR_UNKN1
);
128 bus_space_write_2(iot
, scooph
, SCOOP_MCR
, 0x0100);
129 bus_space_write_2(iot
, scooph
, SCOOP_CDR
, 0x0000);
130 bus_space_write_2(iot
, scooph
, SCOOP_CPR
, 0x0000);
131 bus_space_write_2(iot
, scooph
, SCOOP_IMR
, 0x0000);
132 bus_space_write_2(iot
, scooph
, SCOOP_IRM
, 0x00ff);
133 bus_space_write_2(iot
, scooph
, SCOOP_ISR
, 0x0000);
134 bus_space_write_2(iot
, scooph
, SCOOP_IRM
, 0x0000);
137 if (so
->socket
== 1) {
138 bus_space_write_2(iot
, scooph
, SCOOP_CPR
, 0x80c1);
139 bus_space_write_2(iot
, scooph
, SCOOP_IMR
, 0x00c4);
140 bus_space_write_2(iot
, scooph
, SCOOP_MCR
, 0x0111);
142 bus_space_write_2(iot
, scooph
, SCOOP_CPR
,
143 SCP_CPR_PWR
|SCP_CPR_5V
);
146 bus_space_write_2(iot
, scooph
, SCOOP_IMR
, 0x00ce);
147 bus_space_write_2(iot
, scooph
, SCOOP_MCR
, 0x0111);
150 so
->power_capability
= PXAPCIC_POWER_3V
;
152 so
->power_capability
|= PXAPCIC_POWER_5V
;
154 so
->pcictag_cookie
= (void *)scooph
;
155 so
->pcictag
= &scoop_pcic_functions
;
159 scoop_pcic_read(struct pxapcic_socket
*so
, int reg
)
161 bus_space_tag_t iot
= so
->sc
->sc_iot
;
162 bus_space_handle_t ioh
= (bus_space_handle_t
)so
->pcictag_cookie
;
165 csr
= bus_space_read_2(iot
, ioh
, SCOOP_CSR
);
168 case PXAPCIC_CARD_STATUS
:
169 if (csr
& SCP_CSR_MISSING
)
170 return (PXAPCIC_CARD_INVALID
);
172 return (PXAPCIC_CARD_VALID
);
174 case PXAPCIC_CARD_READY
:
175 return ((bus_space_read_2(iot
, ioh
, SCOOP_CSR
) &
176 SCP_CSR_READY
) != 0);
179 panic("scoop_pcic_read: bogus register");
185 scoop_pcic_write(struct pxapcic_socket
*so
, int reg
, u_int val
)
187 bus_space_tag_t iot
= so
->sc
->sc_iot
;
188 bus_space_handle_t ioh
= (bus_space_handle_t
)so
->pcictag_cookie
;
195 case PXAPCIC_CARD_POWER
:
196 newval
= bus_space_read_2(iot
, ioh
, SCOOP_CPR
);
197 newval
&= ~(SCP_CPR_PWR
| SCP_CPR_3V
| SCP_CPR_5V
);
199 if (val
== PXAPCIC_POWER_3V
)
200 newval
|= (SCP_CPR_PWR
| SCP_CPR_3V
);
201 else if (val
== PXAPCIC_POWER_5V
)
202 newval
|= (SCP_CPR_PWR
| SCP_CPR_5V
);
204 bus_space_write_2(iot
, ioh
, SCOOP_CPR
, newval
);
207 case PXAPCIC_CARD_RESET
:
208 bus_space_write_2(iot
, ioh
, SCOOP_CCR
,
209 val
? SCP_CCR_RESET
: 0);
213 panic("scoop_pcic_write: bogus register");
220 scoop_pcic_set_power(struct pxapcic_socket
*so
, int pwr
)
222 bus_space_tag_t iot
= so
->sc
->sc_iot
;
223 bus_space_handle_t ioh
= (bus_space_handle_t
)so
->pcictag_cookie
;
230 case PXAPCIC_POWER_OFF
:
232 /* XXX does this disable power to both sockets? */
233 reg
= bus_space_read_2(iot
, ioh
, SCOOP_GPWR
);
234 bus_space_write_2(iot
, ioh
, SCOOP_GPWR
,
235 reg
& ~(1 << SCOOP0_CF_POWER_C3000
));
239 case PXAPCIC_POWER_3V
:
240 case PXAPCIC_POWER_5V
:
242 if (so
->socket
== 0) {
243 reg
= bus_space_read_2(iot
, ioh
, SCOOP_GPWR
);
244 bus_space_write_2(iot
, ioh
, SCOOP_GPWR
,
245 reg
| (1 << SCOOP0_CF_POWER_C3000
));
251 panic("scoop_pcic_set_power: bogus power state");
258 scoop_pcic_clear_intr(struct pxapcic_socket
*so
)
260 bus_space_tag_t iot
= so
->sc
->sc_iot
;
261 bus_space_handle_t ioh
= (bus_space_handle_t
)so
->pcictag_cookie
;
263 bus_space_write_2(iot
, ioh
, SCOOP_IRM
, 0x00ff);
264 bus_space_write_2(iot
, ioh
, SCOOP_ISR
, 0x0000);
265 bus_space_write_2(iot
, ioh
, SCOOP_IRM
, 0x0000);
269 scoop_pcic_intr_establish(struct pxapcic_socket
*so
, int ipl
,
270 int (*func
)(void *), void *arg
)
273 return (pxa2x0_gpio_intr_establish(so
->irqpin
, IST_EDGE_FALLING
,
278 scoop_pcic_intr_disestablish(struct pxapcic_socket
*so
, void *ih
)
281 pxa2x0_gpio_intr_disestablish(ih
);