1 /* $NetBSD: etna.c,v 1.4 2021/04/24 23:36:32 thorpej Exp $ */ 2 /* 3 * Copyright (c) 2012 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: etna.c,v 1.4 2021/04/24 23:36:32 thorpej Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/device.h> 34 #include <sys/errno.h> 35 #include <sys/kthread.h> 36 #include <sys/lwp.h> 37 38 #include <machine/epoc32.h> 39 40 #include <arm/pic/picvar.h> 41 42 #include <dev/pcmcia/pcmciachip.h> 43 #include <dev/pcmcia/pcmciavar.h> 44 45 #define ETNA_SIZE 0x10 46 #define ETNA_CFSPACE_SIZE 0x10000000 47 #define ETNA_ATTR_BASE 0x00000000 48 #define ETNA_MEM_BASE 0x04000000 49 #define ETNA_IO8_BASE 0x08000000 50 #define ETNA_IO16_BASE 0x0c000000 51 52 #define ETNA_INT_STATUS 0x6 /* Interrupt Status */ 53 #define ETNA_INT_MASK 0x7 /* Interrupt Mask */ 54 #define ETNA_INT_CLEAR 0x8 /* Interrupt Clear */ 55 #define INT_CARD (1 << 0) /* Card Interrupt */ 56 #define INT_BUSY (1 << 2) /* Socket Interrupt */ 57 #define INT_SOCK_1 (1 << 4) 58 #define INT_SOCK_2 (1 << 5) 59 #define INT_RESV (1 << 6) /* Reserved ? */ 60 #define ETNA_SKT_STATUS 0x9 61 #define SKT_BUSY (1 << 0) /* Socket BUSY */ 62 #define SKT_NOT_READY (1 << 1) /* Socket Not Ready */ 63 #define SKT_CARD_OUT (1 << 2) /* Socket Card Out */ 64 #define ETNA_SKT_CONFIG 0xa 65 #define ETNA_SKT_CTRL 0xb 66 #define ETNA_WAKE_1 0xc 67 #define ETNA_SKT_ACTIVE 0xd 68 #define ETNA_WAKE_2 0xf 69 70 struct etna_softc { 71 device_t sc_dev; 72 bus_space_tag_t sc_iot; 73 bus_space_handle_t sc_ioh; 74 75 device_t sc_pcmcia; 76 bus_addr_t sc_pcmcia_space; /* attr/mem/io spaces */ 77 #define NMEM_HANDLE 8 78 struct pcmcia_mem_handle *sc_pcmhp[NMEM_HANDLE]; 79 #define NIO_HANDLE 8 80 struct pcmcia_io_handle *sc_pcihp[NIO_HANDLE]; 81 82 int (*sc_card_handler)(void *); 83 void *sc_card_arg; 84 85 struct lwp *sc_event_thread; 86 }; 87 88 89 static int etna_match(device_t, cfdata_t, void *); 90 static void etna_attach(device_t, device_t, void *); 91 92 static int etna_card_intr(void *); 93 94 static void etna_doattach(device_t); 95 static void etna_event_thread(void *); 96 97 static void etna_attach_card(struct etna_softc *); 98 99 static int etna_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 100 struct pcmcia_mem_handle *); 101 static void etna_mem_free(pcmcia_chipset_handle_t, struct pcmcia_mem_handle *); 102 static int etna_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t, 103 struct pcmcia_mem_handle *, bus_size_t *, int *); 104 static void etna_mem_unmap(pcmcia_chipset_handle_t, int); 105 106 static int etna_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t, 107 bus_size_t, struct pcmcia_io_handle *); 108 static void etna_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *); 109 static int etna_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t, 110 struct pcmcia_io_handle *, int *); 111 static void etna_io_unmap(pcmcia_chipset_handle_t, int); 112 113 static void *etna_intr_establish(pcmcia_chipset_handle_t, 114 struct pcmcia_function *, int, 115 int (*)(void *), void *); 116 static void etna_intr_disestablish(pcmcia_chipset_handle_t, void *); 117 118 static void etna_socket_enable(pcmcia_chipset_handle_t); 119 static void etna_socket_disable(pcmcia_chipset_handle_t); 120 static void etna_socket_settype(pcmcia_chipset_handle_t, int); 121 122 CFATTACH_DECL_NEW(etna, sizeof(struct etna_softc), 123 etna_match, etna_attach, NULL, NULL); 124 125 struct pcmcia_chip_functions etna_pcmcia_functions = { 126 etna_mem_alloc, 127 etna_mem_free, 128 etna_mem_map, 129 etna_mem_unmap, 130 131 etna_io_alloc, 132 etna_io_free, 133 etna_io_map, 134 etna_io_unmap, 135 136 etna_intr_establish, 137 etna_intr_disestablish, 138 139 etna_socket_enable, 140 etna_socket_disable, 141 etna_socket_settype, 142 }; 143 144 /* ARGSUSED */ 145 static int 146 etna_match(device_t parent, cfdata_t match, void *aux) 147 { 148 struct external_attach_args *aa = aux; 149 bus_space_handle_t ioh; 150 int x, rv = 0; 151 152 if (bus_space_map(aa->iot, aa->addr, ETNA_SIZE, 0, &ioh) != 0) 153 return 0; 154 if (bus_space_read_1(aa->iot, ioh, 0x0) != 0x0f || 155 bus_space_read_1(aa->iot, ioh, 0x1) != 0x00 || 156 bus_space_read_1(aa->iot, ioh, 0x2) != 0x02 || 157 bus_space_read_1(aa->iot, ioh, 0x3) != 0x00 || 158 bus_space_read_1(aa->iot, ioh, 0x4) != 0x00 || 159 bus_space_read_1(aa->iot, ioh, 0xc) != 0x88) 160 goto out; 161 x = bus_space_read_1(aa->iot, ioh, ETNA_INT_MASK); 162 bus_space_write_1(aa->iot, ioh, ETNA_INT_MASK, (~x & 0xff) | INT_RESV); 163 if (bus_space_read_1(aa->iot, ioh, ETNA_INT_MASK) != 164 ((~x & 0xff) | INT_RESV)) { 165 bus_space_write_1(aa->iot, ioh, ETNA_INT_MASK, x); 166 goto out; 167 } 168 bus_space_write_1(aa->iot, ioh, ETNA_INT_MASK, x); 169 if (bus_space_read_1(aa->iot, ioh, ETNA_INT_MASK) != x) 170 goto out; 171 rv = 1; 172 out: 173 bus_space_unmap(aa->iot, ioh, ETNA_SIZE); 174 return rv; 175 } 176 177 /* ARGSUSED */ 178 static void 179 etna_attach(device_t parent, device_t self, void *aux) 180 { 181 struct etna_softc *sc = device_private(self); 182 struct external_attach_args *aa = aux; 183 struct pcmciabus_attach_args paa; 184 185 aprint_naive("\n"); 186 aprint_normal("\n"); 187 188 sc->sc_dev = self; 189 if (bus_space_map(aa->iot, aa->addr, ETNA_SIZE, 0, &sc->sc_ioh) != 0) { 190 aprint_error_dev(self, "can't map register\n"); 191 return; 192 } 193 sc->sc_iot = aa->iot; 194 if (intr_establish(aa->irq, IPL_BIO, 0, etna_card_intr, sc) == NULL) { 195 aprint_error_dev(self, "can't establish interrupt\n"); 196 bus_space_unmap(sc->sc_iot, sc->sc_ioh, ETNA_SIZE); 197 return; 198 } 199 sc->sc_pcmcia_space = aa->addr2; 200 201 paa.paa_busname = "pcmcia"; 202 paa.pct = &etna_pcmcia_functions; 203 paa.pch = sc; 204 sc->sc_pcmcia = config_found(self, &paa, NULL, CFARG_EOL); 205 206 config_interrupts(self, etna_doattach); 207 } 208 209 static int 210 etna_card_intr(void *arg) 211 { 212 struct etna_softc *sc = arg; 213 int status; 214 215 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ETNA_INT_STATUS); 216 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ETNA_INT_CLEAR, status); 217 218 if (sc->sc_card_handler == NULL) 219 return 0; 220 return sc->sc_card_handler(sc->sc_card_arg); 221 } 222 223 static void 224 etna_doattach(device_t self) 225 { 226 struct etna_softc *sc = device_private(self); 227 int status; 228 229 config_pending_incr(self); 230 231 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ETNA_SKT_STATUS); 232 if ((status & SKT_CARD_OUT) != SKT_CARD_OUT) 233 etna_attach_card(sc); 234 235 if (kthread_create(PRI_NONE, 0, NULL, etna_event_thread, sc, 236 &sc->sc_event_thread, device_xname(self))) 237 aprint_error_dev(self, "unable to create event thread\n"); 238 } 239 240 static void 241 etna_event_thread(void *arg) 242 { 243 struct etna_softc *sc = arg; 244 245 config_pending_decr(sc->sc_dev); 246 247 // while (1) { 248 // } 249 250 /* NOTREACHED */ 251 252 sc->sc_event_thread = NULL; 253 kthread_exit(0); 254 } 255 256 257 static void 258 etna_attach_card(struct etna_softc *sc) 259 { 260 261 pcmcia_card_attach(sc->sc_pcmcia); 262 } 263 264 265 /* 266 * pcmcia chip functions 267 */ 268 269 /* ARGSUSED */ 270 static int 271 etna_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 272 struct pcmcia_mem_handle *pcmhp) 273 { 274 struct etna_softc *sc = (struct etna_softc *)pch; 275 276 memset(pcmhp, 0, sizeof(*pcmhp)); 277 pcmhp->memt = sc->sc_iot; 278 return 0; 279 } 280 281 /* ARGSUSED */ 282 static void 283 etna_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pcmhp) 284 { 285 /* Nothing */ 286 } 287 288 static int 289 etna_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t card_addr, 290 bus_size_t size, struct pcmcia_mem_handle *pcmhp, 291 bus_size_t *offsetp, int *windowp) 292 { 293 struct etna_softc *sc = (struct etna_softc *)pch; 294 bus_addr_t addr; 295 int rv, i; 296 297 for (i = 0; i < NMEM_HANDLE; i++) 298 if (sc->sc_pcmhp[i] == NULL) 299 break; 300 if (i == NMEM_HANDLE) { 301 aprint_error_dev(sc->sc_dev, "no mem window\n"); 302 return ENOMEM; 303 } 304 305 addr = trunc_page(card_addr); 306 size = round_page(card_addr + size) - addr; 307 *offsetp = card_addr - addr; 308 addr += sc->sc_pcmcia_space; 309 switch (kind & ~PCMCIA_WIDTH_MEM_MASK) { 310 case PCMCIA_MEM_ATTR: 311 addr += ETNA_ATTR_BASE; 312 break; 313 case PCMCIA_MEM_COMMON: 314 addr += ETNA_MEM_BASE; 315 break; 316 default: 317 panic("etna_mem_map: bogus kind\n"); 318 } 319 rv = bus_space_map(pcmhp->memt, addr, size, 0, &pcmhp->memh); 320 if (rv) 321 return rv; 322 pcmhp->realsize = size; 323 sc->sc_pcmhp[i] = pcmhp; 324 *windowp = i; 325 return 0; 326 } 327 328 static void 329 etna_mem_unmap(pcmcia_chipset_handle_t pch, int window) 330 { 331 struct etna_softc *sc = (struct etna_softc *)pch; 332 struct pcmcia_mem_handle *pcmhp = sc->sc_pcmhp[window]; 333 334 bus_space_unmap(pcmhp->memt, pcmhp->memh, pcmhp->realsize); 335 sc->sc_pcmhp[window] = NULL; 336 } 337 338 /* ARGSUSED */ 339 static int 340 etna_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size, 341 bus_size_t align, struct pcmcia_io_handle *pcihp) 342 { 343 struct etna_softc *sc = (struct etna_softc *)pch; 344 extern char epoc32_model[]; 345 346 /* 347 * XXXXX: Series 5 can't allocate I/O map??? 348 */ 349 if (strcmp(epoc32_model, "SERIES5 R1") == 0) 350 return -1; 351 352 memset(pcihp, 0, sizeof(*pcihp)); 353 pcihp->iot = sc->sc_iot; 354 pcihp->addr = start; 355 pcihp->size = size; 356 357 return 0; 358 } 359 360 /* ARGSUSED */ 361 static void 362 etna_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pcihp) 363 { 364 /* Nothing */ 365 } 366 367 /* ARGSUSED */ 368 static int 369 etna_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset, 370 bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp) 371 { 372 struct etna_softc *sc = (struct etna_softc *)pch; 373 bus_addr_t addr; 374 int rv, i; 375 376 for (i = 0; i < NIO_HANDLE; i++) 377 if (sc->sc_pcihp[i] == NULL) 378 break; 379 if (i == NIO_HANDLE) { 380 aprint_error_dev(sc->sc_dev, "no io window\n"); 381 return ENOMEM; 382 } 383 384 addr = trunc_page(pcihp->addr); 385 size = round_page(pcihp->addr + size) - addr; 386 addr += sc->sc_pcmcia_space; 387 switch (width) { 388 case PCMCIA_WIDTH_AUTO: 389 case PCMCIA_WIDTH_IO16: 390 addr += ETNA_IO16_BASE; 391 break; 392 case PCMCIA_WIDTH_IO8: 393 addr += ETNA_IO8_BASE; 394 break; 395 default: 396 panic("etna_io_map: bogus width\n"); 397 } 398 rv = bus_space_map(pcihp->iot, addr, size, 0, &pcihp->ioh); 399 if (rv) 400 return rv; 401 sc->sc_pcihp[i] = pcihp; 402 *windowp = i; 403 return 0; 404 } 405 406 static void 407 etna_io_unmap(pcmcia_chipset_handle_t pch, int window) 408 { 409 struct etna_softc *sc = (struct etna_softc *)pch; 410 struct pcmcia_io_handle *pcihp = sc->sc_pcihp[window]; 411 412 bus_space_unmap(pcihp->iot, pcihp->ioh, pcihp->size); 413 sc->sc_pcihp[window] = NULL; 414 } 415 416 /* ARGSUSED */ 417 static void * 418 etna_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf, 419 int ipl, int (*fct)(void *), void *arg) 420 { 421 struct etna_softc *sc = (struct etna_softc *)pch; 422 423 sc->sc_card_handler = fct; 424 sc->sc_card_arg = arg; 425 426 /* Enable card interrupt */ 427 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ETNA_INT_MASK, INT_CARD); 428 429 return sc->sc_card_handler; /* XXXX: Is it OK? */ 430 } 431 432 static void 433 etna_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 434 { 435 struct etna_softc *sc = (struct etna_softc *)pch; 436 437 KASSERT(ih == sc->sc_card_handler); 438 439 /* Disable card interrupt */ 440 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ETNA_INT_MASK, 0x00); 441 442 sc->sc_card_handler = NULL; 443 sc->sc_card_arg = NULL; 444 } 445 446 static void 447 etna_socket_enable(pcmcia_chipset_handle_t pch) 448 { 449 /* XXXX: type depend */ 450 } 451 452 static void 453 etna_socket_disable(pcmcia_chipset_handle_t pch) 454 { 455 /* XXXX: type depend */ 456 } 457 458 static void 459 etna_socket_settype(pcmcia_chipset_handle_t pch, int type) 460 { 461 /* Nothing */ 462 } 463