Home | History | Annotate | Line # | Download | only in maple
maple.c revision 1.6
      1 /*	$NetBSD: maple.c,v 1.6 2001/03/16 19:57:49 marcus Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 Marcus Comstedt
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Marcus Comstedt.
     18  * 4. Neither the name of The NetBSD Foundation nor the names of its
     19  *    contributors may be used to endorse or promote products derived
     20  *    from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     32  * POSSIBILITY OF SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/param.h>
     36 #include <sys/device.h>
     37 #include <sys/fcntl.h>
     38 #include <sys/poll.h>
     39 #include <sys/select.h>
     40 #include <sys/proc.h>
     41 #include <sys/signalvar.h>
     42 #include <sys/systm.h>
     43 
     44 #include <uvm/uvm_extern.h>
     45 
     46 #include <machine/cpu.h>
     47 #include <machine/bus.h>
     48 #include <sh3/shbvar.h>
     49 #include <sh3/pmap.h>
     50 
     51 
     52 #include <dreamcast/dev/maple/maple.h>
     53 #include <dreamcast/dev/maple/mapleconf.h>
     54 #include <dreamcast/dev/maple/maplevar.h>
     55 #include <dreamcast/dev/maple/maplereg.h>
     56 
     57 
     58 #define MAPLE_CALLOUT_TICKS 2
     59 
     60 /*
     61  * Function declarations.
     62  */
     63 static int	maplematch __P((struct device *, struct cfdata *, void *));
     64 static void	mapleattach __P((struct device *, struct device *, void *));
     65 static int	mapleprint __P((void *, const char *));
     66 static int	maplesubmatch __P((struct device *, struct cfdata *, void *));
     67 static void	maple_attach_dev __P((struct maple_softc *, int, int));
     68 static void	maple_begin_txbuf __P((struct maple_softc *));
     69 static int	maple_end_txbuf __P((struct maple_softc *));
     70 static void	maple_write_command __P((struct maple_softc *, int, int,
     71 					 int, int, void *));
     72 static void	maple_scanbus __P((struct maple_softc *));
     73 static void	maple_callout __P((void *));
     74 static void	maple_send_commands __P((struct maple_softc *));
     75 static void	maple_check_responses __P((struct maple_softc *));
     76 
     77 int maple_alloc_dma __P((size_t, vaddr_t *, paddr_t *));
     78 void maple_free_dma __P((paddr_t, size_t));
     79 
     80 
     81 /*
     82  * Global variables.
     83  */
     84 int	maple_polling = 0;	/* Are we polling?  (Debugger mode) */
     85 
     86 /*
     87  * Driver definition.
     88  */
     89 struct cfattach maple_ca = {
     90 	sizeof(struct maple_softc), maplematch, mapleattach
     91 };
     92 
     93 static int
     94 maplematch(parent, cf, aux)
     95 	struct device *parent;
     96 	struct cfdata *cf;
     97 	void *aux;
     98 {
     99 	struct shb_attach_args *sa = aux;
    100 
    101 	if (strcmp("maple", cf->cf_driver->cd_name))
    102 	  return (0);
    103 
    104 	sa->ia_iosize = 0 /* 0x100 */;
    105 	return (1);
    106 }
    107 
    108 static void
    109 maple_attach_dev(sc, port, subunit)
    110 	struct maple_softc *sc;
    111 	int port;
    112 	int subunit;
    113 {
    114 	struct maple_attach_args ma;
    115 
    116 	ma.ma_port = port;
    117 	ma.ma_subunit = subunit;
    118 	ma.ma_devinfo = &sc->sc_unit[port][subunit].devinfo;
    119 
    120 	(void) config_found_sm(&sc->sc_dev, &ma, mapleprint, maplesubmatch);
    121 }
    122 
    123 static void
    124 maple_begin_txbuf(sc)
    125 	struct maple_softc *sc;
    126 {
    127 	sc->sc_txlink = sc->sc_txpos = sc->sc_txbuf;
    128 }
    129 
    130 static int
    131 maple_end_txbuf(sc)
    132 	struct maple_softc *sc;
    133 {
    134 	/* if no frame have been written, we can't mark the
    135 	   list end, and so the DMA must not be activated   */
    136   	if (sc->sc_txpos == sc->sc_txbuf)
    137 	  return (0);
    138 
    139 	*sc->sc_txlink |= 0x80000000;
    140 
    141 	return (1);
    142 }
    143 
    144 static int8_t subunit_code[] = { 0x20, 0x01, 0x02, 0x04, 0x08, 0x10 };
    145 
    146 static void
    147 maple_write_command(sc, port, subunit, command, datalen, dataaddr)
    148 	struct maple_softc *sc;
    149 	int port;
    150 	int subunit;
    151 	int command;
    152 	int datalen;
    153 	void *dataaddr;
    154 {
    155 	int to, from;
    156 	u_int32_t *p = sc->sc_txpos;
    157 
    158 	if ((port & ~(MAPLE_PORTS-1)) != 0 ||
    159 	    subunit < 0 || subunit >= MAPLE_SUBUNITS)
    160 	  return;
    161 
    162 	/* Compute sender and recipient address */
    163 	from = port << 6;
    164 	to = from | subunit_code[subunit];
    165 
    166 	/* Max data length = 255 longs = 1020 bytes */
    167 	if(datalen > 255)
    168 	  datalen = 255;
    169 	else if(datalen < 0)
    170 	  datalen = 0;
    171 
    172 	sc->sc_txlink = p;
    173 
    174 	/* Set length of packet and destination port (A-D) */
    175 	*p++ = datalen | (port << 16);
    176 
    177 	/* Write address to receive buffer where the response
    178 	   frame should be put */
    179 	*p++ = sc->sc_rxbuf_phys[port][subunit];
    180 
    181 	/* Create the frame header.  The fields are assembled "backwards"
    182 	   because of the Maple Bus big-endianness.                       */
    183 	*p++ = (command & 0xff) | (to << 8) | (from << 16) | (datalen << 24);
    184 
    185 	/* Copy parameter data, if any */
    186 	if (datalen > 0) {
    187 	  u_int32_t *param = dataaddr;
    188 	  int i;
    189 	  for (i = 0; i < datalen; i++)
    190 	    *p++ = *param++;
    191 	}
    192 
    193 	sc->sc_txpos = p;
    194 }
    195 
    196 static void
    197 maple_scanbus(sc)
    198 	struct maple_softc *sc;
    199 {
    200 	int p, s;
    201 
    202 	maple_polling = 1;
    203 
    204 	maple_begin_txbuf(sc);
    205 
    206 	for (p = 0; p < MAPLE_PORTS; p++) {
    207 	  maple_write_command(sc, p, 0, MAPLE_COMMAND_DEVINFO, 0, NULL);
    208 	}
    209 
    210 	if (maple_end_txbuf(sc)) {
    211 
    212 	  MAPLE_DMAADDR = sc->sc_txbuf_phys;
    213 	  MAPLE_STATE = 1;
    214 	  while (MAPLE_STATE != 0)
    215 	    ;
    216 
    217 	  for (p = 0; p < MAPLE_PORTS; p++)
    218 	    if ((sc->sc_rxbuf[p][0][0] & 0xff) == MAPLE_RESPONSE_DEVINFO)
    219 
    220 	      sc->sc_port_units[p] = ((sc->sc_rxbuf[p][0][0]>>15)&0x3e)|1;
    221 
    222 	    else
    223 
    224 	      sc->sc_port_units[p] = 0;
    225 
    226 
    227 	  maple_begin_txbuf(sc);
    228 
    229 	  for (p = 0; p < MAPLE_PORTS; p++) {
    230 	    for (s = 0; s < MAPLE_SUBUNITS; s++) {
    231 	      if (sc->sc_port_units[p] & (1<<s))
    232 		maple_write_command(sc, p, s, MAPLE_COMMAND_DEVINFO, 0, NULL);
    233 	    }
    234 	  }
    235 
    236 	  if (maple_end_txbuf(sc)) {
    237 
    238 	    MAPLE_DMAADDR = sc->sc_txbuf_phys;
    239 	    MAPLE_STATE = 1;
    240 	    while (MAPLE_STATE != 0)
    241 	      ;
    242 
    243 	    for (p = 0; p < MAPLE_PORTS; p++)
    244 	      for (s = 0; s < MAPLE_SUBUNITS; s++)
    245 		if (sc->sc_port_units[p] & (1<<s)) {
    246 
    247 		  if ((sc->sc_rxbuf[p][s][0] & 0xff) ==
    248 		      MAPLE_RESPONSE_DEVINFO) {
    249 
    250 		    u_int32_t *to_swap;
    251 		    int i;
    252 
    253 		    bcopy(sc->sc_rxbuf[p][s]+1,
    254 			  (to_swap = &sc->sc_unit[p][s].devinfo.di_func),
    255 			  sizeof(struct maple_devinfo));
    256 
    257 		    for (i = 0; i < 4; i++, to_swap++)
    258 		      *to_swap = ntohl(*to_swap);
    259 
    260 		    maple_attach_dev(sc, p, s);
    261 
    262 		  } else {
    263 
    264 		    printf("%s: no response from port %d subunit %d\n",
    265 			   sc->sc_dev.dv_xname, p, s);
    266 		  }
    267 		}
    268 
    269 	  }
    270 
    271 	}
    272 
    273 	maple_polling = 0;
    274 
    275 }
    276 
    277 static void
    278 maple_send_commands(sc)
    279 	struct maple_softc *sc;
    280 {
    281 	int p, s;
    282 
    283 	if (sc->maple_commands_pending || MAPLE_STATE != 0)
    284 	  return;
    285 
    286 	maple_begin_txbuf(sc);
    287 
    288 	for (p = 0; p < MAPLE_PORTS; p++) {
    289 
    290 	  for (s = 0; s < MAPLE_SUBUNITS; s++) {
    291 
    292 	    if (sc->sc_unit[p][s].getcond_callback != NULL) {
    293 
    294 	      u_int32_t func = ntohl(sc->sc_unit[p][s].getcond_func);
    295 
    296 	      maple_write_command(sc, p, s, MAPLE_COMMAND_GETCOND, 1, &func);
    297 
    298 	    }
    299 
    300 	  }
    301 
    302 	}
    303 
    304 	if (!maple_end_txbuf(sc))
    305 	  return;
    306 
    307 	MAPLE_DMAADDR = sc->sc_txbuf_phys;
    308 	MAPLE_STATE = 1;
    309 
    310 	sc->maple_commands_pending = 1;
    311 }
    312 
    313 static void
    314 maple_check_responses(sc)
    315 	struct maple_softc *sc;
    316 {
    317 	int p, s;
    318 
    319 	if (!sc->maple_commands_pending || MAPLE_STATE != 0)
    320 	  return;
    321 
    322 	for (p = 0; p < MAPLE_PORTS; p++) {
    323 	  for (s = 0; s < MAPLE_SUBUNITS; s++) {
    324 	    struct maple_unit * u = &sc->sc_unit[p][s];
    325 	    if (u->getcond_callback != NULL &&
    326 		(sc->sc_rxbuf[p][s][0] & 0xff) == MAPLE_RESPONSE_DATATRF &&
    327 		(sc->sc_rxbuf[p][s][0]>>24) >= 1 &&
    328 		htonl(sc->sc_rxbuf[p][s][1]) == u->getcond_func) {
    329 	      (*u->getcond_callback)(u->getcond_data,
    330 				     (void *)(sc->sc_rxbuf[p][s]+2),
    331 				     ((sc->sc_rxbuf[p][s][0]>>22)&1020)-4);
    332 	    }
    333 	  }
    334 	}
    335 
    336 	sc->maple_commands_pending = 0;
    337 }
    338 
    339 void
    340 maple_run_polling(dev)
    341 	struct device *dev;
    342 {
    343 	struct maple_softc *sc;
    344 
    345 	sc = (struct maple_softc *)dev;
    346 
    347 	if (MAPLE_STATE != 0)
    348 	  return;
    349 
    350 	maple_send_commands(sc);
    351 
    352 	while (MAPLE_STATE != 0)
    353 	  ;
    354 
    355 	maple_check_responses(sc);
    356 }
    357 
    358 void
    359 maple_set_condition_callback(dev, port, subunit, func, callback, data)
    360 	struct device *dev;
    361 	int port;
    362 	int subunit;
    363 	u_int32_t func;
    364 	void (*callback)(void *, void *, int);
    365 	void *data;
    366 {
    367 	struct maple_softc *sc;
    368 
    369 	sc = (struct maple_softc *)dev;
    370 
    371 	if ((port & ~(MAPLE_PORTS-1)) != 0 ||
    372 	    subunit < 0 || subunit >= MAPLE_SUBUNITS)
    373 	  return;
    374 
    375 	sc->sc_unit[port][subunit].getcond_func = func;
    376 	sc->sc_unit[port][subunit].getcond_callback = callback;
    377 	sc->sc_unit[port][subunit].getcond_data = data;
    378 }
    379 
    380 static void
    381 maple_callout(ctx)
    382 	void *ctx;
    383 {
    384 	struct maple_softc *sc = ctx;
    385 
    386 	if(!maple_polling) {
    387 
    388 	  maple_check_responses(sc);
    389 
    390 	  maple_send_commands(sc);
    391 
    392 	}
    393 
    394 	callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
    395 		      (void *)maple_callout, sc);
    396 }
    397 
    398 int
    399 maple_alloc_dma(size, vap, pap)
    400 	size_t size;
    401 	vaddr_t *vap;
    402 	paddr_t *pap;
    403 {
    404 	extern paddr_t avail_start, avail_end;	/* from pmap.c */
    405 
    406 	struct pglist mlist;
    407 	vm_page_t m;
    408 	int error;
    409 
    410 	size = round_page(size);
    411 
    412 	TAILQ_INIT(&mlist);
    413 	error = uvm_pglistalloc(size, avail_start, avail_end - PAGE_SIZE,
    414 	    0, 0, &mlist, 1, 0);
    415 	if (error)
    416 		return (error);
    417 
    418 	m = TAILQ_FIRST(&mlist);
    419 	*pap = VM_PAGE_TO_PHYS(m);
    420 	*vap = SH3_PHYS_TO_P2SEG(VM_PAGE_TO_PHYS(m));
    421 
    422 	return (0);
    423 }
    424 
    425 void
    426 maple_free_dma(paddr, size)
    427 	paddr_t paddr;
    428 	size_t size;
    429 {
    430 	struct pglist mlist;
    431 	vm_page_t m;
    432 	bus_addr_t addr;
    433 
    434 	TAILQ_INIT(&mlist);
    435 	for (addr = paddr; addr < paddr + size; addr += PAGE_SIZE) {
    436 		m = PHYS_TO_VM_PAGE(addr);
    437 		TAILQ_INSERT_TAIL(&mlist, m, pageq);
    438 	}
    439 	uvm_pglistfree(&mlist);
    440 }
    441 
    442 static void
    443 mapleattach(parent, self, aux)
    444 	struct device *parent, *self;
    445 	void *aux;
    446 {
    447 	struct maple_softc *sc;
    448 	vaddr_t dmabuffer;
    449 	paddr_t dmabuffer_phys;
    450 	u_int32_t *p;
    451 	int i, j;
    452 
    453 	sc = (struct maple_softc *)self;
    454 
    455 	printf("\n");
    456 
    457 	if (maple_alloc_dma(MAPLE_DMABUF_SIZE, &dmabuffer, &dmabuffer_phys)) {
    458 	  printf("%s: unable to allocate DMA buffers.\n", sc->sc_dev.dv_xname);
    459 	  return;
    460 	}
    461 
    462 	p = (u_int32_t *) dmabuffer;
    463 
    464 	for (i = 0; i < MAPLE_PORTS; i++)
    465 	  for (j = 0; j < MAPLE_SUBUNITS; j++) {
    466 
    467 	    sc->sc_rxbuf[i][j] = p;
    468 	    sc->sc_rxbuf_phys[i][j] = SH3_P2SEG_TO_PHYS(p);
    469 	    p += 256;
    470 
    471 	  }
    472 
    473 	sc->sc_txbuf = p;
    474 	sc->sc_txbuf_phys = SH3_P2SEG_TO_PHYS(p);
    475 
    476 	sc->maple_commands_pending = 0;
    477 
    478 	MAPLE_RESET = RESET_MAGIC;
    479 	MAPLE_RESET2 = 0;
    480 
    481 	MAPLE_SPEED = SPEED_2MBPS | TIMEOUT(50000);
    482 
    483 	MAPLE_ENABLE = 1;
    484 
    485 	maple_scanbus(sc);
    486 
    487 	bzero(&sc->maple_callout_ch, sizeof(sc->maple_callout_ch));
    488 
    489 	callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
    490 		      (void *)maple_callout, sc);
    491 }
    492 
    493 int
    494 mapleprint(aux, pnp)
    495 	void *aux;
    496 	const char *pnp;
    497 {
    498 	struct maple_attach_args *ma = aux;
    499 
    500 	if (pnp != NULL)
    501 		printf("%.*s at %s",
    502 		    (int)sizeof(ma->ma_devinfo->di_product_name),
    503 		    ma->ma_devinfo->di_product_name, pnp);
    504 
    505 	printf(" port %d", ma->ma_port);
    506 
    507 	if (ma->ma_subunit != 0)
    508 		printf(" subunit %d", ma->ma_subunit);
    509 
    510 	return (UNCONF);
    511 }
    512 
    513 static int
    514 maplesubmatch(parent, match, aux)
    515 	struct device *parent;
    516 	struct cfdata *match;
    517 	void *aux;
    518 {
    519 	struct maple_attach_args *ma = aux;
    520 
    521 	if (match->cf_loc[MAPLECF_PORT] != MAPLECF_PORT_DEFAULT &&
    522 	    match->cf_loc[MAPLECF_PORT] != ma->ma_port)
    523 		return (0);
    524 
    525 	if (match->cf_loc[MAPLECF_SUBUNIT] != MAPLECF_SUBUNIT_DEFAULT &&
    526 	    match->cf_loc[MAPLECF_SUBUNIT] != ma->ma_subunit)
    527 		return (0);
    528 
    529 	return ((*match->cf_attach->ca_match)(parent, match, aux));
    530 }
    531 
    532 u_int32_t
    533 maple_get_function_data(devinfo, function_code)
    534 	struct maple_devinfo *devinfo;
    535 	u_int32_t function_code;
    536 {
    537 	int i, p = 0;
    538 
    539 	for (i = 31; i >= 0; --i)
    540 	  if (devinfo->di_func & (1U<<i))
    541 	    if (function_code & (1U<<i))
    542 	      return devinfo->di_function_data[p];
    543 	    else
    544 	      if (++p >= 3)
    545 		break;
    546 	return (0);
    547 }
    548