Home | History | Annotate | Line # | Download | only in maple
maple.c revision 1.3
      1 /*	$NetBSD: maple.c,v 1.3 2001/01/21 22:45:57 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 1
     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 void	maple_attach_dev __P((struct maple_softc *, int, int));
     67 static void	maple_begin_txbuf __P((struct maple_softc *));
     68 static int	maple_end_txbuf __P((struct maple_softc *));
     69 static void	maple_write_command __P((struct maple_softc *, int, int,
     70 					 int, int, void *));
     71 static void	maple_scanbus __P((struct maple_softc *));
     72 static void	maple_callout __P((void *));
     73 static void	maple_send_commands __P((struct maple_softc *));
     74 static void	maple_check_responses __P((struct maple_softc *));
     75 
     76 int maple_alloc_dma __P((size_t, vaddr_t *, paddr_t *));
     77 void maple_free_dma __P((paddr_t, size_t));
     78 
     79 
     80 /*
     81  * Global variables.
     82  */
     83 int	maple_polling = 0;	/* Are we polling?  (Debugger mode) */
     84 
     85 /*
     86  * Driver definition.
     87  */
     88 struct cfattach maple_ca = {
     89 	sizeof(struct maple_softc), maplematch, mapleattach
     90 };
     91 
     92 int	maplesearch __P((struct device *, struct cfdata *, void *));
     93 
     94 static int
     95 maplematch(parent, cf, aux)
     96 	struct device *parent;
     97 	struct cfdata *cf;
     98 	void *aux;
     99 {
    100 	struct shb_attach_args *sa = aux;
    101 
    102 	if (strcmp("maple", cf->cf_driver->cd_name))
    103 	  return (0);
    104 
    105 	sa->ia_iosize = 0 /* 0x100 */;
    106 	return (1);
    107 }
    108 
    109 
    110 static void
    111 maple_attach_dev(sc, port, subunit)
    112 	struct maple_softc *sc;
    113 	int port;
    114 	int subunit;
    115 {
    116 	struct maple_attach_args ma;
    117 	ma.ma_port = port;
    118 	ma.ma_subunit = subunit;
    119 	ma.ma_devinfo = &sc->sc_unit[port][subunit].devinfo;
    120 	config_search(maplesearch, &sc->sc_dev, &ma);
    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;
    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 	      u_int32_t *to_swap;
    221 	      int i;
    222 
    223 	      bcopy(sc->sc_rxbuf[p][0]+1,
    224 		    (to_swap = &sc->sc_unit[p][0].devinfo.di_func),
    225 		    sizeof(struct maple_devinfo));
    226 
    227 	      for (i = 0; i < 4; i++, to_swap++)
    228 		*to_swap = ntohl(*to_swap);
    229 
    230 	      maple_attach_dev(sc, p, 0);
    231 	    }
    232 
    233 	}
    234 
    235 	maple_polling = 0;
    236 
    237 }
    238 
    239 static void
    240 maple_send_commands(sc)
    241 	struct maple_softc *sc;
    242 {
    243 	int p;
    244 
    245 	if (sc->maple_commands_pending || MAPLE_STATE != 0)
    246 	  return;
    247 
    248 	maple_begin_txbuf(sc);
    249 
    250 	for (p = 0; p < MAPLE_PORTS; p++) {
    251 
    252 	  if (sc->sc_unit[p][0].getcond_callback != NULL) {
    253 
    254 	    u_int32_t func = ntohl(sc->sc_unit[p][0].getcond_func);
    255 
    256 	    maple_write_command(sc, p, 0, MAPLE_COMMAND_GETCOND, 1, &func);
    257 
    258 	  }
    259 
    260 	}
    261 
    262 	if (!maple_end_txbuf(sc))
    263 	  return;
    264 
    265 	MAPLE_DMAADDR = sc->sc_txbuf_phys;
    266 	MAPLE_STATE = 1;
    267 
    268 	sc->maple_commands_pending = 1;
    269 }
    270 
    271 static void
    272 maple_check_responses(sc)
    273 	struct maple_softc *sc;
    274 {
    275 	int p;
    276 
    277 	if (!sc->maple_commands_pending || MAPLE_STATE != 0)
    278 	  return;
    279 
    280 	for (p = 0; p < MAPLE_PORTS; p++) {
    281 	  struct maple_unit * u = &sc->sc_unit[p][0];
    282 	  if (u->getcond_callback != NULL &&
    283 	      (sc->sc_rxbuf[p][0][0] & 0xff) == MAPLE_RESPONSE_DATATRF &&
    284 	      (sc->sc_rxbuf[p][0][0]>>24) >= 1 &&
    285 	      htonl(sc->sc_rxbuf[p][0][1]) == u->getcond_func) {
    286 	    (*u->getcond_callback)(u->getcond_data,
    287 				   (void *)(sc->sc_rxbuf[p][0]+2),
    288 				   ((sc->sc_rxbuf[p][0][0]>>22)&1020)-4);
    289 	  }
    290 	}
    291 
    292 	sc->maple_commands_pending = 0;
    293 }
    294 
    295 void
    296 maple_run_polling(dev)
    297 	struct device *dev;
    298 {
    299 	struct maple_softc *sc;
    300 
    301 	sc = (struct maple_softc *)dev;
    302 
    303 	if (MAPLE_STATE != 0)
    304 	  return;
    305 
    306 	maple_send_commands(sc);
    307 
    308 	while (MAPLE_STATE != 0)
    309 	  ;
    310 
    311 	maple_check_responses(sc);
    312 }
    313 
    314 void
    315 maple_set_condition_callback(dev, port, subunit, func, callback, data)
    316 	struct device *dev;
    317 	int port;
    318 	int subunit;
    319 	u_int32_t func;
    320 	void (*callback)(void *, void *, int);
    321 	void *data;
    322 {
    323 	struct maple_softc *sc;
    324 
    325 	sc = (struct maple_softc *)dev;
    326 
    327 	if ((port & ~(MAPLE_PORTS-1)) != 0 ||
    328 	    subunit < 0 || subunit >= MAPLE_SUBUNITS)
    329 	  return;
    330 
    331 	sc->sc_unit[port][subunit].getcond_func = func;
    332 	sc->sc_unit[port][subunit].getcond_callback = callback;
    333 	sc->sc_unit[port][subunit].getcond_data = data;
    334 }
    335 
    336 static void
    337 maple_callout(ctx)
    338 	void *ctx;
    339 {
    340 	struct maple_softc *sc = ctx;
    341 
    342 	if(!maple_polling) {
    343 
    344 	  maple_check_responses(sc);
    345 
    346 	  maple_send_commands(sc);
    347 
    348 	}
    349 
    350 	callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
    351 		      (void *)maple_callout, sc);
    352 }
    353 
    354 int
    355 maple_alloc_dma(size, vap, pap)
    356 	size_t size;
    357 	vaddr_t *vap;
    358 	paddr_t *pap;
    359 {
    360 	extern paddr_t avail_start, avail_end;	/* from pmap.c */
    361 
    362 	struct pglist mlist;
    363 	vm_page_t m;
    364 	int error;
    365 
    366 	size = round_page(size);
    367 
    368 	TAILQ_INIT(&mlist);
    369 	error = uvm_pglistalloc(size, avail_start, avail_end - PAGE_SIZE,
    370 	    0, 0, &mlist, 1, 0);
    371 	if (error)
    372 		return (error);
    373 
    374 	m = TAILQ_FIRST(&mlist);
    375 	*pap = VM_PAGE_TO_PHYS(m);
    376 	*vap = SH3_PHYS_TO_P2SEG(VM_PAGE_TO_PHYS(m));
    377 
    378 	return (0);
    379 }
    380 
    381 void
    382 maple_free_dma(paddr, size)
    383 	paddr_t paddr;
    384 	size_t size;
    385 {
    386 	struct pglist mlist;
    387 	vm_page_t m;
    388 	bus_addr_t addr;
    389 
    390 	TAILQ_INIT(&mlist);
    391 	for (addr = paddr; addr < paddr + size; addr += PAGE_SIZE) {
    392 		m = PHYS_TO_VM_PAGE(addr);
    393 		TAILQ_INSERT_TAIL(&mlist, m, pageq);
    394 	}
    395 	uvm_pglistfree(&mlist);
    396 }
    397 
    398 
    399 static void
    400 mapleattach(parent, self, aux)
    401 	struct device *parent, *self;
    402 	void *aux;
    403 {
    404 	struct maple_softc *sc;
    405 	vaddr_t dmabuffer;
    406 	paddr_t dmabuffer_phys;
    407 	u_int32_t *p;
    408 	int i, j;
    409 
    410 	sc = (struct maple_softc *)self;
    411 
    412 	printf("\n");
    413 
    414 	if (maple_alloc_dma(MAPLE_DMABUF_SIZE, &dmabuffer, &dmabuffer_phys)) {
    415 	  printf("%s: unable to allocate DMA buffers.\n", sc->sc_dev.dv_xname);
    416 	  return;
    417 	}
    418 
    419 	p = (u_int32_t *) dmabuffer;
    420 
    421 	for (i = 0; i < MAPLE_PORTS; i++)
    422 	  for (j = 0; j < MAPLE_SUBUNITS; j++) {
    423 
    424 	    sc->sc_rxbuf[i][j] = p;
    425 	    sc->sc_rxbuf_phys[i][j] = SH3_P2SEG_TO_PHYS(p);
    426 	    p += 256;
    427 
    428 	  }
    429 
    430 	sc->sc_txbuf = p;
    431 	sc->sc_txbuf_phys = SH3_P2SEG_TO_PHYS(p);
    432 
    433 	sc->maple_commands_pending = 0;
    434 
    435 	MAPLE_RESET = RESET_MAGIC;
    436 	MAPLE_RESET2 = 0;
    437 
    438 	MAPLE_SPEED = SPEED_2MBPS | TIMEOUT(50000);
    439 
    440 	MAPLE_ENABLE = 1;
    441 
    442 	maple_scanbus(sc);
    443 
    444 	bzero(&sc->maple_callout_ch, sizeof(sc->maple_callout_ch));
    445 
    446 	callout_reset(&sc->maple_callout_ch, MAPLE_CALLOUT_TICKS,
    447 		      (void *)maple_callout, sc);
    448 }
    449 
    450 int
    451 mapleprint(aux, pnp)
    452 	void *aux;
    453 	const char *pnp;
    454 {
    455 	struct maple_attach_args *ma = aux;
    456 
    457 	if (pnp != NULL)
    458 		printf("%s", pnp);
    459 
    460 	printf(" port %c", ma->ma_port+'A');
    461 
    462 	if (ma->ma_subunit != 0)
    463 	  printf("%d", ma->ma_subunit);
    464 
    465 	return (UNCONF);
    466 }
    467 
    468 int
    469 maplesearch(parent, cf, aux)
    470 	struct device *parent;
    471 	struct cfdata *cf;
    472 	void *aux;
    473 {
    474 	if ((*cf->cf_attach->ca_match)(parent, cf, aux) > 0)
    475 	  config_attach(parent, cf, aux, mapleprint);
    476 
    477 	return (0);
    478 }
    479 
    480 u_int32_t
    481 maple_get_function_data(devinfo, function_code)
    482 	struct maple_devinfo *devinfo;
    483 	u_int32_t function_code;
    484 {
    485 	int i, p = 0;
    486 
    487 	for (i = 31; i >= 0; --i)
    488 	  if (devinfo->di_func & (1U<<i))
    489 	    if (function_code & (1U<<i))
    490 	      return devinfo->di_function_data[p];
    491 	    else
    492 	      if (++p >= 3)
    493 		break;
    494 	return (0);
    495 }
    496 
    497