diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2006-10-06 21:02:56 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2006-10-06 21:02:56 +0000 |
commit | f2984aabfd358ae2731013df5d571a596cb9a5eb (patch) | |
tree | 0b36a098a4b5fcb0d202c68c5a85123e7d95f419 /sys/arch/sh/dev | |
parent | b50063e7723d8a96f3eaeb641e59f7f161dcd917 (diff) |
Preliminary bits for SuperH-based ports, based on NetBSD/sh3 codebase with
minor changes.
Diffstat (limited to 'sys/arch/sh/dev')
-rw-r--r-- | sys/arch/sh/dev/pcicreg.h | 141 | ||||
-rw-r--r-- | sys/arch/sh/dev/scif.c | 1398 | ||||
-rw-r--r-- | sys/arch/sh/dev/scifreg.h | 164 | ||||
-rw-r--r-- | sys/arch/sh/dev/scireg.h | 82 | ||||
-rw-r--r-- | sys/arch/sh/dev/shb.c | 91 | ||||
-rw-r--r-- | sys/arch/sh/dev/shpcic.c | 1182 | ||||
-rw-r--r-- | sys/arch/sh/dev/shpcicvar.h | 184 |
7 files changed, 3242 insertions, 0 deletions
diff --git a/sys/arch/sh/dev/pcicreg.h b/sys/arch/sh/dev/pcicreg.h new file mode 100644 index 00000000000..f4ed0e3c75d --- /dev/null +++ b/sys/arch/sh/dev/pcicreg.h @@ -0,0 +1,141 @@ +/* $OpenBSD: pcicreg.h,v 1.1.1.1 2006/10/06 21:02:55 miod Exp $ */ +/* $NetBSD: pcicreg.h,v 1.2 2005/12/11 12:18:58 christos Exp $ */ + +/*- + * Copyright (c) 2005 NONAKA Kimihiro + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sh/devreg.h> + +/* + * PCI Controller + */ + +#define SH4_PCIC 0xfe200000 + +#define SH4_PCIC_IO 0xfe240000 +#define SH4_PCIC_IO_SIZE 0x00040000 +#define SH4_PCIC_IO_MASK (SH4_PCIC_IO_SIZE-1) +#define SH4_PCIC_MEM 0xfd000000 +#define SH4_PCIC_MEM_SIZE 0x01000000 +#define SH4_PCIC_MEM_MASK (SH4_PCIC_MEM_SIZE-1) + +#define SH4_PCICONF (SH4_PCIC+0x000) /* 32bit */ +#define SH4_PCICONF0 (SH4_PCICONF+0x00) /* 32bit */ +#define SH4_PCICONF1 (SH4_PCICONF+0x04) /* 32bit */ +#define SH4_PCICONF2 (SH4_PCICONF+0x08) /* 32bit */ +#define SH4_PCICONF3 (SH4_PCICONF+0x0c) /* 32bit */ +#define SH4_PCICONF4 (SH4_PCICONF+0x10) /* 32bit */ +#define SH4_PCICONF5 (SH4_PCICONF+0x14) /* 32bit */ +#define SH4_PCICONF6 (SH4_PCICONF+0x18) /* 32bit */ +#define SH4_PCICONF7 (SH4_PCICONF+0x1c) /* 32bit */ +#define SH4_PCICONF8 (SH4_PCICONF+0x20) /* 32bit */ +#define SH4_PCICONF9 (SH4_PCICONF+0x24) /* 32bit */ +#define SH4_PCICONF10 (SH4_PCICONF+0x28) /* 32bit */ +#define SH4_PCICONF11 (SH4_PCICONF+0x2c) /* 32bit */ +#define SH4_PCICONF12 (SH4_PCICONF+0x30) /* 32bit */ +#define SH4_PCICONF13 (SH4_PCICONF+0x34) /* 32bit */ +#define SH4_PCICONF14 (SH4_PCICONF+0x38) /* 32bit */ +#define SH4_PCICONF15 (SH4_PCICONF+0x3c) /* 32bit */ +#define SH4_PCICONF16 (SH4_PCICONF+0x40) /* 32bit */ +#define SH4_PCICONF17 (SH4_PCICONF+0x44) /* 32bit */ +#define SH4_PCICR (SH4_PCIC+0x100) /* 32bit */ +#define SH4_PCILSR0 (SH4_PCIC+0x104) /* 32bit */ +#define SH4_PCILSR1 (SH4_PCIC+0x108) /* 32bit */ +#define SH4_PCILAR0 (SH4_PCIC+0x10c) /* 32bit */ +#define SH4_PCILAR1 (SH4_PCIC+0x110) /* 32bit */ +#define SH4_PCIINT (SH4_PCIC+0x114) /* 32bit */ +#define SH4_PCIINTM (SH4_PCIC+0x118) /* 32bit */ +#define SH4_PCIALR (SH4_PCIC+0x11c) /* 32bit */ +#define SH4_PCICLR (SH4_PCIC+0x120) /* 32bit */ +#define SH4_PCIAINT (SH4_PCIC+0x130) /* 32bit */ +#define SH4_PCIAINTM (SH4_PCIC+0x134) /* 32bit */ +#define SH4_PCIDMABT (SH4_PCIC+0x140) /* 32bit */ +#define SH4_PCIDPA0 (SH4_PCIC+0x180) /* 32bit */ +#define SH4_PCIDLA0 (SH4_PCIC+0x184) /* 32bit */ +#define SH4_PCIDTC0 (SH4_PCIC+0x188) /* 32bit */ +#define SH4_PCIDCR0 (SH4_PCIC+0x18c) /* 32bit */ +#define SH4_PCIDPA1 (SH4_PCIC+0x190) /* 32bit */ +#define SH4_PCIDLA1 (SH4_PCIC+0x194) /* 32bit */ +#define SH4_PCIDTC1 (SH4_PCIC+0x198) /* 32bit */ +#define SH4_PCIDCR1 (SH4_PCIC+0x19c) /* 32bit */ +#define SH4_PCIDPA2 (SH4_PCIC+0x1a0) /* 32bit */ +#define SH4_PCIDLA2 (SH4_PCIC+0x1a4) /* 32bit */ +#define SH4_PCIDTC2 (SH4_PCIC+0x1a8) /* 32bit */ +#define SH4_PCIDCR2 (SH4_PCIC+0x1ac) /* 32bit */ +#define SH4_PCIDPA3 (SH4_PCIC+0x1b0) /* 32bit */ +#define SH4_PCIDLA3 (SH4_PCIC+0x1b4) /* 32bit */ +#define SH4_PCIDTC3 (SH4_PCIC+0x1b8) /* 32bit */ +#define SH4_PCIDCR3 (SH4_PCIC+0x1bc) /* 32bit */ +#define SH4_PCIPAR (SH4_PCIC+0x1c0) /* 32bit */ +#define SH4_PCIMBR (SH4_PCIC+0x1c4) /* 32bit */ +#define SH4_PCIIOBR (SH4_PCIC+0x1c8) /* 32bit */ +#define SH4_PCIPINT (SH4_PCIC+0x1cc) /* 32bit */ +#define SH4_PCIPINTM (SH4_PCIC+0x1d0) /* 32bit */ +#define SH4_PCICLKR (SH4_PCIC+0x1d4) /* 32bit */ +#define SH4_PCIBCR1 (SH4_PCIC+0x1e0) /* 32bit */ +#define SH4_PCIBCR2 (SH4_PCIC+0x1e4) /* 32bit */ +#define SH4_PCIWCR1 (SH4_PCIC+0x1e8) /* 32bit */ +#define SH4_PCIWCR2 (SH4_PCIC+0x1ec) /* 32bit */ +#define SH4_PCIWCR3 (SH4_PCIC+0x1f0) /* 32bit */ +#define SH4_PCIMCR (SH4_PCIC+0x1f4) /* 32bit */ +#define SH4_PCIBCR3 (SH4_PCIC+0x1f8) /* 32bit: SH7751R */ +#define SH4_PCIPCTR (SH4_PCIC+0x200) /* 32bit */ +#define SH4_PCIPDTR (SH4_PCIC+0x204) /* 32bit */ +#define SH4_PCIPDR (SH4_PCIC+0x220) /* 32bit */ + +#define PCICR_BASE 0xa5000000 +#define PCICR_TRDSGL 0x00000200 +#define PCICR_BYTESWAP 0x00000100 +#define PCICR_PCIPUP 0x00000080 +#define PCICR_BMABT 0x00000040 +#define PCICR_MD10 0x00000020 +#define PCICR_MD9 0x00000010 +#define PCICR_SERR 0x00000008 +#define PCICR_INTA 0x00000004 +#define PCICR_RSTCTL 0x00000002 +#define PCICR_CFINIT 0x00000001 + +#define PCIINT_M_LOCKON 0x00008000 +#define PCIINT_T_TGT_ABORT 0x00004000 +#define PCIINT_TGT_RETRY 0x00000200 +#define PCIINT_MST_DIS 0x00000100 +#define PCIINT_ADRPERR 0x00000080 +#define PCIINT_SERR_DET 0x00000040 +#define PCIINT_T_DPERR_WT 0x00000020 +#define PCIINT_T_PERR_DET 0x00000010 +#define PCIINT_M_TGT_ABORT 0x00000008 +#define PCIINT_M_MST_ABORT 0x00000004 +#define PCIINT_M_DPERR_WT 0x00000002 +#define PCIINT_M_DPERR_RD 0x00000001 +#define PCIINT_ALL 0x0000c3ff +#define PCIINT_CLEAR_ALL PCIINT_ALL + +#define PCIINTM_MASK_ALL 0x00000000 +#define PCIINTM_UNMASK_ALL PCIINT_ALL + +#define PCIMBR_MASK 0xff000000 + +#define PCIIOBR_MASK 0xffc00000 diff --git a/sys/arch/sh/dev/scif.c b/sys/arch/sh/dev/scif.c new file mode 100644 index 00000000000..c2449a8cbd4 --- /dev/null +++ b/sys/arch/sh/dev/scif.c @@ -0,0 +1,1398 @@ +/* $OpenBSD: scif.c,v 1.1 2006/10/06 21:02:55 miod Exp $ */ +/* $NetBSD: scif.c,v 1.47 2006/07/23 22:06:06 ad Exp $ */ + +/*- + * Copyright (C) 1999 T.Horiuchi and SAITOH Masanobu. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)com.c 7.5 (Berkeley) 5/16/91 + */ + +/* + * SH internal serial driver + * + * This code is derived from both z8530tty.c and com.c + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/syslog.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/timeout.h> + +#include <dev/cons.h> + +#include <sh/clock.h> +#include <sh/trap.h> +#include <machine/intr.h> + +#include <sh/dev/scifreg.h> + +#ifdef DDB +#include <ddb/db_var.h> +#endif + +void scifstart(struct tty *); +int scifparam(struct tty *, struct termios *); + +void scifcnprobe(struct consdev *); +void scifcninit(struct consdev *); +void scifcnputc(dev_t, int); +int scifcngetc(dev_t); +void scifcnpoolc(dev_t, int); +void scif_intr_init(void); +int scifintr(void *); + +struct scif_softc { + struct device sc_dev; /* boilerplate */ + struct tty *sc_tty; + void *sc_si; + + struct timeout sc_diag_tmo; + +#if 0 + bus_space_tag_t sc_iot; /* ISA i/o space identifier */ + bus_space_handle_t sc_ioh; /* ISA io handle */ + + int sc_drq; + + int sc_frequency; +#endif + + u_int sc_overflows, + sc_floods, + sc_errors; /* number of retries so far */ + u_char sc_status[7]; /* copy of registers */ + + int sc_hwflags; + int sc_swflags; + u_int sc_fifolen; + + u_int sc_r_hiwat, + sc_r_lowat; + u_char *volatile sc_rbget, + *volatile sc_rbput; + volatile u_int sc_rbavail; + u_char *sc_rbuf, + *sc_ebuf; + + u_char *sc_tba; /* transmit buffer address */ + u_int sc_tbc, /* transmit byte count */ + sc_heldtbc; + + volatile u_char sc_rx_flags, +#define RX_TTY_BLOCKED 0x01 +#define RX_TTY_OVERFLOWED 0x02 +#define RX_IBUF_BLOCKED 0x04 +#define RX_IBUF_OVERFLOWED 0x08 +#define RX_ANY_BLOCK 0x0f + sc_tx_busy, /* working on an output chunk */ + sc_tx_done, /* done with one output chunk */ + sc_tx_stopped, /* H/W level stop (lost CTS) */ + sc_st_check, /* got a status interrupt */ + sc_rx_ready; + + volatile u_char sc_heldchange; +}; + +/* controller driver configuration */ +int scif_match(struct device *, void *, void *); +void scif_attach(struct device *, struct device *, void *); + +void scif_break(struct scif_softc *, int); +void scif_iflush(struct scif_softc *); + +void scifsoft(void *); +void scif_rxsoft(struct scif_softc *, struct tty *); +void scif_txsoft(struct scif_softc *, struct tty *); +void scif_stsoft(struct scif_softc *, struct tty *); +void scif_schedrx(struct scif_softc *); +void scifdiag(void *); + + +#define SCIFUNIT_MASK 0x7ffff +#define SCIFDIALOUT_MASK 0x80000 + +#define SCIFUNIT(x) (minor(x) & SCIFUNIT_MASK) +#define SCIFDIALOUT(x) (minor(x) & SCIFDIALOUT_MASK) + +/* Hardware flag masks */ +#define SCIF_HW_NOIEN 0x01 +#define SCIF_HW_FIFO 0x02 +#define SCIF_HW_FLOW 0x08 +#define SCIF_HW_DEV_OK 0x20 +#define SCIF_HW_CONSOLE 0x40 + +/* Buffer size for character buffer */ +#define SCIF_RING_SIZE 2048 + +/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */ +u_int scif_rbuf_hiwat = (SCIF_RING_SIZE * 1) / 4; +u_int scif_rbuf_lowat = (SCIF_RING_SIZE * 3) / 4; + +#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ +int scifconscflag = CONMODE; +int scifisconsole = 0; + +#ifdef SCIFCN_SPEED +unsigned int scifcn_speed = SCIFCN_SPEED; +#else +unsigned int scifcn_speed = 9600; +#endif + +#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ + +u_int scif_rbuf_size = SCIF_RING_SIZE; + +struct cfattach scif_ca = { + sizeof(struct scif_softc), scif_match, scif_attach +}; + +struct cfdriver scif_cd = { + 0, "scif", DV_DULL +}; + +static int scif_attached; + +cdev_decl(scif); + +void InitializeScif(unsigned int); + +/* + * following functions are debugging prupose only + */ +#define CR 0x0D +#define USART_ON (unsigned int)~0x08 + +void scif_putc(unsigned char); +unsigned char scif_getc(void); +int ScifErrCheck(void); + + +/* XXX: uwe + * Prepare for bus_spacification. The difference in access widths is + * still handled by the magic definitions in scifreg.h + */ +#define scif_smr_read() SHREG_SCSMR2 +#define scif_smr_write(v) (SHREG_SCSMR2 = (v)) + +#define scif_brr_read() SHREG_SCBRR2 +#define scif_brr_write(v) (SHREG_SCBRR2 = (v)) + +#define scif_scr_read() SHREG_SCSCR2 +#define scif_scr_write(v) (SHREG_SCSCR2 = (v)) + +#define scif_ftdr_write(v) (SHREG_SCFTDR2 = (v)) + +#define scif_ssr_read() SHREG_SCSSR2 +#define scif_ssr_write(v) (SHREG_SCSSR2 = (v)) + +#define scif_frdr_read() SHREG_SCFRDR2 + +#define scif_fcr_read() SHREG_SCFCR2 +#define scif_fcr_write(v) (SHREG_SCFCR2 = (v)) + +#define scif_fdr_read() SHREG_SCFDR2 + +#ifdef SH4 /* additional registers in sh4 */ + +#define scif_sptr_read() SHREG_SCSPTR2 +#define scif_sptr_write(v) (SHREG_SCSPTR2 = (v)) + +#define scif_lsr_read() SHREG_SCLSR2 +#define scif_lsr_write(v) (SHREG_SCLSR2 = (v)) + +#endif /* SH4 */ + + +/* + * InitializeScif + * : unsigned int bps; + * : SCIF(Serial Communication Interface) + */ + +void +InitializeScif(unsigned int bps) +{ + /* Initialize SCR */ + scif_scr_write(0x00); + +#if 0 + scif_fcr_write(SCFCR2_TFRST | SCFCR2_RFRST | SCFCR2_MCE); +#else + scif_fcr_write(SCFCR2_TFRST | SCFCR2_RFRST); +#endif + /* Serial Mode Register */ + scif_smr_write(0x00); /* 8bit,NonParity,Even,1Stop */ + + /* Bit Rate Register */ + scif_brr_write(divrnd(sh_clock_get_pclock(), 32 * bps) - 1); + + /* + * wait 2m Sec, because Send/Recv must begin 1 bit period after + * BRR is set. + */ + delay(2000); + +#if 0 + scif_fcr_write(FIFO_RCV_TRIGGER_14 | FIFO_XMT_TRIGGER_1 | SCFCR2_MCE); +#else + scif_fcr_write(FIFO_RCV_TRIGGER_14 | FIFO_XMT_TRIGGER_1); +#endif + + /* Send permission, Receive permission ON */ + scif_scr_write(SCSCR2_TE | SCSCR2_RE); + + /* Serial Status Register */ + scif_ssr_write(scif_ssr_read() & SCSSR2_TDFE); /* Clear Status */ +} + + +/* + * scif_putc + * : unsigned char c; + */ + +void +scif_putc(unsigned char c) +{ + /* wait for ready */ + while ((scif_fdr_read() & SCFDR2_TXCNT) == SCFDR2_TXF_FULL) + continue; + + /* write send data to send register */ + scif_ftdr_write(c); + + /* clear ready flag */ + scif_ssr_write(scif_ssr_read() & ~(SCSSR2_TDFE | SCSSR2_TEND)); +} + +/* + * : ScifErrCheck + * 0x80 = error + * 0x08 = frame error + * 0x04 = parity error + */ +int +ScifErrCheck(void) +{ + return (scif_ssr_read() & (SCSSR2_ER | SCSSR2_FER | SCSSR2_PER)); +} + +/* + * scif_getc + */ +unsigned char +scif_getc(void) +{ + unsigned char c, err_c; +#ifdef SH4 + unsigned short err_c2 = 0; /* XXXGCC: -Wuninitialized */ +#endif + + for (;;) { + /* wait for ready */ + while ((scif_fdr_read() & SCFDR2_RECVCNT) == 0) + continue; + + c = scif_frdr_read(); + err_c = scif_ssr_read(); + scif_ssr_write(scif_ssr_read() + & ~(SCSSR2_ER | SCSSR2_BRK | SCSSR2_RDF | SCSSR2_DR)); +#ifdef SH4 + if (CPU_IS_SH4) { + err_c2 = scif_lsr_read(); + scif_lsr_write(scif_lsr_read() & ~SCLSR2_ORER); + } +#endif + if ((err_c & (SCSSR2_ER | SCSSR2_BRK | SCSSR2_FER + | SCSSR2_PER)) == 0) { +#ifdef SH4 + if (CPU_IS_SH4 && ((err_c2 & SCLSR2_ORER) == 0)) +#endif + return(c); + } + } + +} + +int +scif_match(struct device *parent, void *vcf, void *aux) +{ + if (scif_attached != 0) + return 0; + + return 1; +} + +void +scif_attach(struct device *parent, struct device *self, void *aux) +{ + struct scif_softc *sc = (struct scif_softc *)self; + struct tty *tp; + + scif_attached = 1; + + sc->sc_hwflags = 0; /* XXX */ + sc->sc_swflags = 0; /* XXX */ + sc->sc_fifolen = 16; + + if (scifisconsole) { + /* InitializeScif(scifcn_speed); */ + SET(sc->sc_hwflags, SCIF_HW_CONSOLE); + SET(sc->sc_swflags, TIOCFLAG_SOFTCAR); + printf("\n%s: console\n", sc->sc_dev.dv_xname); + } else { + InitializeScif(9600); + printf("\n"); + } + + timeout_set(&sc->sc_diag_tmo, scifdiag, sc); +#ifdef SH4 + intc_intr_establish(SH4_INTEVT_SCIF_ERI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); + intc_intr_establish(SH4_INTEVT_SCIF_RXI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); + intc_intr_establish(SH4_INTEVT_SCIF_BRI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); + intc_intr_establish(SH4_INTEVT_SCIF_TXI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); +#else + intc_intr_establish(SH7709_INTEVT2_SCIF_ERI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); + intc_intr_establish(SH7709_INTEVT2_SCIF_RXI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); + intc_intr_establish(SH7709_INTEVT2_SCIF_BRI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); + intc_intr_establish(SH7709_INTEVT2_SCIF_TXI, IST_LEVEL, IPL_SERIAL, + scifintr, sc, self->dv_xname); +#endif + + sc->sc_si = softintr_establish(IPL_SOFTSERIAL, scifsoft, sc); + SET(sc->sc_hwflags, SCIF_HW_DEV_OK); + + tp = ttymalloc(); + tp->t_oproc = scifstart; + tp->t_param = scifparam; + tp->t_hwiflow = NULL; + + sc->sc_tty = tp; + sc->sc_rbuf = malloc(scif_rbuf_size << 1, M_DEVBUF, M_NOWAIT); + if (sc->sc_rbuf == NULL) { + printf("%s: unable to allocate ring buffer\n", + sc->sc_dev.dv_xname); + return; + } + sc->sc_ebuf = sc->sc_rbuf + (scif_rbuf_size << 1); +} + +/* + * Start or restart transmission. + */ +void +scifstart(struct tty *tp) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(tp->t_dev)]; + int s; + + s = spltty(); + if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) + goto out; + if (sc->sc_tx_stopped) + goto out; + + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (ISSET(tp->t_state, TS_ASLEEP)) { + CLR(tp->t_state, TS_ASLEEP); + wakeup(&tp->t_outq); + } + selwakeup(&tp->t_wsel); + if (tp->t_outq.c_cc == 0) + goto out; + } + + /* Grab the first contiguous region of buffer space. */ + { + u_char *tba; + int tbc; + + tba = tp->t_outq.c_cf; + tbc = ndqb(&tp->t_outq, 0); + + (void)splserial(); + + sc->sc_tba = tba; + sc->sc_tbc = tbc; + } + + SET(tp->t_state, TS_BUSY); + sc->sc_tx_busy = 1; + + /* Enable transmit completion interrupts if necessary. */ + scif_scr_write(scif_scr_read() | SCSCR2_TIE | SCSCR2_RIE); + + /* Output the first chunk of the contiguous buffer. */ + { + int n; + int maxchars; + int i; + + n = sc->sc_tbc; + maxchars = sc->sc_fifolen + - ((scif_fdr_read() & SCFDR2_TXCNT) >> 8); + if (n > maxchars) + n = maxchars; + + for (i = 0; i < n; i++) { + scif_putc(*(sc->sc_tba)); + sc->sc_tba++; + } + sc->sc_tbc -= n; + } +out: + splx(s); + return; +} + +/* + * Set SCIF tty parameters from termios. + * XXX - Should just copy the whole termios after + * making sure all the changes could be done. + */ +int +scifparam(struct tty *tp, struct termios *t) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(tp->t_dev)]; + int ospeed = t->c_ospeed; + int s; + + /* Check requested parameters. */ + if (ospeed < 0) + return (EINVAL); + if (t->c_ispeed && t->c_ispeed != t->c_ospeed) + return (EINVAL); + + /* + * For the console, always force CLOCAL and !HUPCL, so that the port + * is always active. + */ + if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || + ISSET(sc->sc_hwflags, SCIF_HW_CONSOLE)) { + SET(t->c_cflag, CLOCAL); + CLR(t->c_cflag, HUPCL); + } + + /* + * If there were no changes, don't do anything. This avoids dropping + * input and improves performance when all we did was frob things like + * VMIN and VTIME. + */ + if (tp->t_ospeed == t->c_ospeed && + tp->t_cflag == t->c_cflag) + return (0); + +#if 0 +/* XXX (msaitoh) */ + lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); +#endif + + s = splserial(); + + /* + * Set the flow control pins depending on the current flow control + * mode. + */ + if (ISSET(t->c_cflag, CRTSCTS)) { + scif_fcr_write(scif_fcr_read() | SCFCR2_MCE); + } else { + scif_fcr_write(scif_fcr_read() & ~SCFCR2_MCE); + } + + scif_brr_write(divrnd(sh_clock_get_pclock(), 32 * ospeed) -1); + + /* + * Set the FIFO threshold based on the receive speed. + * + * * If it's a low speed, it's probably a mouse or some other + * interactive device, so set the threshold low. + * * If it's a high speed, trim the trigger level down to prevent + * overflows. + * * Otherwise set it a bit higher. + */ +#if 0 +/* XXX (msaitoh) */ + if (ISSET(sc->sc_hwflags, SCIF_HW_HAYESP)) + sc->sc_fifo = FIFO_DMA_MODE | FIFO_ENABLE | FIFO_TRIGGER_8; + else if (ISSET(sc->sc_hwflags, SCIF_HW_FIFO)) + sc->sc_fifo = FIFO_ENABLE | + (t->c_ospeed <= 1200 ? FIFO_TRIGGER_1 : + t->c_ospeed <= 38400 ? FIFO_TRIGGER_8 : FIFO_TRIGGER_4); + else + sc->sc_fifo = 0; +#endif + + /* And copy to tty. */ + tp->t_ispeed = 0; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + + if (!sc->sc_heldchange) { + if (sc->sc_tx_busy) { + sc->sc_heldtbc = sc->sc_tbc; + sc->sc_tbc = 0; + sc->sc_heldchange = 1; + } +#if 0 +/* XXX (msaitoh) */ + else + scif_loadchannelregs(sc); +#endif + } + + if (!ISSET(t->c_cflag, CHWFLOW)) { + /* Disable the high water mark. */ + sc->sc_r_hiwat = 0; + sc->sc_r_lowat = 0; + if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED); + scif_schedrx(sc); + } + } else { + sc->sc_r_hiwat = scif_rbuf_hiwat; + sc->sc_r_lowat = scif_rbuf_lowat; + } + + splx(s); + +#ifdef SCIF_DEBUG + if (scif_debug) + scifstatus(sc, "scifparam "); +#endif + + if (!ISSET(t->c_cflag, CHWFLOW)) { + if (sc->sc_tx_stopped) { + sc->sc_tx_stopped = 0; + scifstart(tp); + } + } + + return (0); +} + +void +scif_iflush(struct scif_softc *sc) +{ + int i; + unsigned char c; + + i = scif_fdr_read() & SCFDR2_RECVCNT; + + while (i > 0) { + c = scif_frdr_read(); + scif_ssr_write(scif_ssr_read() & ~(SCSSR2_RDF | SCSSR2_DR)); + i--; + } +} + +int +scifopen(dev_t dev, int flag, int mode, struct proc *p) +{ + int unit = SCIFUNIT(dev); + struct scif_softc *sc; + struct tty *tp; + int s, s2; + int error; + + if (unit >= scif_cd.cd_ndevs) + return (ENXIO); + sc = scif_cd.cd_devs[unit]; + if (sc == 0 || !ISSET(sc->sc_hwflags, SCIF_HW_DEV_OK) || + sc->sc_rbuf == NULL) + return (ENXIO); + + tp = sc->sc_tty; + + if (ISSET(tp->t_state, TS_ISOPEN) && + ISSET(tp->t_state, TS_XCLUDE) && + p->p_ucred->cr_uid != 0) + return (EBUSY); + + s = spltty(); + + /* + * Do the following iff this is a first open. + */ + if (!ISSET(tp->t_state, TS_ISOPEN)) { + struct termios t; + + tp->t_dev = dev; + + s2 = splserial(); + + /* Turn on interrupts. */ + scif_scr_write(scif_scr_read() | SCSCR2_TIE | SCSCR2_RIE); + + splx(s2); + + /* + * Initialize the termios status to the defaults. Add in the + * sticky bits from TIOCSFLAGS. + */ + t.c_ispeed = 0; + if (ISSET(sc->sc_hwflags, SCIF_HW_CONSOLE)) { + t.c_ospeed = scifcn_speed; /* XXX (msaitoh) */ + t.c_cflag = scifconscflag; + } else { + t.c_ospeed = TTYDEF_SPEED; + t.c_cflag = TTYDEF_CFLAG; + } + if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) + SET(t.c_cflag, CLOCAL); + if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) + SET(t.c_cflag, CRTSCTS); + if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) + SET(t.c_cflag, MDMBUF); + /* Make sure scifparam() will do something. */ + tp->t_ospeed = 0; + (void) scifparam(tp, &t); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + ttychars(tp); + ttsetwater(tp); + + s2 = splserial(); + + /* Clear the input ring, and unblock. */ + sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; + sc->sc_rbavail = scif_rbuf_size; + scif_iflush(sc); + CLR(sc->sc_rx_flags, RX_ANY_BLOCK); +#if 0 +/* XXX (msaitoh) */ + scif_hwiflow(sc); +#endif + +#ifdef SCIF_DEBUG + if (scif_debug) + scifstatus(sc, "scifopen "); +#endif + + splx(s2); + } + + splx(s); + + error = ttyopen(dev, tp); + if (error) + goto bad; + + error = (*linesw[tp->t_line].l_open)(dev, tp); + if (error) + goto bad; + + return (0); + +bad: + + return (error); +} + +int +scifclose(dev_t dev, int flag, int mode, struct proc *p) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + /* XXX This is for cons.c. */ + if (!ISSET(tp->t_state, TS_ISOPEN)) + return (0); + + (*linesw[tp->t_line].l_close)(tp, flag); + ttyclose(tp); + + return (0); +} + +int +scifread(dev_t dev, struct uio *uio, int flag) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +scifwrite(dev_t dev, struct uio *uio, int flag) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +#if 0 +int +scifpoll(dev_t dev, int events, struct proc *p) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return ((*linesw[tp->t_line].l_poll)(tp, events, p)); +} +#endif + +struct tty * +sciftty(dev_t dev) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return (tp); +} + +int +scifioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)]; + struct tty *tp = sc->sc_tty; + int error; + int s; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error != -1) + return (error); + + error = ttioctl(tp, cmd, data, flag, p); + if (error != -1) + return (error); + + error = 0; + + s = splserial(); + + switch (cmd) { + case TIOCSBRK: + scif_break(sc, 1); + break; + + case TIOCCBRK: + scif_break(sc, 0); + break; + + case TIOCGFLAGS: + *(int *)data = sc->sc_swflags; + break; + + case TIOCSFLAGS: + error = suser(p, 0); + if (error) + break; + sc->sc_swflags = *(int *)data; + break; + + default: + error = -1; + break; + } + + splx(s); + + return (error); +} + +void +scif_schedrx(struct scif_softc *sc) +{ + sc->sc_rx_ready = 1; + + /* Wake up the poller. */ + softintr_schedule(sc->sc_si); +} + +void +scif_break(struct scif_softc *sc, int onoff) +{ + if (onoff) + scif_ssr_write(scif_ssr_read() & ~SCSSR2_TDFE); + else + scif_ssr_write(scif_ssr_read() | SCSSR2_TDFE); + +#if 0 /* XXX */ + if (!sc->sc_heldchange) { + if (sc->sc_tx_busy) { + sc->sc_heldtbc = sc->sc_tbc; + sc->sc_tbc = 0; + sc->sc_heldchange = 1; + } else + scif_loadchannelregs(sc); + } +#endif +} + +/* + * Stop output, e.g., for ^S or output flush. + */ +int +scifstop(struct tty *tp, int flag) +{ + struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(tp->t_dev)]; + int s; + + s = splserial(); + if (ISSET(tp->t_state, TS_BUSY)) { + /* Stop transmitting at the next chunk. */ + sc->sc_tbc = 0; + sc->sc_heldtbc = 0; + if (!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + } + splx(s); + return (0); +} + +void +scif_intr_init() +{ + /* XXX */ +} + +void +scifdiag(void *arg) +{ + struct scif_softc *sc = arg; + int overflows, floods; + int s; + + s = splserial(); + overflows = sc->sc_overflows; + sc->sc_overflows = 0; + floods = sc->sc_floods; + sc->sc_floods = 0; + sc->sc_errors = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n", + sc->sc_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +void +scif_rxsoft(struct scif_softc *sc, struct tty *tp) +{ + int (*rint)(int, struct tty *) = *linesw[tp->t_line].l_rint; + u_char *get, *end; + u_int cc, scc; + u_char ssr2; + int code; + int s; + + end = sc->sc_ebuf; + get = sc->sc_rbget; + scc = cc = scif_rbuf_size - sc->sc_rbavail; + + if (cc == scif_rbuf_size) { + sc->sc_floods++; + if (sc->sc_errors++ == 0) + timeout_add(&sc->sc_diag_tmo, 60 * hz); + } + + while (cc) { + code = get[0]; + ssr2 = get[1]; + if (ISSET(ssr2, SCSSR2_BRK | SCSSR2_FER | SCSSR2_PER)) { + if (ISSET(ssr2, SCSSR2_BRK | SCSSR2_FER)) + SET(code, TTY_FE); + if (ISSET(ssr2, SCSSR2_PER)) + SET(code, TTY_PE); + } + if ((*rint)(code, tp) == -1) { + /* + * The line discipline's buffer is out of space. + */ + if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) { + /* + * We're either not using flow control, or the + * line discipline didn't tell us to block for + * some reason. Either way, we have no way to + * know when there's more space available, so + * just drop the rest of the data. + */ + get += cc << 1; + if (get >= end) + get -= scif_rbuf_size << 1; + cc = 0; + } else { + /* + * Don't schedule any more receive processing + * until the line discipline tells us there's + * space available (through scifhwiflow()). + * Leave the rest of the data in the input + * buffer. + */ + SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED); + } + break; + } + get += 2; + if (get >= end) + get = sc->sc_rbuf; + cc--; + } + + if (cc != scc) { + sc->sc_rbget = get; + s = splserial(); + cc = sc->sc_rbavail += scc - cc; + /* Buffers should be ok again, release possible block. */ + if (cc >= sc->sc_r_lowat) { + if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { + CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); + scif_scr_write(scif_scr_read() | SCSCR2_RIE); + } +#if 0 + if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) { + CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED); + scif_hwiflow(sc); + } +#endif + } + splx(s); + } +} + +void +scif_txsoft(struct scif_softc *sc, struct tty *tp) +{ + CLR(tp->t_state, TS_BUSY); + if (ISSET(tp->t_state, TS_FLUSH)) + CLR(tp->t_state, TS_FLUSH); + else + ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); + (*linesw[tp->t_line].l_start)(tp); +} + +void +scif_stsoft(struct scif_softc *sc, struct tty *tp) +{ +#if 0 +/* XXX (msaitoh) */ + u_char msr, delta; + int s; + + s = splserial(); + msr = sc->sc_msr; + delta = sc->sc_msr_delta; + sc->sc_msr_delta = 0; + splx(s); + + if (ISSET(delta, sc->sc_msr_dcd)) { + /* + * Inform the tty layer that carrier detect changed. + */ + (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSR_DCD)); + } + + if (ISSET(delta, sc->sc_msr_cts)) { + /* Block or unblock output according to flow control. */ + if (ISSET(msr, sc->sc_msr_cts)) { + sc->sc_tx_stopped = 0; + (*linesw[tp->t_line].l_start)(tp); + } else { + sc->sc_tx_stopped = 1; + } + } + +#ifdef SCIF_DEBUG + if (scif_debug) + scifstatus(sc, "scif_stsoft"); +#endif +#endif +} + +void +scifsoft(void *arg) +{ + struct scif_softc *sc = arg; + struct tty *tp; + + tp = sc->sc_tty; + + if (sc->sc_rx_ready) { + sc->sc_rx_ready = 0; + scif_rxsoft(sc, tp); + } + +#if 0 + if (sc->sc_st_check) { + sc->sc_st_check = 0; + scif_stsoft(sc, tp); + } +#endif + + if (sc->sc_tx_done) { + sc->sc_tx_done = 0; + scif_txsoft(sc, tp); + } +} + +int +scifintr(void *arg) +{ + struct scif_softc *sc = arg; + u_char *put, *end; + u_int cc; + u_short ssr2; + int count; + + end = sc->sc_ebuf; + put = sc->sc_rbput; + cc = sc->sc_rbavail; + + do { + ssr2 = scif_ssr_read(); + if (ISSET(ssr2, SCSSR2_BRK)) { + scif_ssr_write(scif_ssr_read() + & ~(SCSSR2_ER | SCSSR2_BRK | SCSSR2_DR)); +#ifdef DDB + if (ISSET(sc->sc_hwflags, SCIF_HW_CONSOLE) && + db_console != 0) { + Debugger(); + } +#endif /* DDB */ + } + count = scif_fdr_read() & SCFDR2_RECVCNT; + if (count != 0) { + for (;;) { + u_char c = scif_frdr_read(); + u_char err = (u_char)(scif_ssr_read() & 0x00ff); + + scif_ssr_write(scif_ssr_read() + & ~(SCSSR2_ER | SCSSR2_RDF | SCSSR2_DR)); +#ifdef SH4 + if (CPU_IS_SH4) + scif_lsr_write(scif_lsr_read() + & ~SCLSR2_ORER); +#endif + if ((cc > 0) && (count > 0)) { + put[0] = c; + put[1] = err; + put += 2; + if (put >= end) + put = sc->sc_rbuf; + cc--; + count--; + } else + break; + } + + /* + * Current string of incoming characters ended because + * no more data was available or we ran out of space. + * Schedule a receive event if any data was received. + * If we're out of space, turn off receive interrupts. + */ + sc->sc_rbput = put; + sc->sc_rbavail = cc; + if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) + sc->sc_rx_ready = 1; + + /* + * See if we are in danger of overflowing a buffer. If + * so, use hardware flow control to ease the pressure. + */ + if (!ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED) && + cc < sc->sc_r_hiwat) { + SET(sc->sc_rx_flags, RX_IBUF_BLOCKED); +#if 0 + scif_hwiflow(sc); +#endif + } + + /* + * If we're out of space, disable receive interrupts + * until the queue has drained a bit. + */ + if (!cc) { + SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); + scif_scr_write(scif_scr_read() & ~SCSCR2_RIE); + } + } else { + if (scif_ssr_read() & (SCSSR2_RDF | SCSSR2_DR)) { + scif_scr_write(scif_scr_read() + & ~(SCSCR2_TIE | SCSCR2_RIE)); + delay(10); + scif_scr_write(scif_scr_read() + | SCSCR2_TIE | SCSCR2_RIE); + continue; + } + } + } while (scif_ssr_read() & (SCSSR2_RDF | SCSSR2_DR)); + +#if 0 + msr = bus_space_read_1(iot, ioh, scif_msr); + delta = msr ^ sc->sc_msr; + sc->sc_msr = msr; + if (ISSET(delta, sc->sc_msr_mask)) { + SET(sc->sc_msr_delta, delta); + + /* + * Pulse-per-second clock signal on edge of DCD? + */ + if (ISSET(delta, sc->sc_ppsmask)) { + struct timeval tv; + if (ISSET(msr, sc->sc_ppsmask) == + sc->sc_ppsassert) { + /* XXX nanotime() */ + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, + &sc->ppsinfo.assert_timestamp); + if (sc->ppsparam.mode & PPS_OFFSETASSERT) { + timespecadd(&sc->ppsinfo.assert_timestamp, + &sc->ppsparam.assert_offset, + &sc->ppsinfo.assert_timestamp); + TIMESPEC_TO_TIMEVAL(&tv, &sc->ppsinfo.assert_timestamp); + } + +#ifdef PPS_SYNC + if (sc->ppsparam.mode & PPS_HARDPPSONASSERT) + hardpps(&tv, tv.tv_usec); +#endif + sc->ppsinfo.assert_sequence++; + sc->ppsinfo.current_mode = + sc->ppsparam.mode; + + } else if (ISSET(msr, sc->sc_ppsmask) == + sc->sc_ppsclear) { + /* XXX nanotime() */ + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, + &sc->ppsinfo.clear_timestamp); + if (sc->ppsparam.mode & PPS_OFFSETCLEAR) { + timespecadd(&sc->ppsinfo.clear_timestamp, + &sc->ppsparam.clear_offset, + &sc->ppsinfo.clear_timestamp); + TIMESPEC_TO_TIMEVAL(&tv, &sc->ppsinfo.clear_timestamp); + } + +#ifdef PPS_SYNC + if (sc->ppsparam.mode & PPS_HARDPPSONCLEAR) + hardpps(&tv, tv.tv_usec); +#endif + sc->ppsinfo.clear_sequence++; + sc->ppsinfo.current_mode = + sc->ppsparam.mode; + } + } + + /* + * Stop output immediately if we lose the output + * flow control signal or carrier detect. + */ + if (ISSET(~msr, sc->sc_msr_mask)) { + sc->sc_tbc = 0; + sc->sc_heldtbc = 0; +#ifdef SCIF_DEBUG + if (scif_debug) + scifstatus(sc, "scifintr "); +#endif + } + + sc->sc_st_check = 1; + } +#endif + + /* + * Done handling any receive interrupts. See if data can be + * transmitted as well. Schedule tx done event if no data left + * and tty was marked busy. + */ + if (((scif_fdr_read() & SCFDR2_TXCNT) >> 8) != 16) { /* XXX (msaitoh) */ + /* + * If we've delayed a parameter change, do it now, and restart + * output. + */ + if (sc->sc_heldchange) { + sc->sc_heldchange = 0; + sc->sc_tbc = sc->sc_heldtbc; + sc->sc_heldtbc = 0; + } + + /* Output the next chunk of the contiguous buffer, if any. */ + if (sc->sc_tbc > 0) { + int n; + int maxchars; + int i; + + n = sc->sc_tbc; + maxchars = sc->sc_fifolen - + ((scif_fdr_read() & SCFDR2_TXCNT) >> 8); + if (n > maxchars) + n = maxchars; + + for (i = 0; i < n; i++) { + scif_putc(*(sc->sc_tba)); + sc->sc_tba++; + } + sc->sc_tbc -= n; + } else { + /* Disable transmit completion interrupts if necessary. */ +#if 0 + if (ISSET(sc->sc_ier, IER_ETXRDY)) +#endif + scif_scr_write(scif_scr_read() & ~SCSCR2_TIE); + + if (sc->sc_tx_busy) { + sc->sc_tx_busy = 0; + sc->sc_tx_done = 1; + } + } + } + + /* Wake up the poller. */ + softintr_schedule(sc->sc_si); + + return (1); +} + +void +scifcnprobe(struct consdev *cp) +{ + int maj; + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == scifopen) + break; + + cp->cn_dev = makedev(maj, 0); +#ifdef SCIFCONSOLE + cp->cn_pri = CN_REMOTE; +#else + cp->cn_pri = CN_NORMAL; +#endif +} + +void +scifcninit(struct consdev *cp) +{ + InitializeScif(scifcn_speed); + scifisconsole = 1; +} + +int +scifcngetc(dev_t dev) +{ + int c; + int s; + + s = splserial(); + c = scif_getc(); + splx(s); + + return (c); +} + +void +scifcnputc(dev_t dev, int c) +{ + int s; + + s = splserial(); + scif_putc((u_char)c); + splx(s); +} diff --git a/sys/arch/sh/dev/scifreg.h b/sys/arch/sh/dev/scifreg.h new file mode 100644 index 00000000000..3baf31f7f90 --- /dev/null +++ b/sys/arch/sh/dev/scifreg.h @@ -0,0 +1,164 @@ +/* $OpenBSD: scifreg.h,v 1.1.1.1 2006/10/06 21:02:55 miod Exp $ */ +/* $NetBSD: scifreg.h,v 1.10 2006/02/18 00:41:32 uwe Exp $ */ + +/*- + * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Serial Communication Interface with FIFO (SCIF) + */ + +#define SH3_SCIF0_BASE 0xa4000150 +#define SH3_SCIF1_BASE 0xa4000140 + +#define SH4_SCIF_BASE 0xffe80000 + +#ifdef SH3 + +/* SH3 definitions */ + +#define SCIF_SMR 0x0 /* serial mode */ +#define SCIF_BRR 0x2 /* bit rate */ +#define SCIF_SCR 0x4 /* serial control */ +#define SCIF_FTDR 0x6 /* transmit fifo data */ +#define SCIF_SSR 0x8 /* serial status */ +#define SCIF_FRDR 0xa /* receive fifo data */ +#define SCIF_FCR 0xc /* fifo control */ +#define SCIF_FDR 0xe /* fifo data count set */ + +#define SHREG_SCSMR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_SMR)) +#define SHREG_SCBRR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_BRR)) +#define SHREG_SCSCR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_SCR)) +#define SHREG_SCFTDR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_FTDR)) +#define SHREG_SCSSR2 (*(volatile uint16_t *)(SH3_SCIF0_BASE + SCIF_SSR)) +#define SHREG_SCFRDR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_FRDR)) +#define SHREG_SCFCR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_FCR)) +#define SHREG_SCFDR2 (*(volatile uint16_t *)(SH3_SCIF0_BASE + SCIF_FDR)) + +#else /* !SH3 */ + +/* SH4 definitions */ + +#define SCIF_SMR 0x00 /* serial mode */ +#define SCIF_BRR 0x04 /* bit rate */ +#define SCIF_SCR 0x08 /* serial control */ +#define SCIF_FTDR 0x0c /* transmit fifo data */ +#define SCIF_SSR 0x10 /* serial status */ +#define SCIF_FRDR 0x14 /* receive fifo data */ +#define SCIF_FCR 0x18 /* fifo control */ +#define SCIF_FDR 0x1c /* fifo data count set */ + +#define SCIF_SPTR 0x20 /* seial port */ +#define SCIF_LSR 0x24 /* line status */ + +#define SHREG_SCSMR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SMR)) +#define SHREG_SCBRR2 (*(volatile uint8_t *)(SH4_SCIF_BASE + SCIF_BRR)) +#define SHREG_SCSCR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SCR)) +#define SHREG_SCFTDR2 (*(volatile uint8_t *)(SH4_SCIF_BASE + SCIF_FTDR)) +#define SHREG_SCSSR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SSR)) +#define SHREG_SCFRDR2 (*(volatile uint8_t *)(SH4_SCIF_BASE + SCIF_FRDR)) +#define SHREG_SCFCR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_FCR)) +#define SHREG_SCFDR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_FDR)) + +#define SHREG_SCSPTR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SPTR)) +#define SHREG_SCLSR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_LSR)) + +/* alias */ +#define SHREG_SCSFDR2 SHREG_SCFTDR2 +#define SHREG_SCFSR2 SHREG_SCSSR2 + +#define SCSPTR2_RTSIO 0x0080 +#define SCSPTR2_RTSDT 0x0040 +#define SCSPTR2_CTSIO 0x0020 +#define SCSPTR2_CTSDT 0x0010 +#define SCSPTR2_SCKIO 0x0008 +#define SCSPTR2_SCKDT 0x0004 +#define SCSPTR2_SPB2IO 0x0002 +#define SCSPTR2_SPB2DT 0x0001 + +#define SCLSR2_ORER 0x0001 /* overrun error */ + +#endif /* !SH3 */ + +/* SMR: serial mode */ +#define SCSMR2_CHR 0x40 /* character width (set = 7bit) */ +#define SCSMR2_PE 0x20 /* Parity Enable */ +#define SCSMR2_O 0x10 /* parity mode Odd */ +#define SCSMR2_STOP 0x08 /* STOP bit (set = 2 stop bits) */ +#define SCSMR2_CKS1 0x02 /* ClocK Select 1 */ +#define SCSMR2_CKS0 0x01 /* ClocK Select 0 */ + +/* SMR: serial mode (for IrDA) */ +#define SCSMR2_IRMOD 0x80 /* IrDA mode */ +#define SCSMR2_ICK3 0x40 +#define SCSMR2_ICK2 0x20 +#define SCSMR2_ICK1 0x10 +#define SCSMR2_ICK0 0x08 +#define SCSMR2_PSEL 0x04 /* Pulse width SELelect */ + +/* SCR: serial control */ +#define SCSCR2_TIE 0x80 /* Transmit Interrupt Enable */ +#define SCSCR2_RIE 0x40 /* Recieve Interrupt Enable */ +#define SCSCR2_TE 0x20 /* Transmit Enable */ +#define SCSCR2_RE 0x10 /* Receive Enable */ +#define SCSCR2_CKE1 0x02 /* ClocK Enable 1 */ +#define SCSCR2_CKE0 0x01 /* ClocK Enable 0 (not in sh4) */ + +/* SSR: serial status */ +#define SCSSR2_ER 0x0080 /* ERror */ +#define SCSSR2_TEND 0x0040 /* Transmit END */ +#define SCSSR2_TDFE 0x0020 /* Transmit Data Fifo Empty */ +#define SCSSR2_BRK 0x0010 /* BReaK detection */ +#define SCSSR2_FER 0x0008 /* Framing ERror */ +#define SCSSR2_PER 0x0004 /* Parity ERror */ +#define SCSSR2_RDF 0x0002 /* Recieve fifo Data Full */ +#define SCSSR2_DR 0x0001 /* Data Ready */ + +/* FCR: fifo control */ +#define SCFCR2_RTRG1 0x80 /* Receive TRiGger 1 */ +#define SCFCR2_RTRG0 0x40 /* Receive TRiGger 0 */ +#define SCFCR2_TTRG1 0x20 /* Transmit TRiGger 1 */ +#define SCFCR2_TTRG0 0x10 /* Transmit TRiGger 0 */ +#define SCFCR2_MCE 0x08 /* Modem Control Enable */ +#define SCFCR2_TFRST 0x04 /* Transmit Fifo register ReSeT */ +#define SCFCR2_RFRST 0x02 /* Receive Fifo register ReSeT */ +#define SCFCR2_LOOP 0x01 /* LOOP back test */ + +#define FIFO_RCV_TRIGGER_1 0x00 +#define FIFO_RCV_TRIGGER_4 0x40 +#define FIFO_RCV_TRIGGER_8 0x80 +#define FIFO_RCV_TRIGGER_14 0xc0 + +#define FIFO_XMT_TRIGGER_8 0x00 +#define FIFO_XMT_TRIGGER_4 0x10 +#define FIFO_XMT_TRIGGER_2 0x20 +#define FIFO_XMT_TRIGGER_1 0x30 + +/* FDR: fifo data count set */ +#define SCFDR2_TXCNT 0xff00 /* Tx CouNT */ +#define SCFDR2_RECVCNT 0x00ff /* Rx CouNT */ +#define SCFDR2_TXF_FULL 0x1000 /* Tx FULL */ +#define SCFDR2_RXF_EPTY 0x0000 /* Rx EMPTY */ diff --git a/sys/arch/sh/dev/scireg.h b/sys/arch/sh/dev/scireg.h new file mode 100644 index 00000000000..bd3d2529c4e --- /dev/null +++ b/sys/arch/sh/dev/scireg.h @@ -0,0 +1,82 @@ +/* $OpenBSD: scireg.h,v 1.1.1.1 2006/10/06 21:02:55 miod Exp $ */ +/* $NetBSD: scireg.h,v 1.8 2003/07/01 11:49:37 uwe Exp $ */ + +/*- + * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Serial Communication Interface (SCI) + */ + +#if !defined(SH4) + +/* SH3 definitions */ + +#define SHREG_SCSMR (*(volatile unsigned char *) 0xFFFFFE80) +#define SHREG_SCBRR (*(volatile unsigned char *) 0xFFFFFE82) +#define SHREG_SCSCR (*(volatile unsigned char *) 0xFFFFFE84) +#define SHREG_SCTDR (*(volatile unsigned char *) 0xFFFFFE86) +#define SHREG_SCSSR (*(volatile unsigned char *) 0xFFFFFE88) +#define SHREG_SCRDR (*(volatile unsigned char *) 0xFFFFFE8A) +#define SHREG_SCSPDR (*(volatile unsigned char *) 0xf4000136) + +#else + +/* SH4 definitions */ + +#define SHREG_SCSMR (*(volatile unsigned char *) 0xffe00000) +#define SHREG_SCBRR (*(volatile unsigned char *) 0xffe00004) +#define SHREG_SCSCR (*(volatile unsigned char *) 0xffe00008) +#define SHREG_SCTDR (*(volatile unsigned char *) 0xffe0000c) +#define SHREG_SCSSR (*(volatile unsigned char *) 0xffe00010) +#define SHREG_SCRDR (*(volatile unsigned char *) 0xffe00014) +#define SHREG_SCSPTR (*(volatile unsigned char *) 0xffe0001c) + +#endif + +#define SCSCR_TIE 0x80 /* Transmit Interrupt Enable */ +#define SCSCR_RIE 0x40 /* Receive Interrupt Enable */ +#define SCSCR_TE 0x20 /* Transmit Enable */ +#define SCSCR_RE 0x10 /* Receive Enable */ +#define SCSCR_MPIE 0x08 /* Multi Processor Interrupt Enable */ +#define SCSCR_TEIE 0x04 /* Transmit End Interrupt Enable */ +#define SCSCR_CKE1 0x02 /* ClocK Enable 1 */ +#define SCSCR_CKE0 0x01 /* ClocK Enable 0 */ + +#define SCSSR_TDRE 0x80 +#define SCSSR_RDRF 0x40 +#define SCSSR_ORER 0x20 +#define SCSSR_FER 0x10 +#define SCSSR_PER 0x08 + +#define SCSPTR_SPB1IO 0x08 +#define SCSPTR_SPB1DT 0x04 +#define SCSPTR_SPB0IO 0x02 +#define SCSPTR_SPB0DT 0x01 + +#if defined(SH3) +#define SCSPDR_SCP0DT 0x01 +#endif diff --git a/sys/arch/sh/dev/shb.c b/sys/arch/sh/dev/shb.c new file mode 100644 index 00000000000..2880a647b0b --- /dev/null +++ b/sys/arch/sh/dev/shb.c @@ -0,0 +1,91 @@ +/* $OpenBSD: shb.c,v 1.1 2006/10/06 21:02:55 miod Exp $ */ +/* $NetBSD: shb.c,v 1.10 2005/12/11 12:18:58 christos Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> + +int shb_match(struct device *, void *, void *); +void shb_attach(struct device *, struct device *, void *); +int shb_print(void *, const char *); +int shb_search(struct device *, void *, void *); + +struct cfattach shb_ca = { + sizeof(struct device), shb_match, shb_attach +}; + +struct cfdriver shb_cd = { + 0, "shb", DV_DULL +}; + +int +shb_match(struct device *parent, void *vcf, void *aux) +{ + extern struct cfdriver shb_cd; + struct mainbus_attach_args *ma = aux; + + if (strcmp(ma->ma_name, shb_cd.cd_name) != 0) + return (0); + + return (1); +} + +void +shb_attach(struct device *parent, struct device *self, void *aux) +{ + printf("\n"); + + config_search(shb_search, self, aux); +} + +int +shb_search(struct device *parent, void *vcf, void *aux) +{ + struct cfdata *cf = vcf; + + if ((*cf->cf_attach->ca_match)(parent, cf, NULL) == 0) + return (0); + config_attach(parent, cf, NULL, shb_print); + return (1); +} + +int +shb_print(void *aux, const char *pnp) +{ + return (UNCONF); +} diff --git a/sys/arch/sh/dev/shpcic.c b/sys/arch/sh/dev/shpcic.c new file mode 100644 index 00000000000..c1357e2d708 --- /dev/null +++ b/sys/arch/sh/dev/shpcic.c @@ -0,0 +1,1182 @@ +/* $OpenBSD: shpcic.c,v 1.1 2006/10/06 21:02:55 miod Exp $ */ +/* $NetBSD: shpcic.c,v 1.10 2005/12/24 20:07:32 perry Exp $ */ + +/* + * Copyright (c) 2005 NONAKA Kimihiro + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/extent.h> +#include <sys/malloc.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <sh/bscreg.h> +#include <sh/cache.h> +#include <sh/trap.h> +#include <sh/dev/pcicreg.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#if defined(SHPCIC_DEBUG) +int shpcic_debug = 0; +#define DPRINTF(arg) if (shpcic_debug) printf arg +#else +#define DPRINTF(arg) +#endif + +#define PCI_MODE1_ENABLE 0x80000000UL + +static const struct shpcic_product { + uint32_t sp_product; + const char *sp_name; +} shpcic_products[] = { + { PCI_PRODUCT_HITACHI_SH7751, "SH7751" }, + { PCI_PRODUCT_HITACHI_SH7751R, "SH7751R" }, + + { 0, NULL }, +}; + +int shpcic_match(struct device *, void *, void *); +void shpcic_attach(struct device *, struct device *, void *); + +struct cfattach shpcic_ca = { + sizeof(struct device), shpcic_match, shpcic_attach +}; + +struct cfdriver shpcic_cd = { + 0, "shpcic", DV_DULL +}; + +/* There can be only one. */ +int shpcic_found = 0; + +/* PCIC intr priotiry */ +static int shpcic_intr_priority[2] = { IPL_BIO, IPL_BIO }; + +static const struct shpcic_product *shpcic_lookup(void); + +static const struct shpcic_product * +shpcic_lookup(void) +{ + const struct shpcic_product *spp; + pcireg_t id; + + id = _reg_read_4(SH4_PCICONF0); + switch (PCI_VENDOR(id)) { + case PCI_VENDOR_HITACHI: + break; + + default: + return (NULL); + } + + for (spp = shpcic_products; spp->sp_name != NULL; spp++) { + if (PCI_PRODUCT(id) == spp->sp_product) { + return (spp); + } + } + return (NULL); +} + +int +shpcic_match(struct device *parent, void *vcf, void *aux) +{ + if (!CPU_IS_SH4) + return (0); + + switch (cpu_product) { + default: + return (0); + + case CPU_PRODUCT_7751: + case CPU_PRODUCT_7751R: + break; + } + + if (shpcic_found) + return (0); + + if (shpcic_lookup() == NULL) + return (0); + + if (_reg_read_2(SH4_BCR2) & BCR2_PORTEN) + return (0); + + return (1); +} + +void +shpcic_attach(struct device *parent, struct device *self, void *aux) +{ + const struct shpcic_product *spp; + struct pcibus_attach_args pba; + + shpcic_found = 1; + + spp = shpcic_lookup(); + if (spp == NULL) { + printf("\n"); + panic("shpcic_attach: impossible"); + } + + if (_reg_read_2(SH4_BCR2) & BCR2_PORTEN) { + printf("\n"); + panic("shpcic_attach: port enabled"); + } + + printf(": HITACHI %s\n", spp->sp_name); + + /* allow PCIC request */ + _reg_write_4(SH4_BCR1, _reg_read_4(SH4_BCR1) | BCR1_BREQEN); + + /* Initialize PCIC */ + _reg_write_4(SH4_PCICR, PCICR_BASE | PCICR_RSTCTL); + delay(10 * 1000); + _reg_write_4(SH4_PCICR, PCICR_BASE); + + /* Class: Host-Bridge */ + _reg_write_4(SH4_PCICONF2, + (PCI_CLASS_BRIDGE << PCI_CLASS_SHIFT) | + (PCI_SUBCLASS_BRIDGE_HOST << PCI_SUBCLASS_SHIFT)); + +#if !defined(DONT_INIT_PCIBSC) +#if defined(PCIBCR_BCR1_VAL) + _reg_write_4(SH4_PCIBCR1, PCIBCR_BCR1_VAL); +#else + _reg_write_4(SH4_PCIBCR1, _reg_read_4(SH4_BCR1) | BCR1_MASTER); +#endif +#if defined(PCIBCR_BCR2_VAL) + _reg_write_4(SH4_PCIBCR2, PCIBCR_BCR2_VAL); +#else + _reg_write_4(SH4_PCIBCR2, _reg_read_2(SH4_BCR2)); +#endif +#if defined(SH4) && defined(SH7751R) + if (cpu_product == CPU_PRODUCT_7751R) { +#if defined(PCIBCR_BCR3_VAL) + _reg_write_4(SH4_PCIBCR3, PCIBCR_BCR3_VAL); +#else + _reg_write_4(SH4_PCIBCR3, _reg_read_2(SH4_BCR3)); +#endif + } +#endif /* SH4 && SH7751R && PCIBCR_BCR3_VAL */ +#if defined(PCIBCR_WCR1_VAL) + _reg_write_4(SH4_PCIWCR1, PCIBCR_WCR1_VAL); +#else + _reg_write_4(SH4_PCIWCR1, _reg_read_4(SH4_WCR1)); +#endif +#if defined(PCIBCR_WCR2_VAL) + _reg_write_4(SH4_PCIWCR2, PCIBCR_WCR2_VAL); +#else + _reg_write_4(SH4_PCIWCR2, _reg_read_4(SH4_WCR2)); +#endif +#if defined(PCIBCR_WCR3_VAL) + _reg_write_4(SH4_PCIWCR3, PCIBCR_WCR3_VAL); +#else + _reg_write_4(SH4_PCIWCR3, _reg_read_4(SH4_WCR3)); +#endif +#if defined(PCIBCR_MCR_VAL) + _reg_write_4(SH4_PCIMCR, PCIBCR_MCR_VAL); +#else + _reg_write_4(SH4_PCIMCR, _reg_read_4(SH4_MCR)); +#endif +#endif /* !DONT_INIT_PCIBSC */ + + /* set PCI I/O, memory base address */ + _reg_write_4(SH4_PCIIOBR, SH4_PCIC_IO); + _reg_write_4(SH4_PCIMBR, SH4_PCIC_MEM); + + /* set PCI local address 0 */ + _reg_write_4(SH4_PCILSR0, (64 - 1) << 20); + _reg_write_4(SH4_PCILAR0, 0xac000000); + _reg_write_4(SH4_PCICONF5, 0xac000000); + + /* set PCI local address 1 */ + _reg_write_4(SH4_PCILSR1, (64 - 1) << 20); + _reg_write_4(SH4_PCILAR1, 0xac000000); + _reg_write_4(SH4_PCICONF6, 0x8c000000); + + /* Enable I/O, memory, bus-master */ + _reg_write_4(SH4_PCICONF1, PCI_COMMAND_IO_ENABLE + | PCI_COMMAND_MEM_ENABLE + | PCI_COMMAND_MASTER_ENABLE + | PCI_COMMAND_STEPPING_ENABLE + | PCI_STATUS_DEVSEL_MEDIUM); + + /* Initialize done. */ + _reg_write_4(SH4_PCICR, PCICR_BASE | PCICR_CFINIT); + + /* set PCI controller interrupt priority */ + intpri_intr_priority(SH4_INTEVT_PCIERR, shpcic_intr_priority[0]); + intpri_intr_priority(SH4_INTEVT_PCISERR, shpcic_intr_priority[1]); + + /* PCI bus */ + memset(&pba, 0, sizeof(pba)); + pba.pba_iot = shpcic_get_bus_io_tag(); + pba.pba_memt = shpcic_get_bus_mem_tag(); + pba.pba_dmat = shpcic_get_bus_dma_tag(); + pba.pba_pc = NULL; + pba.pba_bus = 0; + pba.pba_bridgetag = NULL; + config_found(self, &pba, NULL); +} + +int +shpcic_bus_maxdevs(void *v, int busno) +{ + /* + * Bus number is irrelevant. Configuration Mechanism 1 is in + * use, can have devices 0-32 (i.e. the `normal' range). + */ + return (32); +} + +pcitag_t +shpcic_make_tag(void *v, int bus, int device, int function) +{ + pcitag_t tag; + + if (bus >= 256 || device >= 32 || function >= 8) + panic("pci_make_tag: bad request"); + + tag = PCI_MODE1_ENABLE | + (bus << 16) | (device << 11) | (function << 8); + + return (tag); +} + +void +shpcic_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) +{ + if (bp != NULL) + *bp = (tag >> 16) & 0xff; + if (dp != NULL) + *dp = (tag >> 11) & 0x1f; + if (fp != NULL) + *fp = (tag >> 8) & 0x7; +} + +pcireg_t +shpcic_conf_read(void *v, pcitag_t tag, int reg) +{ + pcireg_t data; + int s; + + s = splhigh(); + _reg_write_4(SH4_PCIPAR, tag | reg); + data = _reg_read_4(SH4_PCIPDR); + _reg_write_4(SH4_PCIPAR, 0); + splx(s); + + return data; +} + +void +shpcic_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) +{ + int s; + + s = splhigh(); + _reg_write_4(SH4_PCIPAR, tag | reg); + _reg_write_4(SH4_PCIPDR, data); + _reg_write_4(SH4_PCIPAR, 0); + splx(s); +} + +int +shpcic_set_intr_priority(int intr, int level) +{ + int evtcode; + + if ((intr != 0) && (intr != 1)) { + return (-1); + } + if ((level < IPL_NONE) || (level > IPL_HIGH)) { + return (-1); + } + + if (intr == 0) { + evtcode = SH4_INTEVT_PCIERR; + } else { + evtcode = SH4_INTEVT_PCISERR; + } + + intpri_intr_priority(evtcode, shpcic_intr_priority[intr]); + shpcic_intr_priority[intr] = level; + + return (0); +} + +void * +shpcic_intr_establish(int evtcode, int (*ih_func)(void *), void *ih_arg, + const char *ih_name) +{ + int level; + + switch (evtcode) { + case SH4_INTEVT_PCISERR: + level = shpcic_intr_priority[1]; + break; + + case SH4_INTEVT_PCIDMA3: + case SH4_INTEVT_PCIDMA2: + case SH4_INTEVT_PCIDMA1: + case SH4_INTEVT_PCIDMA0: + case SH4_INTEVT_PCIPWON: + case SH4_INTEVT_PCIPWDWN: + case SH4_INTEVT_PCIERR: + level = shpcic_intr_priority[0]; + break; + + default: + printf("shpcic_intr_establish: unknown evtcode = 0x%08x\n", + evtcode); + return NULL; + } + + return intc_intr_establish(evtcode, IST_LEVEL, level, ih_func, ih_arg, + ih_name); +} + +void +shpcic_intr_disestablish(void *ih) +{ + intc_intr_disestablish(ih); +} + +/* + * shpcic bus space + */ +int +shpcic_iomem_map(void *v, bus_addr_t bpa, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + *bshp = (bus_space_handle_t)bpa; + + return (0); +} + +void +shpcic_iomem_unmap(void *v, bus_space_handle_t bsh, bus_size_t size) +{ + /* Nothing to do */ +} + +int +shpcic_iomem_subregion(void *v, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + *nbshp = bsh + offset; + + return (0); +} + +int +shpcic_iomem_alloc(void *v, bus_addr_t rstart, bus_addr_t rend, + bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, + bus_addr_t *bpap, bus_space_handle_t *bshp) +{ + *bshp = *bpap = rstart; + + return (0); +} + +void +shpcic_iomem_free(void *v, bus_space_handle_t bsh, bus_size_t size) +{ + /* Nothing to do */ +} + +/* + * shpcic bus space io/mem read/write + */ +/* read */ +static inline uint8_t __shpcic_io_read_1(bus_space_handle_t bsh, + bus_size_t offset); +static inline uint16_t __shpcic_io_read_2(bus_space_handle_t bsh, + bus_size_t offset); +static inline uint32_t __shpcic_io_read_4(bus_space_handle_t bsh, + bus_size_t offset); +static inline uint8_t __shpcic_mem_read_1(bus_space_handle_t bsh, + bus_size_t offset); +static inline uint16_t __shpcic_mem_read_2(bus_space_handle_t bsh, + bus_size_t offset); +static inline uint32_t __shpcic_mem_read_4(bus_space_handle_t bsh, + bus_size_t offset); + +static inline uint8_t +__shpcic_io_read_1(bus_space_handle_t bsh, bus_size_t offset) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_IO_MASK; + + return *(volatile uint8_t *)(SH4_PCIC_IO + adr); +} + +static inline uint16_t +__shpcic_io_read_2(bus_space_handle_t bsh, bus_size_t offset) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_IO_MASK; + + return *(volatile uint16_t *)(SH4_PCIC_IO + adr); +} + +static inline uint32_t +__shpcic_io_read_4(bus_space_handle_t bsh, bus_size_t offset) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_IO_MASK; + + return *(volatile uint32_t *)(SH4_PCIC_IO + adr); +} + +static inline uint8_t +__shpcic_mem_read_1(bus_space_handle_t bsh, bus_size_t offset) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_MEM_MASK; + + return *(volatile uint8_t *)(SH4_PCIC_MEM + adr); +} + +static inline uint16_t +__shpcic_mem_read_2(bus_space_handle_t bsh, bus_size_t offset) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_MEM_MASK; + + return *(volatile uint16_t *)(SH4_PCIC_MEM + adr); +} + +static inline uint32_t +__shpcic_mem_read_4(bus_space_handle_t bsh, bus_size_t offset) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_MEM_MASK; + + return *(volatile uint32_t *)(SH4_PCIC_MEM + adr); +} + +/* + * read single + */ +uint8_t +shpcic_io_read_1(void *v, bus_space_handle_t bsh, bus_size_t offset) +{ + uint8_t value; + + value = __shpcic_io_read_1(bsh, offset); + + return value; +} + +uint16_t +shpcic_io_read_2(void *v, bus_space_handle_t bsh, bus_size_t offset) +{ + uint16_t value; + + value = __shpcic_io_read_2(bsh, offset); + + return value; +} + +uint32_t +shpcic_io_read_4(void *v, bus_space_handle_t bsh, bus_size_t offset) +{ + uint32_t value; + + value = __shpcic_io_read_4(bsh, offset); + + return value; +} + +uint8_t +shpcic_mem_read_1(void *v, bus_space_handle_t bsh, bus_size_t offset) +{ + uint8_t value; + + value = __shpcic_mem_read_1(bsh, offset); + + return value; +} + +uint16_t +shpcic_mem_read_2(void *v, bus_space_handle_t bsh, bus_size_t offset) +{ + uint16_t value; + + value = __shpcic_mem_read_2(bsh, offset); + + return value; +} + +uint32_t +shpcic_mem_read_4(void *v, bus_space_handle_t bsh, bus_size_t offset) +{ + uint32_t value; + + value = __shpcic_mem_read_4(bsh, offset); + + return value; +} + +/* + * read multi + */ +void +shpcic_io_read_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_io_read_1(bsh, offset); + } +} + +void +shpcic_io_read_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_io_read_2(bsh, offset); + } +} + +void +shpcic_io_read_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_io_read_4(bsh, offset); + } +} + +void +shpcic_mem_read_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_mem_read_1(bsh, offset); + } +} + +void +shpcic_mem_read_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_mem_read_2(bsh, offset); + } +} + +void +shpcic_mem_read_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_mem_read_4(bsh, offset); + } +} + +/* + * + * read region + */ +void +shpcic_io_read_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_io_read_1(bsh, offset); + offset += 1; + } +} + +void +shpcic_io_read_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_io_read_2(bsh, offset); + offset += 2; + } +} + +void +shpcic_io_read_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_io_read_4(bsh, offset); + offset += 4; + } +} + +void +shpcic_mem_read_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_mem_read_1(bsh, offset); + offset += 1; + } +} + +void +shpcic_mem_read_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_mem_read_2(bsh, offset); + offset += 2; + } +} + +void +shpcic_mem_read_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count) +{ + while (count--) { + *addr++ = __shpcic_mem_read_4(bsh, offset); + offset += 4; + } +} + +/* write */ +static inline void __shpcic_io_write_1(bus_space_handle_t bsh, + bus_size_t offset, uint8_t value); +static inline void __shpcic_io_write_2(bus_space_handle_t bsh, + bus_size_t offset, uint16_t value); +static inline void __shpcic_io_write_4(bus_space_handle_t bsh, + bus_size_t offset, uint32_t value); +static inline void __shpcic_mem_write_1(bus_space_handle_t bsh, + bus_size_t offset, uint8_t value); +static inline void __shpcic_mem_write_2(bus_space_handle_t bsh, + bus_size_t offset, uint16_t value); +static inline void __shpcic_mem_write_4(bus_space_handle_t bsh, + bus_size_t offset, uint32_t value); + +static inline void +__shpcic_io_write_1(bus_space_handle_t bsh, bus_size_t offset, + uint8_t value) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_IO_MASK; + + *(volatile uint8_t *)(SH4_PCIC_IO + adr) = value; +} + +static inline void +__shpcic_io_write_2(bus_space_handle_t bsh, bus_size_t offset, + uint16_t value) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_IO_MASK; + + *(volatile uint16_t *)(SH4_PCIC_IO + adr) = value; +} + +static inline void +__shpcic_io_write_4(bus_space_handle_t bsh, bus_size_t offset, + uint32_t value) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_IO_MASK; + + *(volatile uint32_t *)(SH4_PCIC_IO + adr) = value; +} + +static inline void +__shpcic_mem_write_1(bus_space_handle_t bsh, bus_size_t offset, + uint8_t value) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_MEM_MASK; + + *(volatile uint8_t *)(SH4_PCIC_MEM + adr) = value; +} + +static inline void +__shpcic_mem_write_2(bus_space_handle_t bsh, bus_size_t offset, + uint16_t value) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_MEM_MASK; + + *(volatile uint16_t *)(SH4_PCIC_MEM + adr) = value; +} + +static inline void +__shpcic_mem_write_4(bus_space_handle_t bsh, bus_size_t offset, + uint32_t value) +{ + u_long adr = (u_long)(bsh + offset) & SH4_PCIC_MEM_MASK; + + *(volatile uint32_t *)(SH4_PCIC_MEM + adr) = value; +} + +/* + * write single + */ +void +shpcic_io_write_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t value) +{ + __shpcic_io_write_1(bsh, offset, value); +} + +void +shpcic_io_write_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t value) +{ + __shpcic_io_write_2(bsh, offset, value); +} + +void +shpcic_io_write_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t value) +{ + __shpcic_io_write_4(bsh, offset, value); +} + +void +shpcic_mem_write_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t value) +{ + __shpcic_mem_write_1(bsh, offset, value); +} + +void +shpcic_mem_write_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t value) +{ + __shpcic_mem_write_2(bsh, offset, value); +} + +void +shpcic_mem_write_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t value) +{ + __shpcic_mem_write_4(bsh, offset, value); +} + +/* + * write multi + */ +void +shpcic_io_write_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_1(bsh, offset, *addr++); + } +} + +void +shpcic_io_write_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_2(bsh, offset, *addr++); + } +} + +void +shpcic_io_write_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_4(bsh, offset, *addr++); + } +} + +void +shpcic_mem_write_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_1(bsh, offset, *addr++); + } +} + +void +shpcic_mem_write_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_2(bsh, offset, *addr++); + } +} + +void +shpcic_mem_write_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_4(bsh, offset, *addr++); + } +} + +/* + * write region + */ +void +shpcic_io_write_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_1(bsh, offset, *addr++); + offset += 1; + } +} + +void +shpcic_io_write_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_2(bsh, offset, *addr++); + offset += 2; + } +} + +void +shpcic_io_write_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_4(bsh, offset, *addr++); + offset += 4; + } +} + +void +shpcic_mem_write_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_1(bsh, offset, *addr++); + offset += 1; + } +} + +void +shpcic_mem_write_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_2(bsh, offset, *addr++); + offset += 2; + } +} + +void +shpcic_mem_write_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_4(bsh, offset, *addr++); + offset += 4; + } +} + +/* + * set multi + */ +void +shpcic_io_set_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t value, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_1(bsh, offset, value); + } +} + +void +shpcic_io_set_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t value, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_2(bsh, offset, value); + } +} + +void +shpcic_io_set_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t value, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_4(bsh, offset, value); + } +} + +void +shpcic_mem_set_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t value, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_1(bsh, offset, value); + } +} + +void +shpcic_mem_set_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t value, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_2(bsh, offset, value); + } +} + +void +shpcic_mem_set_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t value, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_4(bsh, offset, value); + } +} + +/* + * set region + */ +void +shpcic_io_set_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t value, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_1(bsh, offset, value); + offset += 1; + } +} + +void +shpcic_io_set_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t value, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_2(bsh, offset, value); + offset += 2; + } +} + +void +shpcic_io_set_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t value, bus_size_t count) +{ + while (count--) { + __shpcic_io_write_4(bsh, offset, value); + offset += 4; + } +} + +void +shpcic_mem_set_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t value, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_1(bsh, offset, value); + offset += 1; + } +} + +void +shpcic_mem_set_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t value, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_2(bsh, offset, value); + offset += 2; + } +} + +void +shpcic_mem_set_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t value, bus_size_t count) +{ + while (count--) { + __shpcic_mem_write_4(bsh, offset, value); + offset += 4; + } +} + +/* + * copy region + */ +void +shpcic_io_copy_region_1(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, bus_size_t count) +{ + u_long addr1 = bsh1 + off1; + u_long addr2 = bsh2 + off2; + uint8_t value; + + if (addr1 >= addr2) { /* src after dest: copy forward */ + while (count--) { + value = __shpcic_io_read_1(bsh1, off1); + __shpcic_io_write_1(bsh2, off2, value); + off1 += 1; + off2 += 1; + } + } else { /* dest after src: copy backwards */ + off1 += (count - 1) * 1; + off2 += (count - 1) * 1; + while (count--) { + value = __shpcic_io_read_1(bsh1, off1); + __shpcic_io_write_1(bsh2, off2, value); + off1 -= 1; + off2 -= 1; + } + } +} + +void +shpcic_io_copy_region_2(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, bus_size_t count) +{ + u_long addr1 = bsh1 + off1; + u_long addr2 = bsh2 + off2; + uint16_t value; + + if (addr1 >= addr2) { /* src after dest: copy forward */ + while (count--) { + value = __shpcic_io_read_2(bsh1, off1); + __shpcic_io_write_2(bsh2, off2, value); + off1 += 2; + off2 += 2; + } + } else { /* dest after src: copy backwards */ + off1 += (count - 1) * 2; + off2 += (count - 1) * 2; + while (count--) { + value = __shpcic_io_read_2(bsh1, off1); + __shpcic_io_write_2(bsh2, off2, value); + off1 -= 2; + off2 -= 2; + } + } +} + +void +shpcic_io_copy_region_4(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, bus_size_t count) +{ + u_long addr1 = bsh1 + off1; + u_long addr2 = bsh2 + off2; + uint32_t value; + + if (addr1 >= addr2) { /* src after dest: copy forward */ + while (count--) { + value = __shpcic_io_read_4(bsh1, off1); + __shpcic_io_write_4(bsh2, off2, value); + off1 += 4; + off2 += 4; + } + } else { /* dest after src: copy backwards */ + off1 += (count - 1) * 4; + off2 += (count - 1) * 4; + while (count--) { + value = __shpcic_io_read_4(bsh1, off1); + __shpcic_io_write_4(bsh2, off2, value); + off1 -= 4; + off2 -= 4; + } + } +} + +void +shpcic_mem_copy_region_1(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, bus_size_t count) +{ + u_long addr1 = bsh1 + off1; + u_long addr2 = bsh2 + off2; + uint8_t value; + + if (addr1 >= addr2) { /* src after dest: copy forward */ + while (count--) { + value = __shpcic_mem_read_1(bsh1, off1); + __shpcic_mem_write_1(bsh2, off2, value); + off1 += 1; + off2 += 1; + } + } else { /* dest after src: copy backwards */ + off1 += (count - 1) * 1; + off2 += (count - 1) * 1; + while (count--) { + value = __shpcic_mem_read_1(bsh1, off1); + __shpcic_mem_write_1(bsh2, off2, value); + off1 -= 1; + off2 -= 1; + } + } +} + +void +shpcic_mem_copy_region_2(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, bus_size_t count) +{ + u_long addr1 = bsh1 + off1; + u_long addr2 = bsh2 + off2; + uint16_t value; + + if (addr1 >= addr2) { /* src after dest: copy forward */ + while (count--) { + value = __shpcic_mem_read_2(bsh1, off1); + __shpcic_mem_write_2(bsh2, off2, value); + off1 += 2; + off2 += 2; + } + } else { /* dest after src: copy backwards */ + off1 += (count - 1) * 2; + off2 += (count - 1) * 2; + while (count--) { + value = __shpcic_mem_read_2(bsh1, off1); + __shpcic_mem_write_2(bsh2, off2, value); + off1 -= 2; + off2 -= 2; + } + } +} + +void +shpcic_mem_copy_region_4(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, bus_size_t count) +{ + u_long addr1 = bsh1 + off1; + u_long addr2 = bsh2 + off2; + uint32_t value; + + if (addr1 >= addr2) { /* src after dest: copy forward */ + while (count--) { + value = __shpcic_mem_read_4(bsh1, off1); + __shpcic_mem_write_4(bsh2, off2, value); + off1 += 4; + off2 += 4; + } + } else { /* dest after src: copy backwards */ + off1 += (count - 1) * 4; + off2 += (count - 1) * 4; + while (count--) { + value = __shpcic_mem_read_4(bsh1, off1); + __shpcic_mem_write_4(bsh2, off2, value); + off1 -= 4; + off2 -= 4; + } + } +} diff --git a/sys/arch/sh/dev/shpcicvar.h b/sys/arch/sh/dev/shpcicvar.h new file mode 100644 index 00000000000..f000fec3084 --- /dev/null +++ b/sys/arch/sh/dev/shpcicvar.h @@ -0,0 +1,184 @@ +/* $OpenBSD: shpcicvar.h,v 1.1 2006/10/06 21:02:55 miod Exp $ */ +/* $NetBSD: shpcicvar.h,v 1.6 2005/12/11 12:18:58 christos Exp $ */ + +/*- + * Copyright (c) 2005 NONAKA Kimihiro + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <machine/bus.h> + +bus_space_tag_t shpcic_get_bus_io_tag(void); +bus_space_tag_t shpcic_get_bus_mem_tag(void); +bus_dma_tag_t shpcic_get_bus_dma_tag(void); + +int shpcic_bus_maxdevs(void *v, int busno); +pcitag_t shpcic_make_tag(void *v, int bus, int device, int function); +void shpcic_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp); +pcireg_t shpcic_conf_read(void *v, pcitag_t tag, int reg); +void shpcic_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data); + +int shpcic_set_intr_priority(int intr, int level); +void *shpcic_intr_establish(int evtcode, int (*ih_func)(void *), void *ih_arg, + const char *ih_name); +void shpcic_intr_disestablish(void *ih); + +/* + * shpcic io/mem bus space + */ +int shpcic_iomem_map(void *v, bus_addr_t bpa, bus_size_t size, int flags, + bus_space_handle_t *bshp); +void shpcic_iomem_unmap(void *v, bus_space_handle_t bsh, bus_size_t size); +int shpcic_iomem_subregion(void *v, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t size, bus_space_handle_t *nbshp); +int shpcic_iomem_alloc(void *v, bus_addr_t rstart, bus_addr_t rend, + bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, + bus_addr_t *bpap, bus_space_handle_t *bshp); +void shpcic_iomem_free(void *v, bus_space_handle_t bsh, bus_size_t size); + +/* read single */ +uint8_t shpcic_io_read_1(void *v, bus_space_handle_t bsh, bus_size_t offset); +uint16_t shpcic_io_read_2(void *v, bus_space_handle_t bsh, bus_size_t offset); +uint32_t shpcic_io_read_4(void *v, bus_space_handle_t bsh, bus_size_t offset); +uint8_t shpcic_mem_read_1(void *v, bus_space_handle_t bsh, bus_size_t offset); +uint16_t shpcic_mem_read_2(void *v, bus_space_handle_t bsh, bus_size_t offset); +uint32_t shpcic_mem_read_4(void *v, bus_space_handle_t bsh, bus_size_t offset); + +/* read multi */ +void shpcic_io_read_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count); +void shpcic_io_read_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count); +void shpcic_io_read_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count); +void shpcic_mem_read_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count); +void shpcic_mem_read_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count); +void shpcic_mem_read_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count); + +/* read region */ +void shpcic_io_read_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count); +void shpcic_io_read_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count); +void shpcic_io_read_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count); +void shpcic_mem_read_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t *addr, bus_size_t count); +void shpcic_mem_read_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t *addr, bus_size_t count); +void shpcic_mem_read_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t *addr, bus_size_t count); + +/* write single */ +void shpcic_io_write_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t data); +void shpcic_io_write_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t data); +void shpcic_io_write_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t data); +void shpcic_mem_write_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t data); +void shpcic_mem_write_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t data); +void shpcic_mem_write_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t data); + +/* write multi */ +void shpcic_io_write_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count); +void shpcic_io_write_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count); +void shpcic_io_write_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count); +void shpcic_mem_write_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count); +void shpcic_mem_write_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count); +void shpcic_mem_write_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count); + +/* write region */ +void shpcic_io_write_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count); +void shpcic_io_write_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count); +void shpcic_io_write_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count); +void shpcic_mem_write_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint8_t *addr, bus_size_t count); +void shpcic_mem_write_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint16_t *addr, bus_size_t count); +void shpcic_mem_write_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, const uint32_t *addr, bus_size_t count); + +/* set multi */ +void shpcic_io_set_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t val, bus_size_t count); +void shpcic_io_set_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t val, bus_size_t count); +void shpcic_io_set_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t val, bus_size_t count); +void shpcic_mem_set_multi_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t val, bus_size_t count); +void shpcic_mem_set_multi_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t val, bus_size_t count); +void shpcic_mem_set_multi_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t val, bus_size_t count); + +/* set region */ +void shpcic_io_set_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t val, bus_size_t count); +void shpcic_io_set_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t val, bus_size_t count); +void shpcic_io_set_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t val, bus_size_t count); +void shpcic_mem_set_region_1(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint8_t val, bus_size_t count); +void shpcic_mem_set_region_2(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint16_t val, bus_size_t count); +void shpcic_mem_set_region_4(void *v, bus_space_handle_t bsh, + bus_size_t offset, uint32_t val, bus_size_t count); + +/* copy region */ +void shpcic_io_copy_region_1(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, + bus_size_t count); +void shpcic_io_copy_region_2(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, + bus_size_t count); +void shpcic_io_copy_region_4(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, + bus_size_t count); +void shpcic_mem_copy_region_1(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, + bus_size_t count); +void shpcic_mem_copy_region_2(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, + bus_size_t count); +void shpcic_mem_copy_region_4(void *v, bus_space_handle_t bsh1, + bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, + bus_size_t count); |