Home | History | Annotate | Line # | Download | only in mca
mca_machdep.c revision 1.4
      1 /*	$NetBSD: mca_machdep.c,v 1.4 2011/07/18 17:26:56 dyoung Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
      5  * Copyright (c) 1996-1999 Scott D. Telford.
      6  * All rights reserved.
      7  *
      8  * This code is derived from software contributed to The NetBSD Foundation
      9  * by Scott Telford <s.telford (at) ed.ac.uk> and Jaromir Dolecek
     10  * <jdolecek (at) NetBSD.org>.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 /*
     35  * Machine-specific functions for MCA autoconfiguration.
     36  */
     37 
     38 #include <sys/cdefs.h>
     39 __KERNEL_RCSID(0, "$NetBSD: mca_machdep.c,v 1.4 2011/07/18 17:26:56 dyoung Exp $");
     40 
     41 #include <sys/types.h>
     42 #include <sys/param.h>
     43 #include <sys/device.h>
     44 #include <sys/malloc.h>
     45 #include <sys/systm.h>
     46 #include <sys/syslog.h>
     47 #include <sys/time.h>
     48 #include <sys/kernel.h>
     49 
     50 #include <powerpc/pio.h>
     51 #define _POWERPC_BUS_DMA_PRIVATE
     52 #include <sys/bus.h>
     53 
     54 #include <dev/mca/mcavar.h>
     55 #include <dev/mca/mcareg.h>
     56 
     57 #include "opt_mcaverbose.h"
     58 
     59 #ifdef UNUSED
     60 static void	_mca_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
     61 		    bus_addr_t, bus_size_t, int);
     62 #endif
     63 
     64 /*
     65  * For now, we use MCA DMA to 0-16M always. Some IBM PS/2 have 32bit MCA bus,
     66  * but majority of them have 24bit only.
     67  */
     68 #define	MCA_DMA_BOUNCE_THRESHOLD	(16 * 1024 * 1024)
     69 
     70 /* Updated in mca_busprobe() if appropriate. */
     71 int MCA_system = 0;
     72 
     73 //static bus_space_handle_t dmaiot, dmacmdh, dmaexech;
     74 
     75 #define MAX_SLAVE_CHANNELS	8
     76 #define MAX_DMA_CHANNELS	16
     77 
     78 #define INIT_DMA_CHN_BITMASK()	(0xFFFFFFFF << (32 - MAX_DMA_CHANS))
     79 #define INIT_SLAVE_CHN_BITMASK(slaves)	(0xFFFFFFFF << (32 - (slaves))
     80 
     81 #define DMA_AVAIL(chn, bitmask)	((bitmask) & (1 << (31 - (chn))))
     82 #define DMA_ALLOC(chn, bitmask) ((bitmask) &= ~(1 << (31 - (chn))))
     83 #define DMA_FREE(chn, bitmask)	((bitmask) |= (1 << (31 - (chn))))
     84 
     85 /*
     86  * MCA DMA controller commands. The exact sense of individual bits
     87  * are from Tymm Twillman <tymm (at) computer.org>, who worked on Linux MCA DMA
     88  * support.
     89  */
     90 #define DMACMD_SET_IO		0x00	/* set port (16bit) for i/o transfer */
     91 #define DMACMD_SET_ADDR		0x20	/* set addr (24bit) for i/o transfer */
     92 #define DMACMD_GET_ADDR		0x30	/* get addr (24bit) for i/o transfer */
     93 #define	DMACMD_SET_CNT		0x40	/* set memory size for DMA (16b) */
     94 #define DMACMD_GET_CNT		0x50	/* get count of remaining bytes in DMA*/
     95 #define DMACMD_GET_STATUS	0x60	/* ?? */
     96 #define DMACMD_SET_MODE		0x70	/* set DMA mode */
     97 # define DMACMD_MODE_XFER	0x04	/* do transfer, read by default */
     98 # define DMACMD_MODE_READ	0x08	/* read transfer */
     99 # define DMACMD_MODE_WRITE	0x00	/* write transfer */
    100 # define DMACMD_MODE_IOPORT	0x01	/* DMA from/to IO register */
    101 # define DMACMD_MODE_16BIT	0x40	/* 16bit transfers (default 8bit) */
    102 #define DMACMD_SET_ARBUS	0x80	/* ?? */
    103 #define DMACMD_MASK		0x90	/* command mask */
    104 #define DMACMD_RESET_MASK	0xA0	/* reset */
    105 #define DMACMD_MASTER_CLEAR	0xD0	/* ?? */
    106 
    107 const struct evcnt *
    108 mca_intr_evcnt(mca_chipset_tag_t ic, int irq)
    109 {
    110 	/* XXX for now, no evcnt parent reported */
    111 	return NULL;
    112 }
    113 
    114 /*
    115  * Map the MCA DMA controller registers.
    116  */
    117 void
    118 mca_attach_hook(device_t parent, device_t self, struct mcabus_attach_args *mba)
    119 {
    120 #if 0
    121 	dmaiot = mba->mba_iot;
    122 
    123 	if (bus_space_map(dmaiot, DMA_CMD, 1, 0, &dmacmdh)
    124 	    || bus_space_map(dmaiot, DMA_EXEC, 1, 0, &dmaexech))
    125 		panic("mca: couldn't map DMA registers");
    126 #endif
    127 }
    128 
    129 /*
    130  * Read value of MCA POS register "reg" in slot "slot".
    131  */
    132 
    133 int
    134 mca_conf_read(mca_chipset_tag_t mc, int slot, int reg)
    135 {
    136 	int	data;
    137 
    138 	slot &= 15;	/* slot must be in range 0-15 */
    139 	data = inb(RS6000_BUS_SPACE_IO + MCA_POS_REG(reg) + (slot<<16));
    140 	return data;
    141 }
    142 
    143 
    144 /*
    145  * Write "data" to MCA POS register "reg" in slot "slot".
    146  */
    147 
    148 void
    149 mca_conf_write(mca_chipset_tag_t mc, int slot, int reg, int data)
    150 {
    151 	slot &= 15;	/* slot must be in range 0-15 */
    152 	outb(RS6000_BUS_SPACE_IO + MCA_POS_REG(reg) + (slot<<16), data);
    153 }
    154 
    155 
    156 void *
    157 mca_intr_establish(mca_chipset_tag_t mc, mca_intr_handle_t ih,
    158     int level, int (*func)(void *), void *arg)
    159 {
    160 	if (ih == 0 || ih >= ICU_LEN)
    161 		panic("mca_intr_establish: bogus handle 0x%x", ih);
    162 
    163 	/* MCA interrupts are always level-triggered */
    164 	return intr_establish(ih, IST_LEVEL, level, func, arg);
    165 }
    166 
    167 void
    168 mca_intr_disestablish(mca_chipset_tag_t mc, void *cookie)
    169 {
    170 	intr_disestablish(cookie);
    171 }
    172 
    173 
    174 /*
    175  * Handle a NMI.
    176  * return true to panic system, false to ignore.
    177  */
    178 int
    179 mca_nmi(void)
    180 {
    181 	/*
    182 	* PS/2 MCA devices can generate NMIs - we can find out which
    183 	* slot generated it from the POS registers.
    184 	*/
    185 
    186 	int 	slot, mcanmi=0;
    187 
    188 	/* if there is no MCA bus, call x86_nmi() */
    189 	if (!MCA_system)
    190 		goto out;
    191 
    192 	/* ensure motherboard setup is disabled */
    193 	outb(MCA_MB_SETUP_REG, 0xff);
    194 
    195 	/* find if an MCA slot has the CHCK bit asserted (low) in POS 5 */
    196 	for(slot=0; slot<MCA_MAX_SLOTS; slot++) {
    197 		outb(MCA_ADAP_SETUP_REG, slot | MCA_ADAP_SET);
    198 		if ((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK) == 0) {
    199 			mcanmi = 1;
    200 			/* find if CHCK status is available in POS 6/7 */
    201 			if((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK_STAT) == 0)
    202 				log(LOG_CRIT, "MCA NMI: slot %d, POS6=0x%02x, POS7=0x%02x\n",
    203 					slot+1, inb(MCA_POS_REG(6)),
    204 						inb(MCA_POS_REG(7)));
    205 			else
    206 				log(LOG_CRIT, "MCA NMI: slot %d\n", slot+1);
    207 		}
    208 	}
    209 	outb(MCA_ADAP_SETUP_REG, 0);
    210 
    211    out:
    212 	if (!mcanmi) {
    213 		/* no CHCK bits asserted, assume ISA NMI */
    214 		//return (x86_nmi());
    215 		return 0;
    216 	} else
    217 		return(0);
    218 }
    219 
    220 /*
    221  * Realistically, we should probe for the presence of an MCA bus here, and
    222  * return a reasonable value.  However, this port is never expected to run
    223  * on anything other than MCA, so rather than write a bunch of complex code
    224  * to find that we indeed have a bus, lets just assume we do.
    225  */
    226 void
    227 mca_busprobe(void)
    228 {
    229 	MCA_system = 1;
    230 }
    231 
    232 #define PORT_DISKLED	0x92
    233 #define DISKLED_ON	0x40
    234 
    235 /*
    236  * Light disk busy LED on IBM PS/2.
    237  */
    238 void
    239 mca_disk_busy(void)
    240 {
    241 	outb(PORT_DISKLED, inb(PORT_DISKLED) | DISKLED_ON);
    242 }
    243 
    244 /*
    245  * Turn off disk LED on IBM PS/2.
    246  */
    247 void
    248 mca_disk_unbusy(void)
    249 {
    250 	outb(PORT_DISKLED, inb(PORT_DISKLED) & ~DISKLED_ON);
    251 }
    252 
    253 /*
    254  * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    255  * MCA DMA specific stuff. We use ISA routines for bulk of the work,
    256  * since MCA shares much of the charasteristics with it. We just hook
    257  * the DMA channel initialization and kick MCA DMA controller appropriately.
    258  * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
    259  */
    260 
    261 #ifdef NOTYET
    262 /*
    263  * Synchronize a MCA DMA map.
    264  */
    265 static void
    266 _mca_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
    267     bus_size_t len, int ops)
    268 {
    269 	struct rs6000_dma_cookie *cookie;
    270 	bus_addr_t phys;
    271 	bus_size_t cnt;
    272 	int dmach, mode;
    273 
    274 	_bus_dmamap_sync(t, map, offset, len, ops);
    275 
    276 	/*
    277 	 * Don't do anything if not using the DMA controller.
    278 	 */
    279 	if ((map->_dm_flags & _MCABUS_DMA_USEDMACTRL) == 0)
    280 		return;
    281 
    282 	/*
    283 	 * Don't do anything if not PRE* operation, allow only
    284 	 * one of PREREAD and PREWRITE.
    285 	 */
    286 	if (ops != BUS_DMASYNC_PREREAD && ops != BUS_DMASYNC_PREWRITE)
    287 		return;
    288 
    289 	cookie = (struct rs6000_dma_cookie *)map->_dm_cookie;
    290 	dmach = (cookie->id_flags & 0xf0) >> 4;
    291 
    292 	phys = map->dm_segs[0].ds_addr;
    293 	cnt = map->dm_segs[0].ds_len;
    294 
    295 	mode = DMACMD_MODE_XFER;
    296 	mode |= (ops == BUS_DMASYNC_PREREAD)
    297 			? DMACMD_MODE_READ : DMACMD_MODE_WRITE;
    298 	if (map->_dm_flags & MCABUS_DMA_IOPORT)
    299 		mode |= DMACMD_MODE_IOPORT;
    300 
    301 	/* Use 16bit DMA if requested */
    302 	if (map->_dm_flags & MCABUS_DMA_16BIT) {
    303 #ifdef DIAGNOSTIC
    304 		if ((cnt % 2) != 0) {
    305 			panic("_mca_bus_dmamap_sync: 16bit DMA and cnt %lu odd",
    306 				cnt);
    307 		}
    308 #endif
    309 		mode |= DMACMD_MODE_16BIT;
    310 		cnt /= 2;
    311 	}
    312 
    313 	/*
    314 	 * Initialize the MCA DMA controller appropriately. The exact
    315 	 * sequence to setup the controller is taken from Minix.
    316 	 */
    317 
    318 	/* Disable access to DMA channel. */
    319 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_MASK | dmach);
    320 
    321 	/* Set the transfer mode. */
    322 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_MODE | dmach);
    323 	bus_space_write_1(dmaiot, dmaexech, 0, mode);
    324 
    325 	/* Set the address byte pointer. */
    326 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_ADDR | dmach);
    327 	/* address bits 0..7   */
    328 	bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 0) & 0xff);
    329 	/* address bits 8..15  */
    330 	bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 8) & 0xff);
    331 	/* address bits 16..23  */
    332 	bus_space_write_1(dmaiot, dmaexech, 0, (phys >> 16) & 0xff);
    333 
    334 	/* Set the count byte pointer */
    335 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_CNT | dmach);
    336 	/* count bits 0..7     */
    337 	bus_space_write_1(dmaiot, dmaexech, 0, ((cnt - 1) >> 0) & 0xff);
    338 	/* count bits 8..15    */
    339 	bus_space_write_1(dmaiot, dmaexech, 0, ((cnt - 1) >> 8) & 0xff);
    340 
    341 	/* Enable access to DMA channel. */
    342 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dmach);
    343 }
    344 #endif
    345 
    346 /*
    347  * Allocate a DMA map, and set up DMA channel.
    348  */
    349 int
    350 mca_dmamap_create(bus_dma_tag_t t, bus_size_t size, int flags,
    351     bus_dmamap_t *dmamp, int dmach)
    352 {
    353 #if 0
    354 	int error;
    355 	struct rs6000_dma_cookie *cookie;
    356 
    357 #ifdef DEBUG
    358 	/* Sanity check */
    359 	if (dmach < 0 || dmach >= MAX_DMA_CHANNELS) {
    360 		printf("mcadma_create: invalid DMA channel %d\n",
    361 			dmach);
    362 		return (EINVAL);
    363 	}
    364 
    365 	if (size > 65536) {
    366 		panic("mca_dmamap_create: dmamap sz %ld > 65536",
    367 		    (long) size);
    368 	}
    369 #endif
    370 
    371 	/*
    372 	 * MCA DMA transfer can be maximum 65536 bytes long and must
    373 	 * be in one chunk. No specific boundary constraints are present.
    374 	 */
    375 	if ((error = _bus_dmamap_create(t, size, 1, 65536, 0, flags, dmamp)))
    376 		return (error);
    377 
    378 	cookie = (struct rs6000_dma_cookie *) (*dmamp)->_dm_cookie;
    379 
    380 	if (cookie == NULL) {
    381 		/*
    382 		 * Allocate our cookie if not yet done.
    383 		 */
    384 		cookie = malloc(sizeof(struct rs6000_dma_cookie), M_DMAMAP,
    385 		    ((flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK) | M_ZERO);
    386 		if (cookie == NULL) {
    387 
    388 			return ENOMEM;
    389 		}
    390 		(*dmamp)->_dm_cookie = cookie;
    391 	}
    392 
    393 
    394 	/* Encode DMA channel */
    395 	cookie->id_flags &= 0x0f;
    396 	cookie->id_flags |= dmach << 4;
    397 
    398 	/* Mark the dmamap as using DMA controller. Some devices
    399 	 * drive DMA themselves, and don't need the MCA DMA controller.
    400 	 * To distinguish the two, use a flag for dmamaps which use the DMA
    401 	 * controller.
    402  	 */
    403 	(*dmamp)->_dm_flags |= _MCABUS_DMA_USEDMACTRL;
    404 #endif
    405 	return (0);
    406 }
    407 
    408 /*
    409  * Set I/O port for DMA. Implemented separately from _mca_bus_dmamap_sync()
    410  * so that it's available for one-shot setup.
    411  */
    412 void
    413 mca_dma_set_ioport(int dma, uint16_t port)
    414 {
    415 #if 0
    416 	/* Disable access to dma channel. */
    417 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_MASK | dma);
    418 
    419 	/* Set I/O port to use for DMA */
    420 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_SET_IO | dma);
    421 	bus_space_write_1(dmaiot, dmaexech, 0, port & 0xff);
    422 	bus_space_write_1(dmaiot, dmaexech, 0, (port >> 8) & 0xff);
    423 
    424 	/* Enable access to DMA channel. */
    425 	bus_space_write_1(dmaiot, dmacmdh, 0, DMACMD_RESET_MASK | dma);
    426 #endif
    427 }
    428