Index: head/sys/arm/arm/ofw_machdep.c =================================================================== --- head/sys/arm/arm/ofw_machdep.c (revision 295661) +++ head/sys/arm/arm/ofw_machdep.c (revision 295662) @@ -1,71 +1,75 @@ /*- * Copyright (c) 2015 Ian Lepore * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include int OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, - bus_space_handle_t *handle) + bus_space_handle_t *handle, bus_size_t *sz) { bus_addr_t addr; bus_size_t size; pcell_t pci_hi; int flags, res; res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); if (res < 0) return (res); /* * Nothing special to do for PCI busses right now. * This may need to be handled per-platform when it does come up. */ #ifdef notyet if (pci_hi == OFW_PADDR_NOT_PCI) { *tag = fdtbus_bs_tag; flags = 0; } else { *tag = fdtbus_bs_tag; flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? BUS_SPACE_MAP_PREFETCHABLE: 0; } #else *tag = fdtbus_bs_tag; flags = 0; #endif + + if (sz != NULL) + *sz = size; + return (bus_space_map(*tag, addr, size, flags, handle)); } Index: head/sys/arm64/arm64/ofw_machdep.c =================================================================== --- head/sys/arm64/arm64/ofw_machdep.c (revision 295661) +++ head/sys/arm64/arm64/ofw_machdep.c (revision 295662) @@ -1,54 +1,58 @@ /*- * Copyright (c) 2015 Ian Lepore * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include extern struct bus_space memmap_bus; int OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, - bus_space_handle_t *handle) + bus_space_handle_t *handle, bus_size_t *sz) { bus_addr_t addr; bus_size_t size; int err; err = ofw_reg_to_paddr(dev, regno, &addr, &size, NULL); if (err != 0) return (err); *tag = &memmap_bus; + + if (sz != NULL) + *sz = size; + return (bus_space_map(*tag, addr, size, 0, handle)); } Index: head/sys/dev/ofw/openfirm.h =================================================================== --- head/sys/dev/ofw/openfirm.h (revision 295661) +++ head/sys/dev/ofw/openfirm.h (revision 295662) @@ -1,183 +1,183 @@ /* $NetBSD: openfirm.h,v 1.1 1998/05/15 10:16:00 tsubai Exp $ */ /*- * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * 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 TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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) 2000 Benno Rice. * 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 Benno Rice ``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 TOOLS GMBH 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. * * $FreeBSD$ */ #ifndef _DEV_OPENFIRM_H_ #define _DEV_OPENFIRM_H_ #include #include /* * Prototypes for Open Firmware Interface Routines */ typedef uint32_t ihandle_t; typedef uint32_t phandle_t; typedef uint32_t pcell_t; #ifdef _KERNEL #include #include MALLOC_DECLARE(M_OFWPROP); /* * Open Firmware interface initialization. OF_install installs the named * interface as the Open Firmware access mechanism, OF_init initializes it. */ boolean_t OF_install(char *name, int prio); int OF_init(void *cookie); /* * Known Open Firmware interface names */ #define OFW_STD_DIRECT "ofw_std" /* Standard OF interface */ #define OFW_STD_REAL "ofw_real" /* Real-mode OF interface */ #define OFW_STD_32BIT "ofw_32bit" /* 32-bit OF interface */ #define OFW_FDT "ofw_fdt" /* Flattened Device Tree */ /* Generic functions */ int OF_test(const char *name); void OF_printf(const char *fmt, ...); /* Device tree functions */ phandle_t OF_peer(phandle_t node); phandle_t OF_child(phandle_t node); phandle_t OF_parent(phandle_t node); ssize_t OF_getproplen(phandle_t node, const char *propname); ssize_t OF_getprop(phandle_t node, const char *propname, void *buf, size_t len); ssize_t OF_getencprop(phandle_t node, const char *prop, pcell_t *buf, size_t len); /* Same as getprop, but maintains endianness */ int OF_hasprop(phandle_t node, const char *propname); ssize_t OF_searchprop(phandle_t node, const char *propname, void *buf, size_t len); ssize_t OF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len); ssize_t OF_getprop_alloc(phandle_t node, const char *propname, int elsz, void **buf); ssize_t OF_getencprop_alloc(phandle_t node, const char *propname, int elsz, void **buf); int OF_nextprop(phandle_t node, const char *propname, char *buf, size_t len); int OF_setprop(phandle_t node, const char *name, const void *buf, size_t len); ssize_t OF_canon(const char *path, char *buf, size_t len); phandle_t OF_finddevice(const char *path); ssize_t OF_package_to_path(phandle_t node, char *buf, size_t len); /* * Some OF implementations (IBM, FDT) have a concept of effective phandles * used for device-tree cross-references. Given one of these, returns the * real phandle. If one can't be found (or running on OF implementations * without this property), returns its input. */ phandle_t OF_node_from_xref(phandle_t xref); phandle_t OF_xref_from_node(phandle_t node); /* * When properties contain references to other nodes using xref handles it is * often necessary to use interfaces provided by the driver for the referenced * instance. These routines allow a driver that provides such an interface to * register its association with an xref handle, and for other drivers to obtain * the device_t associated with an xref handle. */ device_t OF_device_from_xref(phandle_t xref); phandle_t OF_xref_from_device(device_t dev); int OF_device_register_xref(phandle_t xref, device_t dev); /* Device I/O functions */ ihandle_t OF_open(const char *path); void OF_close(ihandle_t instance); ssize_t OF_read(ihandle_t instance, void *buf, size_t len); ssize_t OF_write(ihandle_t instance, const void *buf, size_t len); int OF_seek(ihandle_t instance, uint64_t where); phandle_t OF_instance_to_package(ihandle_t instance); ssize_t OF_instance_to_path(ihandle_t instance, char *buf, size_t len); int OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns, ...); /* Memory functions */ void *OF_claim(void *virtrequest, size_t size, u_int align); void OF_release(void *virt, size_t size); /* Control transfer functions */ void OF_enter(void); void OF_exit(void) __attribute__((noreturn)); /* User interface functions */ int OF_interpret(const char *cmd, int nreturns, ...); /* * Decode the Nth register property of the given device node and create a bus * space tag and handle for accessing it. This is for use in setting up things * like early console output before newbus is available. The implementation is * machine-dependent, and sparc uses a different function signature as well. */ #ifndef __sparc64__ int OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *ptag, - bus_space_handle_t *phandle); + bus_space_handle_t *phandle, bus_size_t *sz); #endif #endif /* _KERNEL */ #endif /* _DEV_OPENFIRM_H_ */ Index: head/sys/dev/tsec/if_tsec_fdt.c =================================================================== --- head/sys/dev/tsec/if_tsec_fdt.c (revision 295661) +++ head/sys/dev/tsec/if_tsec_fdt.c (revision 295662) @@ -1,353 +1,353 @@ /*- * Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski * Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski * 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. * * From: FreeBSD: head/sys/dev/tsec/if_tsec_ocp.c 188712 2009-02-17 14:59:47Z raj */ /* * FDT 'simple-bus' attachment for Freescale TSEC controller. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miibus_if.h" #define TSEC_RID_TXIRQ 0 #define TSEC_RID_RXIRQ 1 #define TSEC_RID_ERRIRQ 2 static int tsec_fdt_probe(device_t dev); static int tsec_fdt_attach(device_t dev); static int tsec_fdt_detach(device_t dev); static int tsec_setup_intr(struct tsec_softc *sc, struct resource **ires, void **ihand, int *irid, driver_intr_t handler, const char *iname); static void tsec_release_intr(struct tsec_softc *sc, struct resource *ires, void *ihand, int irid, const char *iname); static device_method_t tsec_methods[] = { /* Device interface */ DEVMETHOD(device_probe, tsec_fdt_probe), DEVMETHOD(device_attach, tsec_fdt_attach), DEVMETHOD(device_detach, tsec_fdt_detach), DEVMETHOD(device_shutdown, tsec_shutdown), DEVMETHOD(device_suspend, tsec_suspend), DEVMETHOD(device_resume, tsec_resume), /* MII interface */ DEVMETHOD(miibus_readreg, tsec_miibus_readreg), DEVMETHOD(miibus_writereg, tsec_miibus_writereg), DEVMETHOD(miibus_statchg, tsec_miibus_statchg), DEVMETHOD_END }; static driver_t tsec_fdt_driver = { "tsec", tsec_methods, sizeof(struct tsec_softc), }; DRIVER_MODULE(tsec, simplebus, tsec_fdt_driver, tsec_devclass, 0, 0); static int tsec_fdt_probe(device_t dev) { struct tsec_softc *sc; uint32_t id; if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev), "network") != 0) return (ENXIO); if (!ofw_bus_is_compatible(dev, "gianfar")) return (ENXIO); sc = device_get_softc(dev); sc->sc_rrid = 0; sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid, RF_ACTIVE); if (sc->sc_rres == NULL) return (ENXIO); sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); /* Check if we are eTSEC (enhanced TSEC) */ id = TSEC_READ(sc, TSEC_REG_ID); sc->is_etsec = ((id >> 16) == TSEC_ETSEC_ID) ? 1 : 0; id |= TSEC_READ(sc, TSEC_REG_ID2); bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres); if (id == 0) { device_printf(dev, "could not identify TSEC type\n"); return (ENXIO); } if (sc->is_etsec) device_set_desc(dev, "Enhanced Three-Speed Ethernet Controller"); else device_set_desc(dev, "Three-Speed Ethernet Controller"); return (BUS_PROBE_DEFAULT); } static int tsec_fdt_attach(device_t dev) { struct tsec_softc *sc; phandle_t phy; int error = 0; sc = device_get_softc(dev); sc->dev = dev; sc->node = ofw_bus_get_node(dev); /* Get phy address from fdt */ if (OF_getencprop(sc->node, "phy-handle", &phy, sizeof(phy)) <= 0) { device_printf(dev, "PHY not found in device tree"); return (ENXIO); } phy = OF_node_from_xref(phy); - OF_decode_addr(OF_parent(phy), 0, &sc->phy_bst, &sc->phy_bsh); + OF_decode_addr(OF_parent(phy), 0, &sc->phy_bst, &sc->phy_bsh, NULL); OF_getencprop(phy, "reg", &sc->phyaddr, sizeof(sc->phyaddr)); /* Init timer */ callout_init(&sc->tsec_callout, 1); /* Init locks */ mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "TSEC TX lock", MTX_DEF); mtx_init(&sc->receive_lock, device_get_nameunit(dev), "TSEC RX lock", MTX_DEF); mtx_init(&sc->ic_lock, device_get_nameunit(dev), "TSEC IC lock", MTX_DEF); /* Allocate IO memory for TSEC registers */ sc->sc_rrid = 0; sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid, RF_ACTIVE); if (sc->sc_rres == NULL) { device_printf(dev, "could not allocate IO memory range!\n"); goto fail1; } sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); /* TSEC attach */ if (tsec_attach(sc) != 0) { device_printf(dev, "could not be configured\n"); goto fail2; } /* Set up interrupts (TX/RX/ERR) */ sc->sc_transmit_irid = TSEC_RID_TXIRQ; error = tsec_setup_intr(sc, &sc->sc_transmit_ires, &sc->sc_transmit_ihand, &sc->sc_transmit_irid, tsec_transmit_intr, "TX"); if (error) goto fail2; sc->sc_receive_irid = TSEC_RID_RXIRQ; error = tsec_setup_intr(sc, &sc->sc_receive_ires, &sc->sc_receive_ihand, &sc->sc_receive_irid, tsec_receive_intr, "RX"); if (error) goto fail3; sc->sc_error_irid = TSEC_RID_ERRIRQ; error = tsec_setup_intr(sc, &sc->sc_error_ires, &sc->sc_error_ihand, &sc->sc_error_irid, tsec_error_intr, "ERR"); if (error) goto fail4; return (0); fail4: tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand, sc->sc_receive_irid, "RX"); fail3: tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand, sc->sc_transmit_irid, "TX"); fail2: bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres); fail1: mtx_destroy(&sc->receive_lock); mtx_destroy(&sc->transmit_lock); return (ENXIO); } static int tsec_setup_intr(struct tsec_softc *sc, struct resource **ires, void **ihand, int *irid, driver_intr_t handler, const char *iname) { int error; *ires = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, irid, RF_ACTIVE); if (*ires == NULL) { device_printf(sc->dev, "could not allocate %s IRQ\n", iname); return (ENXIO); } error = bus_setup_intr(sc->dev, *ires, INTR_TYPE_NET | INTR_MPSAFE, NULL, handler, sc, ihand); if (error) { device_printf(sc->dev, "failed to set up %s IRQ\n", iname); if (bus_release_resource(sc->dev, SYS_RES_IRQ, *irid, *ires)) device_printf(sc->dev, "could not release %s IRQ\n", iname); *ires = NULL; return (error); } return (0); } static void tsec_release_intr(struct tsec_softc *sc, struct resource *ires, void *ihand, int irid, const char *iname) { int error; if (ires == NULL) return; error = bus_teardown_intr(sc->dev, ires, ihand); if (error) device_printf(sc->dev, "bus_teardown_intr() failed for %s intr" ", error %d\n", iname, error); error = bus_release_resource(sc->dev, SYS_RES_IRQ, irid, ires); if (error) device_printf(sc->dev, "bus_release_resource() failed for %s " "intr, error %d\n", iname, error); } static int tsec_fdt_detach(device_t dev) { struct tsec_softc *sc; int error; sc = device_get_softc(dev); /* Wait for stopping watchdog */ callout_drain(&sc->tsec_callout); /* Stop and release all interrupts */ tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand, sc->sc_transmit_irid, "TX"); tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand, sc->sc_receive_irid, "RX"); tsec_release_intr(sc, sc->sc_error_ires, sc->sc_error_ihand, sc->sc_error_irid, "ERR"); /* TSEC detach */ tsec_detach(sc); /* Free IO memory handler */ if (sc->sc_rres) { error = bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres); if (error) device_printf(dev, "bus_release_resource() failed for" " IO memory, error %d\n", error); } /* Destroy locks */ mtx_destroy(&sc->receive_lock); mtx_destroy(&sc->transmit_lock); mtx_destroy(&sc->ic_lock); return (0); } void tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr) { union { uint32_t reg[2]; uint8_t addr[6]; } hw; int i; hw.reg[0] = hw.reg[1] = 0; /* Retrieve the hardware address from the device tree. */ i = OF_getprop(sc->node, "local-mac-address", (void *)hw.addr, 6); if (i == 6 && (hw.reg[0] != 0 || hw.reg[1] != 0)) { bcopy(hw.addr, addr, 6); return; } /* Also try the mac-address property, which is second-best */ i = OF_getprop(sc->node, "mac-address", (void *)hw.addr, 6); if (i == 6 && (hw.reg[0] != 0 || hw.reg[1] != 0)) { bcopy(hw.addr, addr, 6); return; } /* * Fall back -- use the currently programmed address in the hope that * it was set be firmware... */ hw.reg[0] = TSEC_READ(sc, TSEC_REG_MACSTNADDR1); hw.reg[1] = TSEC_READ(sc, TSEC_REG_MACSTNADDR2); for (i = 0; i < 6; i++) addr[5-i] = hw.addr[i]; } Index: head/sys/dev/uart/uart_cpu_fdt.c =================================================================== --- head/sys/dev/uart/uart_cpu_fdt.c (revision 295661) +++ head/sys/dev/uart/uart_cpu_fdt.c (revision 295662) @@ -1,216 +1,216 @@ /*- * Copyright (c) 2009-2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Semihalf under sponsorship from * the FreeBSD Foundation. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #ifndef __aarch64__ #include #endif #include #include #include #include #include #include #include #ifdef __aarch64__ extern bus_space_tag_t fdtbus_bs_tag; #endif /* * UART console routines. */ bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { if (b1->bst != b2->bst) return (0); if (pmap_kextract(b1->bsh) == 0) return (0); if (pmap_kextract(b2->bsh) == 0) return (0); return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0); } static int phandle_chosen_propdev(phandle_t chosen, const char *name, phandle_t *node) { char buf[64]; if (OF_getprop(chosen, name, buf, sizeof(buf)) <= 0) return (ENXIO); if ((*node = OF_finddevice(buf)) == -1) return (ENXIO); return (0); } static const struct ofw_compat_data * uart_fdt_find_compatible(phandle_t node, const struct ofw_compat_data *cd) { const struct ofw_compat_data *ocd; for (ocd = cd; ocd->ocd_str != NULL; ocd++) { if (fdt_is_compatible(node, ocd->ocd_str)) return (ocd); } return (NULL); } static uintptr_t uart_fdt_find_by_node(phandle_t node, int class_list) { struct ofw_compat_data **cd; const struct ofw_compat_data *ocd; if (class_list) { SET_FOREACH(cd, uart_fdt_class_set) { ocd = uart_fdt_find_compatible(node, *cd); if ((ocd != NULL) && (ocd->ocd_data != 0)) return (ocd->ocd_data); } } else { SET_FOREACH(cd, uart_fdt_class_and_device_set) { ocd = uart_fdt_find_compatible(node, *cd); if ((ocd != NULL) && (ocd->ocd_data != 0)) return (ocd->ocd_data); } } return (0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { const char *propnames[] = {"stdout-path", "linux,stdout-path", "stdout", "stdin-path", "stdin", NULL}; const char **name; struct uart_class *class; phandle_t node, chosen; pcell_t shift, br, rclk; char *cp; int err; uart_bus_space_mem = fdtbus_bs_tag; uart_bus_space_io = NULL; /* Allow overriding the FDT using the environment. */ class = &uart_ns8250_class; err = uart_getenv(devtype, di, class); if (!err) return (0); if (devtype != UART_DEV_CONSOLE) return (ENXIO); /* Has the user forced a specific device node? */ cp = kern_getenv("hw.fdt.console"); if (cp == NULL) { /* * Retrieve /chosen/std{in,out}. */ node = -1; if ((chosen = OF_finddevice("/chosen")) != -1) { for (name = propnames; *name != NULL; name++) { if (phandle_chosen_propdev(chosen, *name, &node) == 0) break; } } if (chosen == -1 || *name == NULL) node = OF_finddevice("serial0"); /* Last ditch */ } else { node = OF_finddevice(cp); } if (node == -1) /* Can't find anything */ return (ENXIO); /* * Check old style of UART definition first. Unfortunately, the common * FDT processing is not possible if we have clock, power domains and * pinmux stuff. */ class = (struct uart_class *)uart_fdt_find_by_node(node, 0); if (class != NULL) { if ((err = uart_fdt_get_clock(node, &rclk)) != 0) return (err); } else { /* Check class only linker set */ class = (struct uart_class *)uart_fdt_find_by_node(node, 1); if (class == NULL) return (ENXIO); rclk = 0; } /* * Retrieve serial attributes. */ if (uart_fdt_get_shift(node, &shift) != 0) shift = uart_getregshift(class); if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0) br = 0; else br = fdt32_to_cpu(br); /* * Finalize configuration. */ di->bas.chan = 0; di->bas.regshft = (u_int)shift; di->baudrate = br; di->bas.rclk = (u_int)rclk; di->ops = uart_getops(class); di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; - return (OF_decode_addr(node, 0, &di->bas.bst, &di->bas.bsh)); + return (OF_decode_addr(node, 0, &di->bas.bst, &di->bas.bsh, NULL)); } Index: head/sys/dev/uart/uart_cpu_powerpc.c =================================================================== --- head/sys/dev/uart/uart_cpu_powerpc.c (revision 295661) +++ head/sys/dev/uart/uart_cpu_powerpc.c (revision 295662) @@ -1,203 +1,203 @@ /*- * Copyright (c) 2006 Marcel Moolenaar * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io = &bs_le_tag; bus_space_tag_t uart_bus_space_mem = &bs_le_tag; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0); } static int ofw_get_uart_console(phandle_t opts, phandle_t *result, const char *inputdev, const char *outputdev) { char buf[64]; phandle_t input; if (OF_getprop(opts, inputdev, buf, sizeof(buf)) == -1) return (ENXIO); input = OF_finddevice(buf); if (input == -1) return (ENXIO); if (outputdev != NULL) { if (OF_getprop(opts, outputdev, buf, sizeof(buf)) == -1) return (ENXIO); if (OF_finddevice(buf) != input) return (ENXIO); } *result = input; return (0); } static int ofw_get_console_phandle_path(phandle_t node, phandle_t *result, const char *prop) { union { char buf[64]; phandle_t ref; } field; phandle_t output; ssize_t size; size = OF_getproplen(node, prop); if (size == -1) return (ENXIO); OF_getprop(node, prop, &field, sizeof(field)); /* This property might be either a ihandle or path. Hooray. */ output = -1; if (field.buf[size - 1] == 0) output = OF_finddevice(field.buf); if (output == -1 && size == 4) output = OF_instance_to_package(field.ref); if (output != -1) { *result = output; return (0); } return (ENXIO); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { char buf[64]; struct uart_class *class; phandle_t input, opts, chosen; int error; opts = OF_finddevice("/options"); chosen = OF_finddevice("/chosen"); switch (devtype) { case UART_DEV_CONSOLE: error = ENXIO; if (chosen != -1 && error != 0) error = ofw_get_uart_console(chosen, &input, "stdout-path", NULL); if (chosen != -1 && error != 0) error = ofw_get_uart_console(chosen, &input, "linux,stdout-path", NULL); if (chosen != -1 && error != 0) error = ofw_get_console_phandle_path(chosen, &input, "stdout"); if (chosen != -1 && error != 0) error = ofw_get_uart_console(chosen, &input, "stdin-path", NULL); if (chosen != -1 && error != 0) error = ofw_get_console_phandle_path(chosen, &input, "stdin"); if (opts != -1 && error != 0) error = ofw_get_uart_console(opts, &input, "input-device", "output-device"); if (opts != -1 && error != 0) error = ofw_get_uart_console(opts, &input, "input-device-1", "output-device-1"); if (error != 0) { input = OF_finddevice("serial0"); /* Last ditch */ if (input == -1) error = (ENXIO); } if (error != 0) return (error); break; case UART_DEV_DBGPORT: if (!getenv_string("hw.uart.dbgport", buf, sizeof(buf))) return (ENXIO); input = OF_finddevice(buf); if (input == -1) return (ENXIO); break; default: return (EINVAL); } if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) return (ENXIO); if (strcmp(buf, "serial") != 0) return (ENXIO); if (OF_getprop(input, "compatible", buf, sizeof(buf)) == -1) return (ENXIO); if (strncmp(buf, "chrp,es", 7) == 0) { class = &uart_z8530_class; di->bas.regshft = 4; di->bas.chan = 1; } else if (strcmp(buf,"ns16550") == 0 || strcmp(buf,"ns8250") == 0) { class = &uart_ns8250_class; di->bas.regshft = 0; di->bas.chan = 0; } else return (ENXIO); if (class == NULL) return (ENXIO); - error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh); + error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh, NULL); if (error) return (error); di->ops = uart_getops(class); if (OF_getprop(input, "clock-frequency", &di->bas.rclk, sizeof(di->bas.rclk)) == -1) di->bas.rclk = 230400; if (OF_getprop(input, "current-speed", &di->baudrate, sizeof(di->baudrate)) == -1) di->baudrate = 0; OF_getprop(input, "reg-shift", &di->bas.regshft, sizeof(di->bas.regshft)); di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; return (0); } Index: head/sys/dev/vt/hw/ofwfb/ofwfb.c =================================================================== --- head/sys/dev/vt/hw/ofwfb/ofwfb.c (revision 295661) +++ head/sys/dev/vt/hw/ofwfb/ofwfb.c (revision 295662) @@ -1,502 +1,503 @@ /*- * Copyright (c) 2011 Nathan Whitehorn * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #ifdef __sparc64__ #include #endif #include #include #include struct ofwfb_softc { struct fb_info fb; phandle_t sc_node; ihandle_t sc_handle; bus_space_tag_t sc_memt; int iso_palette; }; static void ofwfb_initialize(struct vt_device *vd); static vd_probe_t ofwfb_probe; static vd_init_t ofwfb_init; static vd_bitblt_text_t ofwfb_bitblt_text; static vd_bitblt_bmp_t ofwfb_bitblt_bitmap; static const struct vt_driver vt_ofwfb_driver = { .vd_name = "ofwfb", .vd_probe = ofwfb_probe, .vd_init = ofwfb_init, .vd_blank = vt_fb_blank, .vd_bitblt_text = ofwfb_bitblt_text, .vd_bitblt_bmp = ofwfb_bitblt_bitmap, .vd_fb_ioctl = vt_fb_ioctl, .vd_fb_mmap = vt_fb_mmap, .vd_priority = VD_PRIORITY_GENERIC+1, }; static unsigned char ofw_colors[16] = { /* See "16-color Text Extension" Open Firmware document, page 4 */ 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 }; static struct ofwfb_softc ofwfb_conssoftc; VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver); static int ofwfb_probe(struct vt_device *vd) { phandle_t chosen, node; ihandle_t stdout; char type[64]; chosen = OF_finddevice("/chosen"); OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); node = OF_instance_to_package(stdout); if (node == -1) { /* * The "/chosen/stdout" does not exist try * using "screen" directly. */ node = OF_finddevice("screen"); } OF_getprop(node, "device_type", type, sizeof(type)); if (strcmp(type, "display") != 0) return (CN_DEAD); /* Looks OK... */ return (CN_INTERNAL); } static void ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, const uint8_t *pattern, const uint8_t *mask, unsigned int width, unsigned int height, unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) { struct fb_info *sc = vd->vd_softc; u_long line; uint32_t fgc, bgc; int c, l; uint8_t b, m; union { uint32_t l; uint8_t c[4]; } ch1, ch2; #ifdef __powerpc__ /* Deal with unmapped framebuffers */ if (sc->fb_flags & FB_FLAG_NOWRITE) { if (pmap_bootstrapped) { sc->fb_flags &= ~FB_FLAG_NOWRITE; ofwfb_initialize(vd); } else { return; } } #endif fgc = sc->fb_cmap[fg]; bgc = sc->fb_cmap[bg]; b = m = 0; if (((struct ofwfb_softc *)vd->vd_softc)->iso_palette) { fg = ofw_colors[fg]; bg = ofw_colors[bg]; } line = (sc->fb_stride * y) + x * sc->fb_bpp/8; if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) { /* Don't try to put off screen pixels */ if (((x + width) > vd->vd_width) || ((y + height) > vd->vd_height)) return; for (; height > 0; height--) { for (c = 0; c < width; c += 8) { b = *pattern++; /* * Assume that there is more background than * foreground in characters and init accordingly */ ch1.l = ch2.l = (bg << 24) | (bg << 16) | (bg << 8) | bg; /* * Calculate 2 x 4-chars at a time, and then * write these out. */ if (b & 0x80) ch1.c[0] = fg; if (b & 0x40) ch1.c[1] = fg; if (b & 0x20) ch1.c[2] = fg; if (b & 0x10) ch1.c[3] = fg; if (b & 0x08) ch2.c[0] = fg; if (b & 0x04) ch2.c[1] = fg; if (b & 0x02) ch2.c[2] = fg; if (b & 0x01) ch2.c[3] = fg; *(uint32_t *)(sc->fb_vbase + line + c) = ch1.l; *(uint32_t *)(sc->fb_vbase + line + c + 4) = ch2.l; } line += sc->fb_stride; } } else { for (l = 0; l < height && y + l < vw->vw_draw_area.tr_end.tp_row; l++) { for (c = 0; c < width && x + c < vw->vw_draw_area.tr_end.tp_col; c++) { if (c % 8 == 0) b = *pattern++; else b <<= 1; if (mask != NULL) { if (c % 8 == 0) m = *mask++; else m <<= 1; /* Skip pixel write, if mask not set. */ if ((m & 0x80) == 0) continue; } switch(sc->fb_bpp) { case 8: *(uint8_t *)(sc->fb_vbase + line + c) = b & 0x80 ? fg : bg; break; case 32: *(uint32_t *)(sc->fb_vbase + line + 4*c) = (b & 0x80) ? fgc : bgc; break; default: /* panic? */ break; } } line += sc->fb_stride; } } } void ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area) { unsigned int col, row, x, y; struct vt_font *vf; term_char_t c; term_color_t fg, bg; const uint8_t *pattern; vf = vw->vw_font; for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; ++col) { x = col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col; y = row * vf->vf_height + vw->vw_draw_area.tr_begin.tp_row; c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); pattern = vtfont_lookup(vf, c); vt_determine_colors(c, VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); ofwfb_bitblt_bitmap(vd, vw, pattern, NULL, vf->vf_width, vf->vf_height, x, y, fg, bg); } } #ifndef SC_NO_CUTPASTE if (!vd->vd_mshown) return; term_rect_t drawn_area; drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; if (vt_is_cursor_in_area(vd, &drawn_area)) { ofwfb_bitblt_bitmap(vd, vw, vd->vd_mcursor->map, vd->vd_mcursor->mask, vd->vd_mcursor->width, vd->vd_mcursor->height, vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, vd->vd_mcursor_fg, vd->vd_mcursor_bg); } #endif } static void ofwfb_initialize(struct vt_device *vd) { struct ofwfb_softc *sc = vd->vd_softc; int i, err; cell_t retval; uint32_t oldpix; sc->fb.fb_cmsize = 16; if (sc->fb.fb_flags & FB_FLAG_NOWRITE) return; /* * Set up the color map */ sc->iso_palette = 0; switch (sc->fb.fb_bpp) { case 8: vt_generate_cons_palette(sc->fb.fb_cmap, COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); for (i = 0; i < 16; i++) { err = OF_call_method("color!", sc->sc_handle, 4, 1, (cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff), (cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff), (cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff), (cell_t)i, &retval); if (err) break; } if (i != 16) sc->iso_palette = 1; break; case 32: /* * We bypass the usual bus_space_() accessors here, mostly * for performance reasons. In particular, we don't want * any barrier operations that may be performed and handle * endianness slightly different. Figure out the host-view * endianness of the frame buffer. */ oldpix = bus_space_read_4(sc->sc_memt, sc->fb.fb_vbase, 0); bus_space_write_4(sc->sc_memt, sc->fb.fb_vbase, 0, 0xff000000); if (*(uint8_t *)(sc->fb.fb_vbase) == 0xff) vt_generate_cons_palette(sc->fb.fb_cmap, COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); else vt_generate_cons_palette(sc->fb.fb_cmap, COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); bus_space_write_4(sc->sc_memt, sc->fb.fb_vbase, 0, oldpix); break; default: panic("Unknown color space depth %d", sc->fb.fb_bpp); break; } } static int ofwfb_init(struct vt_device *vd) { struct ofwfb_softc *sc; char type[64]; phandle_t chosen; phandle_t node; uint32_t depth, height, width, stride; uint32_t fb_phys; int i, len; #ifdef __sparc64__ static struct bus_space_tag ofwfb_memt[1]; bus_addr_t phys; int space; #endif /* Initialize softc */ vd->vd_softc = sc = &ofwfb_conssoftc; chosen = OF_finddevice("/chosen"); OF_getprop(chosen, "stdout", &sc->sc_handle, sizeof(ihandle_t)); node = OF_instance_to_package(sc->sc_handle); if (node == -1) { /* * The "/chosen/stdout" does not exist try * using "screen" directly. */ node = OF_finddevice("screen"); sc->sc_handle = OF_open("screen"); } OF_getprop(node, "device_type", type, sizeof(type)); if (strcmp(type, "display") != 0) return (CN_DEAD); /* Keep track of the OF node */ sc->sc_node = node; /* * Try to use a 32-bit framebuffer if possible. This may be * unimplemented and fail. That's fine -- it just means we are * stuck with the defaults. */ OF_call_method("set-depth", sc->sc_handle, 1, 1, (cell_t)32, &i); /* Make sure we have needed properties */ if (OF_getproplen(node, "height") != sizeof(height) || OF_getproplen(node, "width") != sizeof(width) || OF_getproplen(node, "depth") != sizeof(depth) || OF_getproplen(node, "linebytes") != sizeof(sc->fb.fb_stride)) return (CN_DEAD); /* Only support 8 and 32-bit framebuffers */ OF_getprop(node, "depth", &depth, sizeof(depth)); if (depth != 8 && depth != 32) return (CN_DEAD); sc->fb.fb_bpp = sc->fb.fb_depth = depth; OF_getprop(node, "height", &height, sizeof(height)); OF_getprop(node, "width", &width, sizeof(width)); OF_getprop(node, "linebytes", &stride, sizeof(stride)); sc->fb.fb_height = height; sc->fb.fb_width = width; sc->fb.fb_stride = stride; sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride; /* * Grab the physical address of the framebuffer, and then map it * into our memory space. If the MMU is not yet up, it will be * remapped for us when relocation turns on. */ if (OF_getproplen(node, "address") == sizeof(fb_phys)) { /* XXX We assume #address-cells is 1 at this point. */ OF_getprop(node, "address", &fb_phys, sizeof(fb_phys)); #if defined(__powerpc__) sc->sc_memt = &bs_be_tag; bus_space_map(sc->sc_memt, fb_phys, sc->fb.fb_size, BUS_SPACE_MAP_PREFETCHABLE, &sc->fb.fb_vbase); #elif defined(__sparc64__) OF_decode_addr(node, 0, &space, &phys); sc->sc_memt = &ofwfb_memt[0]; sc->fb.fb_vbase = sparc64_fake_bustag(space, fb_phys, sc->sc_memt); #elif defined(__arm__) sc->sc_memt = fdtbus_bs_tag; bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size, BUS_SPACE_MAP_PREFETCHABLE, (bus_space_handle_t *)&sc->fb.fb_vbase); #else #error Unsupported platform! #endif sc->fb.fb_pbase = fb_phys; } else { /* * Some IBM systems don't have an address property. Try to * guess the framebuffer region from the assigned addresses. * This is ugly, but there doesn't seem to be an alternative. * Linux does the same thing. */ struct ofw_pci_register pciaddrs[8]; int num_pciaddrs = 0; /* * Get the PCI addresses of the adapter, if present. The node * may be the child of the PCI device: in that case, try the * parent for the assigned-addresses property. */ len = OF_getprop(node, "assigned-addresses", pciaddrs, sizeof(pciaddrs)); if (len == -1) { len = OF_getprop(OF_parent(node), "assigned-addresses", pciaddrs, sizeof(pciaddrs)); } if (len == -1) len = 0; num_pciaddrs = len / sizeof(struct ofw_pci_register); fb_phys = num_pciaddrs; for (i = 0; i < num_pciaddrs; i++) { /* If it is too small, not the framebuffer */ if (pciaddrs[i].size_lo < sc->fb.fb_stride * height) continue; /* If it is not memory, it isn't either */ if (!(pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_SPACE_MEM32)) continue; /* This could be the framebuffer */ fb_phys = i; /* If it is prefetchable, it certainly is */ if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) break; } if (fb_phys == num_pciaddrs) /* No candidates found */ return (CN_DEAD); #if defined(__powerpc__) - OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->fb.fb_vbase); + OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->fb.fb_vbase, + NULL); sc->fb.fb_pbase = sc->fb.fb_vbase; /* 1:1 mapped */ #ifdef __powerpc64__ /* Real mode under a hypervisor probably doesn't cover FB */ if (!(mfmsr() & (PSL_HV | PSL_DR))) sc->fb.fb_flags |= FB_FLAG_NOWRITE; #endif #else /* No ability to interpret assigned-addresses otherwise */ return (CN_DEAD); #endif } ofwfb_initialize(vd); vt_fb_init(vd); return (CN_INTERNAL); } Index: head/sys/mips/mips/ofw_machdep.c =================================================================== --- head/sys/mips/mips/ofw_machdep.c (revision 295661) +++ head/sys/mips/mips/ofw_machdep.c (revision 295662) @@ -1,70 +1,74 @@ /*- * Copyright (c) 2015 Ian Lepore * All rights excluded. * * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include int OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, - bus_space_handle_t *handle) + bus_space_handle_t *handle, bus_size_t *sz) { bus_addr_t addr; bus_size_t size; pcell_t pci_hi; int flags, res; res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); if (res < 0) return (res); /* * Nothing special to do for PCI busses right now. * This may need to be handled per-platform when it does come up. */ #ifdef notyet if (pci_hi == OFW_PADDR_NOT_PCI) { *tag = fdtbus_bs_tag; flags = 0; } else { *tag = fdtbus_bs_tag; flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? BUS_SPACE_MAP_PREFETCHABLE: 0; } #else *tag = fdtbus_bs_tag; flags = 0; #endif + + if (sz != NULL) + *sz = size; + return (bus_space_map(*tag, addr, size, flags, handle)); } Index: head/sys/powerpc/ofw/ofw_machdep.c =================================================================== --- head/sys/powerpc/ofw/ofw_machdep.c (revision 295661) +++ head/sys/powerpc/ofw/ofw_machdep.c (revision 295662) @@ -1,590 +1,593 @@ /*- * Copyright (C) 1996 Wolfgang Solfrank. * Copyright (C) 1996 TooLs GmbH. * 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 TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. * * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void *fdt; int ofw_real_mode; #ifdef AIM extern register_t ofmsr[5]; extern void *openfirmware_entry; char save_trap_init[0x2f00]; /* EXC_LAST */ char save_trap_of[0x2f00]; /* EXC_LAST */ int ofwcall(void *); static int openfirmware(void *args); __inline void ofw_save_trap_vec(char *save_trap_vec) { if (!ofw_real_mode) return; bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST); } static __inline void ofw_restore_trap_vec(char *restore_trap_vec) { if (!ofw_real_mode) return; bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST); __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); } /* * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. */ register_t ofw_sprg0_save; static __inline void ofw_sprg_prepare(void) { if (ofw_real_mode) return; /* * Assume that interrupt are disabled at this point, or * SPRG1-3 could be trashed */ __asm __volatile("mfsprg0 %0\n\t" "mtsprg0 %1\n\t" "mtsprg1 %2\n\t" "mtsprg2 %3\n\t" "mtsprg3 %4\n\t" : "=&r"(ofw_sprg0_save) : "r"(ofmsr[1]), "r"(ofmsr[2]), "r"(ofmsr[3]), "r"(ofmsr[4])); } static __inline void ofw_sprg_restore(void) { if (ofw_real_mode) return; /* * Note that SPRG1-3 contents are irrelevant. They are scratch * registers used in the early portion of trap handling when * interrupts are disabled. * * PCPU data cannot be used until this routine is called ! */ __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); } #endif static int parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) { cell_t address_cells, size_cells; cell_t OFmem[4 * PHYS_AVAIL_SZ]; int sz, i, j; phandle_t phandle; sz = 0; /* * Get #address-cells from root node, defaulting to 1 if it cannot * be found. */ phandle = OF_finddevice("/"); if (OF_getencprop(phandle, "#address-cells", &address_cells, sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) address_cells = 1; if (OF_getencprop(phandle, "#size-cells", &size_cells, sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) size_cells = 1; /* * Get memory. */ if (node == -1 || (sz = OF_getencprop(node, prop, OFmem, sizeof(OFmem))) <= 0) panic("Physical memory map not found"); i = 0; j = 0; while (i < sz/sizeof(cell_t)) { #if !defined(__powerpc64__) && !defined(BOOKE) /* On 32-bit PPC (OEA), ignore regions starting above 4 GB */ if (address_cells > 1 && OFmem[i] > 0) { i += address_cells + size_cells; continue; } #endif output[j].mr_start = OFmem[i++]; if (address_cells == 2) { output[j].mr_start <<= 32; output[j].mr_start += OFmem[i++]; } output[j].mr_size = OFmem[i++]; if (size_cells == 2) { output[j].mr_size <<= 32; output[j].mr_size += OFmem[i++]; } #if !defined(__powerpc64__) && !defined(BOOKE) /* Book-E can support 36-bit addresses. */ /* * Check for memory regions extending above 32-bit * memory space, and restrict them to stay there. */ if (((uint64_t)output[j].mr_start + (uint64_t)output[j].mr_size) > BUS_SPACE_MAXADDR_32BIT) { output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - output[j].mr_start; } #endif j++; } sz = j*sizeof(output[0]); return (sz); } static int excise_fdt_reserved(struct mem_region *avail, int asz) { struct { uint64_t address; uint64_t size; } fdtmap[16]; ssize_t fdtmapsize; phandle_t chosen; int i, j, k; chosen = OF_finddevice("/chosen"); fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { fdtmap[j].address = be64toh(fdtmap[j].address); fdtmap[j].size = be64toh(fdtmap[j].size); } for (i = 0; i < asz; i++) { for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { /* * Case 1: Exclusion region encloses complete * available entry. Drop it and move on. */ if (fdtmap[j].address <= avail[i].mr_start && fdtmap[j].address + fdtmap[j].size >= avail[i].mr_start + avail[i].mr_size) { for (k = i+1; k < asz; k++) avail[k-1] = avail[k]; asz--; i--; /* Repeat some entries */ continue; } /* * Case 2: Exclusion region starts in available entry. * Trim it to where the entry begins and append * a new available entry with the region after * the excluded region, if any. */ if (fdtmap[j].address >= avail[i].mr_start && fdtmap[j].address < avail[i].mr_start + avail[i].mr_size) { if (fdtmap[j].address + fdtmap[j].size < avail[i].mr_start + avail[i].mr_size) { avail[asz].mr_start = fdtmap[j].address + fdtmap[j].size; avail[asz].mr_size = avail[i].mr_start + avail[i].mr_size - avail[asz].mr_start; asz++; } avail[i].mr_size = fdtmap[j].address - avail[i].mr_start; } /* * Case 3: Exclusion region ends in available entry. * Move start point to where the exclusion zone ends. * The case of a contained exclusion zone has already * been caught in case 2. */ if (fdtmap[j].address + fdtmap[j].size >= avail[i].mr_start && fdtmap[j].address + fdtmap[j].size < avail[i].mr_start + avail[i].mr_size) { avail[i].mr_size += avail[i].mr_start; avail[i].mr_start = fdtmap[j].address + fdtmap[j].size; avail[i].mr_size -= avail[i].mr_start; } } } return (asz); } /* * This is called during powerpc_init, before the system is really initialized. * It shall provide the total and the available regions of RAM. * The available regions need not take the kernel into account. */ void ofw_mem_regions(struct mem_region *memp, int *memsz, struct mem_region *availp, int *availsz) { phandle_t phandle; int asz, msz; int res; char name[31]; asz = msz = 0; /* * Get memory from all the /memory nodes. */ for (phandle = OF_child(OF_peer(0)); phandle != 0; phandle = OF_peer(phandle)) { if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) continue; if (strncmp(name, "memory", sizeof(name)) != 0 && strncmp(name, "memory@", strlen("memory@")) != 0) continue; res = parse_ofw_memory(phandle, "reg", &memp[msz]); msz += res/sizeof(struct mem_region); if (OF_getproplen(phandle, "available") >= 0) res = parse_ofw_memory(phandle, "available", &availp[asz]); else res = parse_ofw_memory(phandle, "reg", &availp[asz]); asz += res/sizeof(struct mem_region); } phandle = OF_finddevice("/chosen"); if (OF_hasprop(phandle, "fdtmemreserv")) asz = excise_fdt_reserved(availp, asz); *memsz = msz; *availsz = asz; } void OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) { #ifdef AIM ofmsr[0] = mfmsr(); #ifdef __powerpc64__ ofmsr[0] &= ~PSL_SF; #endif __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); openfirmware_entry = openfirm; if (ofmsr[0] & PSL_DR) ofw_real_mode = 0; else ofw_real_mode = 1; ofw_save_trap_vec(save_trap_init); #else ofw_real_mode = 1; #endif fdt = fdt_ptr; #ifdef FDT_DTB_STATIC /* Check for a statically included blob */ if (fdt == NULL) fdt = &fdt_static_dtb; #endif } boolean_t OF_bootstrap() { boolean_t status = FALSE; #ifdef AIM if (openfirmware_entry != NULL) { if (ofw_real_mode) { status = OF_install(OFW_STD_REAL, 0); } else { #ifdef __powerpc64__ status = OF_install(OFW_STD_32BIT, 0); #else status = OF_install(OFW_STD_DIRECT, 0); #endif } if (status != TRUE) return status; OF_init(openfirmware); } else #endif if (fdt != NULL) { status = OF_install(OFW_FDT, 0); if (status != TRUE) return status; OF_init(fdt); OF_interpret("perform-fixup", 0); } return (status); } #ifdef AIM void ofw_quiesce(void) { struct { cell_t name; cell_t nargs; cell_t nreturns; } args; KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); args.name = (cell_t)(uintptr_t)"quiesce"; args.nargs = 0; args.nreturns = 0; openfirmware(&args); } static int openfirmware_core(void *args) { int result; register_t oldmsr; if (openfirmware_entry == NULL) return (-1); /* * Turn off exceptions - we really don't want to end up * anywhere unexpected with PCPU set to something strange * or the stack pointer wrong. */ oldmsr = intr_disable(); ofw_sprg_prepare(); /* Save trap vectors */ ofw_save_trap_vec(save_trap_of); /* Restore initially saved trap vectors */ ofw_restore_trap_vec(save_trap_init); #if defined(AIM) && !defined(__powerpc64__) /* * Clear battable[] translations */ if (!(cpu_features & PPC_FEATURE_64)) __asm __volatile("mtdbatu 2, %0\n" "mtdbatu 3, %0" : : "r" (0)); isync(); #endif result = ofwcall(args); /* Restore trap vecotrs */ ofw_restore_trap_vec(save_trap_of); ofw_sprg_restore(); intr_restore(oldmsr); return (result); } #ifdef SMP struct ofw_rv_args { void *args; int retval; volatile int in_progress; }; static void ofw_rendezvous_dispatch(void *xargs) { struct ofw_rv_args *rv_args = xargs; /* NOTE: Interrupts are disabled here */ if (PCPU_GET(cpuid) == 0) { /* * Execute all OF calls on CPU 0 */ rv_args->retval = openfirmware_core(rv_args->args); rv_args->in_progress = 0; } else { /* * Spin with interrupts off on other CPUs while OF has * control of the machine. */ while (rv_args->in_progress) cpu_spinwait(); } } #endif static int openfirmware(void *args) { int result; #ifdef SMP struct ofw_rv_args rv_args; #endif if (openfirmware_entry == NULL) return (-1); #ifdef SMP rv_args.args = args; rv_args.in_progress = 1; smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, smp_no_rendevous_barrier, &rv_args); result = rv_args.retval; #else result = openfirmware_core(args); #endif return (result); } void OF_reboot() { struct { cell_t name; cell_t nargs; cell_t nreturns; cell_t arg; } args; args.name = (cell_t)(uintptr_t)"interpret"; args.nargs = 1; args.nreturns = 0; args.arg = (cell_t)(uintptr_t)"reset-all"; openfirmware_core(&args); /* Don't do rendezvous! */ for (;;); /* just in case */ } #endif /* AIM */ void OF_getetheraddr(device_t dev, u_char *addr) { phandle_t node; node = ofw_bus_get_node(dev); OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); } /* * Return a bus handle and bus tag that corresponds to the register * numbered regno for the device referenced by the package handle * dev. This function is intended to be used by console drivers in * early boot only. It works by mapping the address of the device's * register in the address space of its parent and recursively walk * the device tree upward this way. */ int OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, - bus_space_handle_t *handle) + bus_space_handle_t *handle, bus_size_t *sz) { bus_addr_t addr; bus_size_t size; pcell_t pci_hi; int flags, res; res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); if (res < 0) return (res); if (pci_hi == OFW_PADDR_NOT_PCI) { *tag = &bs_be_tag; flags = 0; } else { *tag = &bs_le_tag; flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? BUS_SPACE_MAP_PREFETCHABLE: 0; } + + if (sz != NULL) + *sz = size; return (bus_space_map(*tag, addr, size, flags, handle)); } Index: head/sys/powerpc/ofw/ofw_syscons.c =================================================================== --- head/sys/powerpc/ofw/ofw_syscons.c (revision 295661) +++ head/sys/powerpc/ofw/ofw_syscons.c (revision 295662) @@ -1,1102 +1,1102 @@ /*- * Copyright (c) 2003 Peter Grehan * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int ofwfb_ignore_mmap_checks = 1; static int ofwfb_reset_on_switch = 1; static SYSCTL_NODE(_hw, OID_AUTO, ofwfb, CTLFLAG_RD, 0, "ofwfb"); SYSCTL_INT(_hw_ofwfb, OID_AUTO, relax_mmap, CTLFLAG_RW, &ofwfb_ignore_mmap_checks, 0, "relaxed mmap bounds checking"); SYSCTL_INT(_hw_ofwfb, OID_AUTO, reset_on_mode_switch, CTLFLAG_RW, &ofwfb_reset_on_switch, 0, "reset the framebuffer driver on mode switch"); extern u_char dflt_font_16[]; extern u_char dflt_font_14[]; extern u_char dflt_font_8[]; static int ofwfb_configure(int flags); static vi_probe_t ofwfb_probe; static vi_init_t ofwfb_init; static vi_get_info_t ofwfb_get_info; static vi_query_mode_t ofwfb_query_mode; static vi_set_mode_t ofwfb_set_mode; static vi_save_font_t ofwfb_save_font; static vi_load_font_t ofwfb_load_font; static vi_show_font_t ofwfb_show_font; static vi_save_palette_t ofwfb_save_palette; static vi_load_palette_t ofwfb_load_palette; static vi_set_border_t ofwfb_set_border; static vi_save_state_t ofwfb_save_state; static vi_load_state_t ofwfb_load_state; static vi_set_win_org_t ofwfb_set_win_org; static vi_read_hw_cursor_t ofwfb_read_hw_cursor; static vi_set_hw_cursor_t ofwfb_set_hw_cursor; static vi_set_hw_cursor_shape_t ofwfb_set_hw_cursor_shape; static vi_blank_display_t ofwfb_blank_display; static vi_mmap_t ofwfb_mmap; static vi_ioctl_t ofwfb_ioctl; static vi_clear_t ofwfb_clear; static vi_fill_rect_t ofwfb_fill_rect; static vi_bitblt_t ofwfb_bitblt; static vi_diag_t ofwfb_diag; static vi_save_cursor_palette_t ofwfb_save_cursor_palette; static vi_load_cursor_palette_t ofwfb_load_cursor_palette; static vi_copy_t ofwfb_copy; static vi_putp_t ofwfb_putp; static vi_putc_t ofwfb_putc; static vi_puts_t ofwfb_puts; static vi_putm_t ofwfb_putm; static video_switch_t ofwfbvidsw = { .probe = ofwfb_probe, .init = ofwfb_init, .get_info = ofwfb_get_info, .query_mode = ofwfb_query_mode, .set_mode = ofwfb_set_mode, .save_font = ofwfb_save_font, .load_font = ofwfb_load_font, .show_font = ofwfb_show_font, .save_palette = ofwfb_save_palette, .load_palette = ofwfb_load_palette, .set_border = ofwfb_set_border, .save_state = ofwfb_save_state, .load_state = ofwfb_load_state, .set_win_org = ofwfb_set_win_org, .read_hw_cursor = ofwfb_read_hw_cursor, .set_hw_cursor = ofwfb_set_hw_cursor, .set_hw_cursor_shape = ofwfb_set_hw_cursor_shape, .blank_display = ofwfb_blank_display, .mmap = ofwfb_mmap, .ioctl = ofwfb_ioctl, .clear = ofwfb_clear, .fill_rect = ofwfb_fill_rect, .bitblt = ofwfb_bitblt, .diag = ofwfb_diag, .save_cursor_palette = ofwfb_save_cursor_palette, .load_cursor_palette = ofwfb_load_cursor_palette, .copy = ofwfb_copy, .putp = ofwfb_putp, .putc = ofwfb_putc, .puts = ofwfb_puts, .putm = ofwfb_putm, }; /* * bitmap depth-specific routines */ static vi_blank_display_t ofwfb_blank_display8; static vi_putc_t ofwfb_putc8; static vi_putm_t ofwfb_putm8; static vi_set_border_t ofwfb_set_border8; static vi_blank_display_t ofwfb_blank_display32; static vi_putc_t ofwfb_putc32; static vi_putm_t ofwfb_putm32; static vi_set_border_t ofwfb_set_border32; VIDEO_DRIVER(ofwfb, ofwfbvidsw, ofwfb_configure); extern sc_rndr_sw_t txtrndrsw; RENDERER(ofwfb, 0, txtrndrsw, gfb_set); RENDERER_MODULE(ofwfb, gfb_set); /* * Define the iso6429-1983 colormap */ static struct { uint8_t red; uint8_t green; uint8_t blue; } ofwfb_cmap[16] = { /* # R G B Color */ /* - - - - ----- */ { 0x00, 0x00, 0x00 }, /* 0 0 0 0 Black */ { 0x00, 0x00, 0xaa }, /* 1 0 0 2/3 Blue */ { 0x00, 0xaa, 0x00 }, /* 2 0 2/3 0 Green */ { 0x00, 0xaa, 0xaa }, /* 3 0 2/3 2/3 Cyan */ { 0xaa, 0x00, 0x00 }, /* 4 2/3 0 0 Red */ { 0xaa, 0x00, 0xaa }, /* 5 2/3 0 2/3 Magenta */ { 0xaa, 0x55, 0x00 }, /* 6 2/3 1/3 0 Brown */ { 0xaa, 0xaa, 0xaa }, /* 7 2/3 2/3 2/3 White */ { 0x55, 0x55, 0x55 }, /* 8 1/3 1/3 1/3 Gray */ { 0x55, 0x55, 0xff }, /* 9 1/3 1/3 1 Bright Blue */ { 0x55, 0xff, 0x55 }, /* 10 1/3 1 1/3 Bright Green */ { 0x55, 0xff, 0xff }, /* 11 1/3 1 1 Bright Cyan */ { 0xff, 0x55, 0x55 }, /* 12 1 1/3 1/3 Bright Red */ { 0xff, 0x55, 0xff }, /* 13 1 1/3 1 Bright Magenta */ { 0xff, 0xff, 0x80 }, /* 14 1 1 1/3 Bright Yellow */ { 0xff, 0xff, 0xff } /* 15 1 1 1 Bright White */ }; #define TODO printf("%s: unimplemented\n", __func__) static u_int16_t ofwfb_static_window[ROW*COL]; static struct ofwfb_softc ofwfb_softc; static __inline int ofwfb_background(uint8_t attr) { return (attr >> 4); } static __inline int ofwfb_foreground(uint8_t attr) { return (attr & 0x0f); } static u_int ofwfb_pix32(struct ofwfb_softc *sc, int attr) { u_int retval; if (sc->sc_tag == &bs_le_tag) retval = (ofwfb_cmap[attr].red << 16) | (ofwfb_cmap[attr].green << 8) | ofwfb_cmap[attr].blue; else retval = (ofwfb_cmap[attr].blue << 16) | (ofwfb_cmap[attr].green << 8) | ofwfb_cmap[attr].red; return (retval); } static int ofwfb_configure(int flags) { struct ofwfb_softc *sc; phandle_t chosen; ihandle_t stdout; phandle_t node; uint32_t fb_phys; int depth; int disable; int len; int i; char type[16]; static int done = 0; disable = 0; TUNABLE_INT_FETCH("hw.syscons.disable", &disable); if (disable != 0) return (0); if (done != 0) return (0); done = 1; sc = &ofwfb_softc; chosen = OF_finddevice("/chosen"); OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); node = OF_instance_to_package(stdout); if (node == -1) { /* * The "/chosen/stdout" does not exist try * using "screen" directly. */ node = OF_finddevice("screen"); } OF_getprop(node, "device_type", type, sizeof(type)); if (strcmp(type, "display") != 0) return (0); /* Only support 8 and 32-bit framebuffers */ OF_getprop(node, "depth", &depth, sizeof(depth)); if (depth == 8) { sc->sc_blank = ofwfb_blank_display8; sc->sc_putc = ofwfb_putc8; sc->sc_putm = ofwfb_putm8; sc->sc_set_border = ofwfb_set_border8; } else if (depth == 32) { sc->sc_blank = ofwfb_blank_display32; sc->sc_putc = ofwfb_putc32; sc->sc_putm = ofwfb_putm32; sc->sc_set_border = ofwfb_set_border32; } else return (0); if (OF_getproplen(node, "height") != sizeof(sc->sc_height) || OF_getproplen(node, "width") != sizeof(sc->sc_width) || OF_getproplen(node, "linebytes") != sizeof(sc->sc_stride)) return (0); sc->sc_depth = depth; sc->sc_node = node; sc->sc_console = 1; OF_getprop(node, "height", &sc->sc_height, sizeof(sc->sc_height)); OF_getprop(node, "width", &sc->sc_width, sizeof(sc->sc_width)); OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride)); /* * Get the PCI addresses of the adapter. The node may be the * child of the PCI device: in that case, try the parent for * the assigned-addresses property. */ len = OF_getprop(node, "assigned-addresses", sc->sc_pciaddrs, sizeof(sc->sc_pciaddrs)); if (len == -1) { len = OF_getprop(OF_parent(node), "assigned-addresses", sc->sc_pciaddrs, sizeof(sc->sc_pciaddrs)); } if (len == -1) len = 0; sc->sc_num_pciaddrs = len / sizeof(struct ofw_pci_register); /* * Grab the physical address of the framebuffer, and then map it * into our memory space. If the MMU is not yet up, it will be * remapped for us when relocation turns on. * * XXX We assume #address-cells is 1 at this point. */ if (OF_getproplen(node, "address") == sizeof(fb_phys)) { OF_getprop(node, "address", &fb_phys, sizeof(fb_phys)); sc->sc_tag = &bs_be_tag; bus_space_map(sc->sc_tag, fb_phys, sc->sc_height * sc->sc_stride, BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr); } else { /* * Some IBM systems don't have an address property. Try to * guess the framebuffer region from the assigned addresses. * This is ugly, but there doesn't seem to be an alternative. * Linux does the same thing. */ fb_phys = sc->sc_num_pciaddrs; for (i = 0; i < sc->sc_num_pciaddrs; i++) { /* If it is too small, not the framebuffer */ if (sc->sc_pciaddrs[i].size_lo < sc->sc_stride*sc->sc_height) continue; /* If it is not memory, it isn't either */ if (!(sc->sc_pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_SPACE_MEM32)) continue; /* This could be the framebuffer */ fb_phys = i; /* If it is prefetchable, it certainly is */ if (sc->sc_pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) break; } if (fb_phys == sc->sc_num_pciaddrs) return (0); - OF_decode_addr(node, fb_phys, &sc->sc_tag, &sc->sc_addr); + OF_decode_addr(node, fb_phys, &sc->sc_tag, &sc->sc_addr, NULL); } ofwfb_init(0, &sc->sc_va, 0); return (0); } static int ofwfb_probe(int unit, video_adapter_t **adp, void *arg, int flags) { TODO; return (0); } static int ofwfb_init(int unit, video_adapter_t *adp, int flags) { struct ofwfb_softc *sc; video_info_t *vi; int cborder; int font_height; sc = (struct ofwfb_softc *)adp; vi = &adp->va_info; vid_init_struct(adp, "ofwfb", -1, unit); /* The default font size can be overridden by loader */ font_height = 16; TUNABLE_INT_FETCH("hw.syscons.fsize", &font_height); if (font_height == 8) { sc->sc_font = dflt_font_8; sc->sc_font_height = 8; } else if (font_height == 14) { sc->sc_font = dflt_font_14; sc->sc_font_height = 14; } else { /* default is 8x16 */ sc->sc_font = dflt_font_16; sc->sc_font_height = 16; } /* The user can set a border in chars - default is 1 char width */ cborder = 1; TUNABLE_INT_FETCH("hw.syscons.border", &cborder); vi->vi_cheight = sc->sc_font_height; vi->vi_width = sc->sc_width/8 - 2*cborder; vi->vi_height = sc->sc_height/sc->sc_font_height - 2*cborder; vi->vi_cwidth = 8; /* * Clamp width/height to syscons maximums */ if (vi->vi_width > COL) vi->vi_width = COL; if (vi->vi_height > ROW) vi->vi_height = ROW; sc->sc_xmargin = (sc->sc_width - (vi->vi_width * vi->vi_cwidth)) / 2; sc->sc_ymargin = (sc->sc_height - (vi->vi_height * vi->vi_cheight))/2; /* * Avoid huge amounts of conditional code in syscons by * defining a dummy h/w text display buffer. */ adp->va_window = (vm_offset_t) ofwfb_static_window; /* * Enable future font-loading and flag color support, as well as * adding V_ADP_MODECHANGE so that we ofwfb_set_mode() gets called * when the X server shuts down. This enables us to get the console * back when X disappears. */ adp->va_flags |= V_ADP_FONT | V_ADP_COLOR | V_ADP_MODECHANGE; ofwfb_set_mode(&sc->sc_va, 0); vid_register(&sc->sc_va); return (0); } static int ofwfb_get_info(video_adapter_t *adp, int mode, video_info_t *info) { bcopy(&adp->va_info, info, sizeof(*info)); return (0); } static int ofwfb_query_mode(video_adapter_t *adp, video_info_t *info) { TODO; return (0); } static int ofwfb_set_mode(video_adapter_t *adp, int mode) { struct ofwfb_softc *sc; char name[64]; ihandle_t ih; int i, retval; sc = (struct ofwfb_softc *)adp; if (ofwfb_reset_on_switch) { /* * Open the display device, which will initialize it. */ memset(name, 0, sizeof(name)); OF_package_to_path(sc->sc_node, name, sizeof(name)); ih = OF_open(name); if (sc->sc_depth == 8) { /* * Install the ISO6429 colormap - older OFW systems * don't do this by default */ for (i = 0; i < 16; i++) { OF_call_method("color!", ih, 4, 1, ofwfb_cmap[i].red, ofwfb_cmap[i].green, ofwfb_cmap[i].blue, i, &retval); } } } ofwfb_blank_display(&sc->sc_va, V_DISPLAY_ON); return (0); } static int ofwfb_save_font(video_adapter_t *adp, int page, int size, int width, u_char *data, int c, int count) { TODO; return (0); } static int ofwfb_load_font(video_adapter_t *adp, int page, int size, int width, u_char *data, int c, int count) { struct ofwfb_softc *sc; sc = (struct ofwfb_softc *)adp; /* * syscons code has already determined that current width/height * are unchanged for this new font */ sc->sc_font = data; return (0); } static int ofwfb_show_font(video_adapter_t *adp, int page) { return (0); } static int ofwfb_save_palette(video_adapter_t *adp, u_char *palette) { /* TODO; */ return (0); } static int ofwfb_load_palette(video_adapter_t *adp, u_char *palette) { /* TODO; */ return (0); } static int ofwfb_set_border8(video_adapter_t *adp, int border) { struct ofwfb_softc *sc; int i, j; uint8_t *addr; uint8_t bground; sc = (struct ofwfb_softc *)adp; bground = ofwfb_background(border); /* Set top margin */ addr = (uint8_t *) sc->sc_addr; for (i = 0; i < sc->sc_ymargin; i++) { for (j = 0; j < sc->sc_width; j++) { *(addr + j) = bground; } addr += sc->sc_stride; } /* bottom margin */ addr = (uint8_t *) sc->sc_addr + (sc->sc_height - sc->sc_ymargin)*sc->sc_stride; for (i = 0; i < sc->sc_ymargin; i++) { for (j = 0; j < sc->sc_width; j++) { *(addr + j) = bground; } addr += sc->sc_stride; } /* remaining left and right borders */ addr = (uint8_t *) sc->sc_addr + sc->sc_ymargin*sc->sc_stride; for (i = 0; i < sc->sc_height - 2*sc->sc_xmargin; i++) { for (j = 0; j < sc->sc_xmargin; j++) { *(addr + j) = bground; *(addr + j + sc->sc_width - sc->sc_xmargin) = bground; } addr += sc->sc_stride; } return (0); } static int ofwfb_set_border32(video_adapter_t *adp, int border) { /* XXX Be lazy for now and blank entire screen */ return (ofwfb_blank_display32(adp, border)); } static int ofwfb_set_border(video_adapter_t *adp, int border) { struct ofwfb_softc *sc; sc = (struct ofwfb_softc *)adp; return ((*sc->sc_set_border)(adp, border)); } static int ofwfb_save_state(video_adapter_t *adp, void *p, size_t size) { TODO; return (0); } static int ofwfb_load_state(video_adapter_t *adp, void *p) { TODO; return (0); } static int ofwfb_set_win_org(video_adapter_t *adp, off_t offset) { TODO; return (0); } static int ofwfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row) { *col = 0; *row = 0; return (0); } static int ofwfb_set_hw_cursor(video_adapter_t *adp, int col, int row) { return (0); } static int ofwfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, int celsize, int blink) { return (0); } static int ofwfb_blank_display8(video_adapter_t *adp, int mode) { struct ofwfb_softc *sc; int i; uint32_t *addr; uint32_t color; uint32_t end; sc = (struct ofwfb_softc *)adp; addr = (uint32_t *) sc->sc_addr; end = (sc->sc_stride/4) * sc->sc_height; /* Splat 4 pixels at once. */ color = (ofwfb_background(SC_NORM_ATTR) << 24) | (ofwfb_background(SC_NORM_ATTR) << 16) | (ofwfb_background(SC_NORM_ATTR) << 8) | (ofwfb_background(SC_NORM_ATTR)); for (i = 0; i < end; i++) *(addr + i) = color; return (0); } static int ofwfb_blank_display32(video_adapter_t *adp, int mode) { struct ofwfb_softc *sc; int i; uint32_t *addr, blank; sc = (struct ofwfb_softc *)adp; addr = (uint32_t *) sc->sc_addr; blank = ofwfb_pix32(sc, ofwfb_background(SC_NORM_ATTR)); for (i = 0; i < (sc->sc_stride/4)*sc->sc_height; i++) *(addr + i) = blank; return (0); } static int ofwfb_blank_display(video_adapter_t *adp, int mode) { struct ofwfb_softc *sc; sc = (struct ofwfb_softc *)adp; return ((*sc->sc_blank)(adp, mode)); } static int ofwfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) { struct ofwfb_softc *sc; int i; sc = (struct ofwfb_softc *)adp; /* * Make sure the requested address lies within the PCI device's * assigned addrs */ for (i = 0; i < sc->sc_num_pciaddrs; i++) if (offset >= sc->sc_pciaddrs[i].phys_lo && offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo)) { /* * If this is a prefetchable BAR, we can (and should) * enable write-combining. */ if (sc->sc_pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) *memattr = VM_MEMATTR_WRITE_COMBINING; *paddr = offset; return (0); } /* * Hack for Radeon... */ if (ofwfb_ignore_mmap_checks) { *paddr = offset; return (0); } /* * This might be a legacy VGA mem request: if so, just point it at the * framebuffer, since it shouldn't be touched */ if (offset < sc->sc_stride*sc->sc_height) { *paddr = sc->sc_addr + offset; return (0); } /* * Error if we didn't have a better idea. */ if (sc->sc_num_pciaddrs == 0) return (ENOMEM); return (EINVAL); } static int ofwfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) { return (0); } static int ofwfb_clear(video_adapter_t *adp) { TODO; return (0); } static int ofwfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) { TODO; return (0); } static int ofwfb_bitblt(video_adapter_t *adp, ...) { TODO; return (0); } static int ofwfb_diag(video_adapter_t *adp, int level) { TODO; return (0); } static int ofwfb_save_cursor_palette(video_adapter_t *adp, u_char *palette) { TODO; return (0); } static int ofwfb_load_cursor_palette(video_adapter_t *adp, u_char *palette) { TODO; return (0); } static int ofwfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n) { TODO; return (0); } static int ofwfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a, int size, int bpp, int bit_ltor, int byte_ltor) { TODO; return (0); } static int ofwfb_putc8(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) { struct ofwfb_softc *sc; int row; int col; int i; uint32_t *addr; u_char *p, fg, bg; union { uint32_t l; uint8_t c[4]; } ch1, ch2; sc = (struct ofwfb_softc *)adp; row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; p = sc->sc_font + c*sc->sc_font_height; addr = (u_int32_t *)((uintptr_t)sc->sc_addr + (row + sc->sc_ymargin)*sc->sc_stride + col + sc->sc_xmargin); fg = ofwfb_foreground(a); bg = ofwfb_background(a); for (i = 0; i < sc->sc_font_height; i++) { u_char fline = p[i]; /* * Assume that there is more background than foreground * in characters and init accordingly */ ch1.l = ch2.l = (bg << 24) | (bg << 16) | (bg << 8) | bg; /* * Calculate 2 x 4-chars at a time, and then * write these out. */ if (fline & 0x80) ch1.c[0] = fg; if (fline & 0x40) ch1.c[1] = fg; if (fline & 0x20) ch1.c[2] = fg; if (fline & 0x10) ch1.c[3] = fg; if (fline & 0x08) ch2.c[0] = fg; if (fline & 0x04) ch2.c[1] = fg; if (fline & 0x02) ch2.c[2] = fg; if (fline & 0x01) ch2.c[3] = fg; addr[0] = ch1.l; addr[1] = ch2.l; addr += (sc->sc_stride / sizeof(u_int32_t)); } return (0); } static int ofwfb_putc32(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) { struct ofwfb_softc *sc; int row; int col; int i, j, k; uint32_t *addr, fg, bg; u_char *p; sc = (struct ofwfb_softc *)adp; row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight; col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth; p = sc->sc_font + c*sc->sc_font_height; addr = (uint32_t *)sc->sc_addr + (row + sc->sc_ymargin)*(sc->sc_stride/4) + col + sc->sc_xmargin; fg = ofwfb_pix32(sc, ofwfb_foreground(a)); bg = ofwfb_pix32(sc, ofwfb_background(a)); for (i = 0; i < sc->sc_font_height; i++) { for (j = 0, k = 7; j < 8; j++, k--) { if ((p[i] & (1 << k)) == 0) *(addr + j) = bg; else *(addr + j) = fg; } addr += (sc->sc_stride/4); } return (0); } static int ofwfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) { struct ofwfb_softc *sc; sc = (struct ofwfb_softc *)adp; return ((*sc->sc_putc)(adp, off, c, a)); } static int ofwfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len) { int i; for (i = 0; i < len; i++) { ofwfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); } return (0); } static int ofwfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, uint32_t pixel_mask, int size, int width) { struct ofwfb_softc *sc; sc = (struct ofwfb_softc *)adp; return ((*sc->sc_putm)(adp, x, y, pixel_image, pixel_mask, size, width)); } static int ofwfb_putm8(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, uint32_t pixel_mask, int size, int width) { struct ofwfb_softc *sc; int i, j, k; uint8_t *addr; u_char fg, bg; sc = (struct ofwfb_softc *)adp; addr = (u_int8_t *)((uintptr_t)sc->sc_addr + (y + sc->sc_ymargin)*sc->sc_stride + x + sc->sc_xmargin); fg = ofwfb_foreground(SC_NORM_ATTR); bg = ofwfb_background(SC_NORM_ATTR); for (i = 0; i < size && i+y < sc->sc_height - 2*sc->sc_ymargin; i++) { /* * Calculate 2 x 4-chars at a time, and then * write these out. */ for (j = 0, k = width; j < 8; j++, k--) { if (x + j >= sc->sc_width - 2*sc->sc_xmargin) continue; if (pixel_image[i] & (1 << k)) addr[j] = (addr[j] == fg) ? bg : fg; } addr += (sc->sc_stride / sizeof(u_int8_t)); } return (0); } static int ofwfb_putm32(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, uint32_t pixel_mask, int size, int width) { struct ofwfb_softc *sc; int i, j, k; uint32_t fg, bg; uint32_t *addr; sc = (struct ofwfb_softc *)adp; addr = (uint32_t *)sc->sc_addr + (y + sc->sc_ymargin)*(sc->sc_stride/4) + x + sc->sc_xmargin; fg = ofwfb_pix32(sc, ofwfb_foreground(SC_NORM_ATTR)); bg = ofwfb_pix32(sc, ofwfb_background(SC_NORM_ATTR)); for (i = 0; i < size && i+y < sc->sc_height - 2*sc->sc_ymargin; i++) { for (j = 0, k = width; j < 8; j++, k--) { if (x + j >= sc->sc_width - 2*sc->sc_xmargin) continue; if (pixel_image[i] & (1 << k)) *(addr + j) = (*(addr + j) == fg) ? bg : fg; } addr += (sc->sc_stride/4); } return (0); } /* * Define the syscons nexus device attachment */ static void ofwfb_scidentify(driver_t *driver, device_t parent) { device_t child; /* * Add with a priority guaranteed to make it last on * the device list */ child = BUS_ADD_CHILD(parent, INT_MAX, SC_DRIVER_NAME, 0); } static int ofwfb_scprobe(device_t dev) { int error; device_set_desc(dev, "System console"); error = sc_probe_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD); if (error != 0) return (error); /* This is a fake device, so make sure we added it ourselves */ return (BUS_PROBE_NOWILDCARD); } static int ofwfb_scattach(device_t dev) { return (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD)); } static device_method_t ofwfb_sc_methods[] = { DEVMETHOD(device_identify, ofwfb_scidentify), DEVMETHOD(device_probe, ofwfb_scprobe), DEVMETHOD(device_attach, ofwfb_scattach), { 0, 0 } }; static driver_t ofwfb_sc_driver = { SC_DRIVER_NAME, ofwfb_sc_methods, sizeof(sc_softc_t), }; static devclass_t sc_devclass; DRIVER_MODULE(ofwfb, nexus, ofwfb_sc_driver, sc_devclass, 0, 0); /* * Define a stub keyboard driver in case one hasn't been * compiled into the kernel */ #include #include static int dummy_kbd_configure(int flags); keyboard_switch_t dummysw; static int dummy_kbd_configure(int flags) { return (0); } KEYBOARD_DRIVER(dummy, dummysw, dummy_kbd_configure); /* * Utility routines from */ void ofwfb_bcopy(const void *s, void *d, size_t c) { bcopy(s, d, c); } void ofwfb_bzero(void *d, size_t c) { bzero(d, c); } void ofwfb_fillw(int pat, void *base, size_t cnt) { u_int16_t *bptr = base; while (cnt--) *bptr++ = pat; } u_int16_t ofwfb_readw(u_int16_t *addr) { return (*addr); } void ofwfb_writew(u_int16_t *addr, u_int16_t val) { *addr = val; }