1 /* $NetBSD: hd64465pcmcia.c,v 1.20 2005/12/11 12:17:36 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 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. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: hd64465pcmcia.c,v 1.20 2005/12/11 12:17:36 christos Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/kthread.h> 47 #include <sys/boot_flag.h> 48 49 #include <uvm/uvm_extern.h> 50 51 #include <machine/bus.h> 52 #include <machine/intr.h> 53 54 #include <dev/pcmcia/pcmciareg.h> 55 #include <dev/pcmcia/pcmciavar.h> 56 #include <dev/pcmcia/pcmciachip.h> 57 58 #include <sh3/bscreg.h> 59 #include <sh3/mmu.h> 60 61 #include <hpcsh/dev/hd64465/hd64465reg.h> 62 #include <hpcsh/dev/hd64465/hd64465var.h> 63 #include <hpcsh/dev/hd64465/hd64465intcreg.h> 64 #include <hpcsh/dev/hd64461/hd64461pcmciareg.h> 65 66 #include "locators.h" 67 68 #ifdef HD64465PCMCIA_DEBUG 69 #define DPRINTF_ENABLE 70 #define DPRINTF_DEBUG hd64465pcmcia_debug 71 #endif 72 #include <machine/debug.h> 73 74 enum memory_window_16 { 75 MEMWIN_16M_COMMON_0, 76 MEMWIN_16M_COMMON_1, 77 MEMWIN_16M_COMMON_2, 78 MEMWIN_16M_COMMON_3, 79 }; 80 #define MEMWIN_16M_MAX 4 81 82 enum hd64465pcmcia_event_type { 83 EVENT_NONE, 84 EVENT_INSERT, 85 EVENT_REMOVE, 86 }; 87 #define EVENT_QUEUE_MAX 5 88 89 struct hd64465pcmcia_softc; /* forward declaration */ 90 91 struct hd64465pcmcia_window_cookie { 92 bus_space_tag_t wc_tag; 93 bus_space_handle_t wc_handle; 94 int wc_size; 95 int wc_window; 96 }; 97 98 struct hd64465pcmcia_channel { 99 struct hd64465pcmcia_softc *ch_parent; 100 struct device *ch_pcmcia; 101 int ch_channel; 102 103 /* memory space */ 104 bus_space_tag_t ch_memt; 105 bus_space_handle_t ch_memh; 106 bus_addr_t ch_membase_addr; 107 bus_size_t ch_memsize; 108 bus_space_tag_t ch_cmemt[MEMWIN_16M_MAX]; 109 110 /* I/O space */ 111 bus_space_tag_t ch_iot; 112 bus_addr_t ch_iobase; 113 bus_size_t ch_iosize; 114 115 /* card interrupt */ 116 int (*ch_ih_card_func)(void *); 117 void *ch_ih_card_arg; 118 int ch_attached; 119 }; 120 121 struct hd64465pcmcia_event { 122 int __queued; 123 enum hd64465pcmcia_event_type pe_type; 124 struct hd64465pcmcia_channel *pe_ch; 125 SIMPLEQ_ENTRY(hd64465pcmcia_event) pe_link; 126 }; 127 128 struct hd64465pcmcia_softc { 129 struct device sc_dev; 130 enum hd64465_module_id sc_module_id; 131 int sc_shutdown; 132 133 /* kv mapped Area 5, 6 */ 134 vaddr_t sc_area5; 135 vaddr_t sc_area6; 136 137 /* CSC event */ 138 struct proc *sc_event_thread; 139 struct hd64465pcmcia_event sc_event_pool[EVENT_QUEUE_MAX]; 140 SIMPLEQ_HEAD (, hd64465pcmcia_event) sc_event_head; 141 142 struct hd64465pcmcia_channel sc_ch[2]; 143 }; 144 145 STATIC int hd64465pcmcia_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 146 struct pcmcia_mem_handle *); 147 STATIC void hd64465pcmcia_chip_mem_free(pcmcia_chipset_handle_t, 148 struct pcmcia_mem_handle *); 149 STATIC int hd64465pcmcia_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, 150 bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *); 151 STATIC void hd64465pcmcia_chip_mem_unmap(pcmcia_chipset_handle_t, int); 152 STATIC int hd64465pcmcia_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, 153 bus_size_t, bus_size_t, struct pcmcia_io_handle *); 154 STATIC void hd64465pcmcia_chip_io_free(pcmcia_chipset_handle_t, 155 struct pcmcia_io_handle *); 156 STATIC int hd64465pcmcia_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, 157 bus_size_t, struct pcmcia_io_handle *, int *); 158 STATIC void hd64465pcmcia_chip_io_unmap(pcmcia_chipset_handle_t, int); 159 STATIC void hd64465pcmcia_chip_socket_enable(pcmcia_chipset_handle_t); 160 STATIC void hd64465pcmcia_chip_socket_disable(pcmcia_chipset_handle_t); 161 STATIC void hd64465pcmcia_chip_socket_settype(pcmcia_chipset_handle_t, int); 162 STATIC void *hd64465pcmcia_chip_intr_establish(pcmcia_chipset_handle_t, 163 struct pcmcia_function *, int, int (*)(void *), void *); 164 STATIC void hd64465pcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t, 165 void *); 166 167 STATIC struct pcmcia_chip_functions hd64465pcmcia_functions = { 168 hd64465pcmcia_chip_mem_alloc, 169 hd64465pcmcia_chip_mem_free, 170 hd64465pcmcia_chip_mem_map, 171 hd64465pcmcia_chip_mem_unmap, 172 hd64465pcmcia_chip_io_alloc, 173 hd64465pcmcia_chip_io_free, 174 hd64465pcmcia_chip_io_map, 175 hd64465pcmcia_chip_io_unmap, 176 hd64465pcmcia_chip_intr_establish, 177 hd64465pcmcia_chip_intr_disestablish, 178 hd64465pcmcia_chip_socket_enable, 179 hd64465pcmcia_chip_socket_disable, 180 hd64465pcmcia_chip_socket_settype, 181 }; 182 183 STATIC int hd64465pcmcia_match(struct device *, struct cfdata *, void *); 184 STATIC void hd64465pcmcia_attach(struct device *, struct device *, void *); 185 STATIC int hd64465pcmcia_print(void *, const char *); 186 STATIC int hd64465pcmcia_submatch(struct device *, struct cfdata *, 187 const int *, void *); 188 189 CFATTACH_DECL(hd64465pcmcia, sizeof(struct hd64465pcmcia_softc), 190 hd64465pcmcia_match, hd64465pcmcia_attach, NULL, NULL); 191 192 STATIC void hd64465pcmcia_attach_channel(struct hd64465pcmcia_softc *, int); 193 /* hot plug */ 194 STATIC void hd64465pcmcia_create_event_thread(void *); 195 STATIC void hd64465pcmcia_event_thread(void *); 196 STATIC void __queue_event(struct hd64465pcmcia_channel *, 197 enum hd64465pcmcia_event_type); 198 /* interrupt handler */ 199 STATIC int hd64465pcmcia_intr(void *); 200 /* card status */ 201 STATIC enum hd64465pcmcia_event_type __detect_card(int); 202 STATIC void hd64465pcmcia_memory_window16_switch(int, enum memory_window_16); 203 /* bus width */ 204 STATIC void __sh_set_bus_width(int, int); 205 /* bus space access */ 206 STATIC int __sh_hd64465_map(vaddr_t, paddr_t, size_t, u_int32_t); 207 STATIC vaddr_t __sh_hd64465_map_2page(paddr_t); 208 209 #define DELAY_MS(x) delay((x) * 1000) 210 211 int 212 hd64465pcmcia_match(struct device *parent, struct cfdata *cf, void *aux) 213 { 214 struct hd64465_attach_args *ha = aux; 215 216 return (ha->ha_module_id == HD64465_MODULE_PCMCIA); 217 } 218 219 void 220 hd64465pcmcia_attach(struct device *parent, struct device *self, void *aux) 221 { 222 struct hd64465_attach_args *ha = aux; 223 struct hd64465pcmcia_softc *sc = (struct hd64465pcmcia_softc *)self; 224 225 sc->sc_module_id = ha->ha_module_id; 226 227 printf("\n"); 228 229 sc->sc_area5 = __sh_hd64465_map_2page(0x14000000); /* area 5 */ 230 sc->sc_area6 = __sh_hd64465_map_2page(0x18000000); /* area 6 */ 231 232 if (sc->sc_area5 == 0 || sc->sc_area6 == 0) { 233 printf("%s: can't map memory.\n", sc->sc_dev.dv_xname); 234 if (sc->sc_area5) 235 uvm_km_free(kernel_map, sc->sc_area5, 0x03000000, 236 UVM_KMF_VAONLY); 237 if (sc->sc_area6) 238 uvm_km_free(kernel_map, sc->sc_area6, 0x03000000, 239 UVM_KMF_VAONLY); 240 241 return; 242 } 243 244 /* Channel 0/1 common CSC event queue */ 245 SIMPLEQ_INIT (&sc->sc_event_head); 246 kthread_create(hd64465pcmcia_create_event_thread, sc); 247 248 hd64465pcmcia_attach_channel(sc, 0); 249 hd64465pcmcia_attach_channel(sc, 1); 250 } 251 252 void 253 hd64465pcmcia_create_event_thread(void *arg) 254 { 255 struct hd64465pcmcia_softc *sc = arg; 256 int error; 257 258 error = kthread_create1(hd64465pcmcia_event_thread, sc, 259 &sc->sc_event_thread, "%s", sc->sc_dev.dv_xname); 260 261 KASSERT(error == 0); 262 } 263 264 void 265 hd64465pcmcia_event_thread(void *arg) 266 { 267 struct hd64465pcmcia_softc *sc = arg; 268 struct hd64465pcmcia_event *pe; 269 int s; 270 271 while (!sc->sc_shutdown) { 272 tsleep(sc, PWAIT, "CSC wait", 0); 273 s = splhigh(); 274 while ((pe = SIMPLEQ_FIRST(&sc->sc_event_head))) { 275 splx(s); 276 switch (pe->pe_type) { 277 default: 278 printf("%s: unknown event.\n", __FUNCTION__); 279 break; 280 case EVENT_INSERT: 281 DPRINTF("insert event.\n"); 282 pcmcia_card_attach(pe->pe_ch->ch_pcmcia); 283 break; 284 case EVENT_REMOVE: 285 DPRINTF("remove event.\n"); 286 pcmcia_card_detach(pe->pe_ch->ch_pcmcia, 287 DETACH_FORCE); 288 break; 289 } 290 s = splhigh(); 291 SIMPLEQ_REMOVE_HEAD(&sc->sc_event_head, pe_link); 292 pe->__queued = 0; 293 } 294 splx(s); 295 } 296 /* NOTREACHED */ 297 } 298 299 int 300 hd64465pcmcia_print(void *arg, const char *pnp) 301 { 302 303 if (pnp) 304 aprint_normal("pcmcia at %s", pnp); 305 306 return (UNCONF); 307 } 308 309 int 310 hd64465pcmcia_submatch(struct device *parent, struct cfdata *cf, 311 const int *ldesc, void *aux) 312 { 313 struct pcmciabus_attach_args *paa = aux; 314 struct hd64465pcmcia_channel *ch = 315 (struct hd64465pcmcia_channel *)paa->pch; 316 317 if (ch->ch_channel == 0) { 318 if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 319 PCMCIABUSCF_CONTROLLER_DEFAULT && 320 cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 0) 321 return 0; 322 } else { 323 if (cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 324 PCMCIABUSCF_CONTROLLER_DEFAULT && 325 cf->cf_loc[PCMCIABUSCF_CONTROLLER] != 1) 326 return 0; 327 } 328 paa->pct = (pcmcia_chipset_tag_t)&hd64465pcmcia_functions; 329 330 return (config_match(parent, cf, aux)); 331 } 332 333 void 334 hd64465pcmcia_attach_channel(struct hd64465pcmcia_softc *sc, int channel) 335 { 336 struct device *parent = (struct device *)sc; 337 struct hd64465pcmcia_channel *ch = &sc->sc_ch[channel]; 338 struct pcmciabus_attach_args paa; 339 bus_addr_t baseaddr; 340 u_int8_t r; 341 int i; 342 343 ch->ch_parent = sc; 344 ch->ch_channel = channel; 345 346 /* 347 * Continuous 16-MB Area Mode 348 */ 349 /* set Continuous 16-MB Area Mode */ 350 r = hd64465_reg_read_1(HD64461_PCCGCR(channel)); 351 r &= ~HD64461_PCCGCR_MMOD; 352 r |= HD64461_PCCGCR_MMOD_16M; 353 hd64465_reg_write_1(HD64461_PCCGCR(channel), r); 354 355 /* Attibute/Common memory extent */ 356 baseaddr = (channel == 0) ? sc->sc_area6 : sc->sc_area5; 357 358 ch->ch_memt = bus_space_create(0, "PCMCIA attribute memory", 359 baseaddr, 0x01000000); /* 16MB */ 360 bus_space_alloc(ch->ch_memt, 0, 0x00ffffff, 0x0001000, 361 0x1000, 0x1000, 0, &ch->ch_membase_addr, &ch->ch_memh); 362 363 /* Common memory space extent */ 364 ch->ch_memsize = 0x01000000; 365 for (i = 0; i < MEMWIN_16M_MAX; i++) { 366 ch->ch_cmemt[i] = bus_space_create(0, "PCMCIA common memory", 367 baseaddr + 0x01000000, ch->ch_memsize); 368 } 369 370 /* I/O port extent */ 371 ch->ch_iobase = 0; 372 ch->ch_iosize = 0x01000000; 373 ch->ch_iot = bus_space_create(0, "PCMCIA I/O port", 374 baseaddr + 0x01000000 * 2, ch->ch_iosize); 375 376 /* Interrupt */ 377 hd64465_intr_establish(channel ? HD64465_PCC1 : HD64465_PCC0, 378 IST_LEVEL, IPL_TTY, hd64465pcmcia_intr, ch); 379 380 paa.paa_busname = "pcmcia"; 381 paa.pch = (pcmcia_chipset_handle_t)ch; 382 paa.iobase = ch->ch_iobase; 383 paa.iosize = ch->ch_iosize; 384 385 ch->ch_pcmcia = config_found_sm_loc(parent, "pcmciabus", NULL, &paa, 386 hd64465pcmcia_print, hd64465pcmcia_submatch); 387 388 if (ch->ch_pcmcia && (__detect_card(ch->ch_channel) == EVENT_INSERT)) { 389 ch->ch_attached = 1; 390 pcmcia_card_attach(ch->ch_pcmcia); 391 } 392 } 393 394 int 395 hd64465pcmcia_intr(void *arg) 396 { 397 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)arg; 398 u_int32_t cscr; 399 u_int8_t r; 400 int ret = 0; 401 402 cscr = HD64461_PCCCSCR(ch->ch_channel); 403 r = hd64465_reg_read_1(cscr); 404 405 /* clear interrtupt (don't change power switch select) */ 406 hd64465_reg_write_1(cscr, r & ~0x40); 407 408 if (r & (0x60 | 0x04/* for memory mapped mode*/)) { 409 if (ch->ch_ih_card_func) { 410 ret = (*ch->ch_ih_card_func)(ch->ch_ih_card_arg); 411 } else { 412 DPRINTF("spurious IREQ interrupt.\n"); 413 } 414 } 415 416 if (r & HD64461_PCC0CSCR_P0CDC) 417 __queue_event(ch, __detect_card(ch->ch_channel)); 418 419 return (ret); 420 } 421 422 void 423 __queue_event(struct hd64465pcmcia_channel *ch, 424 enum hd64465pcmcia_event_type type) 425 { 426 struct hd64465pcmcia_event *pe, *pool; 427 struct hd64465pcmcia_softc *sc = ch->ch_parent; 428 int i; 429 int s = splhigh(); 430 431 if (type == EVENT_NONE) 432 goto out; 433 434 pe = 0; 435 pool = sc->sc_event_pool; 436 for (i = 0; i < EVENT_QUEUE_MAX; i++) { 437 if (!pool[i].__queued) { 438 pe = &pool[i]; 439 break; 440 } 441 } 442 443 if (pe == 0) { 444 printf("%s: event FIFO overflow (max %d).\n", __FUNCTION__, 445 EVENT_QUEUE_MAX); 446 goto out; 447 } 448 449 if ((ch->ch_attached && (type == EVENT_INSERT)) || 450 (!ch->ch_attached && (type == EVENT_REMOVE))) { 451 DPRINTF("spurious CSC interrupt.\n"); 452 goto out; 453 } 454 455 ch->ch_attached = (type == EVENT_INSERT); 456 pe->__queued = 1; 457 pe->pe_type = type; 458 pe->pe_ch = ch; 459 SIMPLEQ_INSERT_TAIL(&sc->sc_event_head, pe, pe_link); 460 wakeup(sc); 461 out: 462 splx(s); 463 } 464 465 /* 466 * Interface for pcmcia driver. 467 */ 468 /* 469 * Interrupt. 470 */ 471 void * 472 hd64465pcmcia_chip_intr_establish(pcmcia_chipset_handle_t pch, 473 struct pcmcia_function *pf, int ipl, int (*ih_func)(void *), void *ih_arg) 474 { 475 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 476 int channel = ch->ch_channel; 477 bus_addr_t cscier = HD64461_PCCCSCIER(channel); 478 u_int8_t r; 479 int s = splhigh(); 480 481 hd6446x_intr_priority(ch->ch_channel == 0 ? HD64465_PCC0 : HD64465_PCC1, 482 ipl); 483 484 ch->ch_ih_card_func = ih_func; 485 ch->ch_ih_card_arg = ih_arg; 486 487 /* Enable card interrupt */ 488 r = hd64465_reg_read_1(cscier); 489 /* set level mode */ 490 r &= ~HD64461_PCC0CSCIER_P0IREQE_MASK; 491 r |= HD64461_PCC0CSCIER_P0IREQE_LEVEL; 492 hd64465_reg_write_1(cscier, r); 493 494 splx(s); 495 496 return (void *)ih_func; 497 } 498 499 void 500 hd64465pcmcia_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 501 { 502 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 503 int channel = ch->ch_channel; 504 bus_addr_t cscier = HD64461_PCCCSCIER(channel); 505 int s = splhigh(); 506 u_int8_t r; 507 508 hd6446x_intr_priority(ch->ch_channel == 0 ? HD64465_PCC0 : HD64465_PCC1, 509 IPL_TTY); 510 511 /* Disable card interrupt */ 512 r = hd64465_reg_read_1(cscier); 513 r &= ~HD64461_PCC0CSCIER_P0IREQE_MASK; 514 r |= HD64461_PCC0CSCIER_P0IREQE_NONE; 515 hd64465_reg_write_1(cscier, r); 516 517 ch->ch_ih_card_func = 0; 518 519 splx(s); 520 } 521 522 /* 523 * Bus resources. 524 */ 525 int 526 hd64465pcmcia_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 527 struct pcmcia_mem_handle *pcmhp) 528 { 529 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 530 531 pcmhp->memt = ch->ch_memt; 532 pcmhp->addr = ch->ch_membase_addr; 533 pcmhp->memh = ch->ch_memh; 534 pcmhp->size = size; 535 pcmhp->realsize = size; 536 537 DPRINTF("base 0x%08lx size %#lx\n", pcmhp->addr, size); 538 539 return (0); 540 } 541 542 void 543 hd64465pcmcia_chip_mem_free(pcmcia_chipset_handle_t pch, 544 struct pcmcia_mem_handle *pcmhp) 545 { 546 /* NO-OP */ 547 } 548 549 int 550 hd64465pcmcia_chip_mem_map(pcmcia_chipset_handle_t pch, int kind, 551 bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pcmhp, 552 bus_size_t *offsetp, int *windowp) 553 { 554 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 555 struct hd64465pcmcia_window_cookie *cookie; 556 bus_addr_t ofs; 557 558 cookie = malloc(sizeof(struct hd64465pcmcia_window_cookie), 559 M_DEVBUF, M_NOWAIT); 560 KASSERT(cookie); 561 memset(cookie, 0, sizeof(struct hd64465pcmcia_window_cookie)); 562 563 /* Address */ 564 if ((kind & ~PCMCIA_WIDTH_MEM_MASK) == PCMCIA_MEM_ATTR) { 565 cookie->wc_tag = ch->ch_memt; 566 if (bus_space_subregion(ch->ch_memt, ch->ch_memh, card_addr, 567 size, &cookie->wc_handle) != 0) 568 goto bad; 569 570 *offsetp = card_addr; 571 cookie->wc_window = -1; 572 } else { 573 int window = card_addr / ch->ch_memsize; 574 KASSERT(window < MEMWIN_16M_MAX); 575 576 cookie->wc_tag = ch->ch_cmemt[window]; 577 ofs = card_addr - window * ch->ch_memsize; 578 if (bus_space_map(cookie->wc_tag, ofs, size, 0, 579 &cookie->wc_handle) != 0) 580 goto bad; 581 582 /* XXX bogus. check window per common memory access. */ 583 hd64465pcmcia_memory_window16_switch(ch->ch_channel, window); 584 *offsetp = ofs + 0x01000000; /* skip attribute area */ 585 cookie->wc_window = window; 586 } 587 cookie->wc_size = size; 588 *windowp = (int)cookie; 589 590 DPRINTF("(%s) %#lx+%#lx-> %#lx+%#lx\n", kind == PCMCIA_MEM_ATTR ? 591 "attribute" : "common", ch->ch_memh, card_addr, *offsetp, size); 592 593 return (0); 594 bad: 595 DPRINTF("%#lx-%#lx map failed.\n", card_addr, size); 596 free(cookie, M_DEVBUF); 597 598 return (1); 599 } 600 601 void 602 hd64465pcmcia_chip_mem_unmap(pcmcia_chipset_handle_t pch, int window) 603 { 604 struct hd64465pcmcia_window_cookie *cookie = (void *)window; 605 606 if (cookie->wc_window != -1) 607 bus_space_unmap(cookie->wc_tag, cookie->wc_handle, 608 cookie->wc_size); 609 DPRINTF("%#lx-%#x\n", cookie->wc_handle, cookie->wc_size); 610 free(cookie, M_DEVBUF); 611 } 612 613 int 614 hd64465pcmcia_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, 615 bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp) 616 { 617 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 618 619 if (start) { 620 if (bus_space_map(ch->ch_iot, start, size, 0, &pcihp->ioh)) { 621 DPRINTF("couldn't map %#lx+%#lx\n", start, size); 622 return (1); 623 } 624 pcihp->addr = pcihp->ioh; 625 DPRINTF("map %#lx+%#lx\n", start, size); 626 } else { 627 if (bus_space_alloc(ch->ch_iot, ch->ch_iobase, 628 ch->ch_iobase + ch->ch_iosize - 1, 629 size, align, 0, 0, &pcihp->addr, &pcihp->ioh)) { 630 DPRINTF("couldn't allocate %#lx\n", size); 631 return (1); 632 } 633 pcihp->flags = PCMCIA_IO_ALLOCATED; 634 } 635 DPRINTF("%#lx from %#lx\n", size, pcihp->addr); 636 637 pcihp->iot = ch->ch_iot; 638 pcihp->size = size; 639 640 return (0); 641 } 642 643 int 644 hd64465pcmcia_chip_io_map(pcmcia_chipset_handle_t pch, int width, 645 bus_addr_t offset, bus_size_t size, struct pcmcia_io_handle *pcihp, 646 int *windowp) 647 { 648 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 649 #ifdef HD64465PCMCIA_DEBUG 650 static const char *width_names[] = { "auto", "io8", "io16" }; 651 #endif 652 653 __sh_set_bus_width(ch->ch_channel, width); 654 655 DPRINTF("%#lx:%#lx+%#lx %s\n", pcihp->ioh, offset, size, 656 width_names[width]); 657 658 return (0); 659 } 660 661 void 662 hd64465pcmcia_chip_io_free(pcmcia_chipset_handle_t pch, 663 struct pcmcia_io_handle *pcihp) 664 { 665 666 if (pcihp->flags & PCMCIA_IO_ALLOCATED) 667 bus_space_free(pcihp->iot, pcihp->ioh, pcihp->size); 668 else 669 bus_space_unmap(pcihp->iot, pcihp->ioh, pcihp->size); 670 671 DPRINTF("%#lx+%#lx\n", pcihp->ioh, pcihp->size); 672 } 673 674 void 675 hd64465pcmcia_chip_io_unmap(pcmcia_chipset_handle_t pch, int window) 676 { 677 /* nothing to do */ 678 } 679 680 /* 681 * Enable/Disable 682 */ 683 void 684 hd64465pcmcia_chip_socket_enable(pcmcia_chipset_handle_t pch) 685 { 686 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 687 int channel = ch->ch_channel; 688 bus_addr_t gcr; 689 u_int8_t r; 690 691 DPRINTF("enable channel %d\n", channel); 692 gcr = HD64461_PCCGCR(channel); 693 694 r = hd64465_reg_read_1(gcr); 695 r &= ~HD64461_PCC0GCR_P0PCCT; 696 hd64465_reg_write_1(gcr, r); 697 698 /* Set Common memory area #0. */ 699 hd64465pcmcia_memory_window16_switch(channel, MEMWIN_16M_COMMON_0); 700 701 DPRINTF("OK.\n"); 702 } 703 704 void 705 hd64465pcmcia_chip_socket_settype(pcmcia_chipset_handle_t pch, int type) 706 { 707 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 708 int channel = ch->ch_channel; 709 bus_addr_t gcr; 710 u_int8_t r; 711 712 DPRINTF("settype channel %d\n", channel); 713 gcr = HD64461_PCCGCR(channel); 714 715 /* Set the card type */ 716 r = hd64465_reg_read_1(gcr); 717 if (type == PCMCIA_IFTYPE_IO) 718 r |= HD64461_PCC0GCR_P0PCCT; 719 else 720 r &= ~HD64461_PCC0GCR_P0PCCT; 721 hd64465_reg_write_1(gcr, r); 722 723 DPRINTF("OK.\n"); 724 } 725 726 void 727 hd64465pcmcia_chip_socket_disable(pcmcia_chipset_handle_t pch) 728 { 729 struct hd64465pcmcia_channel *ch = (struct hd64465pcmcia_channel *)pch; 730 int channel = ch->ch_channel; 731 732 /* dont' disable CSC interrupt */ 733 hd64465_reg_write_1(HD64461_PCCCSCIER(channel), HD64461_PCCCSCIER_CDE); 734 hd64465_reg_write_1(HD64461_PCCCSCR(channel), 0); 735 } 736 737 /* 738 * Card detect 739 */ 740 enum hd64465pcmcia_event_type 741 __detect_card(int channel) 742 { 743 u_int8_t r; 744 745 r = hd64465_reg_read_1(HD64461_PCCISR(channel)) & 746 (HD64461_PCCISR_CD2 | HD64461_PCCISR_CD1); 747 748 if (r == (HD64461_PCCISR_CD2 | HD64461_PCCISR_CD1)) { 749 DPRINTF("remove\n"); 750 return EVENT_REMOVE; 751 } 752 if (r == 0) { 753 DPRINTF("insert\n"); 754 return EVENT_INSERT; 755 } 756 DPRINTF("transition\n"); 757 758 return (EVENT_NONE); 759 } 760 761 /* 762 * Memory window access ops. 763 */ 764 void 765 hd64465pcmcia_memory_window16_switch(int channel, enum memory_window_16 window) 766 { 767 bus_addr_t a = HD64461_PCCGCR(channel); 768 u_int8_t r; 769 770 r = hd64465_reg_read_1(a); 771 r &= ~(HD64461_PCCGCR_PA25 | HD64461_PCCGCR_PA24); 772 773 switch (window) { 774 case MEMWIN_16M_COMMON_0: 775 break; 776 case MEMWIN_16M_COMMON_1: 777 r |= HD64461_PCCGCR_PA24; 778 break; 779 case MEMWIN_16M_COMMON_2: 780 r |= HD64461_PCCGCR_PA25; 781 break; 782 case MEMWIN_16M_COMMON_3: 783 r |= (HD64461_PCCGCR_PA25 | HD64461_PCCGCR_PA24); 784 break; 785 } 786 787 hd64465_reg_write_1(a, r); 788 } 789 790 /* 791 * SH interface. 792 */ 793 void 794 __sh_set_bus_width(int channel, int width) 795 { 796 u_int16_t r16; 797 798 r16 = _reg_read_2(SH4_BCR2); 799 #ifdef HD64465PCMCIA_DEBUG 800 dbg_bit_print_msg(r16, "BCR2"); 801 #endif 802 if (channel == 0) { 803 r16 &= ~((1 << 13)|(1 << 12)); 804 r16 |= 1 << (width == PCMCIA_WIDTH_IO8 ? 12 : 13); 805 } else { 806 r16 &= ~((1 << 11)|(1 << 10)); 807 r16 |= 1 << (width == PCMCIA_WIDTH_IO8 ? 10 : 11); 808 } 809 _reg_write_2(SH4_BCR2, r16); 810 } 811 812 vaddr_t 813 __sh_hd64465_map_2page(paddr_t pa) 814 { 815 static const u_int32_t mode[] = 816 { _PG_PCMCIA_ATTR16, _PG_PCMCIA_MEM16, _PG_PCMCIA_IO }; 817 vaddr_t va, v; 818 int i; 819 820 /* allocate kernel virtual */ 821 v = va = uvm_km_alloc(kernel_map, 0x03000000, 0, UVM_KMF_VAONLY); 822 if (va == 0) { 823 PRINTF("can't allocate virtual for paddr 0x%08x\n", 824 (unsigned)pa); 825 826 return (0); 827 } 828 829 /* map to physical addreess with specified memory type. */ 830 for (i = 0; i < 3; i++, pa += 0x01000000, va += 0x01000000) { 831 if (__sh_hd64465_map(va, pa, 0x2000, mode[i]) != 0) { 832 pmap_kremove(v, 0x03000000); 833 uvm_km_free(kernel_map, v, 0x03000000, UVM_KMF_VAONLY); 834 return (0); 835 } 836 } 837 838 return (v); 839 } 840 841 int 842 __sh_hd64465_map(vaddr_t va, paddr_t pa, size_t sz, u_int32_t flags) 843 { 844 pt_entry_t *pte; 845 paddr_t epa; 846 847 KDASSERT(((pa & PAGE_MASK) == 0) && ((va & PAGE_MASK) == 0) && 848 ((sz & PAGE_MASK) == 0)); 849 850 epa = pa + sz; 851 while (pa < epa) { 852 pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); 853 pte = __pmap_kpte_lookup(va); 854 KDASSERT(pte); 855 *pte |= flags; /* PTEA PCMCIA assistant bit */ 856 sh_tlb_update(0, va, *pte); 857 pa += PAGE_SIZE; 858 va += PAGE_SIZE; 859 } 860 861 return (0); 862 } 863