plumpcmcia.c revision 1.2 1 1.2 uch /* $NetBSD: plumpcmcia.c,v 1.2 1999/12/07 17:23:54 uch Exp $ */
2 1.1 uch
3 1.1 uch /*
4 1.1 uch * Copyright (c) 1999 UCHIYAMA Yasushi
5 1.1 uch * Copyright (c) 1997 Marc Horowitz.
6 1.1 uch * All rights reserved.
7 1.1 uch *
8 1.1 uch * Redistribution and use in source and binary forms, with or without
9 1.1 uch * modification, are permitted provided that the following conditions
10 1.1 uch * are met:
11 1.1 uch * 1. Redistributions of source code must retain the above copyright
12 1.1 uch * notice, this list of conditions and the following disclaimer.
13 1.1 uch * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 uch * notice, this list of conditions and the following disclaimer in the
15 1.1 uch * documentation and/or other materials provided with the distribution.
16 1.1 uch * 3. All advertising materials mentioning features or use of this software
17 1.1 uch * must display the following acknowledgement:
18 1.1 uch * This product includes software developed by Marc Horowitz.
19 1.1 uch * 4. The name of the author may not be used to endorse or promote products
20 1.1 uch * derived from this software without specific prior written permission.
21 1.1 uch *
22 1.1 uch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 1.1 uch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 1.1 uch * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 1.1 uch * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 1.1 uch * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 1.1 uch * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 1.1 uch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 1.1 uch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 1.1 uch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 1.1 uch * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 1.1 uch */
33 1.1 uch
34 1.1 uch #include "opt_tx39_debug.h"
35 1.1 uch
36 1.1 uch #include <sys/param.h>
37 1.1 uch #include <sys/systm.h>
38 1.1 uch #include <sys/device.h>
39 1.1 uch
40 1.1 uch #include <machine/bus.h>
41 1.1 uch
42 1.1 uch #include <dev/pcmcia/pcmciareg.h>
43 1.1 uch #include <dev/pcmcia/pcmciavar.h>
44 1.1 uch #include <dev/pcmcia/pcmciachip.h>
45 1.1 uch
46 1.1 uch #include <hpcmips/tx/tx39var.h>
47 1.1 uch #include <hpcmips/dev/plumvar.h>
48 1.1 uch #include <hpcmips/dev/plumicuvar.h>
49 1.2 uch #include <hpcmips/dev/plumpowervar.h>
50 1.1 uch #include <hpcmips/dev/plumpcmciareg.h>
51 1.1 uch
52 1.1 uch #ifdef PLUMPCMCIADEBUG
53 1.1 uch #define DPRINTF(arg) printf arg
54 1.1 uch #else
55 1.1 uch #define DPRINTF(arg)
56 1.1 uch #endif
57 1.1 uch
58 1.1 uch int plumpcmcia_match __P((struct device*, struct cfdata*, void*));
59 1.1 uch void plumpcmcia_attach __P((struct device*, struct device*, void*));
60 1.1 uch int plumpcmcia_print __P((void*, const char*));
61 1.1 uch int plumpcmcia_submatch __P((struct device*, struct cfdata*, void*));
62 1.1 uch
63 1.1 uch struct plumpcmcia_softc;
64 1.1 uch
65 1.1 uch struct plumpcmcia_handle {
66 1.1 uch /* parent */
67 1.1 uch struct device *ph_parent;
68 1.1 uch /* child */
69 1.1 uch struct device *ph_pcmcia;
70 1.1 uch
71 1.1 uch /* PCMCIA controller register space */
72 1.1 uch bus_space_tag_t ph_regt;
73 1.1 uch bus_space_handle_t ph_regh;
74 1.1 uch
75 1.1 uch /* I/O port space */
76 1.1 uch int ph_ioarea; /* not PCMCIA window */
77 1.1 uch struct {
78 1.1 uch bus_addr_t pi_addr;
79 1.1 uch bus_size_t pi_size;
80 1.1 uch int pi_width;
81 1.1 uch } ph_io[PLUM_PCMCIA_IO_WINS];
82 1.1 uch int ph_ioalloc;
83 1.1 uch bus_space_tag_t ph_iot;
84 1.1 uch bus_space_handle_t ph_ioh;
85 1.1 uch bus_addr_t ph_iobase;
86 1.1 uch bus_size_t ph_iosize;
87 1.1 uch
88 1.1 uch /* I/O Memory space */
89 1.1 uch int ph_memarea; /* not PCMCIA window */
90 1.1 uch struct {
91 1.1 uch bus_addr_t pm_addr;
92 1.1 uch bus_size_t pm_size;
93 1.1 uch int32_t pm_offset;
94 1.1 uch int pm_kind;
95 1.1 uch } ph_mem[PLUM_PCMCIA_MEM_WINS];
96 1.1 uch int ph_memalloc;
97 1.1 uch bus_space_tag_t ph_memt;
98 1.1 uch bus_space_handle_t ph_memh;
99 1.1 uch bus_addr_t ph_membase;
100 1.1 uch bus_size_t ph_memsize;
101 1.1 uch
102 1.1 uch /* Interrupt handler */
103 1.1 uch int ph_plum_irq;
104 1.1 uch void *ph_card_ih;
105 1.1 uch };
106 1.1 uch
107 1.1 uch struct plumpcmcia_softc {
108 1.1 uch struct device sc_dev;
109 1.1 uch plum_chipset_tag_t sc_pc;
110 1.1 uch
111 1.1 uch /* Register space */
112 1.1 uch bus_space_tag_t sc_regt;
113 1.1 uch bus_space_handle_t sc_regh;
114 1.1 uch
115 1.1 uch struct plumpcmcia_handle sc_ph[PLUMPCMCIA_NSLOTS];
116 1.1 uch };
117 1.1 uch
118 1.1 uch void plumpcmcia_attach_socket __P((struct plumpcmcia_handle*));
119 1.1 uch void plumpcmcia_dump __P((struct plumpcmcia_softc*));
120 1.1 uch
121 1.1 uch int plumpcmcia_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t, struct pcmcia_mem_handle*));
122 1.1 uch void plumpcmcia_chip_mem_free __P((pcmcia_chipset_handle_t, struct pcmcia_mem_handle*));
123 1.1 uch int plumpcmcia_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t, struct pcmcia_mem_handle*, bus_addr_t*, int*));
124 1.1 uch void plumpcmcia_chip_mem_unmap __P((pcmcia_chipset_handle_t, int));
125 1.1 uch int plumpcmcia_chip_io_alloc __P((pcmcia_chipset_handle_t, bus_addr_t, bus_size_t, bus_size_t, struct pcmcia_io_handle*));
126 1.1 uch void plumpcmcia_chip_io_free __P((pcmcia_chipset_handle_t, struct pcmcia_io_handle*));
127 1.1 uch int plumpcmcia_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t, struct pcmcia_io_handle*, int*));
128 1.1 uch void plumpcmcia_chip_io_unmap __P((pcmcia_chipset_handle_t, int));
129 1.1 uch void plumpcmcia_chip_socket_enable __P((pcmcia_chipset_handle_t));
130 1.1 uch void plumpcmcia_chip_socket_disable __P((pcmcia_chipset_handle_t));
131 1.1 uch void *plumpcmcia_chip_intr_establish __P((pcmcia_chipset_handle_t, struct pcmcia_function*, int, int (*) (void*), void*));
132 1.1 uch void plumpcmcia_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void*));
133 1.1 uch
134 1.1 uch void plumpcmcia_wait_ready __P(( struct plumpcmcia_handle*));
135 1.1 uch void plumpcmcia_chip_do_mem_map __P((struct plumpcmcia_handle *, int));
136 1.1 uch void plumpcmcia_chip_do_io_map __P((struct plumpcmcia_handle *, int));
137 1.1 uch
138 1.1 uch static struct pcmcia_chip_functions plumpcmcia_functions = {
139 1.1 uch plumpcmcia_chip_mem_alloc,
140 1.1 uch plumpcmcia_chip_mem_free,
141 1.1 uch plumpcmcia_chip_mem_map,
142 1.1 uch plumpcmcia_chip_mem_unmap,
143 1.1 uch plumpcmcia_chip_io_alloc,
144 1.1 uch plumpcmcia_chip_io_free,
145 1.1 uch plumpcmcia_chip_io_map,
146 1.1 uch plumpcmcia_chip_io_unmap,
147 1.1 uch plumpcmcia_chip_intr_establish,
148 1.1 uch plumpcmcia_chip_intr_disestablish,
149 1.1 uch plumpcmcia_chip_socket_enable,
150 1.1 uch plumpcmcia_chip_socket_disable
151 1.1 uch };
152 1.1 uch
153 1.1 uch struct cfattach plumpcmcia_ca = {
154 1.1 uch sizeof(struct plumpcmcia_softc), plumpcmcia_match, plumpcmcia_attach
155 1.1 uch };
156 1.1 uch
157 1.1 uch int
158 1.1 uch plumpcmcia_match(parent, cf, aux)
159 1.1 uch struct device *parent;
160 1.1 uch struct cfdata *cf;
161 1.1 uch void *aux;
162 1.1 uch {
163 1.1 uch return 1;
164 1.1 uch }
165 1.1 uch
166 1.1 uch void
167 1.1 uch plumpcmcia_attach(parent, self, aux)
168 1.1 uch struct device *parent;
169 1.1 uch struct device *self;
170 1.1 uch void *aux;
171 1.1 uch {
172 1.1 uch struct plum_attach_args *pa = aux;
173 1.1 uch struct plumpcmcia_softc *sc = (void*)self;
174 1.1 uch struct plumpcmcia_handle *ph;
175 1.1 uch
176 1.1 uch sc->sc_pc = pa->pa_pc;
177 1.1 uch sc->sc_regt = pa->pa_regt;
178 1.1 uch if (bus_space_map(sc->sc_regt, PLUM_PCMCIA_REGBASE,
179 1.1 uch PLUM_PCMCIA_REGSIZE, 0, &sc->sc_regh)) {
180 1.1 uch printf(": register map failed\n");
181 1.1 uch }
182 1.1 uch
183 1.1 uch printf("\n");
184 1.1 uch
185 1.1 uch /* Slot 0 */
186 1.1 uch ph = &sc->sc_ph[0];
187 1.1 uch ph->ph_plum_irq = PLUM_INT_C1IO;
188 1.1 uch ph->ph_memarea = PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1;
189 1.1 uch ph->ph_membase = PLUM_PCMCIA_MEMBASE1;
190 1.1 uch ph->ph_memsize = PLUM_PCMCIA_MEMSIZE1;
191 1.1 uch ph->ph_ioarea = PLUM_PCMCIA_IOWINADDRCTRL_AREA1;
192 1.1 uch ph->ph_iobase = PLUM_PCMCIA_IOBASE1;
193 1.1 uch ph->ph_iosize = PLUM_PCMCIA_IOSIZE1;
194 1.1 uch ph->ph_regt = sc->sc_regt;
195 1.1 uch bus_space_subregion(sc->sc_regt, sc->sc_regh,
196 1.1 uch PLUM_PCMCIA_REGSPACE_SLOT0,
197 1.1 uch PLUM_PCMCIA_REGSPACE_SIZE,
198 1.1 uch &ph->ph_regh);
199 1.1 uch ph->ph_iot = pa->pa_iot;
200 1.1 uch ph->ph_memt = pa->pa_iot;
201 1.1 uch ph->ph_parent = (void*)sc;
202 1.2 uch
203 1.2 uch plum_power_establish(sc->sc_pc, PLUM_PWR_PCC1);
204 1.1 uch plumpcmcia_attach_socket(ph);
205 1.1 uch
206 1.1 uch /* Slot 1 */
207 1.1 uch ph = &sc->sc_ph[1];
208 1.1 uch ph->ph_plum_irq = PLUM_INT_C2IO;
209 1.1 uch ph->ph_memarea = PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2;
210 1.1 uch ph->ph_membase = PLUM_PCMCIA_MEMBASE2;
211 1.1 uch ph->ph_memsize = PLUM_PCMCIA_MEMSIZE2;
212 1.1 uch ph->ph_ioarea = PLUM_PCMCIA_IOWINADDRCTRL_AREA2;
213 1.1 uch ph->ph_iobase = PLUM_PCMCIA_IOBASE2;
214 1.1 uch ph->ph_iosize = PLUM_PCMCIA_IOSIZE2;
215 1.1 uch ph->ph_regt = sc->sc_regt;
216 1.1 uch bus_space_subregion(sc->sc_regt, sc->sc_regh,
217 1.1 uch PLUM_PCMCIA_REGSPACE_SLOT1,
218 1.1 uch PLUM_PCMCIA_REGSPACE_SIZE,
219 1.1 uch &ph->ph_regh);
220 1.1 uch ph->ph_iot = pa->pa_iot;
221 1.1 uch ph->ph_memt = pa->pa_iot;
222 1.1 uch ph->ph_parent = (void*)sc;
223 1.2 uch
224 1.2 uch plum_power_establish(sc->sc_pc, PLUM_PWR_PCC2);
225 1.1 uch plumpcmcia_attach_socket(ph);
226 1.1 uch }
227 1.1 uch
228 1.1 uch int
229 1.1 uch plumpcmcia_print(arg, pnp)
230 1.1 uch void *arg;
231 1.1 uch const char *pnp;
232 1.1 uch {
233 1.1 uch if (pnp) {
234 1.1 uch printf("pcmcia at %s", pnp);
235 1.1 uch }
236 1.1 uch
237 1.1 uch return UNCONF;
238 1.1 uch }
239 1.1 uch
240 1.1 uch int
241 1.1 uch plumpcmcia_submatch(parent, cf, aux)
242 1.1 uch struct device *parent;
243 1.1 uch struct cfdata *cf;
244 1.1 uch void *aux;
245 1.1 uch {
246 1.1 uch return ((*cf->cf_attach->ca_match)(parent, cf, aux));
247 1.1 uch }
248 1.1 uch
249 1.1 uch void
250 1.1 uch plumpcmcia_attach_socket(ph)
251 1.1 uch struct plumpcmcia_handle *ph;
252 1.1 uch {
253 1.1 uch struct pcmciabus_attach_args paa;
254 1.1 uch struct plumpcmcia_softc *sc = (void*)ph->ph_parent;
255 1.1 uch
256 1.1 uch paa.paa_busname = "pcmcia";
257 1.1 uch paa.pct = (pcmcia_chipset_tag_t)&plumpcmcia_functions;
258 1.1 uch paa.pch = (pcmcia_chipset_handle_t)ph;
259 1.1 uch paa.iobase = 0; /* I don't use them */
260 1.1 uch paa.iosize = 0;
261 1.1 uch
262 1.1 uch
263 1.1 uch if ((ph->ph_pcmcia = config_found_sm((void*)sc, &paa,
264 1.1 uch plumpcmcia_print,
265 1.1 uch plumpcmcia_submatch))) {
266 1.1 uch /* Enable slot */
267 1.1 uch plum_conf_write(ph->ph_regt, ph->ph_regh,
268 1.1 uch PLUM_PCMCIA_SLOTCTRL,
269 1.1 uch PLUM_PCMCIA_SLOTCTRL_ENABLE);
270 1.1 uch /* Support 3.3V card & enable Voltage Sense Status */
271 1.1 uch plum_conf_write(ph->ph_regt, ph->ph_regh,
272 1.1 uch PLUM_PCMCIA_FUNCCTRL,
273 1.1 uch PLUM_PCMCIA_FUNCCTRL_VSSEN |
274 1.1 uch PLUM_PCMCIA_FUNCCTRL_3VSUPPORT);
275 1.1 uch pcmcia_card_attach(ph->ph_pcmcia);
276 1.1 uch }
277 1.1 uch }
278 1.1 uch
279 1.1 uch void *
280 1.1 uch plumpcmcia_chip_intr_establish(pch, pf, ipl, ih_fun, ih_arg)
281 1.1 uch pcmcia_chipset_handle_t pch;
282 1.1 uch struct pcmcia_function *pf;
283 1.1 uch int ipl;
284 1.1 uch int (*ih_fun) __P((void *));
285 1.1 uch void *ih_arg;
286 1.1 uch {
287 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
288 1.1 uch struct plumpcmcia_softc *sc = (void*)ph->ph_parent;
289 1.1 uch
290 1.1 uch if (!(ph->ph_card_ih =
291 1.1 uch plum_intr_establish(sc->sc_pc, ph->ph_plum_irq,
292 1.1 uch IST_EDGE, IPL_BIO, ih_fun, ih_arg))) {
293 1.1 uch printf("plumpcmcia_chip_intr_establish: can't establish\n");
294 1.1 uch return 0;
295 1.1 uch }
296 1.1 uch
297 1.1 uch return ph->ph_card_ih;
298 1.1 uch }
299 1.1 uch
300 1.1 uch void
301 1.1 uch plumpcmcia_chip_intr_disestablish(pch, ih)
302 1.1 uch pcmcia_chipset_handle_t pch;
303 1.1 uch void *ih;
304 1.1 uch {
305 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
306 1.1 uch struct plumpcmcia_softc *sc = (void*)ph->ph_parent;
307 1.1 uch
308 1.1 uch plum_intr_disestablish(sc->sc_pc, ih);
309 1.1 uch }
310 1.1 uch
311 1.1 uch int
312 1.1 uch plumpcmcia_chip_mem_alloc(pch, size, pcmhp)
313 1.1 uch pcmcia_chipset_handle_t pch;
314 1.1 uch bus_size_t size;
315 1.1 uch struct pcmcia_mem_handle *pcmhp;
316 1.1 uch {
317 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
318 1.1 uch bus_size_t realsize;
319 1.1 uch
320 1.1 uch /* convert size to PCIC pages */
321 1.1 uch realsize = ((size + (PLUM_PCMCIA_MEM_PAGESIZE - 1)) /
322 1.1 uch PLUM_PCMCIA_MEM_PAGESIZE) * PLUM_PCMCIA_MEM_PAGESIZE;
323 1.1 uch
324 1.1 uch if (bus_space_alloc(ph->ph_memt, ph->ph_membase,
325 1.1 uch ph->ph_membase + ph->ph_memsize,
326 1.1 uch realsize, PLUM_PCMCIA_MEM_PAGESIZE,
327 1.1 uch 0, 0, 0, &pcmhp->memh)) {
328 1.1 uch return 1;
329 1.1 uch }
330 1.1 uch
331 1.1 uch pcmhp->memt = ph->ph_memt;
332 1.1 uch /* Address offset from MEM area base */
333 1.1 uch pcmhp->addr = pcmhp->memh - ph->ph_membase - ph->ph_memt->t_base;
334 1.1 uch pcmhp->size = size;
335 1.1 uch pcmhp->realsize = realsize;
336 1.1 uch
337 1.1 uch DPRINTF(("plumpcmcia_chip_mem_alloc: size %#x->%#x addr %#x->%#x\n",
338 1.1 uch size, realsize, pcmhp->addr, pcmhp->memh));
339 1.1 uch
340 1.1 uch return 0;
341 1.1 uch }
342 1.1 uch
343 1.1 uch void
344 1.1 uch plumpcmcia_chip_mem_free(pch, pcmhp)
345 1.1 uch pcmcia_chipset_handle_t pch;
346 1.1 uch struct pcmcia_mem_handle *pcmhp;
347 1.1 uch {
348 1.1 uch bus_space_free(pcmhp->memt, pcmhp->memh, pcmhp->size);
349 1.1 uch }
350 1.1 uch
351 1.1 uch int
352 1.1 uch plumpcmcia_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
353 1.1 uch pcmcia_chipset_handle_t pch;
354 1.1 uch int kind;
355 1.1 uch bus_addr_t card_addr;
356 1.1 uch bus_size_t size;
357 1.1 uch struct pcmcia_mem_handle *pcmhp;
358 1.1 uch bus_addr_t *offsetp;
359 1.1 uch int *windowp;
360 1.1 uch {
361 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
362 1.1 uch bus_addr_t busaddr;
363 1.1 uch int32_t card_offset;
364 1.1 uch int i, win;
365 1.1 uch
366 1.1 uch for (win = -1, i = 0; i < PLUM_PCMCIA_MEM_WINS; i++) {
367 1.1 uch if ((ph->ph_memalloc & (1 << i)) == 0) {
368 1.1 uch win = i;
369 1.1 uch ph->ph_memalloc |= (1 << i);
370 1.1 uch break;
371 1.1 uch }
372 1.1 uch }
373 1.1 uch if (win == -1) {
374 1.1 uch DPRINTF(("plumpcmcia_chip_mem_map: no window\n"));
375 1.1 uch return 1;
376 1.1 uch }
377 1.1 uch
378 1.1 uch busaddr = pcmhp->addr;
379 1.1 uch
380 1.1 uch *offsetp = card_addr % PLUM_PCMCIA_MEM_PAGESIZE;
381 1.1 uch card_addr -= *offsetp;
382 1.1 uch size += *offsetp - 1;
383 1.1 uch *windowp = win;
384 1.1 uch card_offset = (((int32_t)card_addr) - ((int32_t)busaddr));
385 1.1 uch
386 1.1 uch DPRINTF(("plumpcmcia_chip_mem_map window %d bus %#x(kv:%#x)+%#x"
387 1.1 uch " size %#x at card addr %#x offset %#x\n", win, busaddr,
388 1.1 uch pcmhp->memh, *offsetp, size, card_addr, card_offset));
389 1.1 uch
390 1.1 uch ph->ph_mem[win].pm_addr = busaddr;
391 1.1 uch ph->ph_mem[win].pm_size = size;
392 1.1 uch ph->ph_mem[win].pm_offset = card_offset;
393 1.1 uch ph->ph_mem[win].pm_kind = kind;
394 1.1 uch ph->ph_memalloc |= (1 << win);
395 1.1 uch
396 1.1 uch plumpcmcia_chip_do_mem_map(ph, win);
397 1.1 uch
398 1.1 uch return 0;
399 1.1 uch }
400 1.1 uch
401 1.1 uch void
402 1.1 uch plumpcmcia_chip_do_mem_map(ph, win)
403 1.1 uch struct plumpcmcia_handle *ph;
404 1.1 uch int win;
405 1.1 uch {
406 1.1 uch bus_space_tag_t regt = ph->ph_regt;
407 1.1 uch bus_space_handle_t regh = ph->ph_regh;
408 1.1 uch plumreg_t reg, addr, offset, size;
409 1.1 uch
410 1.1 uch if (win < 0 || win > 4) {
411 1.1 uch panic("plumpcmcia_chip_do_mem_map: bogus window %d", win);
412 1.1 uch }
413 1.1 uch
414 1.1 uch addr = (ph->ph_mem[win].pm_addr) >> PLUM_PCMCIA_MEM_SHIFT;
415 1.1 uch size = (ph->ph_mem[win].pm_size) >> PLUM_PCMCIA_MEM_SHIFT;
416 1.1 uch offset = (ph->ph_mem[win].pm_offset) >> PLUM_PCMCIA_MEM_SHIFT;
417 1.1 uch
418 1.1 uch /* Attribute memory or not */
419 1.1 uch reg = ph->ph_mem[win].pm_kind == PCMCIA_MEM_ATTR ?
420 1.1 uch PLUM_PCMCIA_MEMWINCTRL_REGACTIVE : 0;
421 1.1 uch
422 1.1 uch /* Notify I/O area to select for PCMCIA controller */
423 1.1 uch reg = PLUM_PCMCIA_MEMWINCTRL_MAP_SET(reg, ph->ph_memarea);
424 1.1 uch
425 1.1 uch /* Zero wait & 16bit access */
426 1.1 uch reg |= (PLUM_PCMCIA_MEMWINCTRL_ZERO_WS |
427 1.1 uch PLUM_PCMCIA_MEMWINCTRL_DATASIZE16);
428 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINCTRL(win), reg);
429 1.1 uch
430 1.1 uch /* Map Host <-> PC-Card address */
431 1.1 uch
432 1.1 uch /* host-side */
433 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINSTARTADDR(win),
434 1.1 uch addr);
435 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINSTOPADDR(win),
436 1.1 uch addr + size);
437 1.1 uch
438 1.1 uch /* card-side */
439 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_MEMWINOFSADDR(win), offset);
440 1.1 uch
441 1.1 uch /* Enable memory window */
442 1.1 uch reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
443 1.1 uch reg |= PLUM_PCMCIA_WINEN_MEM(win);
444 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
445 1.1 uch
446 1.2 uch DPRINTF(("plumpcmcia_chip_do_mem_map: window:%d %#x(%#x)+%#x\n",
447 1.2 uch win, offset, addr, size));
448 1.1 uch
449 1.1 uch delay(100);
450 1.1 uch }
451 1.1 uch
452 1.1 uch void
453 1.1 uch plumpcmcia_chip_mem_unmap(pch, window)
454 1.1 uch pcmcia_chipset_handle_t pch;
455 1.1 uch int window;
456 1.1 uch {
457 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
458 1.1 uch bus_space_tag_t regt = ph->ph_regt;
459 1.1 uch bus_space_handle_t regh = ph->ph_regh;
460 1.1 uch plumreg_t reg;
461 1.1 uch
462 1.1 uch reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
463 1.1 uch reg &= ~PLUM_PCMCIA_WINEN_MEM(window);
464 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
465 1.1 uch
466 1.1 uch ph->ph_memalloc &= ~(1 << window);
467 1.1 uch }
468 1.1 uch
469 1.1 uch int
470 1.1 uch plumpcmcia_chip_io_alloc(pch, start, size, align, pcihp)
471 1.1 uch pcmcia_chipset_handle_t pch;
472 1.1 uch bus_addr_t start;
473 1.1 uch bus_size_t size;
474 1.1 uch bus_size_t align;
475 1.1 uch struct pcmcia_io_handle *pcihp;
476 1.1 uch {
477 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
478 1.1 uch
479 1.1 uch DPRINTF(("plumpcmcia_chip_io_alloc: start=%#x size=%#x ",
480 1.1 uch start, size));
481 1.1 uch if (start) {
482 1.1 uch if (bus_space_map(ph->ph_iot, ph->ph_iobase + start,
483 1.1 uch size, 0, &pcihp->ioh)) {
484 1.1 uch DPRINTF(("bus_space_map failed\n"));
485 1.1 uch return 1;
486 1.1 uch }
487 1.1 uch pcihp->flags = 0;
488 1.2 uch pcihp->addr = start;
489 1.1 uch DPRINTF(("(mapped) %#x+%#x\n", start, size));
490 1.1 uch } else {
491 1.1 uch if (bus_space_alloc(ph->ph_iot, ph->ph_iobase,
492 1.1 uch ph->ph_iobase + ph->ph_iosize, size,
493 1.2 uch align, 0, 0, 0, &pcihp->ioh)) {
494 1.1 uch DPRINTF(("bus_space_alloc failed\n"));
495 1.1 uch return 1;
496 1.1 uch }
497 1.2 uch /* Address offset from IO area base */
498 1.2 uch pcihp->addr = pcihp->ioh - ph->ph_iobase -
499 1.2 uch ph->ph_iot->t_base;
500 1.1 uch pcihp->flags = PCMCIA_IO_ALLOCATED;
501 1.2 uch DPRINTF(("(allocated) %#x+%#x\n", pcihp->addr, size));
502 1.1 uch }
503 1.1 uch
504 1.1 uch pcihp->iot = ph->ph_iot;
505 1.1 uch pcihp->size = size;
506 1.1 uch
507 1.1 uch return 0;
508 1.1 uch }
509 1.1 uch
510 1.1 uch int
511 1.1 uch plumpcmcia_chip_io_map(pch, width, offset, size, pcihp, windowp)
512 1.1 uch pcmcia_chipset_handle_t pch;
513 1.1 uch int width;
514 1.1 uch bus_addr_t offset;
515 1.1 uch bus_size_t size;
516 1.1 uch struct pcmcia_io_handle *pcihp;
517 1.1 uch int *windowp;
518 1.1 uch {
519 1.2 uch #ifdef PLUMPCMCIADEBUG
520 1.1 uch static char *width_names[] = { "auto", "io8", "io16" };
521 1.2 uch #endif /* PLUMPCMCIADEBUG */
522 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
523 1.1 uch bus_addr_t winofs;
524 1.1 uch int i, win;
525 1.1 uch
526 1.2 uch winofs = pcihp->addr + offset;
527 1.2 uch
528 1.2 uch if (winofs > 0x3ff) {
529 1.2 uch printf("plumpcmcia_chip_io_map: WARNING port %#x > 0x3ff\n",
530 1.2 uch winofs);
531 1.2 uch }
532 1.1 uch
533 1.1 uch for (win = -1, i = 0; i < PLUM_PCMCIA_IO_WINS; i++) {
534 1.1 uch if ((ph->ph_ioalloc & (1 << i)) == 0) {
535 1.1 uch win = i;
536 1.1 uch ph->ph_ioalloc |= (1 << i);
537 1.1 uch break;
538 1.1 uch }
539 1.1 uch }
540 1.1 uch if (win == -1) {
541 1.1 uch DPRINTF(("plumpcmcia_chip_io_map: no window\n"));
542 1.1 uch return 1;
543 1.1 uch }
544 1.1 uch *windowp = win;
545 1.1 uch
546 1.1 uch ph->ph_io[win].pi_addr = winofs;
547 1.1 uch ph->ph_io[win].pi_size = size;
548 1.1 uch ph->ph_io[win].pi_width = width;
549 1.1 uch
550 1.1 uch plumpcmcia_chip_do_io_map(ph, win);
551 1.1 uch
552 1.1 uch DPRINTF(("plumpcmcia_chip_io_map: %#x(kv:%#x)+%#x %s\n",
553 1.1 uch offset, pcihp->ioh, size, width_names[width]));
554 1.1 uch
555 1.1 uch return 0;
556 1.1 uch }
557 1.1 uch
558 1.1 uch void
559 1.1 uch plumpcmcia_chip_do_io_map(ph, win)
560 1.1 uch struct plumpcmcia_handle *ph;
561 1.1 uch int win;
562 1.1 uch {
563 1.1 uch bus_space_tag_t regt = ph->ph_regt;
564 1.1 uch bus_space_handle_t regh = ph->ph_regh;
565 1.1 uch plumreg_t reg;
566 1.1 uch bus_addr_t addr;
567 1.1 uch bus_size_t size;
568 1.1 uch int shift;
569 1.1 uch plumreg_t ioctlbits[3] = {
570 1.1 uch PLUM_PCMCIA_IOWINCTRL_IOCS16SRC,
571 1.1 uch 0,
572 1.1 uch PLUM_PCMCIA_IOWINCTRL_DATASIZE16
573 1.1 uch };
574 1.1 uch
575 1.1 uch if (win < 0 || win > 1) {
576 1.1 uch panic("plumpcmcia_chip_do_io_map: bogus window %d", win);
577 1.1 uch }
578 1.1 uch
579 1.1 uch addr = ph->ph_io[win].pi_addr;
580 1.1 uch size = ph->ph_io[win].pi_size;
581 1.1 uch
582 1.1 uch /* Notify I/O area to select for PCMCIA controller */
583 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINADDRCTRL(win),
584 1.1 uch ph->ph_ioarea);
585 1.1 uch
586 1.1 uch /* Start/Stop addr */
587 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINSTARTADDR(win), addr);
588 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINSTOPADDR(win),
589 1.1 uch addr + size - 1);
590 1.1 uch
591 1.1 uch /* Set bus width */
592 1.1 uch reg = plum_conf_read(regt, regh, PLUM_PCMCIA_IOWINCTRL);
593 1.1 uch shift = win == 0 ? PLUM_PCMCIA_IOWINCTRL_WIN0SHIFT :
594 1.1 uch PLUM_PCMCIA_IOWINCTRL_WIN1SHIFT;
595 1.1 uch
596 1.1 uch reg &= ~(PLUM_PCMCIA_IOWINCTRL_WINMASK << shift);
597 1.1 uch reg |= ((ioctlbits[ph->ph_io[win].pi_width] |
598 1.1 uch PLUM_PCMCIA_IOWINCTRL_ZEROWAIT) << shift);
599 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_IOWINCTRL, reg);
600 1.1 uch
601 1.1 uch /* Enable window */
602 1.1 uch reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
603 1.1 uch reg |= (win == 0 ? PLUM_PCMCIA_WINEN_IO0 :
604 1.1 uch PLUM_PCMCIA_WINEN_IO1);
605 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
606 1.1 uch
607 1.1 uch delay(100);
608 1.1 uch }
609 1.1 uch
610 1.1 uch
611 1.1 uch void
612 1.1 uch plumpcmcia_chip_io_free(pch, pcihp)
613 1.1 uch pcmcia_chipset_handle_t pch;
614 1.1 uch struct pcmcia_io_handle *pcihp;
615 1.1 uch {
616 1.1 uch if (pcihp->flags & PCMCIA_IO_ALLOCATED) {
617 1.1 uch bus_space_free(pcihp->iot, pcihp->ioh, pcihp->size);
618 1.1 uch } else {
619 1.1 uch bus_space_unmap(pcihp->iot, pcihp->ioh, pcihp->size);
620 1.1 uch }
621 1.1 uch
622 1.1 uch DPRINTF(("plumpcmcia_chip_io_free %#x+%#x\n", pcihp->ioh,
623 1.1 uch pcihp->size));
624 1.1 uch }
625 1.1 uch
626 1.1 uch void
627 1.1 uch plumpcmcia_chip_io_unmap(pch, window)
628 1.1 uch pcmcia_chipset_handle_t pch;
629 1.1 uch int window;
630 1.1 uch {
631 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
632 1.1 uch bus_space_tag_t regt = ph->ph_regt;
633 1.1 uch bus_space_handle_t regh = ph->ph_regh;
634 1.1 uch plumreg_t reg;
635 1.1 uch
636 1.1 uch reg = plum_conf_read(regt, regh, PLUM_PCMCIA_WINEN);
637 1.1 uch switch (window) {
638 1.1 uch default:
639 1.1 uch panic("plumpcmcia_chip_io_unmap: bogus window");
640 1.1 uch case 0:
641 1.1 uch reg &= ~PLUM_PCMCIA_WINEN_IO0;
642 1.1 uch break;
643 1.1 uch case 1:
644 1.1 uch reg &= ~PLUM_PCMCIA_WINEN_IO1;
645 1.1 uch break;
646 1.1 uch }
647 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, reg);
648 1.1 uch ph->ph_ioalloc &= ~(1 << window);
649 1.1 uch }
650 1.1 uch
651 1.1 uch void
652 1.1 uch plumpcmcia_wait_ready(ph)
653 1.1 uch struct plumpcmcia_handle *ph;
654 1.1 uch {
655 1.1 uch bus_space_tag_t regt = ph->ph_regt;
656 1.1 uch bus_space_handle_t regh = ph->ph_regh;
657 1.1 uch int i;
658 1.1 uch
659 1.1 uch for (i = 0; i < 10000; i++) {
660 1.1 uch if ((plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS) &
661 1.1 uch PLUM_PCMCIA_STATUS_READY) &&
662 1.1 uch (plum_conf_read(regt, regh, PLUM_PCMCIA_STATUS) &
663 1.1 uch PLUM_PCMCIA_STATUS_PWROK)) {
664 1.1 uch return;
665 1.1 uch }
666 1.1 uch delay(500);
667 1.1 uch
668 1.1 uch if ((i > 5000) && (i % 100 == 99)) {
669 1.1 uch printf(".");
670 1.1 uch }
671 1.1 uch }
672 1.1 uch printf("plumpcmcia_wait_ready: failed\n");
673 1.1 uch }
674 1.1 uch
675 1.1 uch void
676 1.1 uch plumpcmcia_chip_socket_enable(pch)
677 1.1 uch pcmcia_chipset_handle_t pch;
678 1.1 uch {
679 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
680 1.1 uch bus_space_tag_t regt = ph->ph_regt;
681 1.1 uch bus_space_handle_t regh = ph->ph_regh;
682 1.1 uch plumreg_t reg, power;
683 1.1 uch int win, cardtype;
684 1.1 uch
685 1.1 uch /* this bit is mostly stolen from pcic_attach_card */
686 1.1 uch
687 1.1 uch /* power down the socket to reset it, clear the card reset pin */
688 1.1 uch
689 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 0);
690 1.1 uch
691 1.1 uch /*
692 1.1 uch * wait 300ms until power fails (Tpf). Then, wait 100ms since
693 1.1 uch * we are changing Vcc (Toff).
694 1.1 uch */
695 1.1 uch delay((300 + 100) * 1000);
696 1.1 uch
697 1.1 uch /*
698 1.1 uch * power up the socket
699 1.1 uch */
700 1.1 uch /* detect voltage */
701 1.1 uch reg = plum_conf_read(regt, regh, PLUM_PCMCIA_GENCTRL2);
702 1.1 uch if ((reg & PLUM_PCMCIA_GENCTRL2_VCC5V) ==
703 1.1 uch PLUM_PCMCIA_GENCTRL2_VCC5V) {
704 1.1 uch power = PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT1; /* 5V */
705 1.1 uch } else {
706 1.1 uch power = PLUM_PCMCIA_PWRCTRL_VCC_CTRLBIT0; /* 3.3V */
707 1.1 uch }
708 1.1 uch
709 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL,
710 1.1 uch PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV |
711 1.1 uch power |
712 1.1 uch PLUM_PCMCIA_PWRCTRL_PWR_ENABLE);
713 1.1 uch
714 1.1 uch /*
715 1.1 uch * wait 100ms until power raise (Tpr) and 20ms to become
716 1.1 uch * stable (Tsu(Vcc)).
717 1.1 uch *
718 1.1 uch * some machines require some more time to be settled
719 1.1 uch * (300ms is added here).
720 1.1 uch */
721 1.1 uch delay((100 + 20 + 300) * 1000);
722 1.1 uch
723 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL,
724 1.1 uch PLUM_PCMCIA_PWRCTRL_DISABLE_RESETDRV |
725 1.1 uch power |
726 1.1 uch PLUM_PCMCIA_PWRCTRL_OE |
727 1.1 uch PLUM_PCMCIA_PWRCTRL_PWR_ENABLE);
728 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL, 0);
729 1.1 uch
730 1.1 uch /*
731 1.1 uch * hold RESET at least 10us.
732 1.1 uch */
733 1.1 uch delay(10);
734 1.1 uch
735 1.1 uch /* clear the reset flag */
736 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL,
737 1.1 uch PLUM_PCMCIA_GENCTRL_RESET);
738 1.1 uch
739 1.1 uch /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
740 1.1 uch
741 1.1 uch delay(20000);
742 1.1 uch
743 1.1 uch /* wait for the chip to finish initializing */
744 1.1 uch plumpcmcia_wait_ready(ph);
745 1.1 uch
746 1.1 uch /* zero out the address windows */
747 1.1 uch
748 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_WINEN, 0);
749 1.1 uch
750 1.1 uch /* set the card type */
751 1.1 uch
752 1.1 uch cardtype = pcmcia_card_gettype(ph->ph_pcmcia);
753 1.1 uch
754 1.1 uch reg = (cardtype == PCMCIA_IFTYPE_IO) ?
755 1.1 uch PLUM_PCMCIA_GENCTRL_CARDTYPE_IO :
756 1.1 uch PLUM_PCMCIA_GENCTRL_CARDTYPE_MEM;
757 1.1 uch reg |= plum_conf_read(regt, regh, PLUM_PCMCIA_GENCTRL);
758 1.1 uch DPRINTF(("%s: plumpcmcia_chip_socket_enable cardtype %s\n",
759 1.1 uch ph->ph_parent->dv_xname,
760 1.1 uch ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem")));
761 1.1 uch
762 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_GENCTRL, reg);
763 1.1 uch
764 1.1 uch /* reinstall all the memory and io mappings */
765 1.1 uch
766 1.1 uch for (win = 0; win < PLUM_PCMCIA_MEM_WINS; win++) {
767 1.1 uch if (ph->ph_memalloc & (1 << win)) {
768 1.1 uch plumpcmcia_chip_do_mem_map(ph, win);
769 1.1 uch }
770 1.1 uch }
771 1.1 uch
772 1.1 uch for (win = 0; win < PLUM_PCMCIA_IO_WINS; win++) {
773 1.1 uch if (ph->ph_ioalloc & (1 << win)) {
774 1.1 uch plumpcmcia_chip_do_io_map(ph, win);
775 1.1 uch }
776 1.1 uch }
777 1.1 uch
778 1.1 uch }
779 1.1 uch
780 1.1 uch void
781 1.1 uch plumpcmcia_chip_socket_disable(pch)
782 1.1 uch pcmcia_chipset_handle_t pch;
783 1.1 uch {
784 1.1 uch struct plumpcmcia_handle *ph = (void*)pch;
785 1.1 uch bus_space_tag_t regt = ph->ph_regt;
786 1.1 uch bus_space_handle_t regh = ph->ph_regh;
787 1.1 uch
788 1.1 uch /* power down the socket */
789 1.1 uch plum_conf_write(regt, regh, PLUM_PCMCIA_PWRCTRL, 0);
790 1.1 uch
791 1.1 uch /*
792 1.1 uch * wait 300ms until power fails (Tpf).
793 1.1 uch */
794 1.1 uch delay(300 * 1000);
795 1.1 uch }
796 1.1 uch
797 1.1 uch void __ioareadump __P((plumreg_t));
798 1.1 uch void __memareadump __P((plumreg_t));
799 1.1 uch
800 1.1 uch void
801 1.1 uch __memareadump(reg)
802 1.1 uch plumreg_t reg;
803 1.1 uch {
804 1.1 uch int maparea;
805 1.1 uch
806 1.1 uch maparea = PLUM_PCMCIA_MEMWINCTRL_MAP(reg);
807 1.1 uch switch (maparea) {
808 1.1 uch case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA1:
809 1.1 uch printf("MEM Area1\n");
810 1.1 uch break;
811 1.1 uch case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA2:
812 1.1 uch printf("MEM Area2\n");
813 1.1 uch break;
814 1.1 uch case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA3:
815 1.1 uch printf("MEM Area3\n");
816 1.1 uch break;
817 1.1 uch case PLUM_PCMCIA_MEMWINCTRL_MAP_AREA4:
818 1.1 uch printf("MEM Area4\n");
819 1.1 uch break;
820 1.1 uch }
821 1.1 uch }
822 1.1 uch
823 1.1 uch void
824 1.1 uch __ioareadump(reg)
825 1.1 uch plumreg_t reg;
826 1.1 uch {
827 1.1 uch if (reg & PLUM_PCMCIA_IOWINADDRCTRL_AREA2) {
828 1.1 uch printf("I/O Area 2\n");
829 1.1 uch } else {
830 1.1 uch printf("I/O Area 1\n");
831 1.1 uch }
832 1.1 uch }
833 1.1 uch
834 1.1 uch void
835 1.1 uch plumpcmcia_dump(sc)
836 1.1 uch struct plumpcmcia_softc *sc;
837 1.1 uch {
838 1.1 uch bus_space_tag_t regt = sc->sc_regt;
839 1.1 uch bus_space_handle_t regh = sc->sc_regh;
840 1.1 uch plumreg_t reg;
841 1.1 uch
842 1.1 uch int i, j;
843 1.1 uch
844 1.1 uch __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN0CTRL));
845 1.1 uch __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN1CTRL));
846 1.1 uch __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN2CTRL));
847 1.1 uch __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN3CTRL));
848 1.1 uch __memareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_MEMWIN4CTRL));
849 1.1 uch
850 1.1 uch __ioareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_IOWIN0ADDRCTRL));
851 1.1 uch __ioareadump(plum_conf_read(regt, regh, PLUM_PCMCIA_IOWIN1ADDRCTRL));
852 1.1 uch
853 1.1 uch for (j = 0; j < 2; j++) {
854 1.1 uch printf("[slot %d]\n", j);
855 1.1 uch for (i = 0; i < 0x120; i += 4) {
856 1.1 uch reg = plum_conf_read(sc->sc_regt, sc->sc_regh, i + 0x800 * j);
857 1.1 uch printf("%03x %08x", i, reg);
858 1.1 uch bitdisp(reg);
859 1.1 uch }
860 1.1 uch }
861 1.1 uch printf("\n");
862 1.1 uch }
863