diff --git a/sys/conf/files b/sys/conf/files index 7b3aa97..eba0d56 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1552,6 +1552,7 @@ dev/uart/uart_dev_sab82532.c optional uart uart_sab82532 dev/uart/uart_dev_sab82532.c optional uart scc dev/uart/uart_dev_z8530.c optional uart uart_z8530 dev/uart/uart_dev_z8530.c optional uart scc +dev/uart/uart_dev_psc.c optional uart psc dev/uart/uart_if.m optional uart dev/uart/uart_subr.c optional uart dev/uart/uart_tty.c optional uart diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index bfaf984..17a5aaf 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -51,7 +51,7 @@ dev/syscons/scvtb.c optional sc dev/syscons/teken/teken.c optional sc dev/tsec/if_tsec.c optional tsec dev/tsec/if_tsec_ocp.c optional tsec mpc85xx -dev/uart/uart_bus_ocp.c optional uart mpc85xx +dev/uart/uart_bus_ocp.c optional uart mpc85xx | mpc5xxx dev/uart/uart_cpu_powerpc.c optional uart kern/syscalls.c optional ktr libkern/ashldi3.c standard @@ -109,8 +109,10 @@ powerpc/fpu/fpu_implode.c optional fpu_emu powerpc/fpu/fpu_mul.c optional fpu_emu powerpc/fpu/fpu_sqrt.c optional fpu_emu powerpc/fpu/fpu_subr.c optional fpu_emu +powerpc/mpc5xxx/ic.c optional mpc5xxx +powerpc/mpc5xxx/ocpbus.c optional mpc5xxx powerpc/mpc85xx/atpic.c optional mpc85xx isa -powerpc/mpc85xx/ds1553_bus_lbc.c optional ds1553 +powerpc/mpc85xx/ds1553_bus_lbc.c optional ds1553 mpc85xx powerpc/mpc85xx/ds1553_core.c optional ds1553 powerpc/mpc85xx/i2c.c optional iicbus mpc85xx powerpc/mpc85xx/isa.c optional mpc85xx isa diff --git a/sys/conf/options.powerpc b/sys/conf/options.powerpc index 5c0dfff..e38998c 100644 --- a/sys/conf/options.powerpc +++ b/sys/conf/options.powerpc @@ -2,6 +2,7 @@ # Options specific to the powerpc platform kernels AIM opt_global.h +E300 opt_global.h E500 opt_global.h FPU_EMU @@ -10,8 +11,10 @@ GFB_DEBUG opt_gfb.h GFB_NO_FONT_LOADING opt_gfb.h GFB_NO_MODE_CHANGE opt_gfb.h -POWERMAC opt_platform.h +EFIKA opt_platform.h +MPC5XXX opt_platform.h MPC85XX opt_platform.h +POWERMAC opt_platform.h PSIM SC_OFWFB opt_ofwfb.h diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 05f47c3..52be3a7 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -217,6 +217,17 @@ #define PCIR_PCCARDIF_2 0x44 + +/* PCIE registers */ +#define PCIR_DCR 0x54 +#define PCIM_DCR_URR 0x0008 +#define PCIM_DCR_FER 0x0004 +#define PCIM_DCR_NFER 0x0002 +#define PCIR_DSR 0x56 +#define PCIR_LTSSM 0x404 +#define PCIM_LTSSM_L0 0x16 + + /* PCI device class, subclass and programming interface definitions */ #define PCIC_OLD 0x00 diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h index bedb9ba..f68b634 100644 --- a/sys/dev/uart/uart.h +++ b/sys/dev/uart/uart.h @@ -68,6 +68,7 @@ extern struct uart_class uart_ns8250_class __attribute__((weak)); extern struct uart_class uart_quicc_class __attribute__((weak)); extern struct uart_class uart_sab82532_class __attribute__((weak)); extern struct uart_class uart_z8530_class __attribute__((weak)); +extern struct uart_class uart_psc_class __attribute__((weak)); #ifdef PC98 struct uart_class *uart_pc98_getdev(u_long port); diff --git a/sys/dev/uart/uart_bus_ocp.c b/sys/dev/uart/uart_bus_ocp.c index 51c51ac..4dc2d47 100644 --- a/sys/dev/uart/uart_bus_ocp.c +++ b/sys/dev/uart/uart_bus_ocp.c @@ -45,6 +45,8 @@ __FBSDID("$FreeBSD: src/sys/dev/uart/uart_bus_ocp.c,v 1.1 2008/03/03 17:16:59 ra #include #include +#include + static int uart_ocp_probe(device_t); static device_method_t uart_ocp_methods[] = { @@ -78,7 +80,11 @@ uart_ocp_probe(device_t dev) return (ENXIO); sc = device_get_softc(dev); +#ifdef MPC5XXX + sc->sc_class = &uart_psc_class; +#else sc->sc_class = &uart_ns8250_class; +#endif if (BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_CLOCK, &clock)) clock = 0; diff --git a/sys/dev/uart/uart_cpu_powerpc.c b/sys/dev/uart/uart_cpu_powerpc.c index 4191196..4aaf03d 100644 --- a/sys/dev/uart/uart_cpu_powerpc.c +++ b/sys/dev/uart/uart_cpu_powerpc.c @@ -44,7 +44,7 @@ __FBSDID("$FreeBSD: src/sys/dev/uart/uart_cpu_powerpc.c,v 1.7 2009/04/08 22:19:3 #include #include -#ifdef MPC85XX +#if (defined MPC85XX) || (defined MPC5XXX) bus_space_tag_t uart_bus_space_io = &bs_be_tag; bus_space_tag_t uart_bus_space_mem = &bs_be_tag; #else @@ -86,10 +86,6 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) phandle_t input, opts; int error; - class = &uart_z8530_class; - if (class == NULL) - return (ENXIO); - if ((opts = OF_finddevice("/options")) == -1) return (ENXIO); switch (devtype) { @@ -126,13 +122,21 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) class = &uart_z8530_class; di->bas.regshft = 4; di->bas.chan = 1; - } else if (strcmp(buf,"serial") == 0) { - class = &uart_ns8250_class; + } else if (strcmp(buf, "serial") == 0) { + OF_getprop(input, "model", buf, sizeof(buf)); + if (strcmp(buf, "mpc5200-serial") == 0) + class = &uart_psc_class; + else + class = &uart_ns8250_class; di->bas.regshft = 0; di->bas.chan = 0; } else return (ENXIO); + if (class == NULL) + return (ENXIO); + + di->bas.bst = uart_bus_space_mem; error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh); if (error) return (error); diff --git a/sys/dev/uart/uart_dev_psc.c b/sys/dev/uart/uart_dev_psc.c new file mode 100644 index 0000000..a7f63fa --- /dev/null +++ b/sys/dev/uart/uart_dev_psc.c @@ -0,0 +1,555 @@ +/*- + * Copyright (c) 2008-2009 Semihalf, Michal Mazur + * 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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "uart_if.h" + +#define IPB_CLOCK 132000000 + +#define PSC_REG_MR 0x00 /* 1B R/W */ +#define PSC_REG_CSR 0x04 /* 2B W */ +#define PSC_REG_SR 0x04 /* 2B R */ +#define PSC_REG_CR 0x08 /* 1B R/W */ +#define PSC_REG_DATA 0x0C +#define PSC_REG_TxBUF PSC_REG_DATA /* 4B W */ +#define PSC_REG_RxBUF PSC_REG_DATA /* 4B R */ +#define PSC_REG_IPCR 0x10 /* 1B R */ +#define PSC_REG_ACR 0x10 /* 1B W */ +#define PSC_REG_ISR 0x14 /* 2B R */ +#define PSC_REG_IMR 0x14 /* 2B W */ +#define PSC_REG_CTUR 0x18 /* 1B W */ +#define PSC_REG_CTLR 0x1C /* 1B W */ +#define PSC_REG_SICR 0x40 /* 4B R/W */ +#define PSC_REG_RFCNTL 0x68 /* 1B R/W */ +#define PSC_REG_RFALARM 0x6E /* 2B R/W */ +#define PSC_REG_TFCNTL 0x88 /* 1B R/W */ +#define PSC_REG_TFALARM 0x8E /* 2B R/W */ +#define PSC_REG_RFNUM 0x58 /* 2B R */ +#define PSC_REG_RFDATA 0x60 /* 4B R/W */ +#define PSC_REG_TFNUM 0x5C /* 2B R */ +#define PSC_REG_TFDATA 0x80 /* 4B R/W */ +#define PSC_REG_OP1 0x38 /* 1B W */ +#define PSC_REG_OP0 0x3C /* 1B W */ + +#define PSC_CR_RSTMRP 0x10 +#define PSC_CR_DISABLE 0x0A +#define PSC_CSR_RCLK32 0x0000 +#define PSC_CSR_RCLK4 0xFF00 +#define PSC_SICR_NODCD 0x00000000 +#define PSC_SICR_DCD 0x08000000 +#define PSC_IMR_ALLINT 0x9FCF +#define PSC_IMR_NOINT 0x0000 +#define PSC_IMR_RxRDY 0x0200 +#define PSC_IMR_ORERR 0x1000 +#define PSC_IMR_DB 0x0400 +#define PSC_IMR_TxRDY 0x0100 +#define PSC_IMR_TxEMP 0x0800 +#define PSC_IMR_IPC 0x8000 +#define PSC_IMR_ERROR 0x0040 +#define PSC_CR_ENABLE 0x05 +#define PSC_MR1_RxRTS 0x80 +#define PSC_MR1_FFULL 0x40 +#define PSC_MR1_NOPARITY 0x10 +#define PSC_MR1_PAREVEN 0x00 +#define PSC_MR1_PARODD 0x04 +#define PSC_MR1_5BITS 0x00 +#define PSC_MR1_6BITS 0x01 +#define PSC_MR1_7BITS 0x02 +#define PSC_MR1_8BITS 0x03 +#define PSC_MR2_AUTOECHO 0x40 +#define PSC_MR2_REMOTELB 0xC0 +#define PSC_MR2_LOCALLB 0x80 +#define PSC_MR2_TxRTS 0x20 +#define PSC_MR2_TxCTS 0x10 +#define PSC_MR2_SB1 0x07 +#define PSC_MR2_SB2 0x0F +#define PSC_MR2_5x1 0x00 +#define PSC_MR2_5x15 0x07 +#define PSC_SR_RxRDY 0x0100 +#define PSC_SR_TxRDY 0x0400 +#define PSC_SR_FFULL 0x0200 +#define PSC_SR_TxEMP 0x0800 +#define PSC_SR_ERROR 0x0040 +#define PSC_ISR_ERROR 0x0040 +#define PSC_ISR_ORERR 0x1000 +#define PSC_ISR_TxEMP 0x0800 +#define PSC_ISR_DB 0x0400 +#define PSC_ISR_RxRDY 0x0200 +#define PSC_ISR_TxRDY 0x0100 +#define PSC_ISR_IPC 0x8000 +#define PSC_IPCR_DDCD 0x20 +#define PSC_IPCR_DCTS 0x10 +#define PSC_IPCR_DCD 0x02 +#define PSC_IPCR_CTS 0x01 +#define PSC_SR_PE 0x2000 +#define PSC_SR_FE 0x4000 +#define PSC_CR_RSTRCV 0x20 +#define PSC_CR_RSTTRN 0x30 +#define PSC_CR_RSTERR 0x40 +#define PSC_OP_RTS 0x01 + +/* settings */ +#define PSC_CSRSTD PSC_CSR_RCLK32 +#define PSC_MR1STD (0x20 | PSC_MR1_RxRTS) +#define PSC_MR2STD (0x00 | PSC_MR2_TxCTS) +#define PSC_IMR_STDINT (PSC_IMR_ORERR | PSC_IMR_RxRDY | \ + PSC_IMR_DB | PSC_IMR_IPC) +#define PSC_RFA_ALMOST_FULL 0x0040 +#define PSC_RFC_RxRDY_LEVEL 0x00 +#define PSC_TFA_TxRDY_LEVEL 0x01CF +#define PSC_TFC_ALMOST_FULL 0x05 + +#define getreg1(bas,reg) bus_space_read_1((bas)->bst,(bas)->bsh, reg) +#define setreg1(bs,rg,vl) bus_space_write_1((bs)->bst,(bs)->bsh, rg, vl) +#define getreg2(bas,reg) bus_space_read_2((bas)->bst,(bas)->bsh, reg) +#define setreg2(bs,rg,vl) bus_space_write_2((bs)->bst,(bs)->bsh, rg, vl) +#define getreg4(bas,reg) bus_space_read_4((bas)->bst,(bas)->bsh, reg) +#define setreg4(bs,rg,vl) bus_space_write_4((bs)->bst,(bs)->bsh, rg, vl) + +static void +psc_param(struct uart_bas *bas, int *baudrate, int *databits, + int *stopbits, int *parity) +{ + uint32_t tmp = 5000; + + while (((getreg2(bas, PSC_REG_SR) & PSC_SR_TxEMP) == 0) && + (--tmp > 0)) + DELAY(100); + + bas->regshft = 0; + setreg1(bas, PSC_REG_CR, PSC_CR_DISABLE | PSC_CR_RSTMRP); + setreg1(bas, PSC_REG_CR, PSC_CR_RSTRCV); + setreg1(bas, PSC_REG_CR, PSC_CR_RSTTRN); + setreg1(bas, PSC_REG_CR, PSC_CR_RSTERR); + setreg2(bas, PSC_REG_CSR, PSC_CSRSTD); + setreg4(bas, PSC_REG_SICR, PSC_SICR_NODCD); + + tmp = PSC_MR1STD; + switch (*databits) { + case 5: + tmp |= PSC_MR1_5BITS; + break; + case 6: + tmp |= PSC_MR1_6BITS; + break; + case 7: + tmp |= PSC_MR1_7BITS; + break; + case 8: + tmp |= PSC_MR1_8BITS; + break; + default: + tmp |= PSC_MR1_8BITS; + *databits = 8; + } + switch (*parity) { + case UART_PARITY_ODD: + tmp |= PSC_MR1_PARODD; + break; + case UART_PARITY_EVEN: + tmp |= PSC_MR1_PAREVEN; + break; + case UART_PARITY_NONE: + tmp |= PSC_MR1_NOPARITY; + break; + default: + tmp |= PSC_MR1_NOPARITY; + *parity = UART_PARITY_NONE; + } + + setreg1(bas, PSC_REG_MR, tmp); + + tmp = PSC_MR2STD; + + if (*databits == 5) { + if (*stopbits == 1) + tmp |= PSC_MR2_5x1; + else { + tmp |= PSC_MR2_5x15; + *stopbits = 2; + } + } else if (*stopbits == 2) + tmp |= PSC_MR2_SB2; + else { + tmp |= PSC_MR2_SB1; + *stopbits = 1; + } + + setreg1(bas, PSC_REG_MR, tmp); + + if (*baudrate == 0) + *baudrate = 115200; + + tmp = (IPB_CLOCK * 10 / (PSC_CSRSTD == PSC_CSR_RCLK32 ? 32 : 4)) / + (*baudrate); + if (tmp % 10 >= 5) + tmp += 10; + tmp /= 10; + + setreg1(bas, PSC_REG_CTUR, tmp >> 8); + setreg1(bas, PSC_REG_CTLR, tmp); + + setreg2(bas, PSC_REG_RFALARM, PSC_RFA_ALMOST_FULL); + setreg1(bas, PSC_REG_RFCNTL, PSC_RFC_RxRDY_LEVEL); + setreg2(bas, PSC_REG_TFALARM, PSC_TFA_TxRDY_LEVEL); + setreg1(bas, PSC_REG_TFCNTL, PSC_TFC_ALMOST_FULL); + setreg2(bas, PSC_REG_IMR, PSC_IMR_NOINT); + + setreg1(bas, PSC_REG_CR, PSC_CR_ENABLE); + + uart_barrier(bas); +} + + +/* + * Low-level UART interface. + */ +static int psc_probe(struct uart_bas *bas); +static void psc_init(struct uart_bas *bas, int, int, int, int); +static void psc_term(struct uart_bas *bas); +static void psc_putc(struct uart_bas *bas, int); +static int psc_rxready(struct uart_bas *bas); +static int psc_getc(struct uart_bas *bas, struct mtx *); + +static struct uart_ops uart_psc_ops = { + .probe = psc_probe, + .init = psc_init, + .term = psc_term, + .putc = psc_putc, + .rxready = psc_rxready, + .getc = psc_getc, +}; + +static int +psc_probe(struct uart_bas *bas) +{ + + return (0); +} + +static void +psc_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, + int parity) +{ + + psc_param(bas, &baudrate, &databits, &stopbits, &parity); +} + +static void +psc_term(struct uart_bas *bas) +{ +} + +static void +psc_putc(struct uart_bas *bas, int c) +{ + uint32_t maxt = 5000; + + while (((getreg2(bas, PSC_REG_SR) & PSC_SR_TxRDY) == 0) && + (maxt-- > 0)) + DELAY(100); + setreg1(bas, PSC_REG_TxBUF, c); + uart_barrier(bas); +} + +static int +psc_rxready(struct uart_bas *bas) +{ + + return ((getreg2(bas, PSC_REG_SR) & PSC_SR_RxRDY) != 0 ? 1 : 0); +} + +static int +psc_getc(struct uart_bas *bas, struct mtx *hwmtx) +{ + uint32_t c; + + uart_lock(hwmtx); + while ((getreg2(bas, PSC_REG_SR) & PSC_SR_RxRDY) == 0) { + uart_unlock(hwmtx); + DELAY(10); + uart_lock(hwmtx); + } + + c = getreg1(bas, PSC_REG_RxBUF); + uart_unlock(hwmtx); + return (c); +} + +/* + * High-level UART interface. + */ +struct psc_softc { + struct uart_softc base; +}; + +static int psc_bus_attach(struct uart_softc *); +static int psc_bus_detach(struct uart_softc *); +static int psc_bus_flush(struct uart_softc *, int); +static int psc_bus_getsig(struct uart_softc *); +static int psc_bus_ioctl(struct uart_softc *, int, intptr_t); +static int psc_bus_ipend(struct uart_softc *); +static int psc_bus_param(struct uart_softc *, int, int, int, int); +static int psc_bus_probe(struct uart_softc *); +static int psc_bus_receive(struct uart_softc *); +static int psc_bus_setsig(struct uart_softc *, int); +static int psc_bus_transmit(struct uart_softc *); + +static kobj_method_t psc_methods[] = { + KOBJMETHOD(uart_attach, psc_bus_attach), + KOBJMETHOD(uart_detach, psc_bus_detach), + KOBJMETHOD(uart_flush, psc_bus_flush), + KOBJMETHOD(uart_getsig, psc_bus_getsig), + KOBJMETHOD(uart_ioctl, psc_bus_ioctl), + KOBJMETHOD(uart_ipend, psc_bus_ipend), + KOBJMETHOD(uart_param, psc_bus_param), + KOBJMETHOD(uart_probe, psc_bus_probe), + KOBJMETHOD(uart_receive, psc_bus_receive), + KOBJMETHOD(uart_setsig, psc_bus_setsig), + KOBJMETHOD(uart_transmit, psc_bus_transmit), + { 0, 0 } +}; + +struct uart_class uart_psc_class = { + "psc", + psc_methods, + sizeof(struct psc_softc), + .uc_ops = &uart_psc_ops, + .uc_range = 0x100, + .uc_rclk = IPB_CLOCK +}; + +#define SIGCHG(c, i, s, d) \ + if (c) { \ + i |= (i & s) ? s : s | d; \ + } else { \ + i = (i & s) ? (i & ~s) | d : i; \ + } + +static int +psc_bus_attach(struct uart_softc *sc) +{ + struct uart_devinfo *di; + struct uart_bas *bas; + + bas = &sc->sc_bas; + if (sc->sc_sysdev != NULL) { + di = sc->sc_sysdev; + psc_param(bas, &(di->baudrate), &(di->databits), + &(di->stopbits), &(di->parity)); + } else + psc_init(bas, 115200, 8, 1, UART_PARITY_NONE); + setreg2(bas, PSC_REG_IMR, PSC_IMR_STDINT | PSC_IMR_TxEMP); + uart_barrier(bas); + sc->sc_txbusy = 0; + return (0); +} + +static int +psc_bus_detach(struct uart_softc *sc) +{ + + return (0); +} + +static int +psc_bus_flush(struct uart_softc *sc, int what) +{ + + return (0); +} + +static int +psc_bus_getsig(struct uart_softc *sc) +{ + uint32_t new, old, sig; + uint32_t ipcr; + + do { + old = sc->sc_hwsig; + sig = old; + uart_lock(sc->sc_hwmtx); + ipcr = getreg1(&sc->sc_bas, PSC_REG_IPCR); + uart_unlock(sc->sc_hwmtx); + SIGCHG(ipcr & PSC_IPCR_CTS, sig, SER_CTS, SER_DCTS); + SIGCHG(ipcr & PSC_IPCR_DCD, sig, SER_DCD, SER_DDCD); + new = sig & ~SER_MASK_DELTA; + } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); + return (sig); +} + +static int +psc_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) +{ + + return (0); +} + +static int +psc_bus_ipend(struct uart_softc *sc) +{ + struct uart_bas *bas; + int ipend; + uint32_t iir, lsr; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + iir = getreg2(bas, PSC_REG_ISR); + ipend = 0; + lsr = getreg2(bas, PSC_REG_SR); + uart_unlock(sc->sc_hwmtx); + + if (iir & PSC_ISR_RxRDY) + if (lsr & PSC_SR_RxRDY) + ipend |= SER_INT_RXREADY; + + if (iir & PSC_ISR_ORERR) + ipend |= SER_INT_OVERRUN; + if (iir & PSC_ISR_TxEMP) { + if (sc->sc_txbusy) + ipend |= SER_INT_TXIDLE; + setreg2(bas, PSC_REG_IMR, PSC_IMR_STDINT); + uart_barrier(bas); + } + if (iir & PSC_ISR_DB) + ipend |= SER_INT_BREAK; + if (iir & PSC_ISR_IPC) + ipend |= SER_INT_SIGCHG; + + return ((sc->sc_leaving) ? 0 : ipend); +} + +static int +psc_bus_param(struct uart_softc *sc, int baudrate, int databits, + int stopbits, int parity) +{ + + uart_lock(sc->sc_hwmtx); + psc_param(&sc->sc_bas, &baudrate, &databits, &stopbits, &parity); + uart_unlock(sc->sc_hwmtx); + sc->sc_txbusy = 0; + return (0); +} + +static int +psc_bus_probe(struct uart_softc *sc) +{ + int error; + + sc->sc_rxfifosz = 512; + sc->sc_txfifosz = 512; + error = psc_probe(&sc->sc_bas); + if (error) + return (error); + device_set_desc(sc->sc_dev, "PSC serial controller"); + return (0); +} + +static int +psc_bus_receive(struct uart_softc *sc) +{ + struct uart_bas *bas; + uint32_t sr, c; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + sr = getreg2(bas, PSC_REG_SR); + while (sr & PSC_SR_RxRDY) { + if (uart_rx_full(sc)) { + sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; + break; + } + c = getreg1(bas, PSC_REG_RxBUF); + uart_rx_put(sc, c); + sr = getreg2(bas, PSC_REG_SR); + } + uart_unlock(sc->sc_hwmtx); + + return (0); +} + +static int +psc_bus_setsig(struct uart_softc *sc, int sig) +{ + struct uart_bas *bas; + uint32_t new, old; + + bas = &sc->sc_bas; + do { + old = sc->sc_hwsig; + new = old; + if (sig & SER_DRTS) { + SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS); + } + } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); + + uart_lock(sc->sc_hwmtx); + if (sig & SER_DRTS) { + if (sig & SER_RTS) + setreg1(bas, PSC_REG_OP1, PSC_OP_RTS); + else + setreg1(bas, PSC_REG_OP0, PSC_OP_RTS); + } + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); + return (0); +} + +static int +psc_bus_transmit(struct uart_softc *sc) +{ + struct uart_bas *bas; + int i,maxt; + + bas = &sc->sc_bas; + uart_lock(sc->sc_hwmtx); + for (i = 0; i < sc->sc_txdatasz; i++) { + maxt = 5000; + while (((getreg2(bas, PSC_REG_SR) & PSC_SR_TxRDY) == 0) && + (maxt-- > 0)) + DELAY(100); + setreg1(bas, PSC_REG_TxBUF, sc->sc_txbuf[i]); + uart_barrier(bas); + } + sc->sc_txbusy = 1; + setreg2(&sc->sc_bas, PSC_REG_IMR, PSC_IMR_STDINT | PSC_IMR_TxEMP); + uart_barrier(bas); + uart_unlock(sc->sc_hwmtx); + return (0); +} diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index d9569d1..d46525b 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -244,6 +244,11 @@ extern void *dsitrap, *dsisize; extern void *decrint, *decrsize; extern void *extint, *extsize; extern void *dblow, *dbsize; +#ifdef E300 +extern void *imisstrap, *imisssize; +extern void *dlmisstrap, *dlmisssize; +extern void *dsmisstrap, *dsmisssize; +#endif u_int powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) @@ -470,6 +475,11 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) bcopy(generictrap, (void *)EXC_VEC, (size_t)&trapsize); bcopy(generictrap, (void *)EXC_VECAST, (size_t)&trapsize); bcopy(generictrap, (void *)EXC_THRM, (size_t)&trapsize); +#ifdef E300 + bcopy(&imisstrap, (void *)EXC_IMISS, (size_t)&imisssize); + bcopy(&dlmisstrap, (void *)EXC_DLMISS, (size_t)&dlmisssize); + bcopy(&dsmisstrap, (void *)EXC_DSMISS, (size_t)&dsmisssize); +#endif __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); /* diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 75562f5..a229d05 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -199,6 +199,8 @@ static struct ofw_map *translations; extern struct pmap ofw_pmap; +extern void bs_remap_earlyboot(void); + /* * Lock for the pteg and pvo tables. */ @@ -905,6 +907,8 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) pmap_bootstrapped++; + bs_remap_earlyboot(); + /* * Set the start and end of kva. */ diff --git a/sys/powerpc/aim/ofw_machdep.c b/sys/powerpc/aim/ofw_machdep.c index 0154dfe..19e0a28 100644 --- a/sys/powerpc/aim/ofw_machdep.c +++ b/sys/powerpc/aim/ofw_machdep.c @@ -58,6 +58,8 @@ __FBSDID("$FreeBSD: src/sys/powerpc/aim/ofw_machdep.c,v 1.24 2009/05/14 00:34:26 #include #include +#include + #define OFMEM_REGIONS 32 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; static struct mem_region OFfree[OFMEM_REGIONS + 3]; @@ -270,7 +272,9 @@ OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) ofw_real_mode = 0; else ofw_real_mode = 1; - +#ifdef EFIKA + ofw_real_mode = 1; +#endif ofwcall = openfirm; fdt = fdt_ptr; } @@ -322,8 +326,6 @@ openfirmware(void *args) : "r" (ofmsr[0]) ); - ofw_sprg_prepare(); - if (pmap_bootstrapped && !ofw_real_mode) { /* * Swap the kernel's address space with Open Firmware's @@ -343,7 +345,82 @@ openfirmware(void *args) isync(); } - result = ofwcall(args); +#ifdef EFIKA + static uint32_t regsave[33]; + vm_offset_t stacksave = 0; + + if (pmap_bootstrapped) { + /* Save SR and SDR1 registers */ + for (i = 0; i < 16; i++) + regsave[i] = mfsrin(i << ADDR_SR_SHFT); + __asm __volatile("mfsdr1 %0 \n\t" + : "=r" (regsave[16])); + + /* Set Stack Pointer to physical address of stack */ + __asm __volatile("addi %0,1,0 \n\t" + : "=r" (stacksave):); + __asm __volatile("addi 1,%0,0 \n\t" + :: "r" (pmap_kextract(stacksave))); + } + + /* Save BATs */ + __asm __volatile("mfibatl %0,0 \n\t" "mfibatl %1,1 \n\t" + "mfibatl %2,2 \n\t" "mfibatl %3,3 \n\t" + "mfibatu %4,0 \n\t" "mfibatu %5,1 \n\t" + "mfibatu %6,2 \n\t" "mfibatu %7,3 \n\t" + "mfdbatl %8,0 \n\t" "mfdbatl %9,1 \n\t" + "mfdbatl %10,2 \n\t" "mfdbatl %11,3 \n\t" + "mfdbatu %12,0 \n\t" "mfdbatu %13,1 \n\t" + "mfdbatu %14,2 \n\t" "mfdbatu %15,3 \n\t" + : "=r"(regsave[17]), "=r"(regsave[18]), + "=r"(regsave[19]), "=r"(regsave[20]), + "=r"(regsave[21]), "=r"(regsave[22]), + "=r"(regsave[23]), "=r"(regsave[24]), + "=r"(regsave[25]), "=r"(regsave[26]), + "=r"(regsave[27]), "=r"(regsave[28]), + "=r"(regsave[29]), "=r"(regsave[30]), + "=r"(regsave[31]), "=r"(regsave[32]) + : ); +#endif + + ofw_sprg_prepare(); + + result = ofwcall(args); + +#ifdef EFIKA + /* Restore BATs */ + __asm __volatile("mtibatl 0,%0 \n\t" "mtibatl 1,%1 \n\t" + "mtibatl 2,%2 \n\t" "mtibatl 3,%3 \n\t" + "mtibatu 0,%4 \n\t" "mtibatu 1,%5 \n\t" + "mtibatu 2,%6 \n\t" "mtibatu 3,%7 \n\t" + "mtdbatl 0,%8 \n\t" "mtdbatl 1,%9 \n\t" + "mtdbatl 2,%10 \n\t" "mtdbatl 3,%11 \n\t" + "mtdbatu 0,%12 \n\t" "mtdbatu 1,%13 \n\t" + "mtdbatu 2,%14 \n\t" "mtdbatu 3,%15 \n\t" + : + : "r"(regsave[17]), "r"(regsave[18]), + "r"(regsave[19]), "r"(regsave[20]), + "r"(regsave[21]), "r"(regsave[22]), + "r"(regsave[23]), "r"(regsave[24]), + "r"(regsave[25]), "r"(regsave[26]), + "r"(regsave[27]), "r"(regsave[28]), + "r"(regsave[29]), "r"(regsave[30]), + "r"(regsave[31]), "r"(regsave[32]) ); + + if (pmap_bootstrapped) { + /* Restore Stack Pointer */ + __asm __volatile("addi 1,%0,0 \n\t" + :: "r" (stacksave)); + + /* Restore SR and SDR1 regs */ + for (i = 0; i < 16; i++) { + mtsrin(i << ADDR_SR_SHFT, regsave[i]); + isync(); + } + __asm __volatile("mtsdr1 %0 \n\t" + :: "r" (regsave[16])); + } +#endif if (pmap_bootstrapped && !ofw_real_mode) { /* @@ -523,7 +600,6 @@ OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, OF_get_addr_props(bridge, &naddr, &nsize, &pci); } - *tag = &bs_le_tag; return (bus_space_map(*tag, addr, size, 0, handle)); } diff --git a/sys/powerpc/aim/trap_subr.S b/sys/powerpc/aim/trap_subr.S index c105250..b60a889 100644 --- a/sys/powerpc/aim/trap_subr.S +++ b/sys/powerpc/aim/trap_subr.S @@ -670,3 +670,202 @@ CNAME(dblow): bla dbtrap CNAME(dbsize) = .-CNAME(dblow) #endif /* KDB */ + +#if defined(E300) +/* + * Instruction TLB miss (603e-specific). + */ + .globl CNAME(imisstrap),CNAME(imisssize) +CNAME(imisstrap): + mfspr %r2, SPR_HASH1 /* get first pointer */ + addi %r1, 0, 8 /* load 8 for counter */ + mfctr %r0 /* save counter */ + mfspr %r3, SPR_ICMP /* get first compare value */ + addi %r2, %r2, -8 /* pre dec the pointer */ +im0: + mtctr %r1 /* load counter */ +im1: + lwzu %r1, 8(%r2) /* get next pte */ + cmp 0, %r1, %r3 /* see if found pte */ + bdnzf 2, im1 /* dec count br if cmp ne and if + * count not zero */ + bne instr_sec_hash /* if not found set up second hash + * or exit */ + lwz %r1, +4(%r2) /* load tlb entry lower-word */ + andi. %r3, %r1, 8 /* check G bit */ + bne do_isi_prot /* if guarded, take an ISI */ + mtctr %r0 /* restore counter */ + mfspr %r0, SPR_IMISS /* get the miss address for the tlbli */ + mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */ + mtcrf 0x80, %r3 /* restore CR0 */ + mtspr SPR_RPA, %r1 /* set the pte */ + ori %r1, %r1, 0x100 /* set reference bit */ + srwi %r1, %r1, 8 /* get byte 7 of pte */ + tlbli %r0 /* load the itlb */ + stb %r1, +6(%r2) /* update page table */ + rfi /* return to executing program */ + +instr_sec_hash: + andi. %r1, %r3, 0x0040 /* see if we have done second hash */ + bne do_isi /* if so, go to ISI interrupt */ + mfspr %r2, SPR_HASH2 /* get the second pointer */ + ori %r3, %r3, 0x0040 /* change the compare value */ + addi %r1, %r0, 8 /* load 8 for counter */ + addi %r2, %r2, -8 /* pre dec for update on load */ + b im0 /* try second hash */ + +/* Create a fake ISI interrupt as the address was not found */ +do_isi_prot: + mfspr %r3, SPR_SRR1 /* get srr1 */ + andi. %r2, %r3, 0xffff /* clean upper srr1 */ + addis %r2, %r2, 0x0800 /* or in srr<4> = 1 to flag prot + * violation */ + b isi1 +do_isi: + mfspr %r3, SPR_SRR1 /* get srr1 */ + andi. %r2, %r3, 0xffff /* clean srr1 */ + addis %r2, %r2, 0x4000 /* or in srr1<1> = 1 to flag pte + * not found */ +isi1: + mtctr %r0 /* restore counter */ + mtspr SPR_SRR1, %r2 /* set srr1 */ + mfmsr %r0 /* get msr */ + xoris %r0, %r0, 0x2 /* flip the msr bit */ + mtcrf 0x80, %r3 /* restore CR0 */ + mtmsr %r0 /* flip back to the native gprs */ + ba EXC_ISI /* go to instr. access interrupt */ +CNAME(imisssize) = .-CNAME(imisstrap) + +/* + * Data load TLB miss (603e-specific). + */ + .globl CNAME(dlmisstrap),CNAME(dlmisssize) +CNAME(dlmisstrap): + mfspr %r2, SPR_HASH1 /* get first pointer */ + addi %r1, 0, 8 /* load 8 for counter */ + mfctr %r0 /* save counter */ + mfspr %r3, SPR_DCMP /* get first compare value */ + addi %r2, %r2, -8 /* pre dec the pointer */ +dm0: + mtctr %r1 /* load counter */ +dm1: + lwzu %r1, 8(%r2) /* get next pte */ + cmp 0, 0, %r1, %r3 /* see if found pte */ + bdnzf 2, dm1 /* dec count br if cmp ne and if + * count not zero */ + bne data_sec_hash /* if not found set up second hash + * or exit */ + lwz %r1, +4(%r2) /* load tlb entry lower-word */ + mtctr %r0 /* restore counter */ + mfspr %r0, SPR_DMISS /* get the miss address for the tlbld */ + mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */ + mtcrf 0x80, %r3 /* restore CR0 */ + mtspr SPR_RPA, %r1 /* set the pte */ + ori %r1, %r1, 0x100 /* set reference bit */ + srwi %r1, %r1, 8 /* get byte 7 of pte */ + tlbld %r0 /* load the dtlb */ + stb %r1, +6(%r2) /* update page table */ + rfi /* return to executing program */ + +data_sec_hash: + andi. %r1, %r3, 0x0040 /* see if we have done second hash */ + bne do_dsi /* if so, go to DSI interrupt */ + mfspr %r2, SPR_HASH2 /* get the second pointer */ + ori %r3, %r3, 0x0040 /* change the compare value */ + addi %r1, 0, 8 /* load 8 for counter */ + addi %r2, %r2, -8 /* pre dec for update on load */ + b dm0 /* try second hash */ +CNAME(dlmisssize) = .-CNAME(dlmisstrap) + +/* + * Data store TLB miss (603e-specific). + */ + .globl CNAME(dsmisstrap),CNAME(dsmisssize) +CNAME(dsmisstrap): + mfspr %r2, SPR_HASH1 /* get first pointer */ + addi %r1, 0, 8 /* load 8 for counter */ + mfctr %r0 /* save counter */ + mfspr %r3, SPR_DCMP /* get first compare value */ + addi %r2, %r2, -8 /* pre dec the pointer */ +ds0: + mtctr %r1 /* load counter */ +ds1: + lwzu %r1, 8(%r2) /* get next pte */ + cmp 0, 0, %r1, %r3 /* see if found pte */ + bdnzf 2, ds1 /* dec count br if cmp ne and if + * count not zero */ + bne data_store_sec_hash /* if not found set up second hash + * or exit */ + lwz %r1, +4(%r2) /* load tlb entry lower-word */ + andi. %r3, %r1, 0x80 /* check the C-bit */ + beq data_store_chk_prot /* if (C==0) + * go check protection modes */ +ds2: + mtctr %r0 /* restore counter */ + mfspr %r0, SPR_DMISS /* get the miss address for the tlbld */ + mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */ + mtcrf 0x80, %r3 /* restore CR0 */ + mtspr SPR_RPA, %r1 /* set the pte */ + tlbld %r0 /* load the dtlb */ + rfi /* return to executing program */ + +data_store_sec_hash: + andi. %r1, %r3, 0x0040 /* see if we have done second hash */ + bne do_dsi /* if so, go to DSI interrupt */ + mfspr %r2, SPR_HASH2 /* get the second pointer */ + ori %r3, %r3, 0x0040 /* change the compare value */ + addi %r1, 0, 8 /* load 8 for counter */ + addi %r2, %r2, -8 /* pre dec for update on load */ + b ds0 /* try second hash */ + +/* Check the protection before setting PTE(c-bit) */ +data_store_chk_prot: + rlwinm. %r3,%r1,30,0,1 /* test PP */ + bge- chk0 /* if (PP == 00 or PP == 01) + * goto chk0: */ + andi. %r3, %r1, 1 /* test PP[0] */ + beq+ chk2 /* return if PP[0] == 0 */ + b do_dsi_prot /* else DSIp */ +chk0: + mfspr %r3,SPR_SRR1 /* get old msr */ + andis. %r3,%r3,0x0008 /* test the KEY bit (SRR1-bit 12) */ + beq chk2 /* if (KEY==0) goto chk2: */ + b do_dsi_prot /* else do_dsi_prot */ +chk2: + ori %r1, %r1, 0x180 /* set reference and change bit */ + sth %r1, 6(%r2) /* update page table */ + b ds2 /* and back we go */ + +/* Create a fake DSI interrupt as the address was not found */ +do_dsi: + mfspr %r3, SPR_SRR1 /* get srr1 */ + rlwinm %r1,%r3,9,6,6 /* get srr1 to bit 6 for + * load/store, zero rest */ + addis %r1, %r1, 0x4000 /* or in dsisr<1> = 1 to flag pte + * not found */ + b dsi1 + +do_dsi_prot: + mfspr %r3, SPR_SRR1 /* get srr1 */ + rlwinm %r1,%r3,9,6,6 /* get srr1 to bit 6 for + * load/store, zero rest */ + addis %r1, %r1, 0x0800 /* or in dsisr<4> = 1 to flag prot + * violation */ +dsi1: + mtctr %r0 /* restore counter */ + andi. %r2, %r3, 0xffff /* clear upper bits of srr1 */ + mtspr SPR_SRR1, %r2 /* set srr1 */ + mtspr SPR_DSISR, %r1 /* load the dsisr */ + mfspr %r1, SPR_DMISS /* get miss address */ + rlwinm. %r2,%r2,0,31,31 /* test LE bit */ + beq dsi2 /* if little endian then: */ + xor %r1, %r1, 0x07 /* de-mung the data address */ +dsi2: + mtspr SPR_DAR, %r1 /* put in dar */ + mfmsr %r0 /* get msr */ + xoris %r0, %r0, 0x2 /* flip the msr bit */ + mtcrf 0x80, %r3 /* restore CR0 */ + mtmsr %r0 /* flip back to the native gprs */ + ba EXC_DSI /* branch to DSI interrupt */ +CNAME(dsmisssize) = .-CNAME(dsmisstrap) +#endif /* E300 */ diff --git a/sys/powerpc/conf/EFIKA b/sys/powerpc/conf/EFIKA new file mode 100644 index 0000000..586c130 --- /dev/null +++ b/sys/powerpc/conf/EFIKA @@ -0,0 +1,64 @@ +# +# Custom kernel for the Efika board +# + +cpu AIM +cpu E300 +ident EFIKA + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +makeoptions NO_MODULES=yes + +# Platform support +options EFIKA +options MPC5XXX + +options FFS +options SCHED_ULE #ULE scheduler +options INET #InterNETworking +options KTRACE #ktrace(1) syscall trace support +options STACK #stack(9) support +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions +options AUDIT # Security event auditing + +# Debugging for use in -current +options KDB #Enable the kernel debugger +options DDB #Support DDB +options DIAGNOSTIC +options INVARIANTS #Enable calls of extra sanity checking +options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +options WITNESS #Enable checks to detect deadlocks and cycles +options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +options KTR +options KTR_COMPILE=0xffffffff +#options KTR_MASK=KTR_SIG +options KTR_VERBOSE + +# syscons is the default console driver, resembling an SCO console +device sc +device kbdmux +options SC_OFWFB # OFW frame buffer +options SC_DFLT_FONT # compile font in +makeoptions SC_DFLT_FONT=cp437 + +# Serial ports +device uart +device psc + +# Pseudo devices. +device loop # Network loopback +device random # Entropy device +device ether # Ethernet support +device ofwd # Open Firmware disks + +# Misc +device powermac_nvram # Open Firmware configuration NVRAM + +device md #Memory/malloc disk +options MD_ROOT #MD is a potential root device +options MD_ROOT_SIZE=(5600) +makeoptions MFS_IMAGE=/nfsroot/reference/ppc-8.0-aim.miniroot.ufs +options ROOTDEVNAME=\"ufs:/dev/md0\" diff --git a/sys/powerpc/include/spr.h b/sys/powerpc/include/spr.h index 165a0b3..04b5e3e 100644 --- a/sys/powerpc/include/spr.h +++ b/sys/powerpc/include/spr.h @@ -168,6 +168,11 @@ #define MPC7448 0x8004 #define MPC7410 0x800c #define MPC8245 0x8081 +#define FSL_G2LE 0x8082 +#define FSL_E300c1 0x8083 +#define FSL_E300c2 0x8084 +#define FSL_E300c3 0x8085 +#define FSL_E300c4 0x8086 #define FSL_E500v1 0x8020 #define FSL_E500v2 0x8021 diff --git a/sys/powerpc/mpc5xxx/ic.c b/sys/powerpc/mpc5xxx/ic.c new file mode 100644 index 0000000..1894f3f --- /dev/null +++ b/sys/powerpc/mpc5xxx/ic.c @@ -0,0 +1,304 @@ +/*- + * Copyright (c) 2008-2009 Semihalf, Michal Mazur + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "icvar.h" + +#include "pic_if.h" + +/* + * Interface + */ +static int mpc5200_ic_probe(device_t); +static int mpc5200_ic_attach(device_t); + +static void mpc5200_ic_dispatch(device_t, struct trapframe *); +static void mpc5200_ic_enable(device_t, u_int, u_int); +static void mpc5200_ic_eoi(device_t, u_int); +static void mpc5200_ic_ipi(device_t, u_int); +static void mpc5200_ic_mask(device_t, u_int); +static void mpc5200_ic_unmask(device_t, u_int); +static void mpc5200_ic_config(device_t, u_int, enum intr_trigger, + enum intr_polarity); + +static void mpc5200_ic_dispatch_peripheral(struct mpc5200_ic_softc *sc, + struct trapframe *tf); + +static device_method_t mpc5200_ic_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, mpc5200_ic_probe), + DEVMETHOD(device_attach, mpc5200_ic_attach), + + /* PIC interface */ + DEVMETHOD(pic_config, mpc5200_ic_config), + DEVMETHOD(pic_dispatch, mpc5200_ic_dispatch), + DEVMETHOD(pic_enable, mpc5200_ic_enable), + DEVMETHOD(pic_eoi, mpc5200_ic_eoi), + DEVMETHOD(pic_ipi, mpc5200_ic_ipi), + DEVMETHOD(pic_mask, mpc5200_ic_mask), + DEVMETHOD(pic_unmask, mpc5200_ic_unmask), + + { 0, 0 }, +}; + +static driver_t mpc5200_ic_driver = { + "ic", + mpc5200_ic_methods, + sizeof(struct mpc5200_ic_softc) +}; + +static devclass_t mpc5200_ic_devclass; + +DRIVER_MODULE(mpc5200_ic, ocpbus, mpc5200_ic_driver, mpc5200_ic_devclass, 0, 0); + +static int +mpc5200_ic_probe(device_t dev) +{ + const char *type = ofw_bus_get_type(dev); + + if (strcmp(type, "interrupt-controller") != 0) + return (ENXIO); + + device_set_desc(dev, "MPC5200 interrupt controller"); + return (0); +} + +static int +mpc5200_ic_attach(device_t dev) +{ + struct mpc5200_ic_softc *sc; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + sc->sc_rrid = 0; + sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT, + &sc->sc_rrid, RF_ACTIVE); + if (sc->sc_rres == NULL) { + device_printf(dev, "Could not alloc mem resource!\n"); + return (ENXIO); + } + + sc->sc_bt = rman_get_bustag(sc->sc_rres); + sc->sc_bh = rman_get_bushandle(sc->sc_rres); + + /* + * Disable all interrupt sources and clear IRQ[0-3] interrupts + */ + mpc5200_ic_write_reg(sc, MPC5200_PRMASK, MPC5200_DISABLE_PERINT); + mpc5200_ic_write_reg(sc, MPC5200_EXCFG, MPC5200_DISABLE_EXTINT); + mpc5200_ic_write_reg(sc, MPC5200_MIMASK, MPC5200_DISABLE_MAININT); + + powerpc_register_pic(dev, 64); + + return (0); +} + +static void +mpc5200_ic_toggle_irq(struct mpc5200_ic_softc *sc, int irq, int enable) +{ + uint32_t reg,mask; + /* no mask for SliceTimer0 and CCSWakeUp */ + + /* for external interrupts: */ + if (IS_EXTERNAL(irq)) { + mask = SETBITS((MPC5200_EENA0 + EXTIRQ(irq)),1); + if (enable) + mpc5200_ic_setb(sc, MPC5200_EXCFG, mask | MPC5200_MEE); + else + mpc5200_ic_clrb(sc, MPC5200_EXCFG, mask); + } + + if (irq >= MPC5200_MAININT) { + if (irq < MPC5200_PERFINT) { + /* MAIN INTS */ + reg = MPC5200_MIMASK; + mask = SETBITS(MPC5200_MAINMASK0 + + (irq - MPC5200_MAININT), 1); + } else if (irq < MPC5200_IRQMAX) { + /* PERIPHERAL INTS */ + reg = MPC5200_PRMASK; + mask = SETBITS( irq - MPC5200_PERFINT, 1); + } else + return; + + if (enable) + mpc5200_ic_clrb(sc, reg, mask); + else + mpc5200_ic_setb(sc, reg, mask); + } +} + +/* + * PIC I/F methods. + */ + +static void +mpc5200_ic_config(device_t dev, u_int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + struct mpc5200_ic_softc *sc; + uint32_t nirq; + + sc = device_get_softc(dev); + + /* only for external interrupts */ + if (IS_EXTERNAL(irq)) { + nirq = MPC5200_ETYPE0 + 2 * EXTIRQ(irq); + mpc5200_ic_clrb(sc, MPC5200_EXCFG, SETBITS(nirq, 2)); + if (pol == INTR_POLARITY_LOW) { + mpc5200_ic_setb(sc, MPC5200_EXCFG, SETBITS(nirq, 1)); + if (trig == INTR_TRIGGER_LEVEL) + mpc5200_ic_setb(sc, MPC5200_EXCFG, + SETBITS(nirq + 1, 1)); + } else if (trig == INTR_TRIGGER_EDGE) + mpc5200_ic_setb(sc, MPC5200_EXCFG, + SETBITS(nirq + 1, 1)); + } +} + +static void +mpc5200_ic_dispatch(device_t dev, struct trapframe *tf) +{ + struct mpc5200_ic_softc *sc; + uint32_t irq; + + sc = device_get_softc(dev); + + /* CRITICAL INTERRUPTS */ + while ((irq = GETBITS(mpc5200_ic_read_reg(sc, MPC5200_ENCREG), + MPC5200_ENC_CSE, 3)) > 0) { + irq &= 0x03; + if (irq == MPC5200_ENC_HIINT) + mpc5200_ic_dispatch_peripheral(sc, tf); + else + powerpc_dispatch_intr(sc->sc_vector[irq], tf); + } + + /* MAIN INTERRUPTS */ + while ((irq = GETBITS(mpc5200_ic_read_reg(sc, MPC5200_ENCREG), + MPC5200_ENC_MSE, 6)) > 0) { + irq &= 0x1F; + if (irq == MPC5200_ENC_LOINT) + mpc5200_ic_dispatch_peripheral(sc, tf); + else + powerpc_dispatch_intr(sc->sc_vector[irq + + MPC5200_MAININT], tf); + } +} + +static void +mpc5200_ic_dispatch_peripheral(struct mpc5200_ic_softc *sc, + struct trapframe *tf) +{ + uint32_t irq; + + irq = GETBITS(mpc5200_ic_read_reg(sc, MPC5200_ENCREG), + MPC5200_ENC_PSE, 6); + if (irq > 0) { + irq &= 0x1F; + powerpc_dispatch_intr(sc->sc_vector[MPC5200_PERFINT + irq], tf); + } +} + +static void +mpc5200_ic_enable(device_t dev, u_int irq, u_int vector) +{ + struct mpc5200_ic_softc *sc; + + if (irq >= MPC5200_IRQMAX) + return; + + sc = device_get_softc(dev); + sc->sc_vector[irq] = vector; + mpc5200_ic_toggle_irq(sc, irq, TRUE); +} + +static void +mpc5200_ic_eoi(device_t dev __unused, u_int irq __unused) +{ + struct mpc5200_ic_softc *sc; + + if (irq >= MPC5200_IRQMAX) + return; + + sc = device_get_softc(dev); + + if (IS_EXTERNAL(irq)) + /* clear external IRQ */ + mpc5200_ic_setb(sc, MPC5200_EXCFG, + SETBITS(MPC5200_ECLR0 + EXTIRQ(irq),1)); + + /* force rescan of interrupt sources */ + mpc5200_ic_setb(sc, MPC5200_ENCREG, MPC5200_RESCAN_INTSRC); +} + +static void +mpc5200_ic_ipi(device_t dev, u_int cpu) +{ + /* No SMP support. */ +} + +static void +mpc5200_ic_mask(device_t dev, u_int irq) +{ + struct mpc5200_ic_softc *sc; + + if (irq >= MPC5200_IRQMAX) + return; + + sc = device_get_softc(dev); + mpc5200_ic_toggle_irq(sc, irq, FALSE); +} + +static void +mpc5200_ic_unmask(device_t dev, u_int irq) +{ + struct mpc5200_ic_softc *sc; + + if (irq >= MPC5200_IRQMAX) + return; + + sc = device_get_softc(dev); + mpc5200_ic_toggle_irq(sc, irq, TRUE); +} diff --git a/sys/powerpc/mpc5xxx/icvar.h b/sys/powerpc/mpc5xxx/icvar.h new file mode 100644 index 0000000..a7f2ffc --- /dev/null +++ b/sys/powerpc/mpc5xxx/icvar.h @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2008-2009 Semihalf, Michal Mazur + * 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. + */ + +#ifndef _POWERPC_MPC5200_PICVAR_H_ +#define _POWERPC_MPC5200_PICVAR_H_ + +#define MPC5200_IRQMAX 45 +#define GETBITS(dt,st,cn) (((dt) >> (32 - (st) - (cn))) & ((0x01 << (cn)) - 1)) +#define SETBITS(st,cn) (((0x01 << (cn)) - 1) << (32 - (cn) - (st))) + +/* PIC REGISTERS */ +#define MPC5200_PRMASK 0x00 +#define MPC5200_PRPRI1 0x04 +#define MPC5200_PRPRI2 0x08 +#define MPC5200_PRPRI3 0x0C +#define MPC5200_EXCFG 0x10 +#define MPC5200_CRPRI 0x14 +#define MPC5200_MIMASK 0x14 +#define MPC5200_MIPRI1 0x18 +#define MPC5200_MIPRI2 0x1C +#define MPC5200_ENCREG 0x24 +#define MPC5200_CRST 0x28 +#define MPC5200_MIST 0x2C +#define MPC5200_PRST 0x30 +#define MPC5200_BEST 0x38 +#define MPC5200_MIEM 0x40 +#define MPC5200_PREM 0x44 +#define MPC5200_IRQEM 0x48 + +/* peripheral 24src, main 17src, crit 4src, sdma 32reqs */ + +/* CRITICAL INTERRUPT */ +#define MPC5200_INT_IRQ0 0 +#define MPC5200_INT_SLTMR0 1 +#define MPC5200_INT_WAKEUP 3 +/* MAIN INTERRUPT */ +#define MPC5200_INT_SLTMR1 4 +#define MPC5200_INT_IRQ1 5 +#define MPC5200_INT_IRQ2 6 +#define MPC5200_INT_IRQ3 7 +#define MPC5200_INT_RTC_PER 9 +#define MPC5200_INT_RTC_STW 10 +#define MPC5200_INT_GPIO_STD 11 +#define MPC5200_INT_GPIO_WKUP 12 +#define MPC5200_INT_TMR0 13 +#define MPC5200_INT_TMR1 14 +#define MPC5200_INT_TMR2 15 +#define MPC5200_INT_TMR3 16 +#define MPC5200_INT_TMR4 17 +#define MPC5200_INT_TMR5 18 +#define MPC5200_INT_TMR6 19 +#define MPC5200_INT_TMR7 20 +/* PERIPHERAL INTERRUPT */ +#define MPC5200_INT_BCIS 21 +#define MPC5200_INT_PSC1 22 +#define MPC5200_INT_PSC2 23 +#define MPC5200_INT_PSC3 24 +#define MPC5200_INT_PSC6 25 +#define MPC5200_INT_ETH 26 +#define MPC5200_INT_USB 27 +#define MPC5200_INT_ATA 28 +#define MPC5200_INT_PCI_CM 29 +#define MPC5200_INT_PCI_RX 30 +#define MPC5200_INT_PCI_TX 31 +#define MPC5200_INT_PSC4 32 +#define MPC5200_INT_PSC5 33 +#define MPC5200_INT_SPI_MODF 34 +#define MPC5200_INT_SPI_SPIF 35 +#define MPC5200_INT_I2C_1 36 +#define MPC5200_INT_I2C_2 37 +#define MPC5200_INT_CAN1 38 +#define MPC5200_INT_CAN2 39 +#define MPC5200_INT_XLBA 42 +#define MPC5200_INT_BDLC 43 +#define MPC5200_INT_BCLP 44 + +/* CONST */ +#define MPC5200_DISABLE_PERINT 0xFFFFFF00 +#define MPC5200_DISABLE_EXTINT 0x0F001000 +#define MPC5200_DISABLE_MAININT 0x0001EFFF +#define MPC5200_RESCAN_INTSRC 0X20200400 + +#define MPC5200_EENA0 20 +#define MPC5200_ETYPE0 8 +#define MPC5200_ECLR0 4 +#define MPC5200_MEE SETBITS(19,1) +#define MPC5200_MAINMASK0 15 +#define MPC5200_ENC_CSE 21 +#define MPC5200_ENC_MSE 10 +#define MPC5200_ENC_PSE 2 +#define MPC5200_ENC_HIINT 2 +#define MPC5200_ENC_LOINT 4 + +#define MPC5200_MAININT 4 +#define MPC5200_PERFINT 21 +#define MPC5200_SDMAREQ 64 +#define IS_EXTERNAL(irq) ((irq == MPC5200_INT_IRQ0) || \ + ((irq >= MPC5200_INT_IRQ1) && (irq <= MPC5200_INT_IRQ3))) +#define EXTIRQ(irq) (irq >= MPC5200_INT_IRQ1 ? \ + irq - MPC5200_INT_IRQ1 + 1 : MPC5200_INT_IRQ0) + +#define mpc5200_ic_read_reg(sc,reg) \ + bus_space_read_4((sc)->sc_bt, (sc)->sc_bh, reg) +#define mpc5200_ic_write_reg(sc,reg,val) \ + bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, reg, val) +#define mpc5200_ic_setb(sc,reg,mask) \ + bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, reg, \ + ((bus_space_read_4((sc)->sc_bt, (sc)->sc_bh, reg)) | (mask))) +#define mpc5200_ic_clrb(sc,reg,mask) \ + bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, reg, \ + ((bus_space_read_4((sc)->sc_bt, (sc)->sc_bh, reg)) & (~(mask)))) + +struct mpc5200_ic_softc { + device_t sc_dev; + struct resource *sc_rres; + bus_space_tag_t sc_bt; + bus_space_handle_t sc_bh; + int sc_rrid; + u_int sc_vector[MPC5200_IRQMAX]; +}; + +#endif /* _POWERPC_MPC5200_PICVAR_H_ */ diff --git a/sys/powerpc/mpc5xxx/ocpbus.c b/sys/powerpc/mpc5xxx/ocpbus.c new file mode 100644 index 0000000..f5633a4 --- /dev/null +++ b/sys/powerpc/mpc5xxx/ocpbus.c @@ -0,0 +1,495 @@ +/*- + * Copyright 2007 by Andrew Turner. + * Copyright 2008-2009 Semihalf, Michal Mazur. + * 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 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 AUTHOR 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. + * + * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 + * from: FreeBSD: src/sys/powerpc/powerpc/nexus.c,v 1.14 2007/04/20 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static MALLOC_DEFINE(M_OCPBUS, "ocpbus", + "Open Firmware Bus device information"); + +struct ocpbus_softc { + struct rman sc_mem_rman; + phandle_t sc_node; + vm_offset_t sc_base; + vm_offset_t sc_size; +}; + +struct ocpbus_devinfo { + struct ofw_bus_devinfo odi_obdinfo; + struct resource_list odi_resources; +}; + +struct ocpbus_reg { + uint32_t or_base; + uint32_t or_size; +}; + +static int ocpbus_probe(device_t); +static int ocpbus_attach(device_t); +static void ocpbus_probe_nomatch(device_t, device_t); +static void ocpbus_add_reg(phandle_t devnode, + struct ocpbus_devinfo *dinfo); +static void ocpbus_add_intr(phandle_t devnode, + struct ocpbus_devinfo *dinfo); + +static struct resource * ocpbus_alloc_resource(device_t, device_t, int, int *, + u_long, u_long, u_long, u_int); + +static const struct ofw_bus_devinfo *ocpbus_ofw_get_devinfo(device_t, device_t); +static int ocpbus_print_child(device_t dev, device_t child); +static device_t ocpbus_add_child(device_t dev, int order, const char *name, + int unit); +static int ocpbus_read_ivar(device_t, device_t, int, uintptr_t *); +static int ocpbus_write_ivar(device_t, device_t, int, uintptr_t); +static int ocpbus_release_resource(device_t, device_t, int, int, + struct resource *); + +static device_method_t ocpbus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ocpbus_probe), + DEVMETHOD(device_attach, ocpbus_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_add_child, ocpbus_add_child), + DEVMETHOD(bus_print_child, ocpbus_print_child), + DEVMETHOD(bus_probe_nomatch, ocpbus_probe_nomatch), + DEVMETHOD(bus_read_ivar, ocpbus_read_ivar), + DEVMETHOD(bus_write_ivar, ocpbus_write_ivar), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_alloc_resource, ocpbus_alloc_resource ), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_release_resource, ocpbus_release_resource), + DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list), + + /* ofw bus interface */ + DEVMETHOD(ofw_bus_get_devinfo, ocpbus_ofw_get_devinfo), + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + {0, 0} +}; + +static driver_t ocpbus_driver = { + "ocpbus", + ocpbus_methods, + sizeof(struct ocpbus_softc) +}; + +static devclass_t ocpbus_devclass; + +DRIVER_MODULE(ocpbus, nexus, ocpbus_driver, ocpbus_devclass, 0, 0); + +static int +ocpbus_probe(device_t dev) +{ + char desc[80]; + phandle_t node; + + node = ofw_bus_get_node(dev); + + /* We want parent node named "builtin" */ + if (OF_child(node) == 0) return (ENXIO); + if (strcmp(ofw_bus_get_name(dev), "builtin") != 0) + return (ENXIO); + + snprintf(desc, 79, "Generic Open Firmware bus device \"%s\"", + ofw_bus_get_name(dev)); + device_set_desc_copy(dev, desc); + + return (BUS_PROBE_GENERIC); +} + +static int +ocpbus_attach(device_t dev) +{ + phandle_t node, child; + device_t cdev; + struct ocpbus_devinfo *dinfo; + struct ocpbus_softc *sc; + u_int reg[2]; + u_int error; + + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + + /* + * Locate the device node and its base address + */ + sc->sc_node = node; + + OF_getprop(node, "reg", reg, sizeof(reg)); + + sc->sc_base = reg[0]; /* F0000000 */ + sc->sc_size = reg[1]; /* C000 */ + + sc->sc_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_mem_rman.rm_descr = "Efika IO Device Memory"; + error = rman_init(&sc->sc_mem_rman); + if (error) { + device_printf(dev, "rman_init() failed. error = %d\n", error); + return (error); + } + error = rman_manage_region(&sc->sc_mem_rman, sc->sc_base, + sc->sc_base + sc->sc_size); + if (error) { + device_printf(dev,"rman_manage_region() failed. error = %d\n", + error); + return (error); + } + + /* + * Walk the OCP tree to locate child devices + */ + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + if (child == -1) + panic("ocpbus_attach(): OF_child failed.\n"); + + dinfo = malloc(sizeof(struct ocpbus_devinfo), M_OCPBUS, + M_WAITOK); + if (ofw_bus_gen_setup_devinfo(&dinfo->odi_obdinfo, child) != 0) { + device_printf(dev, + "ocpbus_attach: gen_setup_devinfo failed\n"); + free(dinfo, M_OCPBUS); + continue; + } + resource_list_init(&dinfo->odi_resources); + ocpbus_add_reg(child, dinfo); + ocpbus_add_intr(child,dinfo); + + cdev = device_add_child(dev, NULL, -1); + if (cdev == NULL) { + device_printf(dev, "<%s>: device_add_child failed\n", + dinfo->odi_obdinfo.obd_name); + resource_list_free(&dinfo->odi_resources); + ofw_bus_gen_destroy_devinfo(&dinfo->odi_obdinfo); + free(dinfo, M_OCPBUS); + continue; + } + device_set_ivars(cdev, dinfo); + } + + return (bus_generic_attach(dev)); +} + +static void +ocpbus_add_intr(phandle_t devnode, struct ocpbus_devinfo *dinfo) +{ + int *intr, nintr; + + nintr = OF_getprop_alloc(devnode, "interrupts", sizeof(*intr), + (void **)&intr); + if (nintr < 3) + return; + if (intr[0] == -1) + return; + + /* 4 critical ints, 17 main ints, 24 peripheral ints + 32 sdma requestors */ + switch (intr[0]) { /* crit 0 - 3 */ + case 1: + /* main 4 - 20 */ + intr[1] += 4; + break; + case 2: + /* peri 21 - 44 */ + intr[1] += 21; + break; + case 3: + /* sdma 64 - 95 */ + intr[1] += 64; + break; + } + + resource_list_add(&dinfo->odi_resources, SYS_RES_IRQ, 0, intr[1], + intr[1], 1); +} + +static void +ocpbus_add_reg(phandle_t devnode, struct ocpbus_devinfo *dinfo) +{ + struct ocpbus_reg *reg; + int i, nreg; + + nreg = OF_getprop_alloc(devnode, "reg", sizeof(*reg), (void **)®); + if (nreg == -1) + return; + + for (i = 0; i < nreg; i++) { + if (bootverbose) + printf("ocpbus_add_reg: <%s>: base: %#X, size: %d\n", + dinfo->odi_obdinfo.obd_name,reg[i].or_base, + reg[i].or_size); + + resource_list_add(&dinfo->odi_resources, SYS_RES_MEMORY, i, + reg[i].or_base, reg[i].or_base + reg[i].or_size - 1, + reg[i].or_size); + } +} + +static struct resource * +ocpbus_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct ocpbus_softc *sc; + int needactivate; + struct resource *rv; + struct rman *rm; + u_long adjstart, adjend, adjcount; + struct ocpbus_devinfo *dinfo; + struct resource_list_entry *rle; + + sc = device_get_softc(bus); + dinfo = device_get_ivars(child); + + needactivate = flags & RF_ACTIVE; + flags &= ~RF_ACTIVE; + + switch (type) { + case SYS_RES_MEMORY: + case SYS_RES_IOPORT: + rle = resource_list_find(&dinfo->odi_resources, + SYS_RES_MEMORY, *rid); + if (rle == NULL) { + device_printf(bus, "no rle for %s memory %d\n", + device_get_nameunit(child), *rid); + return (NULL); + } + + if (start < rle->start) + adjstart = rle->start; + else if (start > rle->end) + adjstart = rle->end; + else + adjstart = start; + + if (end < rle->start) + adjend = rle->start; + else if (end > rle->end) + adjend = rle->end; + else + adjend = end; + + adjcount = adjend - adjstart + 1; + rm = &sc->sc_mem_rman; + break; + + case SYS_RES_IRQ: + rle = resource_list_find(&dinfo->odi_resources, + SYS_RES_IRQ,*rid); + + if (rle == NULL) { + device_printf(bus, "no rle for %s \n", + device_get_nameunit(child)); + return (NULL); + } + + return (bus_generic_alloc_resource(bus, child, type, rid, + rle->start, rle->end, rle->count, flags)); + + default: + return (bus_generic_alloc_resource(bus, child, type, rid, + start, end, count, flags)); + } + + if (rm == NULL) { + device_printf(bus, + "failed to reserve resource: rm == NULL\n"); + return (NULL); + } + + rv = rman_reserve_resource(rm, adjstart, adjend, adjcount, + flags, child); + if (rv == NULL) { + device_printf(bus, + "failed to reserve resource %#lx - %#lx (%#lx) for %s\n", + adjstart, adjend, adjcount, device_get_nameunit(child)); + return (NULL); + } + + rman_set_bustag(rv, &bs_be_tag); + rman_set_bushandle(rv,rman_get_start(rv)); + rman_set_rid(rv, *rid); + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv) != 0) { + device_printf(bus, + "failed to activate resource for %s\n", + device_get_nameunit(child)); + rman_release_resource(rv); + return (NULL); + } + } + + return (rv); +} + +static int +ocpbus_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *res) +{ + int error; + + if (rman_get_flags(res) & RF_ACTIVE) { + error = bus_deactivate_resource(child, type, rid, res); + if (error) + return (error); + } + + switch (type) { + case SYS_RES_MEMORY: + case SYS_RES_IOPORT: + return (rman_release_resource(res)); + default: + return (bus_generic_release_resource(dev, child, + type, rid, res)); + } +} + +static void +ocpbus_probe_nomatch(device_t dev, device_t child) +{ + const char *name, *type; + + if (bootverbose) { + name = ofw_bus_get_name(child); + if (name == NULL) + return; + + type = ofw_bus_get_type(child); + if (type == NULL) + type = "(unknown)"; + + device_printf(dev, "<%s>, type %s (no driver attached)\n", + name, type); + } +} + +static const struct ofw_bus_devinfo * +ocpbus_ofw_get_devinfo(device_t bus, device_t dev) +{ + struct ocpbus_devinfo * dinfo; + + dinfo = device_get_ivars(dev); + return (&dinfo->odi_obdinfo); +} + +static int +ocpbus_print_child(device_t dev, device_t child) +{ + int retval = 0; + + retval += bus_print_child_header(dev, child); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static device_t +ocpbus_add_child(device_t dev, int order, const char *name, int unit) +{ + device_t child; + struct ocpbus_devinfo *dinfo; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (NULL); + + dinfo = malloc(sizeof(struct ocpbus_devinfo), M_OCPBUS, + M_NOWAIT | M_ZERO); + if (dinfo == NULL) + return (NULL); + + device_set_ivars(child, dinfo); + + return (child); +} + +static int +ocpbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct ocpbus_devinfo *dinfo; + + if ((dinfo = device_get_ivars(child)) == 0) { + printf(" OCP read ivar error\n"); + return (ENOENT); + } + + switch (which) { + case OCPBUS_IVAR_DEVTYPE: + if (!strcmp(dinfo->odi_obdinfo.obd_type, "serial")) + *result = OCPBUS_DEVTYPE_UART; + break; + default: + return (ENOENT); + } + return (0); +} + +static int +ocpbus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +{ + struct ocpbus_devinfo *dinfo; + + if ((dinfo = device_get_ivars(child)) == 0) + return (ENOENT); + + switch (which) { + default: + return (ENOENT); + } + + return (0); +} diff --git a/sys/powerpc/ofw/ofw_real.c b/sys/powerpc/ofw/ofw_real.c index 2e2f971..f966dc1 100644 --- a/sys/powerpc/ofw/ofw_real.c +++ b/sys/powerpc/ofw/ofw_real.c @@ -78,6 +78,8 @@ __FBSDID("$FreeBSD: src/sys/powerpc/ofw/ofw_real.c,v 1.2 2009/06/11 17:15:20 avg static void ofw_real_init(ofw_t, void *openfirm); static int ofw_real_test(ofw_t, const char *name); +static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, + unsigned long *returns); static phandle_t ofw_real_peer(ofw_t, phandle_t node); static phandle_t ofw_real_child(ofw_t, phandle_t node); static phandle_t ofw_real_parent(ofw_t, phandle_t node); @@ -126,6 +128,7 @@ static ofw_method_t ofw_real_methods[] = { OFWMETHOD(ofw_test, ofw_real_test), OFWMETHOD(ofw_call_method, ofw_real_call_method), + OFWMETHOD(ofw_interpret, ofw_real_interpret), OFWMETHOD(ofw_open, ofw_real_open), OFWMETHOD(ofw_close, ofw_real_close), OFWMETHOD(ofw_read, ofw_real_read), @@ -261,7 +264,7 @@ ofw_real_init(ofw_t ofw, void *openfirm) { openfirmware = (int (*)(void *))openfirm; - mtx_init(&of_bounce_mtx, "OF Bounce Page", MTX_DEF, 0); + mtx_init(&of_bounce_mtx, "OF Bounce Page", NULL, MTX_DEF); of_bounce_virt = NULL; } @@ -296,6 +299,36 @@ ofw_real_test(ofw_t ofw, const char *name) return (args.missing); } +static int +ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, + unsigned long *returns) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t slot[16]; + } args = { + (cell_t)"interpret", + 1, + }; + + cell_t status; + int i = 0, j = 0; + + args.nreturns = ++nreturns; + args.slot[i++] = (cell_t)cmd; + if (openfirmware(&args) == -1) + return (-1); + + status = args.slot[i++]; + while (i < 1 + nreturns) + returns[j++] = args.slot[i++]; + + return (status); +} + + /* * Device tree functions */ diff --git a/sys/powerpc/powerpc/bus_machdep.c b/sys/powerpc/powerpc/bus_machdep.c index 6ef3f35..7d1973f 100644 --- a/sys/powerpc/powerpc/bus_machdep.c +++ b/sys/powerpc/powerpc/bus_machdep.c @@ -99,9 +99,6 @@ bs_remap_earlyboot(void) int i; vm_offset_t pa, spa; - if (hw_direct_map) - return; - for (i = 0; i < earlyboot_map_idx; i++) { spa = earlyboot_mappings[i].addr; diff --git a/sys/powerpc/powerpc/cpu.c b/sys/powerpc/powerpc/cpu.c index d0d54a6..fc390bd 100644 --- a/sys/powerpc/powerpc/cpu.c +++ b/sys/powerpc/powerpc/cpu.c @@ -104,8 +104,13 @@ static const struct cputab models[] = { { "Motorola PowerPC 7447A", MPC7447A, REVFMT_MAJMIN }, { "Motorola PowerPC 7448", MPC7448, REVFMT_MAJMIN }, { "Motorola PowerPC 8240", MPC8240, REVFMT_MAJMIN }, + { "Freescale e300c1 core", FSL_E300c1, REVFMT_MAJMIN }, + { "Freescale e300c2 core", FSL_E300c2, REVFMT_MAJMIN }, + { "Freescale e300c3 core", FSL_E300c3, REVFMT_MAJMIN }, + { "Freescale e300c4 core", FSL_E300c4, REVFMT_MAJMIN }, { "Freescale e500v1 core", FSL_E500v1, REVFMT_MAJMIN }, { "Freescale e500v2 core", FSL_E500v2, REVFMT_MAJMIN }, + { "Freescale G2_LE core", FSL_G2LE, REVFMT_MAJMIN }, { "Unknown PowerPC CPU", 0, REVFMT_HEX } }; @@ -135,8 +140,13 @@ cpu_setup(u_int cpuid) min = (pvr >> 0) & 0xff; maj = min <= 4 ? 1 : 2; break; + case FSL_E300c1: + case FSL_E300c2: + case FSL_E300c3: + case FSL_E300c4: case FSL_E500v1: case FSL_E500v2: + case FSL_G2LE: maj = (pvr >> 4) & 0xf; min = (pvr >> 0) & 0xf; break; @@ -236,6 +246,7 @@ cpu_setup(u_int cpuid) } mtspr(SPR_HID0, hid0); + __asm __volatile("isync"); switch (vers) { case MPC7447A: