1 /* $NetBSD: mca_machdep.c,v 1.37 2008/12/16 22:35:23 christos Exp $ */
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
5 * Copyright (c) 1996-1999 Scott D. Telford.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Scott Telford <s.telford@ed.ac.uk> and Jaromir Dolecek
10 * <jdolecek@NetBSD.org>.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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.
35 * Machine-specific functions for MCA autoconfiguration.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: mca_machdep.c,v 1.37 2008/12/16 22:35:23 christos Exp $");
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>
48 #include <sys/kernel.h>
50 #include <machine/bioscall.h>
51 #include <machine/psl.h>
52 #include <machine/bus.h>
53 #include <machine/bus_private.h>
54 #include <machine/pio.h>
56 #include <dev/isa/isavar.h>
57 #include <dev/isa/isareg.h>
58 #include <dev/mca/mcavar.h>
59 #include <dev/mca/mcareg.h>
62 #include "opt_mcaverbose.h"
64 /* System Configuration Block - this info is returned by the BIOS call */
71 #define FEATURE_MCAISA 0x01 /* Machine contains both MCA and ISA bus */
72 #define FEATURE_MCABUS 0x02 /* Machine has MCA bus instead of ISA */
73 #define FEATURE_EBDA 0x04 /* Extended BIOS data area allocated */
74 #define FEATURE_WAITEV 0x08 /* Wait for external event is supported */
75 #define FEATURE_KBDINT 0x10 /* Keyboard intercept called by Int 09h */
76 #define FEATURE_RTC 0x20 /* Real-time clock present */
77 #define FEATURE_IC2 0x40 /* Second interrupt chip present */
78 #define FEATURE_DMA3 0x80 /* DMA channel 3 used by hard disk BIOS */
84 * Used to encode DMA channel into ISA DMA cookie. We use upper 4 bits of
85 * ISA DMA cookie id_flags, it's unused.
87 struct x86_isa_dma_cookie
{
89 /* We don't care about rest */
93 static void _mca_bus_dmamap_sync(bus_dma_tag_t
, bus_dmamap_t
,
94 bus_addr_t
, bus_size_t
, int);
98 * For now, we use MCA DMA to 0-16M always. Some IBM PS/2 have 32bit MCA bus,
99 * but majority of them have 24bit only.
101 #define MCA_DMA_BOUNCE_THRESHOLD (16 * 1024 * 1024)
103 struct x86_bus_dma_tag mca_bus_dma_tag
= {
105 MCA_DMA_BOUNCE_THRESHOLD
, /* _bounce_thresh */
106 0, /* _bounce_alloc_lo */
107 MCA_DMA_BOUNCE_THRESHOLD
, /* _bounce_alloc_hi */
108 NULL
, /* _may_bounce */
112 _bus_dmamap_load_mbuf
,
113 _bus_dmamap_load_uio
,
114 _bus_dmamap_load_raw
,
122 _bus_dmatag_subregion
,
126 /* Updated in mca_busprobe() if appropriate. */
129 /* Used to kick MCA DMA controller */
130 #define DMA_CMD 0x18 /* command the controller */
131 #define DMA_EXEC 0x1A /* tell controller how to do things */
132 static bus_space_handle_t dmaiot
, dmacmdh
, dmaexech
;
135 * MCA DMA controller commands. The exact sense of individual bits
136 * are from Tymm Twillman <tymm@computer.org>, who worked on Linux MCA DMA
139 #define DMACMD_SET_IO 0x00 /* set port (16bit) for i/o transfer */
140 #define DMACMD_SET_ADDR 0x20 /* set addr (24bit) for i/o transfer */
141 #define DMACMD_GET_ADDR 0x30 /* get addr (24bit) for i/o transfer */
142 #define DMACMD_SET_CNT 0x40 /* set memory size for DMA (16b) */
143 #define DMACMD_GET_CNT 0x50 /* get count of remaining bytes in DMA*/
144 #define DMACMD_GET_STATUS 0x60 /* ?? */
145 #define DMACMD_SET_MODE 0x70 /* set DMA mode */
146 # define DMACMD_MODE_XFER 0x04 /* do transfer, read by default */
147 # define DMACMD_MODE_READ 0x08 /* read transfer */
148 # define DMACMD_MODE_WRITE 0x00 /* write transfer */
149 # define DMACMD_MODE_IOPORT 0x01 /* DMA from/to IO register */
150 # define DMACMD_MODE_16BIT 0x40 /* 16bit transfers (default 8bit) */
151 #define DMACMD_SET_ARBUS 0x80 /* ?? */
152 #define DMACMD_MASK 0x90 /* command mask */
153 #define DMACMD_RESET_MASK 0xA0 /* reset */
154 #define DMACMD_MASTER_CLEAR 0xD0 /* ?? */
157 * Map the MCA DMA controller registers.
160 mca_attach_hook(device_t parent
, device_t self
,
161 struct mcabus_attach_args
*mba
)
163 dmaiot
= mba
->mba_iot
;
165 if (bus_space_map(dmaiot
, DMA_CMD
, 1, 0, &dmacmdh
)
166 || bus_space_map(dmaiot
, DMA_EXEC
, 1, 0, &dmaexech
))
167 panic("mca: couldn't map DMA registers");
171 * Read value of MCA POS register "reg" in slot "slot".
175 mca_conf_read(mca_chipset_tag_t mc
, int slot
, int reg
)
179 slot
&= 7; /* slot must be in range 0-7 */
180 outb(MCA_MB_SETUP_REG
, 0xff); /* ensure m/board setup is disabled */
181 outb(MCA_ADAP_SETUP_REG
, slot
| MCA_ADAP_SET
);
182 data
= inb(MCA_POS_REG(reg
));
183 outb(MCA_ADAP_SETUP_REG
, 0);
189 * Write "data" to MCA POS register "reg" in slot "slot".
193 mca_conf_write(mca_chipset_tag_t mc
, int slot
, int reg
, int data
)
195 slot
&=7; /* slot must be in range 0-7 */
196 outb(MCA_MB_SETUP_REG
, 0xff); /* ensure m/board setup is disabled */
197 outb(MCA_ADAP_SETUP_REG
, slot
| MCA_ADAP_SET
);
198 outb(MCA_POS_REG(reg
), data
);
199 outb(MCA_ADAP_SETUP_REG
, 0);
203 #error mca_intr_(dis)establish: needs ISA to be configured into kernel
208 mca_intr_establish(mca_chipset_tag_t mc
, mca_intr_handle_t ih
)
211 /* XXX for now, no evcnt parent reported */
217 mca_intr_establish(mca_chipset_tag_t mc
, mca_intr_handle_t ih
,
218 int level
, int (*func
)(void *), void *arg
)
220 if (ih
== 0 || ih
>= NUM_LEGACY_IRQS
|| ih
== 2)
221 panic("mca_intr_establish: bogus handle 0x%x", ih
);
223 /* MCA interrupts are always level-triggered */
224 return isa_intr_establish(NULL
, ih
, IST_LEVEL
, level
, func
, arg
);
228 mca_intr_disestablish(mca_chipset_tag_t mc
, void *cookie
)
230 isa_intr_disestablish(NULL
, cookie
);
236 * return true to panic system, false to ignore.
242 * PS/2 MCA devices can generate NMIs - we can find out which
243 * slot generated it from the POS registers.
248 /* if there is no MCA bus, call x86_nmi() */
252 /* ensure motherboard setup is disabled */
253 outb(MCA_MB_SETUP_REG
, 0xff);
255 /* find if an MCA slot has the CHCK bit asserted (low) in POS 5 */
256 for(slot
=0; slot
<MCA_MAX_SLOTS
; slot
++) {
257 outb(MCA_ADAP_SETUP_REG
, slot
| MCA_ADAP_SET
);
258 if ((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK
) == 0) {
260 /* find if CHCK status is available in POS 6/7 */
261 if((inb(MCA_POS_REG(5)) & MCA_POS5_CHCK_STAT
) == 0)
262 log(LOG_CRIT
, "MCA NMI: slot %d, POS6=0x%02x, POS7=0x%02x\n",
263 slot
+1, inb(MCA_POS_REG(6)),
264 inb(MCA_POS_REG(7)));
266 log(LOG_CRIT
, "MCA NMI: slot %d\n", slot
+1);
269 outb(MCA_ADAP_SETUP_REG
, 0);
273 /* no CHCK bits asserted, assume ISA NMI */
280 * We can obtain the information about MCA bus presence via
281 * GET CONFIGURATION BIOS call - int 0x15, function 0xc0.
282 * The call returns a pointer to memory place with the configuration block
283 * in es:bx (on AT-compatible, e.g. all we care about, computers).
285 * Configuration block contains block length (2 bytes), model
286 * number (1 byte), submodel number (1 byte), BIOS revision
287 * (1 byte) and up to 5 feature bytes. We only care about
288 * first feature byte.
293 struct bioscallregs regs
;
294 struct bios_config
*scp
;
298 memset(®s
, 0, sizeof(regs
));
300 bioscall(0x15, ®s
);
302 if ((regs
.EFLAGS
& PSL_C
) || regs
.AH
!= 0) {
303 aprint_verbose("BIOS CFG: Not supported. Not AT-compatible?\n");
307 paddr
= (regs
.ES
<< 4) + regs
.BX
;
308 scp
= (struct bios_config
*)ISA_HOLE_VADDR(paddr
);
310 snprintb(buf
, sizeof(buf
),
327 "\020DMA32\n", (scp
->feature2
<< 8) | scp
->feature1
);
329 aprint_verbose("BIOS CFG: Model-SubM-Rev: %02x-%02x-%02x, 0x%s\n",
330 scp
->model
, scp
->submodel
, scp
->bios_rev
, buf
);
332 MCA_system
= (scp
->feature1
& FEATURE_MCABUS
) ? 1 : 0;
335 #define PORT_DISKLED 0x92
336 #define DISKLED_ON 0x40
339 * Light disk busy LED on IBM PS/2.
344 outb(PORT_DISKLED
, inb(PORT_DISKLED
) | DISKLED_ON
);
348 * Turn off disk LED on IBM PS/2.
351 mca_disk_unbusy(void)
353 outb(PORT_DISKLED
, inb(PORT_DISKLED
) & ~DISKLED_ON
);
357 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
358 * MCA DMA specific stuff. We use ISA routines for bulk of the work,
359 * since MCA shares much of the charasteristics with it. We just hook
360 * the DMA channel initialization and kick MCA DMA controller appropriately.
361 * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
366 * Synchronize a MCA DMA map.
369 _mca_bus_dmamap_sync(bus_dma_tag_t t
, bus_dmamap_t map
, bus_addr_t offset
,
370 bus_size_t len
, int ops
)
372 struct x86_isa_dma_cookie
*cookie
;
377 _bus_dmamap_sync(t
, map
, offset
, len
, ops
);
380 * Don't do anything if not using the DMA controller.
382 if ((map
->_dm_flags
& _MCABUS_DMA_USEDMACTRL
) == 0)
386 * Don't do anything if not PRE* operation, allow only
387 * one of PREREAD and PREWRITE.
389 if (ops
!= BUS_DMASYNC_PREREAD
&& ops
!= BUS_DMASYNC_PREWRITE
)
392 cookie
= (struct x86_isa_dma_cookie
*)map
->_dm_cookie
;
393 dmach
= (cookie
->id_flags
& 0xf0) >> 4;
395 phys
= map
->dm_segs
[0].ds_addr
;
396 cnt
= map
->dm_segs
[0].ds_len
;
398 mode
= DMACMD_MODE_XFER
;
399 mode
|= (ops
== BUS_DMASYNC_PREREAD
)
400 ? DMACMD_MODE_READ
: DMACMD_MODE_WRITE
;
401 if (map
->_dm_flags
& MCABUS_DMA_IOPORT
)
402 mode
|= DMACMD_MODE_IOPORT
;
404 /* Use 16bit DMA if requested */
405 if (map
->_dm_flags
& MCABUS_DMA_16BIT
) {
407 if ((cnt
% 2) != 0) {
408 panic("_mca_bus_dmamap_sync: 16bit DMA and cnt %lu odd",
412 mode
|= DMACMD_MODE_16BIT
;
417 * Initialize the MCA DMA controller appropriately. The exact
418 * sequence to setup the controller is taken from Minix.
421 /* Disable access to DMA channel. */
422 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_MASK
| dmach
);
424 /* Set the transfer mode. */
425 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_SET_MODE
| dmach
);
426 bus_space_write_1(dmaiot
, dmaexech
, 0, mode
);
428 /* Set the address byte pointer. */
429 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_SET_ADDR
| dmach
);
430 /* address bits 0..7 */
431 bus_space_write_1(dmaiot
, dmaexech
, 0, (phys
>> 0) & 0xff);
432 /* address bits 8..15 */
433 bus_space_write_1(dmaiot
, dmaexech
, 0, (phys
>> 8) & 0xff);
434 /* address bits 16..23 */
435 bus_space_write_1(dmaiot
, dmaexech
, 0, (phys
>> 16) & 0xff);
437 /* Set the count byte pointer */
438 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_SET_CNT
| dmach
);
439 /* count bits 0..7 */
440 bus_space_write_1(dmaiot
, dmaexech
, 0, ((cnt
- 1) >> 0) & 0xff);
441 /* count bits 8..15 */
442 bus_space_write_1(dmaiot
, dmaexech
, 0, ((cnt
- 1) >> 8) & 0xff);
444 /* Enable access to DMA channel. */
445 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_RESET_MASK
| dmach
);
450 * Allocate a DMA map, and set up DMA channel.
453 mca_dmamap_create(bus_dma_tag_t t
, bus_size_t size
, int flags
,
454 bus_dmamap_t
*dmamp
, int dmach
)
457 struct x86_isa_dma_cookie
*cookie
;
461 if (dmach
< 0 || dmach
>= 16) {
462 printf("mcadma_create: invalid DMA channel %d\n",
468 panic("mca_dmamap_create: dmamap sz %ld > 65536",
474 * MCA DMA transfer can be maximum 65536 bytes long and must
475 * be in one chunk. No specific boundary constraints are present.
477 if ((error
= _bus_dmamap_create(t
, size
, 1, 65536, 0, flags
, dmamp
)))
480 cookie
= (struct x86_isa_dma_cookie
*) (*dmamp
)->_dm_cookie
;
482 if (cookie
== NULL
) {
484 * Allocate our cookie if not yet done.
486 cookie
= malloc(sizeof(struct x86_bus_dma_cookie
), M_DMAMAP
,
487 ((flags
& BUS_DMA_NOWAIT
) ? M_NOWAIT
: M_WAITOK
) | M_ZERO
);
488 if (cookie
== NULL
) {
492 (*dmamp
)->_dm_cookie
= cookie
;
496 /* Encode DMA channel */
497 cookie
->id_flags
&= 0x0f;
498 cookie
->id_flags
|= dmach
<< 4;
500 /* Mark the dmamap as using DMA controller. Some devices
501 * drive DMA themselves, and don't need the MCA DMA controller.
502 * To distinguish the two, use a flag for dmamaps which use the DMA
505 (*dmamp
)->_dm_flags
|= _MCABUS_DMA_USEDMACTRL
;
511 * Set I/O port for DMA. Implemented separately from _mca_bus_dmamap_sync()
512 * so that it's available for one-shot setup.
515 mca_dma_set_ioport(int dma
, uint16_t port
)
517 /* Disable access to dma channel. */
518 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_MASK
| dma
);
520 /* Set I/O port to use for DMA */
521 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_SET_IO
| dma
);
522 bus_space_write_1(dmaiot
, dmaexech
, 0, port
& 0xff);
523 bus_space_write_1(dmaiot
, dmaexech
, 0, (port
>> 8) & 0xff);
525 /* Enable access to DMA channel. */
526 bus_space_write_1(dmaiot
, dmacmdh
, 0, DMACMD_RESET_MASK
| dma
);