Index: head/sys/arm/allwinner/a20/a20_mp.c =================================================================== --- head/sys/arm/allwinner/a20/a20_mp.c (revision 281091) +++ head/sys/arm/allwinner/a20/a20_mp.c (revision 281092) @@ -1,158 +1,161 @@ /*- * Copyright (c) 2014 Ganbold Tsagaankhuu * 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 + #include #include #include #define CPUCFG_BASE 0x01c25c00 #define CPUCFG_SIZE 0x400 #define CPU0_RST_CTL 0x40 #define CPU0_CTL 0x44 #define CPU0_STATUS 0x48 #define CPU1_RST_CTL 0x80 #define CPU1_CTL 0x84 #define CPU1_STATUS 0x88 #define CPUCFG_GENCTL 0x184 #define CPUCFG_P_REG0 0x1a4 #define CPU1_PWR_CLAMP 0x1b0 #define CPU1_PWROFF_REG 0x1b4 #define CPUCFG_DBGCTL0 0x1e0 #define CPUCFG_DBGCTL1 0x1e4 void platform_mp_init_secondary(void) { arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { int ncpu; if (mp_ncpus != 0) return; /* Read current CP15 Cache Size ID Register */ __asm __volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (ncpu)); ncpu = ((ncpu >> 24) & 0x3) + 1; mp_ncpus = ncpu; mp_maxid = ncpu - 1; } int platform_mp_probe(void) { if (mp_ncpus == 0) platform_mp_setmaxid(); return (mp_ncpus > 1); } void platform_mp_start_ap(void) { bus_space_handle_t cpucfg; uint32_t val; if (bus_space_map(fdtbus_bs_tag, CPUCFG_BASE, CPUCFG_SIZE, 0, &cpucfg) != 0) panic("Couldn't map the CPUCFG\n"); cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_P_REG0, pmap_kextract((vm_offset_t)mpentry)); /* * Assert nCOREPORESET low and set L1RSTDISABLE low. * Ensure DBGPWRDUP is set to LOW to prevent any external * debug access to the processor. */ bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_RST_CTL, 0); /* Set L1RSTDISABLE low */ val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_GENCTL); val &= ~(1 << 1); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_GENCTL, val); /* Set DBGPWRDUP low */ val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1); val &= ~(1 << 1); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1, val); /* Release power clamp */ bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0xff); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x7f); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x3f); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x1f); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x0f); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x07); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x03); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x01); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWR_CLAMP, 0x00); DELAY(10000); /* Clear power-off gating */ val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPU1_PWROFF_REG); val &= ~(1 << 0); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_PWROFF_REG, val); DELAY(1000); /* De-assert cpu core reset */ bus_space_write_4(fdtbus_bs_tag, cpucfg, CPU1_RST_CTL, 3); /* Assert DBGPWRDUP signal */ val = bus_space_read_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1); val |= (1 << 1); bus_space_write_4(fdtbus_bs_tag, cpucfg, CPUCFG_DBGCTL1, val); armv7_sev(); bus_space_unmap(fdtbus_bs_tag, cpucfg, CPUCFG_SIZE); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } Index: head/sys/arm/altera/socfpga/socfpga_mp.c =================================================================== --- head/sys/arm/altera/socfpga/socfpga_mp.c (revision 281091) +++ head/sys/arm/altera/socfpga/socfpga_mp.c (revision 281092) @@ -1,180 +1,183 @@ /*- * Copyright (c) 2014 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * 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 #define SCU_PHYSBASE 0xFFFEC000 #define SCU_SIZE 0x100 #define SCU_CONTROL_REG 0x00 #define SCU_CONTROL_ENABLE (1 << 0) #define SCU_CONFIG_REG 0x04 #define SCU_CONFIG_REG_NCPU_MASK 0x03 #define SCU_CPUPOWER_REG 0x08 #define SCU_INV_TAGS_REG 0x0c #define SCU_DIAG_CONTROL 0x30 #define SCU_DIAG_DISABLE_MIGBIT (1 << 0) #define SCU_FILTER_START_REG 0x40 #define SCU_FILTER_END_REG 0x44 #define SCU_SECURE_ACCESS_REG 0x50 #define SCU_NONSECURE_ACCESS_REG 0x54 #define RSTMGR_PHYSBASE 0xFFD05000 #define RSTMGR_SIZE 0x100 #define MPUMODRST 0x10 #define MPUMODRST_CPU1 (1 << 1) #define RAM_PHYSBASE 0x0 #define RAM_SIZE 0x1000 extern char *mpentry_addr; static void socfpga_trampoline(void); static void socfpga_trampoline(void) { __asm __volatile( "ldr pc, 1f\n" ".globl mpentry_addr\n" "mpentry_addr:\n" "1: .space 4\n"); } void platform_mp_init_secondary(void) { arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { int hwcpu, ncpu; /* If we've already set this don't bother to do it again. */ if (mp_ncpus != 0) return; hwcpu = 2; ncpu = hwcpu; TUNABLE_INT_FETCH("hw.ncpu", &ncpu); if (ncpu < 1 || ncpu > hwcpu) ncpu = hwcpu; mp_ncpus = ncpu; mp_maxid = ncpu - 1; } int platform_mp_probe(void) { if (mp_ncpus == 0) platform_mp_setmaxid(); return (mp_ncpus > 1); } void platform_mp_start_ap(void) { bus_space_handle_t scu, rst, ram; int reg; if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) panic("Couldn't map the SCU\n"); if (bus_space_map(fdtbus_bs_tag, RSTMGR_PHYSBASE, RSTMGR_SIZE, 0, &rst) != 0) panic("Couldn't map the reset manager (RSTMGR)\n"); if (bus_space_map(fdtbus_bs_tag, RAM_PHYSBASE, RAM_SIZE, 0, &ram) != 0) panic("Couldn't map the first physram page\n"); /* Invalidate SCU cache tags */ bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff); /* * Erratum ARM/MP: 764369 (problems with cache maintenance). * Setting the "disable-migratory bit" in the undocumented SCU * Diagnostic Control Register helps work around the problem. */ reg = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL); reg |= (SCU_DIAG_DISABLE_MIGBIT); bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL, reg); /* Put CPU1 to reset state */ bus_space_write_4(fdtbus_bs_tag, rst, MPUMODRST, MPUMODRST_CPU1); /* Enable the SCU, then clean the cache on this core */ reg = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG); reg |= (SCU_CONTROL_ENABLE); bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, reg); /* Set up trampoline code */ mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry); bus_space_write_region_4(fdtbus_bs_tag, ram, 0, (uint32_t *)&socfpga_trampoline, 8); cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); /* Put CPU1 out from reset */ bus_space_write_4(fdtbus_bs_tag, rst, MPUMODRST, 0); armv7_sev(); bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); bus_space_unmap(fdtbus_bs_tag, rst, RSTMGR_SIZE); bus_space_unmap(fdtbus_bs_tag, ram, RAM_SIZE); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } Index: head/sys/arm/amlogic/aml8726/aml8726_fb.c =================================================================== --- head/sys/arm/amlogic/aml8726/aml8726_fb.c (revision 281091) +++ head/sys/arm/amlogic/aml8726/aml8726_fb.c (revision 281092) @@ -1,468 +1,471 @@ /*- * Copyright 2013-2014 John Wehle * 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. */ /* * Amlogic aml8726 frame buffer driver. * * The current implementation has limited flexibility. * For example only progressive scan is supported when * using HDMI and the resolution / frame rate is not * negotiated. */ #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 "fb_if.h" enum aml8726_fb_output { aml8726_unknown_fb_output, aml8726_cvbs_fb_output, aml8726_hdmi_fb_output, aml8726_lcd_fb_output }; struct aml8726_fb_clk { uint32_t freq; uint32_t video_pre; uint32_t video_post; uint32_t video_x; uint32_t hdmi_tx; uint32_t encp; uint32_t enci; uint32_t enct; uint32_t encl; uint32_t vdac0; uint32_t vdac1; }; struct aml8726_fb_softc { device_t dev; struct resource *res[4]; struct mtx mtx; void *ih_cookie; struct fb_info info; enum aml8726_fb_output output; struct aml8726_fb_clk clk; }; static struct resource_spec aml8726_fb_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* CANVAS */ { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* VIU */ { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* VPP */ { SYS_RES_IRQ, 1, RF_ACTIVE }, /* INT_VIU_VSYNC */ { -1, 0 } }; #define AML_FB_LOCK(sc) mtx_lock(&(sc)->mtx) #define AML_FB_UNLOCK(sc) mtx_unlock(&(sc)->mtx) #define AML_FB_LOCK_INIT(sc) \ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \ "fb", MTX_DEF) #define AML_FB_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx); #define CAV_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], reg, (val)) #define CAV_READ_4(sc, reg) bus_read_4((sc)->res[0], reg) #define CAV_BARRIER(sc, reg) bus_barrier((sc)->res[0], reg, 4, \ (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) #define VIU_WRITE_4(sc, reg, val) bus_write_4((sc)->res[1], reg, (val)) #define VIU_READ_4(sc, reg) bus_read_4((sc)->res[1], reg) #define VPP_WRITE_4(sc, reg, val) bus_write_4((sc)->res[2], reg, (val)) #define VPP_READ_4(sc, reg) bus_read_4((sc)->res[2], reg) #define CLK_WRITE_4(sc, reg, val) bus_write_4((sc)->res[X], reg, (val)) #define CLK_READ_4(sc, reg) bus_read_4((sc)->res[X], reg) #define AML_FB_CLK_FREQ_SD 1080 #define AML_FB_CLK_FREQ_HD 1488 static void aml8726_fb_cfg_output(struct aml8726_fb_softc *sc) { /* XXX */ } static void aml8726_fb_cfg_video(struct aml8726_fb_softc *sc) { uint32_t value; /* * basic initialization * * The fifo depth is in units of 8 so programming 32 * sets the depth to 256. */ value = (32 << AML_VIU_OSD_FIFO_CTRL_DEPTH_SHIFT); value |= AML_VIU_OSD_FIFO_CTRL_BURST_LEN_64; value |= (4 << AML_VIU_OSD_FIFO_CTRL_HOLD_LINES_SHIFT); VIU_WRITE_4(sc, AML_VIU_OSD1_FIFO_CTRL_REG, value); VIU_WRITE_4(sc, AML_VIU_OSD2_FIFO_CTRL_REG, value); value = VPP_READ_4(sc, AML_VPP_MISC_REG); value &= ~AML_VPP_MISC_PREBLEND_EN; value |= AML_VPP_MISC_POSTBLEND_EN; value &= ~(AML_VPP_MISC_OSD1_POSTBLEND | AML_VPP_MISC_OSD2_POSTBLEND | AML_VPP_MISC_VD1_POSTBLEND | AML_VPP_MISC_VD2_POSTBLEND); VPP_WRITE_4(sc, AML_VPP_MISC_REG, value); value = AML_VIU_OSD_CTRL_OSD_EN; value |= (0xff << AML_VIU_OSD_CTRL_GLOBAL_ALPHA_SHIFT); VIU_WRITE_4(sc, AML_VIU_OSD1_CTRL_REG, value); VIU_WRITE_4(sc, AML_VIU_OSD2_CTRL_REG, value); /* color mode for OSD1 block 0 */ value = (AML_CAV_OSD1_INDEX << AML_VIU_OSD_BLK_CFG_W0_INDEX_SHIFT) | AML_VIU_OSD_BLK_CFG_W0_LITTLE_ENDIAN | AML_VIU_OSD_BLK_CFG_W0_BLKMODE_24 | AML_VIU_OSD_BLK_CFG_W0_RGB_EN | AML_VIU_OSD_BLK_CFG_W0_CMATRIX_RGB; VIU_WRITE_4(sc, AML_VIU_OSD1_BLK0_CFG_W0_REG, value); /* geometry / scaling for OSD1 block 0 */ value = ((sc->info.fb_width - 1) << AML_VIU_OSD_BLK_CFG_W1_X_END_SHIFT) & AML_VIU_OSD_BLK_CFG_W1_X_END_MASK; value |= (0 << AML_VIU_OSD_BLK_CFG_W1_X_START_SHIFT) & AML_VIU_OSD_BLK_CFG_W1_X_START_MASK; VIU_WRITE_4(sc, AML_VIU_OSD1_BLK0_CFG_W1_REG, value); value = ((sc->info.fb_height - 1) << AML_VIU_OSD_BLK_CFG_W2_Y_END_SHIFT) & AML_VIU_OSD_BLK_CFG_W2_Y_END_MASK; value |= (0 << AML_VIU_OSD_BLK_CFG_W2_Y_START_SHIFT) & AML_VIU_OSD_BLK_CFG_W2_Y_START_MASK; VIU_WRITE_4(sc, AML_VIU_OSD1_BLK0_CFG_W2_REG, value); value = ((sc->info.fb_width - 1) << AML_VIU_OSD_BLK_CFG_W3_H_END_SHIFT) & AML_VIU_OSD_BLK_CFG_W3_H_END_MASK; value |= (0 << AML_VIU_OSD_BLK_CFG_W3_H_START_SHIFT) & AML_VIU_OSD_BLK_CFG_W3_H_START_MASK; VIU_WRITE_4(sc, AML_VIU_OSD1_BLK0_CFG_W3_REG, value); value = ((sc->info.fb_height - 1) << AML_VIU_OSD_BLK_CFG_W4_V_END_SHIFT) & AML_VIU_OSD_BLK_CFG_W4_V_END_MASK; value |= (0 << AML_VIU_OSD_BLK_CFG_W4_V_START_SHIFT) & AML_VIU_OSD_BLK_CFG_W4_V_START_MASK; VIU_WRITE_4(sc, AML_VIU_OSD1_BLK0_CFG_W4_REG, value); /* Enable the OSD block now that it's fully configured */ value = VIU_READ_4(sc, AML_VIU_OSD1_CTRL_REG); value &= ~AML_VIU_OSD_CTRL_OSD_BLK_EN_MASK; value |= 1 << AML_VIU_OSD_CTRL_OSD_BLK_EN_SHIFT; VIU_WRITE_4(sc, AML_VIU_OSD1_CTRL_REG, value); /* enable video processing of OSD1 */ value = VPP_READ_4(sc, AML_VPP_MISC_REG); value |= AML_VPP_MISC_OSD1_POSTBLEND; VPP_WRITE_4(sc, AML_VPP_MISC_REG, value); } static void aml8726_fb_cfg_canvas(struct aml8726_fb_softc *sc) { uint32_t value; uint32_t width; /* * The frame buffer address and width are programmed in units of 8 * (meaning they need to be aligned and the actual values divided * by 8 prior to programming the hardware). */ width = (uint32_t)sc->info.fb_stride / 8; /* lower bits of the width */ value = (width << AML_CAV_LUT_DATAL_WIDTH_SHIFT) & AML_CAV_LUT_DATAL_WIDTH_MASK; /* physical address */ value |= (uint32_t)sc->info.fb_pbase / 8; CAV_WRITE_4(sc, AML_CAV_LUT_DATAL_REG, value); /* upper bits of the width */ value = ((width >> AML_CAV_LUT_DATAL_WIDTH_WIDTH) << AML_CAV_LUT_DATAH_WIDTH_SHIFT) & AML_CAV_LUT_DATAH_WIDTH_MASK; /* height */ value |= ((uint32_t)sc->info.fb_height << AML_CAV_LUT_DATAH_HEIGHT_SHIFT) & AML_CAV_LUT_DATAH_HEIGHT_MASK; /* mode */ value |= AML_CAV_LUT_DATAH_BLKMODE_LINEAR; CAV_WRITE_4(sc, AML_CAV_LUT_DATAH_REG, value); CAV_WRITE_4(sc, AML_CAV_LUT_ADDR_REG, (AML_CAV_LUT_ADDR_WR_EN | (AML_CAV_OSD1_INDEX << AML_CAV_LUT_ADDR_INDEX_SHIFT))); CAV_BARRIER(sc, AML_CAV_LUT_ADDR_REG); } static void aml8726_fb_intr(void *arg) { struct aml8726_fb_softc *sc = (struct aml8726_fb_softc *)arg; AML_FB_LOCK(sc); AML_FB_UNLOCK(sc); } static int aml8726_fb_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "amlogic,aml8726-fb")) return (ENXIO); device_set_desc(dev, "Amlogic aml8726 FB"); return (BUS_PROBE_DEFAULT); } static int aml8726_fb_attach(device_t dev) { struct aml8726_fb_softc *sc = device_get_softc(dev); int error; device_t child; pcell_t prop; phandle_t node; sc->dev = dev; sc->info.fb_name = device_get_nameunit(sc->dev); node = ofw_bus_get_node(dev); if (OF_getencprop(node, "width", &prop, sizeof(prop)) <= 0) { device_printf(dev, "missing width attribute in FDT\n"); return (ENXIO); } if ((prop % 8) != 0) { device_printf(dev, "width attribute in FDT must be a multiple of 8\n"); return (ENXIO); } sc->info.fb_width = prop; if (OF_getencprop(node, "height", &prop, sizeof(prop)) <= 0) { device_printf(dev, "missing height attribute in FDT\n"); return (ENXIO); } sc->info.fb_height = prop; if (OF_getencprop(node, "depth", &prop, sizeof(prop)) <= 0) { device_printf(dev, "missing depth attribute in FDT\n"); return (ENXIO); } if (prop != 24) { device_printf(dev, "depth attribute in FDT is an unsupported value\n"); return (ENXIO); } sc->info.fb_depth = prop; sc->info.fb_bpp = prop; if (OF_getencprop(node, "linebytes", &prop, sizeof(prop)) <= 0) { device_printf(dev, "missing linebytes attribute in FDT\n"); return (ENXIO); } if ((prop % 8) != 0) { device_printf(dev, "linebytes attribute in FDT must be a multiple of 8\n"); return (ENXIO); } if (prop < (sc->info.fb_width * 3)) { device_printf(dev, "linebytes attribute in FDT is too small\n"); return (ENXIO); } sc->info.fb_stride = prop; if (OF_getencprop(node, "address", &prop, sizeof(prop)) <= 0) { device_printf(dev, "missing address attribute in FDT\n"); return (ENXIO); } if ((prop % 8) != 0) { device_printf(dev, "address attribute in FDT must be a multiple of 8\n"); return (ENXIO); } sc->info.fb_pbase = prop; sc->info.fb_size = sc->info.fb_height * sc->info.fb_stride; sc->info.fb_vbase = (intptr_t)pmap_mapdev(sc->info.fb_pbase, sc->info.fb_size); if (bus_alloc_resources(dev, aml8726_fb_spec, sc->res)) { device_printf(dev, "could not allocate resources for device\n"); pmap_unmapdev(sc->info.fb_vbase, sc->info.fb_size); return (ENXIO); } aml8726_fb_cfg_output(sc); aml8726_fb_cfg_video(sc); aml8726_fb_cfg_canvas(sc); AML_FB_LOCK_INIT(sc); error = bus_setup_intr(dev, sc->res[3], INTR_TYPE_MISC | INTR_MPSAFE, NULL, aml8726_fb_intr, sc, &sc->ih_cookie); if (error) { device_printf(dev, "could not setup interrupt handler\n"); goto fail; } child = device_add_child(dev, "fbd", device_get_unit(dev)); if (!child) { device_printf(dev, "could not add fbd\n"); error = ENXIO; goto fail; } error = device_probe_and_attach(child); if (error) { device_printf(dev, "could not attach fbd\n"); goto fail; } return (0); fail: if (sc->ih_cookie) bus_teardown_intr(dev, sc->res[3], sc->ih_cookie); AML_FB_LOCK_DESTROY(sc); bus_release_resources(dev, aml8726_fb_spec, sc->res); pmap_unmapdev(sc->info.fb_vbase, sc->info.fb_size); return (error); } static int aml8726_fb_detach(device_t dev) { struct aml8726_fb_softc *sc = device_get_softc(dev); bus_generic_detach(dev); bus_teardown_intr(dev, sc->res[3], sc->ih_cookie); AML_FB_LOCK_DESTROY(sc); bus_release_resources(dev, aml8726_fb_spec, sc->res); pmap_unmapdev(sc->info.fb_vbase, sc->info.fb_size); return (0); } static struct fb_info * aml8726_fb_getinfo(device_t dev) { struct aml8726_fb_softc *sc = device_get_softc(dev); return (&sc->info); } static device_method_t aml8726_fb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aml8726_fb_probe), DEVMETHOD(device_attach, aml8726_fb_attach), DEVMETHOD(device_detach, aml8726_fb_detach), /* FB interface */ DEVMETHOD(fb_getinfo, aml8726_fb_getinfo), DEVMETHOD_END }; static driver_t aml8726_fb_driver = { "fb", aml8726_fb_methods, sizeof(struct aml8726_fb_softc), }; static devclass_t aml8726_fb_devclass; DRIVER_MODULE(fb, simplebus, aml8726_fb_driver, aml8726_fb_devclass, 0, 0); Index: head/sys/arm/amlogic/aml8726/aml8726_mp.c =================================================================== --- head/sys/arm/amlogic/aml8726/aml8726_mp.c (revision 281091) +++ head/sys/arm/amlogic/aml8726/aml8726_mp.c (revision 281092) @@ -1,657 +1,660 @@ /*- * Copyright 2015 John Wehle * 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. */ /* * Amlogic aml8726 multiprocessor support. * * Some processors require powering on which involves poking registers * on the aobus and cbus ... it's expected that these locations are set * in stone. * * Locking is not used as these routines should only be called by the BP * during startup and should complete prior to the APs being released (the * issue being to ensure that a register such as AML_SOC_CPU_CLK_CNTL_REG * is not concurrently modified). */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include +#include +#include + #include #include #include #include #include #include #include #include static const char *scu_compatible[] = { "arm,cortex-a5-scu", "arm,cortex-a9-scu", NULL }; static const char *scu_errata_764369[] = { "arm,cortex-a9-scu", NULL }; static const char *cpucfg_compatible[] = { "amlogic,aml8726-cpuconfig", NULL }; static struct { boolean_t errata_764369; u_long scu_size; struct resource scu_res; u_long cpucfg_size; struct resource cpucfg_res; struct resource aobus_res; struct resource cbus_res; } aml8726_smp; #define AML_SCU_CONTROL_REG 0 #define AML_SCU_CONTROL_ENABLE 1 #define AML_SCU_CONFIG_REG 4 #define AML_SCU_CONFIG_NCPU_MASK 0x3 #define AML_SCU_CPU_PWR_STATUS_REG 8 #define AML_SCU_CPU_PWR_STATUS_CPU3_MASK (3 << 24) #define AML_SCU_CPU_PWR_STATUS_CPU2_MASK (3 << 16) #define AML_SCU_CPU_PWR_STATUS_CPU1_MASK (3 << 8) #define AML_SCU_CPU_PWR_STATUS_CPU0_MASK 3 #define AML_SCU_INV_TAGS_REG 12 #define AML_SCU_DIAG_CONTROL_REG 48 #define AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT 1 #define AML_CPUCONF_CONTROL_REG 0 #define AML_CPUCONF_CPU1_ADDR_REG 4 #define AML_CPUCONF_CPU2_ADDR_REG 8 #define AML_CPUCONF_CPU3_ADDR_REG 12 /* aobus */ #define AML_M8_CPU_PWR_CNTL0_REG 0xe0 #define AML_M8B_CPU_PWR_CNTL0_MODE_CPU3_MASK (3 << 22) #define AML_M8B_CPU_PWR_CNTL0_MODE_CPU2_MASK (3 << 20) #define AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK (3 << 18) #define AML_M8_CPU_PWR_CNTL0_ISO_CPU3 (1 << 3) #define AML_M8_CPU_PWR_CNTL0_ISO_CPU2 (1 << 2) #define AML_M8_CPU_PWR_CNTL0_ISO_CPU1 (1 << 1) #define AML_M8_CPU_PWR_CNTL1_REG 0xe4 #define AML_M8B_CPU_PWR_CNTL1_PWR_CPU3 (1 << 19) #define AML_M8B_CPU_PWR_CNTL1_PWR_CPU2 (1 << 18) #define AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 (1 << 17) #define AML_M8_CPU_PWR_CNTL1_MODE_CPU3_MASK (3 << 8) #define AML_M8_CPU_PWR_CNTL1_MODE_CPU2_MASK (3 << 6) #define AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK (3 << 4) #define AML_M8B_CPU_PWR_MEM_PD0_REG 0xf4 #define AML_M8B_CPU_PWR_MEM_PD0_CPU3 (0xf << 20) #define AML_M8B_CPU_PWR_MEM_PD0_CPU2 (0xf << 24) #define AML_M8B_CPU_PWR_MEM_PD0_CPU1 (0xf << 28) /* cbus */ #define AML_SOC_CPU_CLK_CNTL_REG 0x419c #define AML_M8_CPU_CLK_CNTL_RESET_CPU3 (1 << 27) #define AML_M8_CPU_CLK_CNTL_RESET_CPU2 (1 << 26) #define AML_M8_CPU_CLK_CNTL_RESET_CPU1 (1 << 25) #define SCU_WRITE_4(reg, value) bus_write_4(&aml8726_smp.scu_res, \ (reg), (value)) #define SCU_READ_4(reg) bus_read_4(&aml8726_smp.scu_res, (reg)) #define SCU_BARRIER(reg) bus_barrier(&aml8726_smp.scu_res, \ (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) #define CPUCONF_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cpucfg_res, \ (reg), (value)) #define CPUCONF_READ_4(reg) bus_read_4(&aml8726_smp.cpucfg_res, \ (reg)) #define CPUCONF_BARRIER(reg) bus_barrier(&aml8726_smp.cpucfg_res, \ (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) #define AOBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.aobus_res, \ (reg), (value)) #define AOBUS_READ_4(reg) bus_read_4(&aml8726_smp.aobus_res, \ (reg)) #define AOBUS_BARRIER(reg) bus_barrier(&aml8726_smp.aobus_res, \ (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) #define CBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cbus_res, \ (reg), (value)) #define CBUS_READ_4(reg) bus_read_4(&aml8726_smp.cbus_res, \ (reg)) #define CBUS_BARRIER(reg) bus_barrier(&aml8726_smp.cbus_res, \ (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) static phandle_t find_node_for_device(const char *device, const char **compatible) { int i; phandle_t node; /* * Try to access the node directly i.e. through /aliases/. */ if ((node = OF_finddevice(device)) != 0) for (i = 0; compatible[i]; i++) if (fdt_is_compatible_strict(node, compatible[i])) return node; /* * Find the node the long way. */ for (i = 0; compatible[i]; i++) { if ((node = OF_finddevice("/soc")) == 0) return (0); if ((node = fdt_find_compatible(node, compatible[i], 1)) != 0) return node; } return (0); } static int alloc_resource_for_node(phandle_t node, struct resource *res, u_long *size) { int err; u_long pbase, psize; u_long start; if ((err = fdt_get_range(OF_parent(node), 0, &pbase, &psize)) != 0 || (err = fdt_regsize(node, &start, size)) != 0) return (err); start += pbase; memset(res, 0, sizeof(*res)); res->r_bustag = fdtbus_bs_tag; err = bus_space_map(res->r_bustag, start, *size, 0, &res->r_bushandle); return (err); } static void power_on_cpu(int cpu) { uint32_t scpsr; uint32_t value; if (cpu <= 0) return; /* * Power on the CPU if the intricate details are known, otherwise * just hope for the best (it may have already be powered on by * the hardware / firmware). */ switch (aml8726_soc_hw_rev) { case AML_SOC_HW_REV_M8: case AML_SOC_HW_REV_M8B: /* * Set the SCU power status for the CPU to normal mode. */ scpsr = SCU_READ_4(AML_SCU_CPU_PWR_STATUS_REG); scpsr &= ~(AML_SCU_CPU_PWR_STATUS_CPU1_MASK << ((cpu - 1) * 8)); SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { /* * Reset may cause the current power status from the * actual CPU to be written to the SCU (over-writing * the value we've just written) so set it to normal * mode as well. */ value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); value &= ~(AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK << ((cpu - 1) * 2)); AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); } DELAY(5); /* * Assert reset. */ value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); value |= AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1); CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { /* * Release RAM pull-down. */ value = AOBUS_READ_4(AML_M8B_CPU_PWR_MEM_PD0_REG); value &= ~((uint32_t)AML_M8B_CPU_PWR_MEM_PD0_CPU1 >> ((cpu - 1) * 4)); AOBUS_WRITE_4(AML_M8B_CPU_PWR_MEM_PD0_REG, value); AOBUS_BARRIER(AML_M8B_CPU_PWR_MEM_PD0_REG); } /* * Power on CPU. */ value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); value &= ~(AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK << ((cpu - 1) * 2)); AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL1_REG, value); AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL1_REG); DELAY(10); if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { /* * Wait for power on confirmation. */ for ( ; ; ) { value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); value &= AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 << (cpu - 1); if (value) break; DELAY(10); } } /* * Release peripheral clamp. */ value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); value &= ~(AML_M8_CPU_PWR_CNTL0_ISO_CPU1 << (cpu - 1)); AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); /* * Release reset. */ value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); value &= ~(AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1)); CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { /* * The Amlogic Linux platform code sets the SCU power * status for the CPU again for some reason so we * follow suit (perhaps in case the reset caused * a stale power status from the actual CPU to be * written to the SCU). */ SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); } break; default: break; } } void platform_mp_init_secondary(void) { /* * Consider modifying the timer driver to support * per-cpu timers and then enabling the timer for * each AP. */ arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { int err; int i; int ncpu; phandle_t cpucfg_node; phandle_t scu_node; uint32_t value; if (mp_ncpus != 0) return; ncpu = 1; /* * Is the hardware necessary for SMP present? */ if ((scu_node = find_node_for_device("scu", scu_compatible)) == 0) goto moveon; if ((cpucfg_node = find_node_for_device("cpuconfig", cpucfg_compatible)) == 0) goto moveon; if (alloc_resource_for_node(scu_node, &aml8726_smp.scu_res, &aml8726_smp.scu_size) != 0) panic("Could not allocate resource for SCU"); if (alloc_resource_for_node(cpucfg_node, &aml8726_smp.cpucfg_res, &aml8726_smp.cpucfg_size) != 0) panic("Could not allocate resource for CPUCONFIG"); /* * Strictly speaking the aobus and cbus may not be required in * order to start an AP (it depends on the processor), however * always mapping them in simplifies the code. */ aml8726_smp.aobus_res.r_bustag = fdtbus_bs_tag; err = bus_space_map(aml8726_smp.aobus_res.r_bustag, AML_SOC_AOBUS_BASE_ADDR, 0x100000, 0, &aml8726_smp.aobus_res.r_bushandle); if (err) panic("Could not allocate resource for AOBUS"); aml8726_smp.cbus_res.r_bustag = fdtbus_bs_tag; err = bus_space_map(aml8726_smp.cbus_res.r_bustag, AML_SOC_CBUS_BASE_ADDR, 0x100000, 0, &aml8726_smp.cbus_res.r_bushandle); if (err) panic("Could not allocate resource for CBUS"); aml8726_smp.errata_764369 = false; for (i = 0; scu_errata_764369[i]; i++) if (fdt_is_compatible_strict(scu_node, scu_errata_764369[i])) { aml8726_smp.errata_764369 = true; break; } /* * Read the number of CPUs present. */ value = SCU_READ_4(AML_SCU_CONFIG_REG); ncpu = (value & AML_SCU_CONFIG_NCPU_MASK) + 1; moveon: mp_ncpus = ncpu; mp_maxid = ncpu - 1; } int platform_mp_probe(void) { if (mp_ncpus == 0) platform_mp_setmaxid(); return (mp_ncpus > 1); } void platform_mp_start_ap(void) { int i; uint32_t reg; uint32_t value; vm_paddr_t paddr; if (mp_ncpus < 2) return; /* * Invalidate SCU cache tags. The 0x0000ffff constant invalidates * all ways on all cores 0-3. Per the ARM docs, it's harmless to * write to the bits for cores that are not present. */ SCU_WRITE_4(AML_SCU_INV_TAGS_REG, 0x0000ffff); if (aml8726_smp.errata_764369) { /* * Erratum ARM/MP: 764369 (problems with cache maintenance). * Setting the "disable-migratory bit" in the undocumented SCU * Diagnostic Control Register helps work around the problem. */ value = SCU_READ_4(AML_SCU_DIAG_CONTROL_REG); value |= AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT; SCU_WRITE_4(AML_SCU_DIAG_CONTROL_REG, value); } /* * Enable the SCU, then clean the cache on this core. After these * two operations the cache tag ram in the SCU is coherent with * the contents of the cache on this core. The other cores aren't * running yet so their caches can't contain valid data yet, however * we've initialized their SCU tag ram above, so they will be * coherent from startup. */ value = SCU_READ_4(AML_SCU_CONTROL_REG); value |= AML_SCU_CONTROL_ENABLE; SCU_WRITE_4(AML_SCU_CONTROL_REG, value); SCU_BARRIER(AML_SCU_CONTROL_REG); cpu_idcache_wbinv_all(); /* Set the boot address and power on each AP. */ paddr = pmap_kextract((vm_offset_t)mpentry); for (i = 1; i < mp_ncpus; i++) { reg = AML_CPUCONF_CPU1_ADDR_REG + ((i - 1) * 4); CPUCONF_WRITE_4(reg, paddr); CPUCONF_BARRIER(reg); power_on_cpu(i); } /* * Enable the APs. * * The Amlogic Linux platform code sets the lsb for some reason * in addition to the enable bit for each AP so we follow suit * (the lsb may be the enable bit for the BP, though in that case * it should already be set since it's currently running). */ value = CPUCONF_READ_4(AML_CPUCONF_CONTROL_REG); value |= 1; for (i = 1; i < mp_ncpus; i++) value |= (1 << i); CPUCONF_WRITE_4(AML_CPUCONF_CONTROL_REG, value); CPUCONF_BARRIER(AML_CPUCONF_CONTROL_REG); /* Wakeup the now enabled APs */ armv7_sev(); /* * Free the resources which are not needed after startup. */ bus_space_unmap(aml8726_smp.scu_res.r_bustag, aml8726_smp.scu_res.r_bushandle, aml8726_smp.scu_size); bus_space_unmap(aml8726_smp.cpucfg_res.r_bustag, aml8726_smp.cpucfg_res.r_bushandle, aml8726_smp.cpucfg_size); bus_space_unmap(aml8726_smp.aobus_res.r_bustag, aml8726_smp.aobus_res.r_bushandle, 0x100000); bus_space_unmap(aml8726_smp.cbus_res.r_bustag, aml8726_smp.cbus_res.r_bushandle, 0x100000); memset(&aml8726_smp, 0, sizeof(aml8726_smp)); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } /* * Stub drivers for cosmetic purposes. */ struct aml8726_scu_softc { device_t dev; }; static int aml8726_scu_probe(device_t dev) { int i; for (i = 0; scu_compatible[i]; i++) if (ofw_bus_is_compatible(dev, scu_compatible[i])) break; if (!scu_compatible[i]) return (ENXIO); device_set_desc(dev, "ARM Snoop Control Unit"); return (BUS_PROBE_DEFAULT); } static int aml8726_scu_attach(device_t dev) { struct aml8726_scu_softc *sc = device_get_softc(dev); sc->dev = dev; return (0); } static int aml8726_scu_detach(device_t dev) { return (0); } static device_method_t aml8726_scu_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aml8726_scu_probe), DEVMETHOD(device_attach, aml8726_scu_attach), DEVMETHOD(device_detach, aml8726_scu_detach), DEVMETHOD_END }; static driver_t aml8726_scu_driver = { "scu", aml8726_scu_methods, sizeof(struct aml8726_scu_softc), }; static devclass_t aml8726_scu_devclass; EARLY_DRIVER_MODULE(scu, simplebus, aml8726_scu_driver, aml8726_scu_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); struct aml8726_cpucfg_softc { device_t dev; }; static int aml8726_cpucfg_probe(device_t dev) { int i; for (i = 0; cpucfg_compatible[i]; i++) if (ofw_bus_is_compatible(dev, cpucfg_compatible[i])) break; if (!cpucfg_compatible[i]) return (ENXIO); device_set_desc(dev, "Amlogic CPU Config"); return (BUS_PROBE_DEFAULT); } static int aml8726_cpucfg_attach(device_t dev) { struct aml8726_cpucfg_softc *sc = device_get_softc(dev); sc->dev = dev; return (0); } static int aml8726_cpucfg_detach(device_t dev) { return (0); } static device_method_t aml8726_cpucfg_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aml8726_cpucfg_probe), DEVMETHOD(device_attach, aml8726_cpucfg_attach), DEVMETHOD(device_detach, aml8726_cpucfg_detach), DEVMETHOD_END }; static driver_t aml8726_cpucfg_driver = { "cpuconfig", aml8726_cpucfg_methods, sizeof(struct aml8726_cpucfg_softc), }; static devclass_t aml8726_cpucfg_devclass; EARLY_DRIVER_MODULE(cpuconfig, simplebus, aml8726_cpucfg_driver, aml8726_cpucfg_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); Index: head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c (revision 281091) +++ head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c (revision 281092) @@ -1,305 +1,308 @@ /*- * Copyright (c) 2012 Oleksandr Tymoshenko * Copyright (c) 2012, 2013 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by Oleksandr Rybalko * 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 #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 #include #include #include #include #include #include #include #include #include "fb_if.h" #include "mbox_if.h" #define FB_WIDTH 640 #define FB_HEIGHT 480 #define FB_DEPTH 24 struct bcm_fb_config { uint32_t xres; uint32_t yres; uint32_t vxres; uint32_t vyres; uint32_t pitch; uint32_t bpp; uint32_t xoffset; uint32_t yoffset; /* Filled by videocore */ uint32_t base; uint32_t screen_size; }; struct bcmsc_softc { device_t dev; struct fb_info *info; bus_dma_tag_t dma_tag; bus_dmamap_t dma_map; struct bcm_fb_config* fb_config; bus_addr_t fb_config_phys; struct intr_config_hook init_hook; }; static int bcm_fb_probe(device_t); static int bcm_fb_attach(device_t); static void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err); static void bcm_fb_init(void *arg) { volatile struct bcm_fb_config *fb_config; struct bcmsc_softc *sc; struct fb_info *info; phandle_t node; pcell_t cell; device_t mbox; device_t fbd; int err = 0; sc = arg; fb_config = sc->fb_config; node = ofw_bus_get_node(sc->dev); fb_config->xres = 0; fb_config->yres = 0; fb_config->bpp = 0; fb_config->vxres = 0; fb_config->vyres = 0; fb_config->xoffset = 0; fb_config->yoffset = 0; fb_config->base = 0; fb_config->pitch = 0; fb_config->screen_size = 0; if ((OF_getprop(node, "broadcom,width", &cell, sizeof(cell))) > 0) fb_config->xres = (int)fdt32_to_cpu(cell); if (fb_config->xres == 0) fb_config->xres = FB_WIDTH; if ((OF_getprop(node, "broadcom,height", &cell, sizeof(cell))) > 0) fb_config->yres = (uint32_t)fdt32_to_cpu(cell); if (fb_config->yres == 0) fb_config->yres = FB_HEIGHT; if ((OF_getprop(node, "broadcom,depth", &cell, sizeof(cell))) > 0) fb_config->bpp = (uint32_t)fdt32_to_cpu(cell); if (fb_config->bpp == 0) fb_config->bpp = FB_DEPTH; bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); mbox = devclass_get_device(devclass_find("mbox"), 0); if (mbox) { MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_FB, sc->fb_config_phys); MBOX_READ(mbox, BCM2835_MBOX_CHAN_FB, &err); } bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_POSTREAD); if (fb_config->base != 0) { device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb_config->xres, fb_config->yres, fb_config->vxres, fb_config->vyres, fb_config->xoffset, fb_config->yoffset, fb_config->bpp); device_printf(sc->dev, "pitch %d, base 0x%08x, screen_size %d\n", fb_config->pitch, fb_config->base, fb_config->screen_size); info = malloc(sizeof(struct fb_info), M_DEVBUF, M_WAITOK | M_ZERO); info->fb_name = device_get_nameunit(sc->dev); info->fb_vbase = (intptr_t)pmap_mapdev(fb_config->base, fb_config->screen_size); info->fb_pbase = fb_config->base; info->fb_size = fb_config->screen_size; info->fb_bpp = info->fb_depth = fb_config->bpp; info->fb_stride = fb_config->pitch; info->fb_width = fb_config->xres; info->fb_height = fb_config->yres; sc->info = info; fbd = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev)); if (fbd == NULL) device_printf(sc->dev, "Failed to add fbd child\n"); else if (device_probe_and_attach(fbd) != 0) device_printf(sc->dev, "Failed to attach fbd device\n"); } else { device_printf(sc->dev, "Failed to set framebuffer info\n"); } config_intrhook_disestablish(&sc->init_hook); } static int bcm_fb_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb")) return (ENXIO); device_set_desc(dev, "BCM2835 VT framebuffer driver"); return (BUS_PROBE_DEFAULT); } static int bcm_fb_attach(device_t dev) { struct bcmsc_softc *sc = device_get_softc(dev); int dma_size = sizeof(struct bcm_fb_config); int err; sc->dev = dev; err = bus_dma_tag_create( bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ dma_size, 1, /* maxsize, nsegments */ dma_size, 0, /* maxsegsize, flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->dma_tag); err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->fb_config, 0, &sc->dma_map); if (err) { device_printf(dev, "cannot allocate framebuffer\n"); goto fail; } err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->fb_config, dma_size, bcm_fb_dmamap_cb, &sc->fb_config_phys, BUS_DMA_NOWAIT); if (err) { device_printf(dev, "cannot load DMA map\n"); goto fail; } /* * We have to wait until interrupts are enabled. * Mailbox relies on it to get data from VideoCore */ sc->init_hook.ich_func = bcm_fb_init; sc->init_hook.ich_arg = sc; if (config_intrhook_establish(&sc->init_hook) != 0) { device_printf(dev, "failed to establish intrhook\n"); return (ENOMEM); } return (0); fail: return (ENXIO); } static void bcm_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) { bus_addr_t *addr; if (err) return; addr = (bus_addr_t*)arg; *addr = PHYS_TO_VCBUS(segs[0].ds_addr); } static struct fb_info * bcm_fb_helper_getinfo(device_t dev) { struct bcmsc_softc *sc; sc = device_get_softc(dev); return (sc->info); } static device_method_t bcm_fb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bcm_fb_probe), DEVMETHOD(device_attach, bcm_fb_attach), /* Framebuffer service methods */ DEVMETHOD(fb_getinfo, bcm_fb_helper_getinfo), DEVMETHOD_END }; static devclass_t bcm_fb_devclass; static driver_t bcm_fb_driver = { "fb", bcm_fb_methods, sizeof(struct bcmsc_softc), }; DRIVER_MODULE(bcm2835fb, ofwbus, bcm_fb_driver, bcm_fb_devclass, 0, 0); Index: head/sys/arm/freescale/imx/imx51_ipuv3.c =================================================================== --- head/sys/arm/freescale/imx/imx51_ipuv3.c (revision 281091) +++ head/sys/arm/freescale/imx/imx51_ipuv3.c (revision 281092) @@ -1,897 +1,900 @@ /*- * Copyright (c) 2012 Oleksandr Tymoshenko * Copyright (c) 2012, 2013 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by Oleksandr Rybalko * 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 #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 #include #include #include #include #include #include #include #include #define IMX51_IPU_HSP_CLOCK 665000000 #define IPU3FB_FONT_HEIGHT 16 struct ipu3sc_softc { device_t dev; bus_addr_t pbase; bus_addr_t vbase; bus_space_tag_t iot; bus_space_handle_t ioh; bus_space_handle_t cm_ioh; bus_space_handle_t dp_ioh; bus_space_handle_t di0_ioh; bus_space_handle_t di1_ioh; bus_space_handle_t dctmpl_ioh; bus_space_handle_t dc_ioh; bus_space_handle_t dmfc_ioh; bus_space_handle_t idmac_ioh; bus_space_handle_t cpmem_ioh; }; struct video_adapter_softc { /* Videoadpater part */ video_adapter_t va; intptr_t fb_addr; intptr_t fb_paddr; unsigned int fb_size; int bpp; int depth; unsigned int height; unsigned int width; unsigned int stride; unsigned int xmargin; unsigned int ymargin; unsigned char *font; int initialized; }; static struct ipu3sc_softc *ipu3sc_softc; static struct video_adapter_softc va_softc; /* FIXME: not only 2 bytes color supported */ static uint16_t colors[16] = { 0x0000, /* black */ 0x001f, /* blue */ 0x07e0, /* green */ 0x07ff, /* cyan */ 0xf800, /* red */ 0xf81f, /* magenta */ 0x3800, /* brown */ 0xc618, /* light grey */ 0xc618, /* XXX: dark grey */ 0x001f, /* XXX: light blue */ 0x07e0, /* XXX: light green */ 0x07ff, /* XXX: light cyan */ 0xf800, /* XXX: light red */ 0xf81f, /* XXX: light magenta */ 0xffe0, /* yellow */ 0xffff, /* white */ }; static uint32_t colors_24[16] = { 0x000000,/* Black */ 0x000080,/* Blue */ 0x008000,/* Green */ 0x008080,/* Cyan */ 0x800000,/* Red */ 0x800080,/* Magenta */ 0xcc6600,/* brown */ 0xC0C0C0,/* Silver */ 0x808080,/* Gray */ 0x0000FF,/* Light Blue */ 0x00FF00,/* Light Green */ 0x00FFFF,/* Light Cyan */ 0xFF0000,/* Light Red */ 0xFF00FF,/* Light Magenta */ 0xFFFF00,/* Yellow */ 0xFFFFFF,/* White */ }; #define IPUV3_READ(ipuv3, module, reg) \ bus_space_read_4((ipuv3)->iot, (ipuv3)->module##_ioh, (reg)) #define IPUV3_WRITE(ipuv3, module, reg, val) \ bus_space_write_4((ipuv3)->iot, (ipuv3)->module##_ioh, (reg), (val)) #define CPMEM_CHANNEL_OFFSET(_c) ((_c) * 0x40) #define CPMEM_WORD_OFFSET(_w) ((_w) * 0x20) #define CPMEM_DP_OFFSET(_d) ((_d) * 0x10000) #define IMX_IPU_DP0 0 #define IMX_IPU_DP1 1 #define CPMEM_CHANNEL(_dp, _ch, _w) \ (CPMEM_DP_OFFSET(_dp) + CPMEM_CHANNEL_OFFSET(_ch) + \ CPMEM_WORD_OFFSET(_w)) #define CPMEM_OFFSET(_dp, _ch, _w, _o) \ (CPMEM_CHANNEL((_dp), (_ch), (_w)) + (_o)) #define IPUV3_DEBUG 100 #ifdef IPUV3_DEBUG #define SUBMOD_DUMP_REG(_sc, _m, _l) \ { \ int i; \ printf("*** " #_m " ***\n"); \ for (i = 0; i <= (_l); i += 4) { \ if ((i % 32) == 0) \ printf("%04x: ", i & 0xffff); \ printf("0x%08x%c", IPUV3_READ((_sc), _m, i), \ ((i + 4) % 32)?' ':'\n'); \ } \ printf("\n"); \ } #endif #ifdef IPUV3_DEBUG int ipuv3_debug = IPUV3_DEBUG; #define DPRINTFN(n,x) if (ipuv3_debug>(n)) printf x; else #else #define DPRINTFN(n,x) #endif static int ipu3_fb_probe(device_t); static int ipu3_fb_attach(device_t); static int ipu3_fb_malloc(struct ipu3sc_softc *sc, size_t size) { sc->vbase = (uint32_t)contigmalloc(size, M_DEVBUF, M_ZERO, 0, ~0, PAGE_SIZE, 0); sc->pbase = vtophys(sc->vbase); return (0); } static void ipu3_fb_init(void *arg) { struct ipu3sc_softc *sc = arg; struct video_adapter_softc *va_sc = &va_softc; uint64_t w0sh96; uint32_t w1sh96; /* FW W0[137:125] - 96 = [41:29] */ /* FH W0[149:138] - 96 = [53:42] */ w0sh96 = IPUV3_READ(sc, cpmem, CPMEM_OFFSET(IMX_IPU_DP1, 23, 0, 16)); w0sh96 <<= 32; w0sh96 |= IPUV3_READ(sc, cpmem, CPMEM_OFFSET(IMX_IPU_DP1, 23, 0, 12)); va_sc->width = ((w0sh96 >> 29) & 0x1fff) + 1; va_sc->height = ((w0sh96 >> 42) & 0x0fff) + 1; /* SLY W1[115:102] - 96 = [19:6] */ w1sh96 = IPUV3_READ(sc, cpmem, CPMEM_OFFSET(IMX_IPU_DP1, 23, 1, 12)); va_sc->stride = ((w1sh96 >> 6) & 0x3fff) + 1; printf("%dx%d [%d]\n", va_sc->width, va_sc->height, va_sc->stride); va_sc->fb_size = va_sc->height * va_sc->stride; ipu3_fb_malloc(sc, va_sc->fb_size); /* DP1 + config_ch_23 + word_2 */ IPUV3_WRITE(sc, cpmem, CPMEM_OFFSET(IMX_IPU_DP1, 23, 1, 0), ((sc->pbase >> 3) | ((sc->pbase >> 3) << 29)) & 0xffffffff); IPUV3_WRITE(sc, cpmem, CPMEM_OFFSET(IMX_IPU_DP1, 23, 1, 4), ((sc->pbase >> 3) >> 3) & 0xffffffff); va_sc->fb_addr = (intptr_t)sc->vbase; va_sc->fb_paddr = (intptr_t)sc->pbase; va_sc->bpp = va_sc->stride / va_sc->width; va_sc->depth = va_sc->bpp * 8; } static int ipu3_fb_probe(device_t dev) { int error; if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "fsl,ipu3")) return (ENXIO); device_set_desc(dev, "i.MX5x Image Processing Unit v3 (FB)"); error = sc_probe_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD); if (error != 0) return (error); return (BUS_PROBE_DEFAULT); } static int ipu3_fb_attach(device_t dev) { struct ipu3sc_softc *sc = device_get_softc(dev); bus_space_tag_t iot; bus_space_handle_t ioh; phandle_t node; pcell_t reg; int err; uintptr_t base; if (ipu3sc_softc) return (ENXIO); ipu3sc_softc = sc; if (bootverbose) device_printf(dev, "clock gate status is %d\n", imx51_get_clk_gating(IMX51CLK_IPU_HSP_CLK_ROOT)); sc->dev = dev; err = (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD)); if (err) { device_printf(dev, "failed to attach syscons\n"); goto fail; } sc = device_get_softc(dev); sc->iot = iot = fdtbus_bs_tag; /* * Retrieve the device address based on the start address in the * DTS. The DTS for i.MX51 specifies 0x5e000000 as the first register * address, so we just subtract IPU_CM_BASE to get the offset at which * the IPU device was memory mapped. * On i.MX53, the offset is 0. */ node = ofw_bus_get_node(dev); if ((OF_getprop(node, "reg", ®, sizeof(reg))) <= 0) base = 0; else base = fdt32_to_cpu(reg) - IPU_CM_BASE(0); /* map controller registers */ err = bus_space_map(iot, IPU_CM_BASE(base), IPU_CM_SIZE, 0, &ioh); if (err) goto fail_retarn_cm; sc->cm_ioh = ioh; /* map Display Multi FIFO Controller registers */ err = bus_space_map(iot, IPU_DMFC_BASE(base), IPU_DMFC_SIZE, 0, &ioh); if (err) goto fail_retarn_dmfc; sc->dmfc_ioh = ioh; /* map Display Interface 0 registers */ err = bus_space_map(iot, IPU_DI0_BASE(base), IPU_DI0_SIZE, 0, &ioh); if (err) goto fail_retarn_di0; sc->di0_ioh = ioh; /* map Display Interface 1 registers */ err = bus_space_map(iot, IPU_DI1_BASE(base), IPU_DI0_SIZE, 0, &ioh); if (err) goto fail_retarn_di1; sc->di1_ioh = ioh; /* map Display Processor registers */ err = bus_space_map(iot, IPU_DP_BASE(base), IPU_DP_SIZE, 0, &ioh); if (err) goto fail_retarn_dp; sc->dp_ioh = ioh; /* map Display Controller registers */ err = bus_space_map(iot, IPU_DC_BASE(base), IPU_DC_SIZE, 0, &ioh); if (err) goto fail_retarn_dc; sc->dc_ioh = ioh; /* map Image DMA Controller registers */ err = bus_space_map(iot, IPU_IDMAC_BASE(base), IPU_IDMAC_SIZE, 0, &ioh); if (err) goto fail_retarn_idmac; sc->idmac_ioh = ioh; /* map CPMEM registers */ err = bus_space_map(iot, IPU_CPMEM_BASE(base), IPU_CPMEM_SIZE, 0, &ioh); if (err) goto fail_retarn_cpmem; sc->cpmem_ioh = ioh; /* map DCTEMPL registers */ err = bus_space_map(iot, IPU_DCTMPL_BASE(base), IPU_DCTMPL_SIZE, 0, &ioh); if (err) goto fail_retarn_dctmpl; sc->dctmpl_ioh = ioh; #ifdef notyet sc->ih = imx51_ipuv3_intr_establish(IMX51_INT_IPUV3, IPL_BIO, ipuv3intr, sc); if (sc->ih == NULL) { device_printf(sc->dev, "unable to establish interrupt at irq %d\n", IMX51_INT_IPUV3); return (ENXIO); } #endif /* * We have to wait until interrupts are enabled. * Mailbox relies on it to get data from VideoCore */ ipu3_fb_init(sc); return (0); fail: return (ENXIO); fail_retarn_dctmpl: bus_space_unmap(sc->iot, sc->cpmem_ioh, IPU_CPMEM_SIZE); fail_retarn_cpmem: bus_space_unmap(sc->iot, sc->idmac_ioh, IPU_IDMAC_SIZE); fail_retarn_idmac: bus_space_unmap(sc->iot, sc->dc_ioh, IPU_DC_SIZE); fail_retarn_dp: bus_space_unmap(sc->iot, sc->dp_ioh, IPU_DP_SIZE); fail_retarn_dc: bus_space_unmap(sc->iot, sc->di1_ioh, IPU_DI1_SIZE); fail_retarn_di1: bus_space_unmap(sc->iot, sc->di0_ioh, IPU_DI0_SIZE); fail_retarn_di0: bus_space_unmap(sc->iot, sc->dmfc_ioh, IPU_DMFC_SIZE); fail_retarn_dmfc: bus_space_unmap(sc->iot, sc->dc_ioh, IPU_CM_SIZE); fail_retarn_cm: device_printf(sc->dev, "failed to map registers (errno=%d)\n", err); return (err); } static device_method_t ipu3_fb_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ipu3_fb_probe), DEVMETHOD(device_attach, ipu3_fb_attach), { 0, 0 } }; static devclass_t ipu3_fb_devclass; static driver_t ipu3_fb_driver = { "fb", ipu3_fb_methods, sizeof(struct ipu3sc_softc), }; DRIVER_MODULE(ipu3fb, simplebus, ipu3_fb_driver, ipu3_fb_devclass, 0, 0); /* * Video driver routines and glue. */ static int ipu3fb_configure(int); static vi_probe_t ipu3fb_probe; static vi_init_t ipu3fb_init; static vi_get_info_t ipu3fb_get_info; static vi_query_mode_t ipu3fb_query_mode; static vi_set_mode_t ipu3fb_set_mode; static vi_save_font_t ipu3fb_save_font; static vi_load_font_t ipu3fb_load_font; static vi_show_font_t ipu3fb_show_font; static vi_save_palette_t ipu3fb_save_palette; static vi_load_palette_t ipu3fb_load_palette; static vi_set_border_t ipu3fb_set_border; static vi_save_state_t ipu3fb_save_state; static vi_load_state_t ipu3fb_load_state; static vi_set_win_org_t ipu3fb_set_win_org; static vi_read_hw_cursor_t ipu3fb_read_hw_cursor; static vi_set_hw_cursor_t ipu3fb_set_hw_cursor; static vi_set_hw_cursor_shape_t ipu3fb_set_hw_cursor_shape; static vi_blank_display_t ipu3fb_blank_display; static vi_mmap_t ipu3fb_mmap; static vi_ioctl_t ipu3fb_ioctl; static vi_clear_t ipu3fb_clear; static vi_fill_rect_t ipu3fb_fill_rect; static vi_bitblt_t ipu3fb_bitblt; static vi_diag_t ipu3fb_diag; static vi_save_cursor_palette_t ipu3fb_save_cursor_palette; static vi_load_cursor_palette_t ipu3fb_load_cursor_palette; static vi_copy_t ipu3fb_copy; static vi_putp_t ipu3fb_putp; static vi_putc_t ipu3fb_putc; static vi_puts_t ipu3fb_puts; static vi_putm_t ipu3fb_putm; static video_switch_t ipu3fbvidsw = { .probe = ipu3fb_probe, .init = ipu3fb_init, .get_info = ipu3fb_get_info, .query_mode = ipu3fb_query_mode, .set_mode = ipu3fb_set_mode, .save_font = ipu3fb_save_font, .load_font = ipu3fb_load_font, .show_font = ipu3fb_show_font, .save_palette = ipu3fb_save_palette, .load_palette = ipu3fb_load_palette, .set_border = ipu3fb_set_border, .save_state = ipu3fb_save_state, .load_state = ipu3fb_load_state, .set_win_org = ipu3fb_set_win_org, .read_hw_cursor = ipu3fb_read_hw_cursor, .set_hw_cursor = ipu3fb_set_hw_cursor, .set_hw_cursor_shape = ipu3fb_set_hw_cursor_shape, .blank_display = ipu3fb_blank_display, .mmap = ipu3fb_mmap, .ioctl = ipu3fb_ioctl, .clear = ipu3fb_clear, .fill_rect = ipu3fb_fill_rect, .bitblt = ipu3fb_bitblt, .diag = ipu3fb_diag, .save_cursor_palette = ipu3fb_save_cursor_palette, .load_cursor_palette = ipu3fb_load_cursor_palette, .copy = ipu3fb_copy, .putp = ipu3fb_putp, .putc = ipu3fb_putc, .puts = ipu3fb_puts, .putm = ipu3fb_putm, }; VIDEO_DRIVER(ipu3fb, ipu3fbvidsw, ipu3fb_configure); extern sc_rndr_sw_t txtrndrsw; RENDERER(ipu3fb, 0, txtrndrsw, gfb_set); RENDERER_MODULE(ipu3fb, gfb_set); static uint16_t ipu3fb_static_window[ROW*COL]; extern u_char dflt_font_16[]; static int ipu3fb_configure(int flags) { struct video_adapter_softc *sc; sc = &va_softc; if (sc->initialized) return 0; sc->width = 640; sc->height = 480; sc->bpp = 2; sc->stride = sc->width * sc->bpp; ipu3fb_init(0, &sc->va, 0); sc->initialized = 1; return (0); } static int ipu3fb_probe(int unit, video_adapter_t **adp, void *arg, int flags) { return (0); } static int ipu3fb_init(int unit, video_adapter_t *adp, int flags) { struct video_adapter_softc *sc; video_info_t *vi; sc = (struct video_adapter_softc *)adp; vi = &adp->va_info; vid_init_struct(adp, "ipu3fb", -1, unit); sc->font = dflt_font_16; vi->vi_cheight = IPU3FB_FONT_HEIGHT; vi->vi_cwidth = 8; vi->vi_width = sc->width/8; vi->vi_height = sc->height/vi->vi_cheight; /* * 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->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; adp->va_window = (vm_offset_t) ipu3fb_static_window; adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */; adp->va_line_width = sc->stride; adp->va_buffer_size = sc->fb_size; vid_register(&sc->va); return (0); } static int ipu3fb_get_info(video_adapter_t *adp, int mode, video_info_t *info) { bcopy(&adp->va_info, info, sizeof(*info)); return (0); } static int ipu3fb_query_mode(video_adapter_t *adp, video_info_t *info) { return (0); } static int ipu3fb_set_mode(video_adapter_t *adp, int mode) { return (0); } static int ipu3fb_save_font(video_adapter_t *adp, int page, int size, int width, u_char *data, int c, int count) { return (0); } static int ipu3fb_load_font(video_adapter_t *adp, int page, int size, int width, u_char *data, int c, int count) { struct video_adapter_softc *sc; sc = (struct video_adapter_softc *)adp; sc->font = data; return (0); } static int ipu3fb_show_font(video_adapter_t *adp, int page) { return (0); } static int ipu3fb_save_palette(video_adapter_t *adp, u_char *palette) { return (0); } static int ipu3fb_load_palette(video_adapter_t *adp, u_char *palette) { return (0); } static int ipu3fb_set_border(video_adapter_t *adp, int border) { return (ipu3fb_blank_display(adp, border)); } static int ipu3fb_save_state(video_adapter_t *adp, void *p, size_t size) { return (0); } static int ipu3fb_load_state(video_adapter_t *adp, void *p) { return (0); } static int ipu3fb_set_win_org(video_adapter_t *adp, off_t offset) { return (0); } static int ipu3fb_read_hw_cursor(video_adapter_t *adp, int *col, int *row) { *col = *row = 0; return (0); } static int ipu3fb_set_hw_cursor(video_adapter_t *adp, int col, int row) { return (0); } static int ipu3fb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, int celsize, int blink) { return (0); } static int ipu3fb_blank_display(video_adapter_t *adp, int mode) { return (0); } static int ipu3fb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) { struct video_adapter_softc *sc; sc = (struct video_adapter_softc *)adp; /* * 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->stride * sc->height) { *paddr = sc->fb_paddr + offset; return (0); } return (EINVAL); } static int ipu3fb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data) { struct video_adapter_softc *sc; struct fbtype *fb; sc = (struct video_adapter_softc *)adp; switch (cmd) { case FBIOGTYPE: fb = (struct fbtype *)data; fb->fb_type = FBTYPE_PCIMISC; fb->fb_height = sc->height; fb->fb_width = sc->width; fb->fb_depth = sc->depth; if (sc->depth <= 1 || sc->depth > 8) fb->fb_cmsize = 0; else fb->fb_cmsize = 1 << sc->depth; fb->fb_size = sc->fb_size; break; case FBIOSCURSOR: return (ENODEV); default: return (fb_commonioctl(adp, cmd, data)); } return (0); } static int ipu3fb_clear(video_adapter_t *adp) { return (ipu3fb_blank_display(adp, 0)); } static int ipu3fb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) { return (0); } static int ipu3fb_bitblt(video_adapter_t *adp, ...) { return (0); } static int ipu3fb_diag(video_adapter_t *adp, int level) { return (0); } static int ipu3fb_save_cursor_palette(video_adapter_t *adp, u_char *palette) { return (0); } static int ipu3fb_load_cursor_palette(video_adapter_t *adp, u_char *palette) { return (0); } static int ipu3fb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n) { return (0); } static int ipu3fb_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) { return (0); } static int ipu3fb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) { struct video_adapter_softc *sc; int col, row, bpp; int b, i, j, k; uint8_t *addr; u_char *p; uint32_t fg, bg, color; sc = (struct video_adapter_softc *)adp; bpp = sc->bpp; if (sc->fb_addr == 0) return (0); 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->font + c * IPU3FB_FONT_HEIGHT; addr = (uint8_t *)sc->fb_addr + (row + sc->ymargin) * (sc->stride) + bpp * (col + sc->xmargin); if (bpp == 2) { bg = colors[(a >> 4) & 0x0f]; fg = colors[a & 0x0f]; } else if (bpp == 3) { bg = colors_24[(a >> 4) & 0x0f]; fg = colors_24[a & 0x0f]; } else { return (ENXIO); } for (i = 0; i < IPU3FB_FONT_HEIGHT; i++) { for (j = 0, k = 7; j < 8; j++, k--) { if ((p[i] & (1 << k)) == 0) color = bg; else color = fg; /* FIXME: BPP maybe different */ for (b = 0; b < bpp; b ++) addr[bpp * j + b] = (color >> (b << 3)) & 0xff; } addr += (sc->stride); } return (0); } static int ipu3fb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len) { int i; for (i = 0; i < len; i++) ipu3fb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8); return (0); } static int ipu3fb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, uint32_t pixel_mask, int size, int width) { return (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 ipu3dummysw; static int dummy_kbd_configure(int flags) { return (0); } KEYBOARD_DRIVER(ipu3dummy, ipu3dummysw, dummy_kbd_configure); Index: head/sys/arm/freescale/imx/imx6_mp.c =================================================================== --- head/sys/arm/freescale/imx/imx6_mp.c (revision 281091) +++ head/sys/arm/freescale/imx/imx6_mp.c (revision 281092) @@ -1,178 +1,181 @@ /*- * Copyright (c) 2014 Juergen Weiss * Copyright (c) 2014 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 ``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 + #include #include #include #define SCU_PHYSBASE 0x00a00000 #define SCU_SIZE 0x00001000 #define SCU_CONTROL_REG 0x00 #define SCU_CONTROL_ENABLE (1 << 0) #define SCU_CONFIG_REG 0x04 #define SCU_CONFIG_REG_NCPU_MASK 0x03 #define SCU_CPUPOWER_REG 0x08 #define SCU_INV_TAGS_REG 0x0c #define SCU_DIAG_CONTROL 0x30 #define SCU_DIAG_DISABLE_MIGBIT (1 << 0) #define SCU_FILTER_START_REG 0x40 #define SCU_FILTER_END_REG 0x44 #define SCU_SECURE_ACCESS_REG 0x50 #define SCU_NONSECURE_ACCESS_REG 0x54 #define SRC_PHYSBASE 0x020d8000 #define SRC_SIZE 0x4000 #define SRC_CONTROL_REG 0x00 #define SRC_CONTROL_C1ENA_SHIFT 22 /* Bit for Core 1 enable */ #define SRC_CONTROL_C1RST_SHIFT 14 /* Bit for Core 1 reset */ #define SRC_GPR0_C1FUNC 0x20 /* Register for Core 1 entry func */ #define SRC_GPR1_C1ARG 0x24 /* Register for Core 1 entry arg */ void platform_mp_init_secondary(void) { arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { bus_space_handle_t scu; int hwcpu, ncpu; uint32_t val; /* If we've already set the global vars don't bother to do it again. */ if (mp_ncpus != 0) return; if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) panic("Couldn't map the SCU\n"); val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG); hwcpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1; bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); ncpu = hwcpu; TUNABLE_INT_FETCH("hw.ncpu", &ncpu); if (ncpu < 1 || ncpu > hwcpu) ncpu = hwcpu; mp_ncpus = ncpu; mp_maxid = ncpu - 1; } int platform_mp_probe(void) { /* I think platform_mp_setmaxid must get called first, but be safe. */ if (mp_ncpus == 0) platform_mp_setmaxid(); return (mp_ncpus > 1); } void platform_mp_start_ap(void) { bus_space_handle_t scu; bus_space_handle_t src; uint32_t val; int i; if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) panic("Couldn't map the SCU\n"); if (bus_space_map(fdtbus_bs_tag, SRC_PHYSBASE, SRC_SIZE, 0, &src) != 0) panic("Couldn't map the system reset controller (SRC)\n"); /* * Invalidate SCU cache tags. The 0x0000ffff constant invalidates all * ways on all cores 0-3. Per the ARM docs, it's harmless to write to * the bits for cores that are not present. */ bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff); /* * Erratum ARM/MP: 764369 (problems with cache maintenance). * Setting the "disable-migratory bit" in the undocumented SCU * Diagnostic Control Register helps work around the problem. */ val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL); bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL, val | SCU_DIAG_DISABLE_MIGBIT); /* * Enable the SCU, then clean the cache on this core. After these two * operations the cache tag ram in the SCU is coherent with the contents * of the cache on this core. The other cores aren't running yet so * their caches can't contain valid data yet, but we've initialized * their SCU tag ram above, so they will be coherent from startup. */ val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG); bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, val | SCU_CONTROL_ENABLE); cpu_idcache_wbinv_all(); /* * For each AP core, set the entry point address and argument registers, * and set the core-enable and core-reset bits in the control register. */ val = bus_space_read_4(fdtbus_bs_tag, src, SRC_CONTROL_REG); for (i=1; i < mp_ncpus; i++) { bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR0_C1FUNC + 8*i, pmap_kextract((vm_offset_t)mpentry)); bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR1_C1ARG + 8*i, 0); val |= ((1 << (SRC_CONTROL_C1ENA_SHIFT - 1 + i )) | ( 1 << (SRC_CONTROL_C1RST_SHIFT - 1 + i))); } bus_space_write_4(fdtbus_bs_tag, src, SRC_CONTROL_REG, val); armv7_sev(); bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); bus_space_unmap(fdtbus_bs_tag, src, SRC_SIZE); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } Index: head/sys/arm/freescale/vybrid/vf_dcu4.c =================================================================== --- head/sys/arm/freescale/vybrid/vf_dcu4.c (revision 281091) +++ head/sys/arm/freescale/vybrid/vf_dcu4.c (revision 281092) @@ -1,467 +1,470 @@ /*- * Copyright (c) 2014 Ruslan Bukin * 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. */ /* * Vybrid Family Display Control Unit (DCU4) * Chapter 55, Vybrid Reference Manual, Rev. 5, 07/2013 */ #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 "gpio_if.h" #include #include #include #include #include "fb_if.h" #include #define DCU_CTRLDESCCURSOR1 0x000 /* Control Descriptor Cursor 1 */ #define DCU_CTRLDESCCURSOR2 0x004 /* Control Descriptor Cursor 2 */ #define DCU_CTRLDESCCURSOR3 0x008 /* Control Descriptor Cursor 3 */ #define DCU_CTRLDESCCURSOR4 0x00C /* Control Descriptor Cursor 4 */ #define DCU_DCU_MODE 0x010 /* DCU4 Mode */ #define DCU_MODE_M 0x3 #define DCU_MODE_S 0 #define DCU_MODE_NORMAL 0x1 #define DCU_MODE_TEST 0x2 #define DCU_MODE_COLBAR 0x3 #define RASTER_EN (1 << 14) /* Raster scan of pixel data */ #define PDI_EN (1 << 13) #define PDI_DE_MODE (1 << 11) #define PDI_MODE_M 2 #define DCU_BGND 0x014 /* Background */ #define DCU_DISP_SIZE 0x018 /* Display Size */ #define DELTA_M 0x7ff #define DELTA_Y_S 16 #define DELTA_X_S 0 #define DCU_HSYN_PARA 0x01C /* Horizontal Sync Parameter */ #define BP_H_SHIFT 22 #define PW_H_SHIFT 11 #define FP_H_SHIFT 0 #define DCU_VSYN_PARA 0x020 /* Vertical Sync Parameter */ #define BP_V_SHIFT 22 #define PW_V_SHIFT 11 #define FP_V_SHIFT 0 #define DCU_SYNPOL 0x024 /* Synchronize Polarity */ #define INV_HS (1 << 0) #define INV_VS (1 << 1) #define INV_PDI_VS (1 << 8) /* Polarity of PDI input VSYNC. */ #define INV_PDI_HS (1 << 9) /* Polarity of PDI input HSYNC. */ #define INV_PDI_DE (1 << 10) /* Polarity of PDI input DE. */ #define DCU_THRESHOLD 0x028 /* Threshold */ #define LS_BF_VS_SHIFT 16 #define OUT_BUF_HIGH_SHIFT 8 #define OUT_BUF_LOW_SHIFT 0 #define DCU_INT_STATUS 0x02C /* Interrupt Status */ #define DCU_INT_MASK 0x030 /* Interrupt Mask */ #define DCU_COLBAR_1 0x034 /* COLBAR_1 */ #define DCU_COLBAR_2 0x038 /* COLBAR_2 */ #define DCU_COLBAR_3 0x03C /* COLBAR_3 */ #define DCU_COLBAR_4 0x040 /* COLBAR_4 */ #define DCU_COLBAR_5 0x044 /* COLBAR_5 */ #define DCU_COLBAR_6 0x048 /* COLBAR_6 */ #define DCU_COLBAR_7 0x04C /* COLBAR_7 */ #define DCU_COLBAR_8 0x050 /* COLBAR_8 */ #define DCU_DIV_RATIO 0x054 /* Divide Ratio */ #define DCU_SIGN_CALC_1 0x058 /* Sign Calculation 1 */ #define DCU_SIGN_CALC_2 0x05C /* Sign Calculation 2 */ #define DCU_CRC_VAL 0x060 /* CRC Value */ #define DCU_PDI_STATUS 0x064 /* PDI Status */ #define DCU_PDI_STA_MSK 0x068 /* PDI Status Mask */ #define DCU_PARR_ERR_STATUS1 0x06C /* Parameter Error Status 1 */ #define DCU_PARR_ERR_STATUS2 0x070 /* Parameter Error Status 2 */ #define DCU_PARR_ERR_STATUS3 0x07C /* Parameter Error Status 3 */ #define DCU_MASK_PARR_ERR_ST1 0x080 /* Mask Parameter Error Status 1 */ #define DCU_MASK_PARR_ERR_ST2 0x084 /* Mask Parameter Error Status 2 */ #define DCU_MASK_PARR_ERR_ST3 0x090 /* Mask Parameter Error Status 3 */ #define DCU_THRESHOLD_INP_BUF_1 0x094 /* Threshold Input 1 */ #define DCU_THRESHOLD_INP_BUF_2 0x098 /* Threshold Input 2 */ #define DCU_THRESHOLD_INP_BUF_3 0x09C /* Threshold Input 3 */ #define DCU_LUMA_COMP 0x0A0 /* LUMA Component */ #define DCU_CHROMA_RED 0x0A4 /* Red Chroma Components */ #define DCU_CHROMA_GREEN 0x0A8 /* Green Chroma Components */ #define DCU_CHROMA_BLUE 0x0AC /* Blue Chroma Components */ #define DCU_CRC_POS 0x0B0 /* CRC Position */ #define DCU_LYR_INTPOL_EN 0x0B4 /* Layer Interpolation Enable */ #define DCU_LYR_LUMA_COMP 0x0B8 /* Layer Luminance Component */ #define DCU_LYR_CHRM_RED 0x0BC /* Layer Chroma Red */ #define DCU_LYR_CHRM_GRN 0x0C0 /* Layer Chroma Green */ #define DCU_LYR_CHRM_BLUE 0x0C4 /* Layer Chroma Blue */ #define DCU_COMP_IMSIZE 0x0C8 /* Compression Image Size */ #define DCU_UPDATE_MODE 0x0CC /* Update Mode */ #define READREG (1 << 30) #define MODE (1 << 31) #define DCU_UNDERRUN 0x0D0 /* Underrun */ #define DCU_GLBL_PROTECT 0x100 /* Global Protection */ #define DCU_SFT_LCK_BIT_L0 0x104 /* Soft Lock Bit Layer 0 */ #define DCU_SFT_LCK_BIT_L1 0x108 /* Soft Lock Bit Layer 1 */ #define DCU_SFT_LCK_DISP_SIZE 0x10C /* Soft Lock Display Size */ #define DCU_SFT_LCK_HS_VS_PARA 0x110 /* Soft Lock Hsync/Vsync Parameter */ #define DCU_SFT_LCK_POL 0x114 /* Soft Lock POL */ #define DCU_SFT_LCK_L0_TRANSP 0x118 /* Soft Lock L0 Transparency */ #define DCU_SFT_LCK_L1_TRANSP 0x11C /* Soft Lock L1 Transparency */ /* Control Descriptor */ #define DCU_CTRLDESCL(n, m) 0x200 + (0x40 * n) + 0x4 * (m - 1) #define DCU_CTRLDESCLn_1(n) DCU_CTRLDESCL(n, 1) #define DCU_CTRLDESCLn_2(n) DCU_CTRLDESCL(n, 2) #define DCU_CTRLDESCLn_3(n) DCU_CTRLDESCL(n, 3) #define TRANS_SHIFT 20 #define DCU_CTRLDESCLn_4(n) DCU_CTRLDESCL(n, 4) #define BPP_MASK 0xf /* Bit per pixel Mask */ #define BPP_SHIFT 16 /* Bit per pixel Shift */ #define BPP24 0x5 #define EN_LAYER (1 << 31) /* Enable the layer */ #define DCU_CTRLDESCLn_5(n) DCU_CTRLDESCL(n, 5) #define DCU_CTRLDESCLn_6(n) DCU_CTRLDESCL(n, 6) #define DCU_CTRLDESCLn_7(n) DCU_CTRLDESCL(n, 7) #define DCU_CTRLDESCLn_8(n) DCU_CTRLDESCL(n, 8) #define DCU_CTRLDESCLn_9(n) DCU_CTRLDESCL(n, 9) #define NUM_LAYERS 64 struct panel_info { uint32_t width; uint32_t height; uint32_t h_back_porch; uint32_t h_pulse_width; uint32_t h_front_porch; uint32_t v_back_porch; uint32_t v_pulse_width; uint32_t v_front_porch; uint32_t clk_div; uint32_t backlight_pin; }; struct dcu_softc { struct resource *res[2]; bus_space_tag_t bst; bus_space_handle_t bsh; void *ih; device_t dev; device_t sc_fbd; /* fbd child */ struct fb_info sc_info; struct panel_info *panel; }; static struct resource_spec dcu_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0 } }; static int dcu_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "fsl,mvf600-dcu4")) return (ENXIO); device_set_desc(dev, "Vybrid Family Display Control Unit (DCU4)"); return (BUS_PROBE_DEFAULT); } static void dcu_intr(void *arg) { struct dcu_softc *sc; int reg; sc = arg; /* Ack interrupts */ reg = READ4(sc, DCU_INT_STATUS); WRITE4(sc, DCU_INT_STATUS, reg); /* TODO interrupt handler */ } static int get_panel_info(struct dcu_softc *sc, struct panel_info *panel) { phandle_t node; pcell_t dts_value[3]; int len; if ((node = ofw_bus_get_node(sc->dev)) == -1) return (ENXIO); /* panel size */ if ((len = OF_getproplen(node, "panel-size")) <= 0) return (ENXIO); OF_getprop(node, "panel-size", &dts_value, len); panel->width = fdt32_to_cpu(dts_value[0]); panel->height = fdt32_to_cpu(dts_value[1]); /* hsync */ if ((len = OF_getproplen(node, "panel-hsync")) <= 0) return (ENXIO); OF_getprop(node, "panel-hsync", &dts_value, len); panel->h_back_porch = fdt32_to_cpu(dts_value[0]); panel->h_pulse_width = fdt32_to_cpu(dts_value[1]); panel->h_front_porch = fdt32_to_cpu(dts_value[2]); /* vsync */ if ((len = OF_getproplen(node, "panel-vsync")) <= 0) return (ENXIO); OF_getprop(node, "panel-vsync", &dts_value, len); panel->v_back_porch = fdt32_to_cpu(dts_value[0]); panel->v_pulse_width = fdt32_to_cpu(dts_value[1]); panel->v_front_porch = fdt32_to_cpu(dts_value[2]); /* clk divider */ if ((len = OF_getproplen(node, "panel-clk-div")) <= 0) return (ENXIO); OF_getprop(node, "panel-clk-div", &dts_value, len); panel->clk_div = fdt32_to_cpu(dts_value[0]); /* backlight pin */ if ((len = OF_getproplen(node, "panel-backlight-pin")) <= 0) return (ENXIO); OF_getprop(node, "panel-backlight-pin", &dts_value, len); panel->backlight_pin = fdt32_to_cpu(dts_value[0]); return (0); } static int dcu_init(struct dcu_softc *sc) { struct panel_info *panel; int reg; int i; panel = sc->panel; /* Configure DCU */ reg = ((sc->sc_info.fb_height) << DELTA_Y_S); reg |= (sc->sc_info.fb_width / 16); WRITE4(sc, DCU_DISP_SIZE, reg); reg = (panel->h_back_porch << BP_H_SHIFT); reg |= (panel->h_pulse_width << PW_H_SHIFT); reg |= (panel->h_front_porch << FP_H_SHIFT); WRITE4(sc, DCU_HSYN_PARA, reg); reg = (panel->v_back_porch << BP_V_SHIFT); reg |= (panel->v_pulse_width << PW_V_SHIFT); reg |= (panel->v_front_porch << FP_V_SHIFT); WRITE4(sc, DCU_VSYN_PARA, reg); WRITE4(sc, DCU_BGND, 0); WRITE4(sc, DCU_DIV_RATIO, panel->clk_div); reg = (INV_VS | INV_HS); WRITE4(sc, DCU_SYNPOL, reg); /* TODO: export to panel info */ reg = (0x3 << LS_BF_VS_SHIFT); reg |= (0x78 << OUT_BUF_HIGH_SHIFT); reg |= (0 << OUT_BUF_LOW_SHIFT); WRITE4(sc, DCU_THRESHOLD, reg); /* Mask all the interrupts */ WRITE4(sc, DCU_INT_MASK, 0xffffffff); /* Reset all layers */ for (i = 0; i < NUM_LAYERS; i++) { WRITE4(sc, DCU_CTRLDESCLn_1(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_2(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_3(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_4(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_5(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_6(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_7(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_8(i), 0x0); WRITE4(sc, DCU_CTRLDESCLn_9(i), 0x0); } /* Setup first layer */ reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 16)); WRITE4(sc, DCU_CTRLDESCLn_1(0), reg); WRITE4(sc, DCU_CTRLDESCLn_2(0), 0x0); WRITE4(sc, DCU_CTRLDESCLn_3(0), sc->sc_info.fb_pbase); reg = (BPP24 << BPP_SHIFT); reg |= EN_LAYER; reg |= (0xFF << TRANS_SHIFT); /* completely opaque */ WRITE4(sc, DCU_CTRLDESCLn_4(0), reg); WRITE4(sc, DCU_CTRLDESCLn_5(0), 0xffffff); WRITE4(sc, DCU_CTRLDESCLn_6(0), 0x0); WRITE4(sc, DCU_CTRLDESCLn_7(0), 0x0); WRITE4(sc, DCU_CTRLDESCLn_8(0), 0x0); WRITE4(sc, DCU_CTRLDESCLn_9(0), 0x0); /* Enable DCU in normal mode */ reg = READ4(sc, DCU_DCU_MODE); reg &= ~(DCU_MODE_M << DCU_MODE_S); reg |= (DCU_MODE_NORMAL << DCU_MODE_S); reg |= (RASTER_EN); WRITE4(sc, DCU_DCU_MODE, reg); WRITE4(sc, DCU_UPDATE_MODE, READREG); return (0); } static int dcu_attach(device_t dev) { struct panel_info panel; struct dcu_softc *sc; device_t gpio_dev; int err; sc = device_get_softc(dev); sc->dev = dev; if (bus_alloc_resources(dev, dcu_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } /* Memory interface */ sc->bst = rman_get_bustag(sc->res[0]); sc->bsh = rman_get_bushandle(sc->res[0]); /* Setup interrupt handler */ err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, NULL, dcu_intr, sc, &sc->ih); if (err) { device_printf(dev, "Unable to alloc interrupt resource.\n"); return (ENXIO); } if (get_panel_info(sc, &panel)) { device_printf(dev, "Can't get panel info\n"); return (ENXIO); } sc->panel = &panel; /* Bypass timing control (used for raw lcd panels) */ tcon_bypass(); /* Get the GPIO device, we need this to give power to USB */ gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (gpio_dev == NULL) { device_printf(sc->dev, "Error: failed to get the GPIO dev\n"); return (1); } /* Turn on backlight */ /* TODO: Use FlexTimer/PWM */ GPIO_PIN_SETFLAGS(gpio_dev, panel.backlight_pin, GPIO_PIN_OUTPUT); GPIO_PIN_SET(gpio_dev, panel.backlight_pin, GPIO_PIN_HIGH); sc->sc_info.fb_width = panel.width; sc->sc_info.fb_height = panel.height; sc->sc_info.fb_stride = sc->sc_info.fb_width * 3; sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 24; sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride; sc->sc_info.fb_vbase = (intptr_t)contigmalloc(sc->sc_info.fb_size, M_DEVBUF, M_ZERO, 0, ~0, PAGE_SIZE, 0); sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase); #if 0 printf("%dx%d [%d]\n", sc->sc_info.fb_width, sc->sc_info.fb_height, sc->sc_info.fb_stride); printf("pbase == 0x%08x\n", sc->sc_info.fb_pbase); #endif memset((int8_t *)sc->sc_info.fb_vbase, 0x0, sc->sc_info.fb_size); dcu_init(sc); sc->sc_info.fb_name = device_get_nameunit(dev); /* Ask newbus to attach framebuffer device to me. */ sc->sc_fbd = device_add_child(dev, "fbd", device_get_unit(dev)); if (sc->sc_fbd == NULL) device_printf(dev, "Can't attach fbd device\n"); if (device_probe_and_attach(sc->sc_fbd) != 0) { device_printf(sc->dev, "Failed to attach fbd device\n"); } return (0); } static struct fb_info * dcu4_fb_getinfo(device_t dev) { struct dcu_softc *sc = device_get_softc(dev); return (&sc->sc_info); } static device_method_t dcu_methods[] = { DEVMETHOD(device_probe, dcu_probe), DEVMETHOD(device_attach, dcu_attach), /* Framebuffer service methods */ DEVMETHOD(fb_getinfo, dcu4_fb_getinfo), { 0, 0 } }; static driver_t dcu_driver = { "fb", dcu_methods, sizeof(struct dcu_softc), }; static devclass_t dcu_devclass; DRIVER_MODULE(fb, simplebus, dcu_driver, dcu_devclass, 0, 0); Index: head/sys/arm/mv/armadaxp/armadaxp_mp.c =================================================================== --- head/sys/arm/mv/armadaxp/armadaxp_mp.c (revision 281091) +++ head/sys/arm/mv/armadaxp/armadaxp_mp.c (revision 281092) @@ -1,194 +1,195 @@ /*- * Copyright (c) 2011 Semihalf. * 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. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #define MV_AXP_CPU_DIVCLK_BASE (MV_BASE + 0x18700) #define CPU_DIVCLK_CTRL0 0x00 #define CPU_DIVCLK_CTRL2_RATIO_FULL0 0x08 #define CPU_DIVCLK_CTRL2_RATIO_FULL1 0x0c #define CPU_DIVCLK_MASK(x) (~(0xff << (8 * (x)))) #define CPU_PMU(x) (MV_BASE + 0x22100 + (0x100 * (x))) #define CPU_PMU_BOOT 0x24 #define MP (MV_BASE + 0x20800) #define MP_SW_RESET(x) ((x) * 8) #define CPU_RESUME_CONTROL (0x20988) void armadaxp_init_coher_fabric(void); int platform_get_ncpus(void); /* Coherency Fabric registers */ static uint32_t read_cpu_clkdiv(uint32_t reg) { return (bus_space_read_4(fdtbus_bs_tag, MV_AXP_CPU_DIVCLK_BASE, reg)); } static void write_cpu_clkdiv(uint32_t reg, uint32_t val) { bus_space_write_4(fdtbus_bs_tag, MV_AXP_CPU_DIVCLK_BASE, reg, val); } void platform_mp_setmaxid(void) { mp_maxid = 3; } int platform_mp_probe(void) { mp_ncpus = platform_get_ncpus(); return (mp_ncpus > 1); } void platform_mp_init_secondary(void) { } void mptramp(void); void mptramp_end(void); extern vm_offset_t mptramp_pmu_boot; void platform_mp_start_ap(void) { uint32_t reg, *src, *dst, cpu_num, div_val, cputype; vm_offset_t pmu_boot_off; /* * Initialization procedure depends on core revision, * in this step CHIP ID is checked to choose proper procedure */ cputype = cpufunc_id(); cputype &= CPU_ID_CPU_MASK; /* * Set the PA of CPU0 Boot Address Redirect register used in * mptramp according to the actual SoC registers' base address. */ pmu_boot_off = (CPU_PMU(0) - MV_BASE) + CPU_PMU_BOOT; mptramp_pmu_boot = fdt_immr_pa + pmu_boot_off; dst = pmap_mapdev(0xffff0000, PAGE_SIZE); for (src = (uint32_t *)mptramp; src < (uint32_t *)mptramp_end; src++, dst++) { *dst = *src; } pmap_unmapdev((vm_offset_t)dst, PAGE_SIZE); if (cputype == CPU_ID_MV88SV584X_V7) { /* Core rev A0 */ div_val = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1); div_val &= 0x3f; for (cpu_num = 1; cpu_num < mp_ncpus; cpu_num++ ) { reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1); reg &= CPU_DIVCLK_MASK(cpu_num); reg |= div_val << (cpu_num * 8); write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1, reg); } } else { /* Core rev Z1 */ div_val = 0x01; if (mp_ncpus > 1) { reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL0); reg &= CPU_DIVCLK_MASK(3); reg |= div_val << 24; write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL0, reg); } for (cpu_num = 2; cpu_num < mp_ncpus; cpu_num++ ) { reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1); reg &= CPU_DIVCLK_MASK(cpu_num); reg |= div_val << (cpu_num * 8); write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1, reg); } } reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL0); reg |= ((0x1 << (mp_ncpus - 1)) - 1) << 21; write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg); reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL0); reg |= 0x01000000; write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg); DELAY(100); reg &= ~(0xf << 21); write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg); DELAY(100); bus_space_write_4(fdtbus_bs_tag, MV_BASE, CPU_RESUME_CONTROL, 0); for (cpu_num = 1; cpu_num < mp_ncpus; cpu_num++ ) bus_space_write_4(fdtbus_bs_tag, CPU_PMU(cpu_num), CPU_PMU_BOOT, pmap_kextract((vm_offset_t)mpentry)); cpu_idcache_wbinv_all(); for (cpu_num = 1; cpu_num < mp_ncpus; cpu_num++ ) bus_space_write_4(fdtbus_bs_tag, MP, MP_SW_RESET(cpu_num), 0); /* XXX: Temporary workaround for hangup after releasing AP's */ wmb(); DELAY(10); armadaxp_init_coher_fabric(); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } Index: head/sys/arm/rockchip/rk30xx_mp.c =================================================================== --- head/sys/arm/rockchip/rk30xx_mp.c (revision 281091) +++ head/sys/arm/rockchip/rk30xx_mp.c (revision 281092) @@ -1,192 +1,195 @@ /*- * Copyright (c) 2014 Ganbold Tsagaankhuu * 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 + #include #include #include #define SCU_PHYSBASE 0x1013c000 #define SCU_SIZE 0x100 #define SCU_CONTROL_REG 0x00 #define SCU_CONTROL_ENABLE (1 << 0) #define SCU_STANDBY_EN (1 << 5) #define SCU_CONFIG_REG 0x04 #define SCU_CONFIG_REG_NCPU_MASK 0x03 #define SCU_CPUPOWER_REG 0x08 #define SCU_INV_TAGS_REG 0x0c #define SCU_FILTER_START_REG 0x10 #define SCU_FILTER_END_REG 0x14 #define SCU_SECURE_ACCESS_REG 0x18 #define SCU_NONSECURE_ACCESS_REG 0x1c #define IMEM_PHYSBASE 0x10080000 #define IMEM_SIZE 0x20 #define PMU_PHYSBASE 0x20004000 #define PMU_SIZE 0x100 #define PMU_PWRDN_CON 0x08 #define PMU_PWRDN_SCU (1 << 4) extern char *mpentry_addr; static void rk30xx_boot2(void); static void rk30xx_boot2(void) { __asm __volatile( "ldr pc, 1f\n" ".globl mpentry_addr\n" "mpentry_addr:\n" "1: .space 4\n"); } void platform_mp_init_secondary(void) { arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { bus_space_handle_t scu; int ncpu; uint32_t val; if (mp_ncpus != 0) return; if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) panic("Could not map the SCU"); val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG); ncpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1; bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); mp_ncpus = ncpu; mp_maxid = ncpu - 1; } int platform_mp_probe(void) { if (mp_ncpus == 0) platform_mp_setmaxid(); return (mp_ncpus > 1); } void platform_mp_start_ap(void) { bus_space_handle_t scu; bus_space_handle_t imem; bus_space_handle_t pmu; uint32_t val; int i; if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) panic("Could not map the SCU"); if (bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE, IMEM_SIZE, 0, &imem) != 0) panic("Could not map the IMEM"); if (bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu) != 0) panic("Could not map the PMU"); /* * Invalidate SCU cache tags. The 0x0000ffff constant invalidates all * ways on all cores 0-3. Per the ARM docs, it's harmless to write to * the bits for cores that are not present. */ bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff); /* Make sure all cores except the first are off */ val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); for (i = 1; i < mp_ncpus; i++) val |= 1 << i; bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); /* Enable SCU power domain */ val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); val &= ~PMU_PWRDN_SCU; bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); /* Enable SCU */ val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG); bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, val | SCU_CONTROL_ENABLE); /* * Cores will execute the code which resides at the start of * the on-chip bootram/sram after power-on. This sram region * should be reserved and the trampoline code that directs * the core to the real startup code in ram should be copied * into this sram region. * * First set boot function for the sram code. */ mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry); /* Copy trampoline to sram, that runs during startup of the core */ bus_space_write_region_4(fdtbus_bs_tag, imem, 0, (uint32_t *)&rk30xx_boot2, 8); cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); /* Start all cores */ val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); for (i = 1; i < mp_ncpus; i++) val &= ~(1 << i); bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); armv7_sev(); bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE); bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } Index: head/sys/arm/samsung/exynos/exynos5_mp.c =================================================================== --- head/sys/arm/samsung/exynos/exynos5_mp.c (revision 281091) +++ head/sys/arm/samsung/exynos/exynos5_mp.c (revision 281092) @@ -1,148 +1,151 @@ /*- * Copyright (c) 2013-2014 Ruslan Bukin * 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 #define EXYNOS_CHIPID 0x10000000 #define EXYNOS5250_SOC_ID 0x43520000 #define EXYNOS5420_SOC_ID 0xE5420000 #define EXYNOS5_SOC_ID_MASK 0xFFFFF000 #define EXYNOS_SYSRAM 0x02020000 #define EXYNOS5420_SYSRAM_NS (EXYNOS_SYSRAM + 0x53000 + 0x1c) #define EXYNOS_PMU_BASE 0x10040000 #define CORE_CONFIG(n) (0x2000 + (0x80 * (n))) #define CORE_STATUS(n) (CORE_CONFIG(n) + 0x4) #define CORE_PWR_EN 0x3 static int exynos_get_soc_id(void) { bus_addr_t chipid; int reg; if (bus_space_map(fdtbus_bs_tag, EXYNOS_CHIPID, 0x1000, 0, &chipid) != 0) panic("Couldn't map chipid\n"); reg = bus_space_read_4(fdtbus_bs_tag, chipid, 0x0); bus_space_unmap(fdtbus_bs_tag, chipid, 0x1000); return (reg & EXYNOS5_SOC_ID_MASK); } void platform_mp_init_secondary(void) { arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { if (exynos_get_soc_id() == EXYNOS5420_SOC_ID) mp_ncpus = 4; else mp_ncpus = 2; mp_maxid = mp_ncpus - 1; } int platform_mp_probe(void) { return (mp_ncpus > 1); } void platform_mp_start_ap(void) { bus_addr_t sysram, pmu; int err, i, j; int status; int reg; err = bus_space_map(fdtbus_bs_tag, EXYNOS_PMU_BASE, 0x20000, 0, &pmu); if (err != 0) panic("Couldn't map pmu\n"); if (exynos_get_soc_id() == EXYNOS5420_SOC_ID) reg = EXYNOS5420_SYSRAM_NS; else reg = EXYNOS_SYSRAM; err = bus_space_map(fdtbus_bs_tag, reg, 0x100, 0, &sysram); if (err != 0) panic("Couldn't map sysram\n"); /* Give power to CPUs */ for (i = 1; i < mp_ncpus; i++) { bus_space_write_4(fdtbus_bs_tag, pmu, CORE_CONFIG(i), CORE_PWR_EN); for (j = 10; j >= 0; j--) { status = bus_space_read_4(fdtbus_bs_tag, pmu, CORE_STATUS(i)); if ((status & CORE_PWR_EN) == CORE_PWR_EN) break; DELAY(10); if (j == 0) printf("Can't power on CPU%d\n", i); } } bus_space_write_4(fdtbus_bs_tag, sysram, 0x0, pmap_kextract((vm_offset_t)mpentry)); cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); armv7_sev(); bus_space_unmap(fdtbus_bs_tag, sysram, 0x100); bus_space_unmap(fdtbus_bs_tag, pmu, 0x20000); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } Index: head/sys/arm/ti/omap4/omap4_mp.c =================================================================== --- head/sys/arm/ti/omap4/omap4_mp.c (revision 281091) +++ head/sys/arm/ti/omap4/omap4_mp.c (revision 281092) @@ -1,84 +1,87 @@ /*- * Copyright (c) 2012 Olivier Houchard. 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 #include #include #include #include void platform_mp_init_secondary(void) { arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { mp_maxid = 1; } int platform_mp_probe(void) { mp_ncpus = 2; return (1); } void platform_mp_start_ap(void) { bus_addr_t scu_addr; if (bus_space_map(fdtbus_bs_tag, 0x48240000, 0x1000, 0, &scu_addr) != 0) panic("Couldn't map the SCU\n"); /* Enable the SCU */ *(volatile unsigned int *)scu_addr |= 1; //*(volatile unsigned int *)(scu_addr + 0x30) |= 1; cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); ti_smc0(0x200, 0xfffffdff, MODIFY_AUX_CORE_0); ti_smc0(pmap_kextract((vm_offset_t)mpentry), 0, WRITE_AUX_CORE_1); armv7_sev(); bus_space_unmap(fdtbus_bs_tag, scu_addr, 0x1000); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); } Index: head/sys/arm/versatile/versatile_pci.c =================================================================== --- head/sys/arm/versatile/versatile_pci.c (revision 281091) +++ head/sys/arm/versatile/versatile_pci.c (revision 281092) @@ -1,517 +1,521 @@ /* * Copyright (c) 2012 Oleksandr Tymoshenko * 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 "pcib_if.h" #include #include #include #include #include #include #define MEM_SYS 0 #define MEM_CORE 1 #define MEM_BASE 2 #define MEM_CONF_BASE 3 #define MEM_REGIONS 4 #define SYS_PCICTL 0x00 #define PCI_CORE_IMAP0 0x00 #define PCI_CORE_IMAP1 0x04 #define PCI_CORE_IMAP2 0x08 #define PCI_CORE_SELFID 0x0C #define PCI_CORE_SMAP0 0x10 #define PCI_CORE_SMAP1 0x14 #define PCI_CORE_SMAP2 0x18 #define VERSATILE_PCI_DEV 0x030010ee #define VERSATILE_PCI_CLASS 0x0b400000 #define PCI_IO_WINDOW 0x44000000 #define PCI_IO_SIZE 0x0c000000 #define PCI_NPREFETCH_WINDOW 0x50000000 #define PCI_NPREFETCH_SIZE 0x10000000 #define PCI_PREFETCH_WINDOW 0x60000000 #define PCI_PREFETCH_SIZE 0x10000000 #define VERSATILE_PCI_IRQ_START 27 #define VERSATILE_PCI_IRQ_END 30 #ifdef DEBUG #define dprintf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define dprintf(fmt, args...) #endif #define versatile_pci_sys_read_4(reg) \ bus_read_4(sc->mem_res[MEM_SYS], (reg)) #define versatile_pci_sys_write_4(reg, val) \ bus_write_4(sc->mem_res[MEM_SYS], (reg), (val)) #define versatile_pci_core_read_4(reg) \ bus_read_4(sc->mem_res[MEM_CORE], (reg)) #define versatile_pci_core_write_4(reg, val) \ bus_write_4(sc->mem_res[MEM_CORE], (reg), (val)) #define versatile_pci_read_4(reg) \ bus_read_4(sc->mem_res[MEM_BASE], (reg)) #define versatile_pci_write_4(reg, val) \ bus_write_4(sc->mem_res[MEM_BASE], (reg), (val)) #define versatile_pci_conf_read_4(reg) \ bus_read_4(sc->mem_res[MEM_CONF_BASE], (reg)) #define versatile_pci_conf_write_4(reg, val) \ bus_write_4(sc->mem_res[MEM_CONF_BASE], (reg), (val)) #define versatile_pci_conf_write_2(reg, val) \ bus_write_2(sc->mem_res[MEM_CONF_BASE], (reg), (val)) #define versatile_pci_conf_write_1(reg, val) \ bus_write_1(sc->mem_res[MEM_CONF_BASE], (reg), (val)) struct versatile_pci_softc { struct resource* mem_res[MEM_REGIONS]; struct resource* irq_res; void* intr_hl; int pcib_slot; /* Bus part */ int busno; struct rman io_rman; struct rman irq_rman; struct rman mem_rman; struct mtx mtx; }; static struct resource_spec versatile_pci_mem_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_MEMORY, 1, RF_ACTIVE }, { SYS_RES_MEMORY, 2, RF_ACTIVE }, { SYS_RES_MEMORY, 3, RF_ACTIVE }, { -1, 0, 0 } }; static int versatile_pci_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "versatile,pci")) { device_set_desc(dev, "Versatile PCI controller"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int versatile_pci_attach(device_t dev) { struct versatile_pci_softc *sc = device_get_softc(dev); int err; int slot; uint32_t vendordev_id, class_id; uint32_t val; /* Request memory resources */ err = bus_alloc_resources(dev, versatile_pci_mem_spec, sc->mem_res); if (err) { device_printf(dev, "Error: could not allocate memory resources\n"); return (ENXIO); } /* * Setup memory windows */ versatile_pci_core_write_4(PCI_CORE_IMAP0, (PCI_IO_WINDOW >> 28)); versatile_pci_core_write_4(PCI_CORE_IMAP1, (PCI_NPREFETCH_WINDOW >> 28)); versatile_pci_core_write_4(PCI_CORE_IMAP2, (PCI_PREFETCH_WINDOW >> 28)); /* * XXX: this is SDRAM offset >> 28 * Unused as of QEMU 1.5 */ versatile_pci_core_write_4(PCI_CORE_SMAP0, (PCI_IO_WINDOW >> 28)); versatile_pci_core_write_4(PCI_CORE_SMAP1, (PCI_NPREFETCH_WINDOW >> 28)); versatile_pci_core_write_4(PCI_CORE_SMAP2, (PCI_NPREFETCH_WINDOW >> 28)); versatile_pci_sys_write_4(SYS_PCICTL, 1); for (slot = 0; slot <= PCI_SLOTMAX; slot++) { vendordev_id = versatile_pci_read_4((slot << 11) + PCIR_DEVVENDOR); class_id = versatile_pci_read_4((slot << 11) + PCIR_REVID); if ((vendordev_id == VERSATILE_PCI_DEV) && (class_id == VERSATILE_PCI_CLASS)) break; } if (slot == (PCI_SLOTMAX + 1)) { bus_release_resources(dev, versatile_pci_mem_spec, sc->mem_res); device_printf(dev, "Versatile PCI core not found\n"); return (ENXIO); } sc->pcib_slot = slot; device_printf(dev, "PCI core at slot #%d\n", slot); versatile_pci_core_write_4(PCI_CORE_SELFID, slot); val = versatile_pci_conf_read_4((slot << 11) + PCIR_COMMAND); val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_MWRICEN); versatile_pci_conf_write_4((slot << 11) + PCIR_COMMAND, val); /* Again SDRAM start >> 28 */ versatile_pci_write_4((slot << 11) + PCIR_BAR(0), 0); versatile_pci_write_4((slot << 11) + PCIR_BAR(1), 0); versatile_pci_write_4((slot << 11) + PCIR_BAR(2), 0); /* Prepare resource managers */ sc->mem_rman.rm_type = RMAN_ARRAY; sc->mem_rman.rm_descr = "versatile PCI memory window"; if (rman_init(&sc->mem_rman) != 0 || rman_manage_region(&sc->mem_rman, PCI_NPREFETCH_WINDOW, PCI_NPREFETCH_WINDOW + PCI_NPREFETCH_SIZE - 1) != 0) { panic("versatile_pci_attach: failed to set up memory rman"); } bootverbose = 1; sc->io_rman.rm_type = RMAN_ARRAY; sc->io_rman.rm_descr = "versatile PCI IO window"; if (rman_init(&sc->io_rman) != 0 || rman_manage_region(&sc->io_rman, PCI_IO_WINDOW, PCI_IO_WINDOW + PCI_IO_SIZE - 1) != 0) { panic("versatile_pci_attach: failed to set up I/O rman"); } sc->irq_rman.rm_type = RMAN_ARRAY; sc->irq_rman.rm_descr = "versatile PCI IRQs"; if (rman_init(&sc->irq_rman) != 0 || rman_manage_region(&sc->irq_rman, VERSATILE_PCI_IRQ_START, VERSATILE_PCI_IRQ_END) != 0) { panic("versatile_pci_attach: failed to set up IRQ rman"); } mtx_init(&sc->mtx, device_get_nameunit(dev), "versatilepci", MTX_SPIN); val = versatile_pci_conf_read_4((12 << 11) + PCIR_COMMAND); for (slot = 0; slot <= PCI_SLOTMAX; slot++) { vendordev_id = versatile_pci_read_4((slot << 11) + PCIR_DEVVENDOR); class_id = versatile_pci_read_4((slot << 11) + PCIR_REVID); if (slot == sc->pcib_slot) continue; if ((vendordev_id == 0xffffffff) && (class_id == 0xffffffff)) continue; val = versatile_pci_conf_read_4((slot << 11) + PCIR_COMMAND); val |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; versatile_pci_conf_write_4((slot << 11) + PCIR_COMMAND, val); } device_add_child(dev, "pci", 0); return (bus_generic_attach(dev)); } static int versatile_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct versatile_pci_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = sc->busno; return (0); } return (ENOENT); } static int versatile_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { struct versatile_pci_softc * sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: sc->busno = result; return (0); } return (ENOENT); } static struct resource * versatile_pci_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 versatile_pci_softc *sc = device_get_softc(bus); struct resource *rv; struct rman *rm; dprintf("Alloc resources %d, %08lx..%08lx, %ld\n", type, start, end, count); switch (type) { case SYS_RES_IOPORT: rm = &sc->io_rman; break; case SYS_RES_IRQ: rm = &sc->irq_rman; break; case SYS_RES_MEMORY: rm = &sc->mem_rman; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); } static int versatile_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { vm_offset_t vaddr; int res; switch(type) { case SYS_RES_MEMORY: case SYS_RES_IOPORT: vaddr = (vm_offset_t)pmap_mapdev(rman_get_start(r), rman_get_size(r)); rman_set_bushandle(r, vaddr); rman_set_bustag(r, arm_base_bs_tag); res = rman_activate_resource(r); break; case SYS_RES_IRQ: res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type, rid, r)); break; default: res = ENXIO; break; } return (res); } static int versatile_pci_setup_intr(device_t bus, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { return BUS_SETUP_INTR(device_get_parent(bus), bus, ires, flags, filt, handler, arg, cookiep); } static int versatile_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { return BUS_TEARDOWN_INTR(device_get_parent(dev), dev, ires, cookie); } static int versatile_pci_maxslots(device_t dev) { return (PCI_SLOTMAX); } static int versatile_pci_route_interrupt(device_t pcib, device_t device, int pin) { return (27 + ((pci_get_slot(device) + pin - 1) & 3)); } static uint32_t versatile_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct versatile_pci_softc *sc = device_get_softc(dev); uint32_t data; uint32_t shift, mask; uint32_t addr; if (sc->pcib_slot == slot) { switch (bytes) { case 4: return (0xffffffff); break; case 2: return (0xffff); break; case 1: return (0xff); break; } } addr = (bus << 16) | (slot << 11) | (func << 8) | (reg & ~3); /* register access is 32-bit aligned */ shift = (reg & 3) * 8; /* Create a mask based on the width, post-shift */ if (bytes == 2) mask = 0xffff; else if (bytes == 1) mask = 0xff; else mask = 0xffffffff; dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, func, reg, bytes); mtx_lock_spin(&sc->mtx); data = versatile_pci_conf_read_4(addr); mtx_unlock_spin(&sc->mtx); /* get request bytes from 32-bit word */ data = (data >> shift) & mask; dprintf("%s: read 0x%x\n", __func__, data); return (data); } static void versatile_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { struct versatile_pci_softc *sc = device_get_softc(dev); uint32_t addr; dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, func, reg, bytes); if (sc->pcib_slot == slot) return; addr = (bus << 16) | (slot << 11) | (func << 8) | reg; mtx_lock_spin(&sc->mtx); switch (bytes) { case 4: versatile_pci_conf_write_4(addr, data); break; case 2: versatile_pci_conf_write_2(addr, data); break; case 1: versatile_pci_conf_write_1(addr, data); break; } mtx_unlock_spin(&sc->mtx); } static device_method_t versatile_pci_methods[] = { DEVMETHOD(device_probe, versatile_pci_probe), DEVMETHOD(device_attach, versatile_pci_attach), /* Bus interface */ DEVMETHOD(bus_read_ivar, versatile_pci_read_ivar), DEVMETHOD(bus_write_ivar, versatile_pci_write_ivar), DEVMETHOD(bus_alloc_resource, versatile_pci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, versatile_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, versatile_pci_setup_intr), DEVMETHOD(bus_teardown_intr, versatile_pci_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, versatile_pci_maxslots), DEVMETHOD(pcib_read_config, versatile_pci_read_config), DEVMETHOD(pcib_write_config, versatile_pci_write_config), DEVMETHOD(pcib_route_interrupt, versatile_pci_route_interrupt), DEVMETHOD_END }; static driver_t versatile_pci_driver = { "pcib", versatile_pci_methods, sizeof(struct versatile_pci_softc), }; static devclass_t versatile_pci_devclass; DRIVER_MODULE(versatile_pci, simplebus, versatile_pci_driver, versatile_pci_devclass, 0, 0); Index: head/sys/arm/xilinx/zy7_mp.c =================================================================== --- head/sys/arm/xilinx/zy7_mp.c (revision 281091) +++ head/sys/arm/xilinx/zy7_mp.c (revision 281092) @@ -1,116 +1,119 @@ /*- * Copyright (c) 2013 Thomas Skibo. 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 #include #include #include #define ZYNQ7_CPU1_ENTRY 0xfffffff0 #define SCU_CONTROL_REG 0xf8f00000 #define SCU_CONTROL_ENABLE (1 << 0) void platform_mp_init_secondary(void) { arm_init_secondary_ic(); } void platform_mp_setmaxid(void) { mp_maxid = 1; } int platform_mp_probe(void) { mp_ncpus = 2; return (1); } void platform_mp_start_ap(void) { bus_space_handle_t scu_handle; bus_space_handle_t ocm_handle; uint32_t scu_ctrl; /* Map in SCU control register. */ if (bus_space_map(fdtbus_bs_tag, SCU_CONTROL_REG, 4, 0, &scu_handle) != 0) panic("platform_mp_start_ap: Couldn't map SCU config reg\n"); /* Set SCU enable bit. */ scu_ctrl = bus_space_read_4(fdtbus_bs_tag, scu_handle, 0); scu_ctrl |= SCU_CONTROL_ENABLE; bus_space_write_4(fdtbus_bs_tag, scu_handle, 0, scu_ctrl); bus_space_unmap(fdtbus_bs_tag, scu_handle, 4); /* Map in magic location to give entry address to CPU1. */ if (bus_space_map(fdtbus_bs_tag, ZYNQ7_CPU1_ENTRY, 4, 0, &ocm_handle) != 0) panic("platform_mp_start_ap: Couldn't map OCM\n"); /* Write start address for CPU1. */ bus_space_write_4(fdtbus_bs_tag, ocm_handle, 0, pmap_kextract((vm_offset_t)mpentry)); bus_space_unmap(fdtbus_bs_tag, ocm_handle, 4); /* * The SCU is enabled above but I think the second CPU doesn't * turn on filtering until after the wake-up below. I think that's why * things don't work if I don't put these cache ops here. Also, the * magic location, 0xfffffff0, isn't in the SCU's filtering range so it * needs a write-back too. */ cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); /* Wake up CPU1. */ armv7_sev(); } void platform_ipi_send(cpuset_t cpus, u_int ipi) { pic_ipi_send(cpus, ipi); }