The BCM7xxx series of Broadcom SoCs are used primarily in set-top boxes. This patch adds machine support for the ARM-based Broadcom SoCs.
Signed-off-by: Marc Carino <marc.cee...@gmail.com> Acked-by: Florian Fainelli <f.faine...@gmail.com> --- arch/arm/Kconfig.debug | 16 +++- arch/arm/configs/brcmstb_defconfig | 127 ++++++++++++++++++++++ arch/arm/mach-bcm/Kconfig | 18 +++ arch/arm/mach-bcm/Makefile | 2 + arch/arm/mach-bcm/brcmstb.c | 205 +++++++++++++++++++++++++++++++++++ arch/arm/mach-bcm/brcmstb.h | 70 ++++++++++++ arch/arm/mach-bcm/headsmp-brcmstb.S | 29 +++++ arch/arm/mach-bcm/hotplug-brcmstb.c | 203 ++++++++++++++++++++++++++++++++++ 8 files changed, 669 insertions(+), 1 deletions(-) create mode 100644 arch/arm/configs/brcmstb_defconfig create mode 100644 arch/arm/mach-bcm/brcmstb.c create mode 100644 arch/arm/mach-bcm/brcmstb.h create mode 100644 arch/arm/mach-bcm/headsmp-brcmstb.S create mode 100644 arch/arm/mach-bcm/hotplug-brcmstb.c diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 5765abf..266c699 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -94,6 +94,17 @@ choice depends on ARCH_BCM2835 select DEBUG_UART_PL01X + config DEBUG_BRCMSTB_UART + bool "Use BRCMSTB UART for low-level debug" + depends on ARCH_BRCMSTB + select DEBUG_UART_8250 + help + Say Y here if you want the debug print routines to direct + their output to the first serial port on these devices. + + If you have a Broadcom STB chip and would like early print + messages to appear over the UART, select this option. + config DEBUG_CLPS711X_UART1 bool "Kernel low-level debugging messages via UART1" depends on ARCH_CLPS711X @@ -988,6 +999,7 @@ config DEBUG_UART_PHYS default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2 default 0x20068000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3 default 0x20201000 if DEBUG_BCM2835 + default 0xf0406b00 if DEBUG_BRCMSTB_UART default 0x4000e400 if DEBUG_LL_UART_EFM32 default 0x40090000 if ARCH_LPC32XX default 0x40100000 if DEBUG_PXA_UART1 @@ -1029,6 +1041,7 @@ config DEBUG_UART_VIRT default 0xf0009000 if DEBUG_CNS3XXX default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 + default 0xfc406b00 if DEBUG_BRCMSTB_UART default 0xf11f1000 if ARCH_VERSATILE default 0xf1600000 if ARCH_INTEGRATOR default 0xf1c28000 if DEBUG_SUNXI_UART0 @@ -1091,7 +1104,8 @@ config DEBUG_UART_8250_WORD default y if DEBUG_PICOXCELL_UART || DEBUG_SOCFPGA_UART || \ ARCH_KEYSTONE || \ DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \ - DEBUG_DAVINCI_DA8XX_UART2 || DEBUG_DAVINCI_TNETV107X_UART1 + DEBUG_DAVINCI_DA8XX_UART2 || DEBUG_DAVINCI_TNETV107X_UART1 || \ + DEBUG_BRCMSTB_UART config DEBUG_UART_8250_FLOW_CONTROL bool "Enable flow control for 8250 UART" diff --git a/arch/arm/configs/brcmstb_defconfig b/arch/arm/configs/brcmstb_defconfig new file mode 100644 index 0000000..1741d92 --- /dev/null +++ b/arch/arm/configs/brcmstb_defconfig @@ -0,0 +1,127 @@ +CONFIG_CROSS_COMPILE="arm-linux-" +CONFIG_KERNEL_LZO=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSFS_DEPRECATED=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BRCMSTB=y +# CONFIG_SWP_EMULATE is not set +CONFIG_SMP=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_CMA_DEBUG=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_RUNTIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_BRIDGE=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_ROM=y +CONFIG_MTD_ABSENT=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_ATA=y +CONFIG_NETDEVICES=y +CONFIG_USB_PEGASUS=y +CONFIG_USB_USBNET=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO is not set +# CONFIG_CONSOLE_TRANSLATIONS is not set +# CONFIG_VT_CONSOLE is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_HW_RANDOM=y +CONFIG_SPI=y +# CONFIG_HWMON is not set +CONFIG_USB=y +CONFIG_USB_MON=y +CONFIG_USB_STORAGE=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set +CONFIG_EXT4_FS=y +CONFIG_JBD2_DEBUG=y +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_UDF_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_UBIFS_FS=y +CONFIG_SQUASHFS=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_LL=y +CONFIG_EARLY_PRINTK=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 9fe6d88..9179259 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -31,6 +31,24 @@ config ARCH_BCM_MOBILE BCM11130, BCM11140, BCM11351, BCM28145 and BCM28155 variants. +config ARCH_BRCMSTB + bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7 + depends on MMU + select ARM_ARCH_TIMER + select ARM_GIC + select BRCMSTB + select MIGHT_HAVE_PCI + select HAVE_SMP + select USE_OF + select CPU_V7 + select GENERIC_CLOCKEVENTS + help + Say Y if you intend to run the kernel on a Broadcom ARM-based STB + chipset. + + This enables support for Broadcom ARM-based set-top box chipsets, + including the 7445 family of chips. + endmenu endif diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index c2ccd5a..1e9060e 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -13,3 +13,5 @@ obj-$(CONFIG_ARCH_BCM_MOBILE) := board_bcm281xx.o bcm_kona_smc.o bcm_kona_smc_asm.o kona.o plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_bcm_kona_smc_asm.o :=-Wa,-march=armv7-a$(plus_sec) + +obj-$(CONFIG_ARCH_BRCMSTB) := brcmstb.o headsmp-brcmstb.o hotplug-brcmstb.o diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c new file mode 100644 index 0000000..9e27fe0 --- /dev/null +++ b/arch/arm/mach-bcm/brcmstb.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/console.h> +#include <linux/clocksource.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/printk.h> +#include <linux/smp.h> + +#include <asm/cacheflush.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> + +#include "brcmstb.h" + +struct platform_regs brcm_plat_regs; + +/*********************************************************************** + * STB CPU (main application processor) + ***********************************************************************/ + +static struct map_desc brcmstb_io_map[] __initdata = { + { + .virtual = (unsigned long)BRCMSTB_PERIPH_VIRT, + .pfn = __phys_to_pfn(BRCMSTB_PERIPH_PHYS), + .length = BRCMSTB_PERIPH_LENGTH, + .type = MT_DEVICE, + }, +}; + +static const char *brcmstb_match[] __initconst = { + "brcm,brcmstb", + NULL +}; + +static struct node_reg sun_top_ctrl_regs[] __initdata = { + {"reset-source-enable-reg", &brcm_plat_regs.reset_source_enable_reg}, + {"sw-master-reset-reg", &brcm_plat_regs.sw_master_reset_reg}, + {NULL, NULL} +}; + +static struct node_reg cpu_biu_ctrl_regs[] __initdata = { + {"cpu-reset-config-reg", &brcm_plat_regs.cpu_reset_config_reg}, + {"cpu0-pwr-zone-ctrl-reg", &brcm_plat_regs.cpu0_pwr_zone_ctrl_reg}, + {NULL, NULL} +}; + +static struct node_reg hif_continuation_regs[] __initdata = { + {"stb-boot-hi-addr0-reg", &brcm_plat_regs.hif_continuation_regs_base}, + {NULL, NULL} +}; + +static struct node_reg_block top_reg_blocks[] __initdata = { + {"brcm,brcmstb-sun-top-ctrl", sun_top_ctrl_regs}, + {"brcm,brcmstb-cpu-biu-ctrl", cpu_biu_ctrl_regs}, + {"brcm,brcmstb-hif-continuation", hif_continuation_regs}, + {NULL, NULL} +}; + +static void __init brcmstb_map_io(void) +{ + iotable_init(brcmstb_io_map, ARRAY_SIZE(brcmstb_io_map)); +} + +static void brcmstb_restart(enum reboot_mode mode, const char *cmd) +{ + writel_relaxed(1, brcm_plat_regs.reset_source_enable_reg); + readl_relaxed(brcm_plat_regs.reset_source_enable_reg); + + writel_relaxed(1, brcm_plat_regs.sw_master_reset_reg); + readl_relaxed(brcm_plat_regs.sw_master_reset_reg); + + while (1) + ; +} + +static void __init brcmstb_init_early(void) +{ + void __iomem *addr; + struct node_reg_block *block; + + add_preferred_console("ttyS", 0, "115200"); + + addr = ioremap(BPHYSADDR(BCHP_IRQ0_IRQEN), sizeof(u32)); + writel_relaxed(BCHP_IRQ0_IRQEN_uarta_irqen_MASK + | BCHP_IRQ0_IRQEN_uartb_irqen_MASK + | BCHP_IRQ0_IRQEN_uartc_irqen_MASK, addr); + iounmap(addr); + + block = top_reg_blocks; + while (block->compatible) { + struct device_node *np; + struct node_reg *reg; + + np = of_find_compatible_node(NULL, NULL, block->compatible); + if (!np) + panic("brcmstb: DT missing \"%s\" node\n", + block->compatible); + + addr = of_iomap(np, 0); + if (!addr) + panic("brcmstb: iomap failure\n"); + + reg = block->regs; + while (reg->prop) { + u32 val; + + if (!of_property_read_u32(np, reg->prop, &val)) + *(reg->addr) = addr + val; + else + panic("brcmstb: node \"%s\" missing prop \"%s\"\n", + block->compatible, reg->prop); + + reg++; + } + + of_node_put(np); + + block++; + } +} + +static void __init brcmstb_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +/*********************************************************************** + * SMP boot + ***********************************************************************/ + +static DEFINE_SPINLOCK(boot_lock); + +static void __cpuinit brcmstb_secondary_init(unsigned int cpu) +{ + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +static int __cpuinit brcmstb_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + /* + * set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* Bring up power to the core if necessary */ + if (brcmstb_cpu_get_power_state(cpu) == 0) + brcmstb_cpu_power_on(cpu); + + brcmstb_cpu_boot(cpu); + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return 0; +} + +struct smp_operations brcmstb_smp_ops __initdata = { + .smp_secondary_init = brcmstb_secondary_init, + .smp_boot_secondary = brcmstb_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = brcmstb_cpu_kill, + .cpu_die = brcmstb_cpu_die, +#endif +}; + +DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)") + .map_io = brcmstb_map_io, + .dt_compat = brcmstb_match, + .restart = brcmstb_restart, + .smp = smp_ops(brcmstb_smp_ops), + .init_early = brcmstb_init_early, + .init_machine = brcmstb_init +MACHINE_END diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h new file mode 100644 index 0000000..d08dffc --- /dev/null +++ b/arch/arm/mach-bcm/brcmstb.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __BRCMSTB_H__ +#define __BRCMSTB_H__ + +#if !defined(__ASSEMBLY__) +#include <linux/smp.h> +#endif + +#define BRCMSTB_PERIPH_VIRT 0xfc000000 +#define BRCMSTB_PERIPH_PHYS 0xf0000000 +#define BRCMSTB_PERIPH_LENGTH 0x02000000 + +#define BVIRTADDR(x) (BRCMSTB_PERIPH_VIRT + ((x) & 0x0fffffff)) +#define BPHYSADDR(x) ((x) + BRCMSTB_PERIPH_PHYS) + +#define BCHP_UARTA_REG_START 0x00406b00 + +#define BCHP_IRQ0_IRQEN 0x00406780 +#define BCHP_IRQ0_IRQEN_uarta_irqen_MASK 0x00010000 +#define BCHP_IRQ0_IRQEN_uartb_irqen_MASK 0x00020000 +#define BCHP_IRQ0_IRQEN_uartc_irqen_MASK 0x00040000 + +#if !defined(__ASSEMBLY__) + +extern void brcmstb_secondary_startup(void); +extern void brcmstb_cpu_boot(unsigned int cpu); +extern void brcmstb_cpu_power_on(unsigned int cpu); +extern int brcmstb_cpu_get_power_state(unsigned int cpu); +extern struct smp_operations brcmstb_smp_ops; + +#ifdef CONFIG_HOTPLUG_CPU +extern void brcmstb_cpu_die(unsigned int cpu); +extern int brcmstb_cpu_kill(unsigned int cpu); +#endif + +struct node_reg { + const char *prop; + void __iomem **addr; +}; + +struct node_reg_block { + const char *compatible; + struct node_reg *regs; +}; + +struct platform_regs { + void __iomem *cpu_reset_config_reg; + void __iomem *cpu0_pwr_zone_ctrl_reg; + void __iomem *hif_continuation_regs_base; + void __iomem *reset_source_enable_reg; + void __iomem *sw_master_reset_reg; +}; + +extern struct platform_regs brcm_plat_regs; + +#endif + +#endif /* __BRCMSTB_H__ */ diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S new file mode 100644 index 0000000..cb86e4b --- /dev/null +++ b/arch/arm/mach-bcm/headsmp-brcmstb.S @@ -0,0 +1,29 @@ +/* + * SMP boot code for secondary CPUs + * Based on arch/arm/mach-tegra/headsmp.S + * + * Copyright (C) 2010 NVIDIA, Inc. + * Copyright (C) 2013 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> +#include <linux/init.h> + + .section ".text.head", "ax" + __CPUINIT + +ENTRY(brcmstb_secondary_startup) + mov r0, #0xd3 + msr cpsr_fsxc, r0 + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(brcmstb_secondary_startup) diff --git a/arch/arm/mach-bcm/hotplug-brcmstb.c b/arch/arm/mach-bcm/hotplug-brcmstb.c new file mode 100644 index 0000000..53ecc6d --- /dev/null +++ b/arch/arm/mach-bcm/hotplug-brcmstb.c @@ -0,0 +1,203 @@ +/* + * Broadcom STB CPU hotplug support for ARM + * + * Copyright (C) 2013 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/printk.h> +#include <linux/smp.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/mach-types.h> + +#include "brcmstb.h" + +#define ZONE_PWR_DN_REQ_MASK 0x00000200 +#define ZONE_PWR_UP_REQ_MASK 0x00000400 +#define ZONE_BLK_RST_ASSERT_MASK 0x00001000 +#define ZONE_PWR_OFF_STATE_MASK 0x02000000 +#define ZONE_PWR_ON_STATE_MASK 0x04000000 +#define ZONE_RESET_STATE_MASK 0x80000000 + +static void __iomem *pwr_zone_ctrl_get_base(unsigned int cpu) +{ + void __iomem *base = brcm_plat_regs.cpu0_pwr_zone_ctrl_reg; + base += (cpu * 4); + return base; +} + +static u32 pwr_zone_ctrl_rd(unsigned int cpu) +{ + void __iomem *base = pwr_zone_ctrl_get_base(cpu); + return readl_relaxed(base); +} + +static void pwr_zone_ctrl_wr(unsigned int cpu, u32 val) +{ + void __iomem *base = pwr_zone_ctrl_get_base(cpu); + writel_relaxed(val, base); + dsb(); +} + +void brcmstb_cpu_boot(unsigned int cpu) +{ + unsigned long boot_vector; + const int reg_ofs = cpu * 8; + u32 val; + + pr_info("SMP: Booting CPU%d...\n", cpu); + + /* + * set the reset vector to point to the secondary_startup + * routine + */ + boot_vector = virt_to_phys(brcmstb_secondary_startup); + writel_relaxed(0, brcm_plat_regs.hif_continuation_regs_base + reg_ofs); + writel_relaxed(boot_vector, brcm_plat_regs.hif_continuation_regs_base + + 4 + reg_ofs); + + flush_cache_all(); + + /* unhalt the cpu */ + val = readl_relaxed(brcm_plat_regs.cpu_reset_config_reg); + val &= ~BIT(cpu); + writel_relaxed(val, brcm_plat_regs.cpu_reset_config_reg); +} + +void brcmstb_cpu_power_on(unsigned int cpu) +{ + /* + * The secondary cores power was cut, so we must go through + * power-on initialization. + */ + u32 tmp; + + pr_info("SMP: Powering up CPU%d...\n", cpu); + + /* Request zone power up */ + pwr_zone_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK); + + /* Wait for the power up FSM to complete */ + do { + tmp = pwr_zone_ctrl_rd(cpu); + } while (!(tmp & ZONE_PWR_ON_STATE_MASK)); +} + +int brcmstb_cpu_get_power_state(unsigned int cpu) +{ + int tmp = pwr_zone_ctrl_rd(cpu); + return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1; +} + +void __ref brcmstb_cpu_die(unsigned int cpu) +{ + /* Derived from misc_bpcm_arm.c */ + + /* Clear SCTLR.C bit */ + __asm__( + "mrc p15, 0, r0, c1, c0, 0\n" + "bic r0, r0, #(1 << 2)\n" + "mcr p15, 0, r0, c1, c0, 0\n" + : /* no output */ + : /* no input */ + : "r0" /* clobber r0 */ + ); + + /* + * Instruction barrier to ensure cache is really disabled before + * cleaning/invalidating the caches + */ + isb(); + + flush_cache_all(); + + /* Invalidate all instruction caches to PoU (ICIALLU) */ + /* Data sync. barrier to ensure caches have emptied out */ + __asm__("mcr p15, 0, r0, c7, c5, 0\n" : : : "r0"); + dsb(); + + /* + * Clear ACTLR.SMP bit to prevent broadcast TLB messages from reaching + * this core + */ + __asm__( + "mrc p15, 0, r0, c1, c0, 1\n" + "bic r0, r0, #(1 << 6)\n" + "mcr p15, 0, r0, c1, c0, 1\n" + : /* no output */ + : /* no input */ + : "r0" /* clobber r0 */ + ); + + /* Disable all IRQs for this CPU */ + arch_local_irq_disable(); + + /* + * Final full barrier to ensure everything before this instruction has + * quiesced. + */ + isb(); + dsb(); + + /* Sit and wait to die */ + wfi(); + + /* We should never get here... */ + nop(); + panic("Spurious interrupt on CPU %d received!\n", cpu); +} + +static void busy_wait(int i) +{ + while (--i != 0) + nop(); +} + +int brcmstb_cpu_kill(unsigned int cpu) +{ + u32 tmp; + u32 val; + + pr_info("SMP: Powering down CPU%d...\n", cpu); + + /* Program zone reset */ + pwr_zone_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK | + ZONE_PWR_DN_REQ_MASK); + + /* Verify zone reset */ + tmp = pwr_zone_ctrl_rd(cpu); + if (!(tmp & ZONE_RESET_STATE_MASK)) + pr_err("%s: Zone reset bit for CPU %d not asserted!\n", + __func__, cpu); + + /* Wait for power down */ + do { + tmp = pwr_zone_ctrl_rd(cpu); + } while (!(tmp & ZONE_PWR_OFF_STATE_MASK)); + + /* Magic delay from misc_bpcm_arm.c */ + busy_wait(10000); + + /* Assert reset on the CPU */ + val = readl_relaxed(brcm_plat_regs.cpu_reset_config_reg); + val |= BIT(cpu); + writel_relaxed(val, brcm_plat_regs.cpu_reset_config_reg); + + return 1; +} + -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/