From d7445676e86900f8dc363825033ff62416c216e0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 1 Apr 2022 14:35:42 +0200 Subject: ARM: versatile: move integrator/realview/vexpress to versatile These are all fairly small platforms by now, and they are closely related. Just move them all into a single directory. Cc: Linus Walleij Cc: Liviu Dudau Cc: Lorenzo Pieralisi Tested-by: Sudeep Holla Acked-by: Sudeep Holla Signed-off-by: Arnd Bergmann --- MAINTAINERS | 3 - arch/arm/Kconfig | 6 - arch/arm/Makefile | 7 +- arch/arm/mach-integrator/Kconfig | 125 ------ arch/arm/mach-integrator/Makefile | 10 - arch/arm/mach-integrator/cm.h | 41 -- arch/arm/mach-integrator/common.h | 7 - arch/arm/mach-integrator/core.c | 96 ---- arch/arm/mach-integrator/hardware.h | 336 -------------- arch/arm/mach-integrator/integrator_ap.c | 202 --------- arch/arm/mach-integrator/integrator_cp.c | 147 ------ arch/arm/mach-realview/Kconfig | 103 ----- arch/arm/mach-realview/Makefile | 8 - arch/arm/mach-realview/platsmp-dt.c | 93 ---- arch/arm/mach-realview/realview-dt.c | 27 -- arch/arm/mach-versatile/Kconfig | 308 +++++++++++++ arch/arm/mach-versatile/Makefile | 32 +- arch/arm/mach-versatile/Makefile.boot | 4 + arch/arm/mach-versatile/dcscb.c | 172 +++++++ arch/arm/mach-versatile/dcscb_setup.S | 33 ++ arch/arm/mach-versatile/headsmp.S | 36 ++ arch/arm/mach-versatile/hotplug.c | 102 +++++ arch/arm/mach-versatile/integrator-cm.h | 41 ++ arch/arm/mach-versatile/integrator-hardware.h | 336 ++++++++++++++ arch/arm/mach-versatile/integrator.c | 94 ++++ arch/arm/mach-versatile/integrator.h | 7 + arch/arm/mach-versatile/integrator_ap.c | 200 +++++++++ arch/arm/mach-versatile/integrator_cp.c | 145 ++++++ arch/arm/mach-versatile/platsmp-realview.c | 93 ++++ arch/arm/mach-versatile/platsmp-vexpress.c | 93 ++++ arch/arm/mach-versatile/platsmp.c | 107 +++++ arch/arm/mach-versatile/platsmp.h | 11 + arch/arm/mach-versatile/realview.c | 27 ++ arch/arm/mach-versatile/spc.c | 598 +++++++++++++++++++++++++ arch/arm/mach-versatile/spc.h | 18 + arch/arm/mach-versatile/tc2_pm.c | 261 +++++++++++ arch/arm/mach-versatile/v2m-mps2.c | 17 + arch/arm/mach-versatile/v2m.c | 40 ++ arch/arm/mach-versatile/versatile.c | 185 ++++++++ arch/arm/mach-versatile/versatile_dt.c | 185 -------- arch/arm/mach-versatile/vexpress.h | 4 + arch/arm/mach-vexpress/Kconfig | 81 ---- arch/arm/mach-vexpress/Makefile | 19 - arch/arm/mach-vexpress/Makefile.boot | 4 - arch/arm/mach-vexpress/core.h | 4 - arch/arm/mach-vexpress/dcscb.c | 172 ------- arch/arm/mach-vexpress/dcscb_setup.S | 35 -- arch/arm/mach-vexpress/platsmp.c | 96 ---- arch/arm/mach-vexpress/spc.c | 598 ------------------------- arch/arm/mach-vexpress/spc.h | 18 - arch/arm/mach-vexpress/tc2_pm.c | 263 ----------- arch/arm/mach-vexpress/v2m-mps2.c | 17 - arch/arm/mach-vexpress/v2m.c | 40 -- arch/arm/plat-versatile/Makefile | 5 - arch/arm/plat-versatile/headsmp.S | 38 -- arch/arm/plat-versatile/hotplug.c | 102 ----- arch/arm/plat-versatile/include/plat/platsmp.h | 13 - arch/arm/plat-versatile/platsmp.c | 109 ----- 58 files changed, 2964 insertions(+), 3010 deletions(-) delete mode 100644 arch/arm/mach-integrator/Kconfig delete mode 100644 arch/arm/mach-integrator/Makefile delete mode 100644 arch/arm/mach-integrator/cm.h delete mode 100644 arch/arm/mach-integrator/common.h delete mode 100644 arch/arm/mach-integrator/core.c delete mode 100644 arch/arm/mach-integrator/hardware.h delete mode 100644 arch/arm/mach-integrator/integrator_ap.c delete mode 100644 arch/arm/mach-integrator/integrator_cp.c delete mode 100644 arch/arm/mach-realview/Kconfig delete mode 100644 arch/arm/mach-realview/Makefile delete mode 100644 arch/arm/mach-realview/platsmp-dt.c delete mode 100644 arch/arm/mach-realview/realview-dt.c create mode 100644 arch/arm/mach-versatile/Makefile.boot create mode 100644 arch/arm/mach-versatile/dcscb.c create mode 100644 arch/arm/mach-versatile/dcscb_setup.S create mode 100644 arch/arm/mach-versatile/headsmp.S create mode 100644 arch/arm/mach-versatile/hotplug.c create mode 100644 arch/arm/mach-versatile/integrator-cm.h create mode 100644 arch/arm/mach-versatile/integrator-hardware.h create mode 100644 arch/arm/mach-versatile/integrator.c create mode 100644 arch/arm/mach-versatile/integrator.h create mode 100644 arch/arm/mach-versatile/integrator_ap.c create mode 100644 arch/arm/mach-versatile/integrator_cp.c create mode 100644 arch/arm/mach-versatile/platsmp-realview.c create mode 100644 arch/arm/mach-versatile/platsmp-vexpress.c create mode 100644 arch/arm/mach-versatile/platsmp.c create mode 100644 arch/arm/mach-versatile/platsmp.h create mode 100644 arch/arm/mach-versatile/realview.c create mode 100644 arch/arm/mach-versatile/spc.c create mode 100644 arch/arm/mach-versatile/spc.h create mode 100644 arch/arm/mach-versatile/tc2_pm.c create mode 100644 arch/arm/mach-versatile/v2m-mps2.c create mode 100644 arch/arm/mach-versatile/v2m.c create mode 100644 arch/arm/mach-versatile/versatile.c delete mode 100644 arch/arm/mach-versatile/versatile_dt.c create mode 100644 arch/arm/mach-versatile/vexpress.h delete mode 100644 arch/arm/mach-vexpress/Kconfig delete mode 100644 arch/arm/mach-vexpress/Makefile delete mode 100644 arch/arm/mach-vexpress/Makefile.boot delete mode 100644 arch/arm/mach-vexpress/core.h delete mode 100644 arch/arm/mach-vexpress/dcscb.c delete mode 100644 arch/arm/mach-vexpress/dcscb_setup.S delete mode 100644 arch/arm/mach-vexpress/platsmp.c delete mode 100644 arch/arm/mach-vexpress/spc.c delete mode 100644 arch/arm/mach-vexpress/spc.h delete mode 100644 arch/arm/mach-vexpress/tc2_pm.c delete mode 100644 arch/arm/mach-vexpress/v2m-mps2.c delete mode 100644 arch/arm/mach-vexpress/v2m.c delete mode 100644 arch/arm/plat-versatile/Makefile delete mode 100644 arch/arm/plat-versatile/headsmp.S delete mode 100644 arch/arm/plat-versatile/hotplug.c delete mode 100644 arch/arm/plat-versatile/include/plat/platsmp.h delete mode 100644 arch/arm/plat-versatile/platsmp.c diff --git a/MAINTAINERS b/MAINTAINERS index fd768d43e048..6a0363b0f106 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1525,10 +1525,7 @@ F: Documentation/devicetree/bindings/mtd/mtd-physmap.yaml F: arch/arm/boot/dts/arm-realview-* F: arch/arm/boot/dts/integrator* F: arch/arm/boot/dts/versatile* -F: arch/arm/mach-integrator/ -F: arch/arm/mach-realview/ F: arch/arm/mach-versatile/ -F: arch/arm/plat-versatile/ F: drivers/bus/arm-integrator-lm.c F: drivers/clk/versatile/ F: drivers/i2c/busses/i2c-versatile.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2e8091e2d8a8..31f024e6e925 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -622,8 +622,6 @@ source "arch/arm/mach-hisi/Kconfig" source "arch/arm/mach-imx/Kconfig" -source "arch/arm/mach-integrator/Kconfig" - source "arch/arm/mach-iop32x/Kconfig" source "arch/arm/mach-ixp4xx/Kconfig" @@ -675,8 +673,6 @@ source "arch/arm/mach-rda/Kconfig" source "arch/arm/mach-realtek/Kconfig" -source "arch/arm/mach-realview/Kconfig" - source "arch/arm/mach-rockchip/Kconfig" source "arch/arm/mach-s3c/Kconfig" @@ -705,8 +701,6 @@ source "arch/arm/mach-ux500/Kconfig" source "arch/arm/mach-versatile/Kconfig" -source "arch/arm/mach-vexpress/Kconfig" - source "arch/arm/mach-vt8500/Kconfig" source "arch/arm/mach-zynq/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index a2391b8de5a5..8740e3a63afb 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -179,7 +179,6 @@ machine-$(CONFIG_ARCH_FOOTBRIDGE) += footbridge machine-$(CONFIG_ARCH_GEMINI) += gemini machine-$(CONFIG_ARCH_HIGHBANK) += highbank machine-$(CONFIG_ARCH_HISI) += hisi -machine-$(CONFIG_ARCH_INTEGRATOR) += integrator machine-$(CONFIG_ARCH_IOP32X) += iop32x machine-$(CONFIG_ARCH_IXP4XX) += ixp4xx machine-$(CONFIG_ARCH_KEYSTONE) += keystone @@ -187,7 +186,6 @@ machine-$(CONFIG_ARCH_LPC18XX) += lpc18xx machine-$(CONFIG_ARCH_LPC32XX) += lpc32xx machine-$(CONFIG_ARCH_MESON) += meson machine-$(CONFIG_ARCH_MMP) += mmp -machine-$(CONFIG_ARCH_MPS2) += vexpress machine-$(CONFIG_ARCH_MOXART) += moxart machine-$(CONFIG_ARCH_MV78XX0) += mv78xx0 machine-$(CONFIG_ARCH_MVEBU) += mvebu @@ -207,7 +205,6 @@ machine-$(CONFIG_ARCH_PXA) += pxa machine-$(CONFIG_ARCH_QCOM) += qcom machine-$(CONFIG_ARCH_RDA) += rda machine-$(CONFIG_ARCH_REALTEK) += realtek -machine-$(CONFIG_ARCH_REALVIEW) += realview machine-$(CONFIG_ARCH_ROCKCHIP) += rockchip machine-$(CONFIG_ARCH_RPC) += rpc machine-$(CONFIG_PLAT_SAMSUNG) += s3c @@ -220,10 +217,9 @@ machine-$(CONFIG_ARCH_STM32) += stm32 machine-$(CONFIG_ARCH_SUNXI) += sunxi machine-$(CONFIG_ARCH_TEGRA) += tegra machine-$(CONFIG_ARCH_U8500) += ux500 -machine-$(CONFIG_ARCH_VERSATILE) += versatile -machine-$(CONFIG_ARCH_VEXPRESS) += vexpress machine-$(CONFIG_ARCH_VT8500) += vt8500 machine-$(CONFIG_ARCH_ZYNQ) += zynq +machine-$(CONFIG_PLAT_VERSATILE) += versatile machine-$(CONFIG_PLAT_SPEAR) += spear # Platform directory name. This list is sorted alphanumerically @@ -231,7 +227,6 @@ machine-$(CONFIG_PLAT_SPEAR) += spear plat-$(CONFIG_ARCH_OMAP) += omap plat-$(CONFIG_PLAT_ORION) += orion plat-$(CONFIG_PLAT_PXA) += pxa -plat-$(CONFIG_PLAT_VERSATILE) += versatile # The byte offset of the kernel image in RAM from the start of RAM. TEXT_OFFSET := $(textofs-y) diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig deleted file mode 100644 index d61ea616cf8e..000000000000 --- a/arch/arm/mach-integrator/Kconfig +++ /dev/null @@ -1,125 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -menuconfig ARCH_INTEGRATOR - bool "ARM Ltd. Integrator family" - depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6 - select ARM_AMBA - select CMA - select DMA_CMA - select HAVE_TCM - select CLK_ICST - select MFD_SYSCON - select PLAT_VERSATILE - select POWER_RESET - select POWER_RESET_VERSATILE - select POWER_SUPPLY - select SOC_INTEGRATOR_CM - select VERSATILE_FPGA_IRQ - help - Support for ARM's Integrator platform. - -if ARCH_INTEGRATOR - -config ARCH_INTEGRATOR_AP - bool "Support Integrator/AP and Integrator/PP2 platforms" - select INTEGRATOR_AP_TIMER - select SERIAL_AMBA_PL010 if TTY - select SERIAL_AMBA_PL010_CONSOLE if TTY - select SOC_BUS - help - Include support for the ARM(R) Integrator/AP and - Integrator/PP2 platforms. - -config INTEGRATOR_IMPD1 - bool "Include support for Integrator/IM-PD1" - depends on ARCH_INTEGRATOR_AP - select ARM_VIC - select GPIO_PL061 - select GPIOLIB - select REGULATOR - select REGULATOR_FIXED_VOLTAGE - help - The IM-PD1 is an add-on logic module for the Integrator which - allows ARM(R) Ltd PrimeCells to be developed and evaluated. - The IM-PD1 can be found on the Integrator/PP2 platform. - -config INTEGRATOR_CM720T - bool "Integrator/CM720T core module" - depends on ARCH_INTEGRATOR_AP - depends on ARCH_MULTI_V4T - select CPU_ARM720T - -config INTEGRATOR_CM920T - bool "Integrator/CM920T core module" - depends on ARCH_INTEGRATOR_AP - depends on ARCH_MULTI_V4T - select CPU_ARM920T - -config INTEGRATOR_CM922T_XA10 - bool "Integrator/CM922T-XA10 core module" - depends on ARCH_MULTI_V4T - depends on ARCH_INTEGRATOR_AP - select CPU_ARM922T - -config INTEGRATOR_CM926EJS - bool "Integrator/CM926EJ-S core module" - depends on ARCH_INTEGRATOR_AP - depends on ARCH_MULTI_V5 - select CPU_ARM926T - -config INTEGRATOR_CM10200E_REV0 - bool "Integrator/CM10200E rev.0 core module" - depends on ARCH_INTEGRATOR_AP && n - depends on ARCH_MULTI_V5 - select CPU_ARM1020 - -config INTEGRATOR_CM10200E - bool "Integrator/CM10200E core module" - depends on ARCH_INTEGRATOR_AP && n - depends on ARCH_MULTI_V5 - select CPU_ARM1020E - -config INTEGRATOR_CM10220E - bool "Integrator/CM10220E core module" - depends on ARCH_INTEGRATOR_AP - depends on ARCH_MULTI_V5 - select CPU_ARM1022 - -config INTEGRATOR_CM1026EJS - bool "Integrator/CM1026EJ-S core module" - depends on ARCH_INTEGRATOR_AP - depends on ARCH_MULTI_V5 - select CPU_ARM1026 - -config INTEGRATOR_CM1136JFS - bool "Integrator/CM1136JF-S core module" - depends on ARCH_INTEGRATOR_AP - depends on ARCH_MULTI_V6 - select CPU_V6 - -config ARCH_INTEGRATOR_CP - bool "Support Integrator/CP platform" - depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 - select ARM_TIMER_SP804 - select SERIAL_AMBA_PL011 if TTY - select SERIAL_AMBA_PL011_CONSOLE if TTY - select SOC_BUS - help - Include support for the ARM(R) Integrator CP platform. - -config INTEGRATOR_CT926 - bool "Integrator/CT926 (ARM926EJ-S) core tile" - depends on ARCH_INTEGRATOR_CP - depends on ARCH_MULTI_V5 - select CPU_ARM926T - -config INTEGRATOR_CTB36 - bool "Integrator/CTB36 (ARM1136JF-S) core tile" - depends on ARCH_INTEGRATOR_CP - depends on ARCH_MULTI_V6 - select CPU_V6 - -config ARCH_CINTEGRATOR - depends on ARCH_INTEGRATOR_CP - def_bool y - -endif diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile deleted file mode 100644 index 7857a55c90b0..000000000000 --- a/arch/arm/mach-integrator/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the linux kernel. -# - -# Object file lists. - -obj-y := core.o -obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o -obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h deleted file mode 100644 index f09ea18a50f8..000000000000 --- a/arch/arm/mach-integrator/cm.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * access the core module control register. - */ -u32 cm_get(void); -void cm_control(u32, u32); - -struct device_node; -void cm_init(void); -void cm_clear_irqs(void); - -#define CM_CTRL_LED (1 << 0) -#define CM_CTRL_nMBDET (1 << 1) -#define CM_CTRL_REMAP (1 << 2) - -/* - * Integrator/AP,PP2 specific - */ -#define CM_CTRL_HIGHVECTORS (1 << 4) -#define CM_CTRL_BIGENDIAN (1 << 5) -#define CM_CTRL_FASTBUS (1 << 6) -#define CM_CTRL_SYNC (1 << 7) - -/* - * ARM926/946/966 Integrator/CP specific - */ -#define CM_CTRL_LCDBIASEN (1 << 8) -#define CM_CTRL_LCDBIASUP (1 << 9) -#define CM_CTRL_LCDBIASDN (1 << 10) -#define CM_CTRL_LCDMUXSEL_MASK (7 << 11) -#define CM_CTRL_LCDMUXSEL_GENLCD (1 << 11) -#define CM_CTRL_LCDMUXSEL_VGA565_TFT555 (2 << 11) -#define CM_CTRL_LCDMUXSEL_SHARPLCD (3 << 11) -#define CM_CTRL_LCDMUXSEL_VGA555_TFT555 (4 << 11) -#define CM_CTRL_LCDEN0 (1 << 14) -#define CM_CTRL_LCDEN1 (1 << 15) -#define CM_CTRL_STATIC1 (1 << 16) -#define CM_CTRL_STATIC2 (1 << 17) -#define CM_CTRL_STATIC (1 << 18) -#define CM_CTRL_n24BITEN (1 << 19) -#define CM_CTRL_EBIWP (1 << 20) diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h deleted file mode 100644 index f053aeebeb7a..000000000000 --- a/arch/arm/mach-integrator/common.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include -#include -extern struct amba_pl010_data ap_uart_data; -void integrator_init_early(void); -int integrator_init(bool is_cp); -void integrator_reserve(void); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c deleted file mode 100644 index 0fe5e1dc9d89..000000000000 --- a/arch/arm/mach-integrator/core.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-integrator/core.c - * - * Copyright (C) 2000-2003 Deep Blue Solutions Ltd - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "hardware.h" -#include "cm.h" -#include "common.h" - -static DEFINE_RAW_SPINLOCK(cm_lock); -static void __iomem *cm_base; - -/** - * cm_get - get the value from the CM_CTRL register - */ -u32 cm_get(void) -{ - return readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET); -} - -/** - * cm_control - update the CM_CTRL register. - * @mask: bits to change - * @set: bits to set - */ -void cm_control(u32 mask, u32 set) -{ - unsigned long flags; - u32 val; - - raw_spin_lock_irqsave(&cm_lock, flags); - val = readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET) & ~mask; - writel(val | set, cm_base + INTEGRATOR_HDR_CTRL_OFFSET); - raw_spin_unlock_irqrestore(&cm_lock, flags); -} - -void cm_clear_irqs(void) -{ - /* disable core module IRQs */ - writel(0xffffffffU, cm_base + INTEGRATOR_HDR_IC_OFFSET + - IRQ_ENABLE_CLEAR); -} - -static const struct of_device_id cm_match[] = { - { .compatible = "arm,core-module-integrator"}, - { }, -}; - -void cm_init(void) -{ - struct device_node *cm = of_find_matching_node(NULL, cm_match); - - if (!cm) { - pr_crit("no core module node found in device tree\n"); - return; - } - cm_base = of_iomap(cm, 0); - if (!cm_base) { - pr_crit("could not remap core module\n"); - return; - } - cm_clear_irqs(); -} - -/* - * We need to stop things allocating the low memory; ideally we need a - * better implementation of GFP_DMA which does not assume that DMA-able - * memory starts at zero. - */ -void __init integrator_reserve(void) -{ - memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); -} diff --git a/arch/arm/mach-integrator/hardware.h b/arch/arm/mach-integrator/hardware.h deleted file mode 100644 index 81ce09e3ad45..000000000000 --- a/arch/arm/mach-integrator/hardware.h +++ /dev/null @@ -1,336 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * This file contains the hardware definitions of the Integrator. - * - * Copyright (C) 1998-1999 ARM Limited. - */ -#ifndef INTEGRATOR_HARDWARE_H -#define INTEGRATOR_HARDWARE_H - -/* - * Where in virtual memory the IO devices (timers, system controllers - * and so on) - */ -#define IO_BASE 0xF0000000 // VA of IO -#define IO_SIZE 0x0B000000 // How much? -#define IO_START INTEGRATOR_HDR_BASE // PA of IO - -/* macro to get at IO space when running virtually */ -#define IO_ADDRESS(x) (((x) & 0x000fffff) | (((x) >> 4) & 0x0ff00000) | IO_BASE) -#define __io_address(n) ((void __iomem *)IO_ADDRESS(n)) - -/* - * Integrator memory map - */ -#define INTEGRATOR_BOOT_ROM_LO 0x00000000 -#define INTEGRATOR_BOOT_ROM_HI 0x20000000 -#define INTEGRATOR_BOOT_ROM_BASE INTEGRATOR_BOOT_ROM_HI /* Normal position */ -#define INTEGRATOR_BOOT_ROM_SIZE SZ_512K - -/* - * New Core Modules have different amounts of SSRAM, the amount of SSRAM - * fitted can be found in HDR_STAT. - * - * The symbol INTEGRATOR_SSRAM_SIZE is kept, however this now refers to - * the minimum amount of SSRAM fitted on any core module. - * - * New Core Modules also alias the SSRAM. - * - */ -#define INTEGRATOR_SSRAM_BASE 0x00000000 -#define INTEGRATOR_SSRAM_ALIAS_BASE 0x10800000 -#define INTEGRATOR_SSRAM_SIZE SZ_256K - -#define INTEGRATOR_FLASH_BASE 0x24000000 -#define INTEGRATOR_FLASH_SIZE SZ_32M - -#define INTEGRATOR_MBRD_SSRAM_BASE 0x28000000 -#define INTEGRATOR_MBRD_SSRAM_SIZE SZ_512K - -/* - * SDRAM is a SIMM therefore the size is not known. - */ -#define INTEGRATOR_SDRAM_BASE 0x00040000 - -#define INTEGRATOR_SDRAM_ALIAS_BASE 0x80000000 -#define INTEGRATOR_HDR0_SDRAM_BASE 0x80000000 -#define INTEGRATOR_HDR1_SDRAM_BASE 0x90000000 -#define INTEGRATOR_HDR2_SDRAM_BASE 0xA0000000 -#define INTEGRATOR_HDR3_SDRAM_BASE 0xB0000000 - -/* - * Logic expansion modules - * - */ -#define INTEGRATOR_LOGIC_MODULES_BASE 0xC0000000 -#define INTEGRATOR_LOGIC_MODULE0_BASE 0xC0000000 -#define INTEGRATOR_LOGIC_MODULE1_BASE 0xD0000000 -#define INTEGRATOR_LOGIC_MODULE2_BASE 0xE0000000 -#define INTEGRATOR_LOGIC_MODULE3_BASE 0xF0000000 - -/* - * Integrator header card registers - */ -#define INTEGRATOR_HDR_ID_OFFSET 0x00 -#define INTEGRATOR_HDR_PROC_OFFSET 0x04 -#define INTEGRATOR_HDR_OSC_OFFSET 0x08 -#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C -#define INTEGRATOR_HDR_STAT_OFFSET 0x10 -#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 -#define INTEGRATOR_HDR_SDRAM_OFFSET 0x20 -#define INTEGRATOR_HDR_INIT_OFFSET 0x24 /* CM9x6 */ -#define INTEGRATOR_HDR_IC_OFFSET 0x40 -#define INTEGRATOR_HDR_SPDBASE_OFFSET 0x100 -#define INTEGRATOR_HDR_SPDTOP_OFFSET 0x200 - -#define INTEGRATOR_HDR_BASE 0x10000000 -#define INTEGRATOR_HDR_ID (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_ID_OFFSET) -#define INTEGRATOR_HDR_PROC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_PROC_OFFSET) -#define INTEGRATOR_HDR_OSC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_OSC_OFFSET) -#define INTEGRATOR_HDR_CTRL (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_CTRL_OFFSET) -#define INTEGRATOR_HDR_STAT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_STAT_OFFSET) -#define INTEGRATOR_HDR_LOCK (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_LOCK_OFFSET) -#define INTEGRATOR_HDR_SDRAM (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SDRAM_OFFSET) -#define INTEGRATOR_HDR_INIT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_INIT_OFFSET) -#define INTEGRATOR_HDR_IC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_IC_OFFSET) -#define INTEGRATOR_HDR_SPDBASE (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDBASE_OFFSET) -#define INTEGRATOR_HDR_SPDTOP (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDTOP_OFFSET) - -#define INTEGRATOR_HDR_CTRL_LED 0x01 -#define INTEGRATOR_HDR_CTRL_MBRD_DETECH 0x02 -#define INTEGRATOR_HDR_CTRL_REMAP 0x04 -#define INTEGRATOR_HDR_CTRL_RESET 0x08 -#define INTEGRATOR_HDR_CTRL_HIGHVECTORS 0x10 -#define INTEGRATOR_HDR_CTRL_BIG_ENDIAN 0x20 -#define INTEGRATOR_HDR_CTRL_FASTBUS 0x40 -#define INTEGRATOR_HDR_CTRL_SYNC 0x80 - -#define INTEGRATOR_HDR_OSC_CORE_10MHz 0x102 -#define INTEGRATOR_HDR_OSC_CORE_15MHz 0x107 -#define INTEGRATOR_HDR_OSC_CORE_20MHz 0x10C -#define INTEGRATOR_HDR_OSC_CORE_25MHz 0x111 -#define INTEGRATOR_HDR_OSC_CORE_30MHz 0x116 -#define INTEGRATOR_HDR_OSC_CORE_35MHz 0x11B -#define INTEGRATOR_HDR_OSC_CORE_40MHz 0x120 -#define INTEGRATOR_HDR_OSC_CORE_45MHz 0x125 -#define INTEGRATOR_HDR_OSC_CORE_50MHz 0x12A -#define INTEGRATOR_HDR_OSC_CORE_55MHz 0x12F -#define INTEGRATOR_HDR_OSC_CORE_60MHz 0x134 -#define INTEGRATOR_HDR_OSC_CORE_65MHz 0x139 -#define INTEGRATOR_HDR_OSC_CORE_70MHz 0x13E -#define INTEGRATOR_HDR_OSC_CORE_75MHz 0x143 -#define INTEGRATOR_HDR_OSC_CORE_80MHz 0x148 -#define INTEGRATOR_HDR_OSC_CORE_85MHz 0x14D -#define INTEGRATOR_HDR_OSC_CORE_90MHz 0x152 -#define INTEGRATOR_HDR_OSC_CORE_95MHz 0x157 -#define INTEGRATOR_HDR_OSC_CORE_100MHz 0x15C -#define INTEGRATOR_HDR_OSC_CORE_105MHz 0x161 -#define INTEGRATOR_HDR_OSC_CORE_110MHz 0x166 -#define INTEGRATOR_HDR_OSC_CORE_115MHz 0x16B -#define INTEGRATOR_HDR_OSC_CORE_120MHz 0x170 -#define INTEGRATOR_HDR_OSC_CORE_125MHz 0x175 -#define INTEGRATOR_HDR_OSC_CORE_130MHz 0x17A -#define INTEGRATOR_HDR_OSC_CORE_135MHz 0x17F -#define INTEGRATOR_HDR_OSC_CORE_140MHz 0x184 -#define INTEGRATOR_HDR_OSC_CORE_145MHz 0x189 -#define INTEGRATOR_HDR_OSC_CORE_150MHz 0x18E -#define INTEGRATOR_HDR_OSC_CORE_155MHz 0x193 -#define INTEGRATOR_HDR_OSC_CORE_160MHz 0x198 -#define INTEGRATOR_HDR_OSC_CORE_MASK 0x7FF - -#define INTEGRATOR_HDR_OSC_MEM_10MHz 0x10C000 -#define INTEGRATOR_HDR_OSC_MEM_15MHz 0x116000 -#define INTEGRATOR_HDR_OSC_MEM_20MHz 0x120000 -#define INTEGRATOR_HDR_OSC_MEM_25MHz 0x12A000 -#define INTEGRATOR_HDR_OSC_MEM_30MHz 0x134000 -#define INTEGRATOR_HDR_OSC_MEM_33MHz 0x13A000 -#define INTEGRATOR_HDR_OSC_MEM_40MHz 0x148000 -#define INTEGRATOR_HDR_OSC_MEM_50MHz 0x15C000 -#define INTEGRATOR_HDR_OSC_MEM_60MHz 0x170000 -#define INTEGRATOR_HDR_OSC_MEM_66MHz 0x17C000 -#define INTEGRATOR_HDR_OSC_MEM_MASK 0x7FF000 - -#define INTEGRATOR_HDR_OSC_BUS_MODE_CM7x0 0x0 -#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x0 0x0800000 -#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x6 0x1000000 -#define INTEGRATOR_HDR_OSC_BUS_MODE_CM10x00 0x1800000 -#define INTEGRATOR_HDR_OSC_BUS_MODE_MASK 0x1800000 - -#define INTEGRATOR_HDR_SDRAM_SPD_OK (1 << 5) - -/* - * Integrator system registers - */ - -/* - * System Controller - */ -#define INTEGRATOR_SC_ID_OFFSET 0x00 -#define INTEGRATOR_SC_OSC_OFFSET 0x04 -#define INTEGRATOR_SC_CTRLS_OFFSET 0x08 -#define INTEGRATOR_SC_CTRLC_OFFSET 0x0C -#define INTEGRATOR_SC_DEC_OFFSET 0x10 -#define INTEGRATOR_SC_ARB_OFFSET 0x14 -#define INTEGRATOR_SC_LOCK_OFFSET 0x1C - -#define INTEGRATOR_SC_BASE 0x11000000 -#define INTEGRATOR_SC_ID (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ID_OFFSET) -#define INTEGRATOR_SC_OSC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_OSC_OFFSET) -#define INTEGRATOR_SC_CTRLS (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET) -#define INTEGRATOR_SC_CTRLC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET) -#define INTEGRATOR_SC_DEC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_DEC_OFFSET) -#define INTEGRATOR_SC_ARB (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ARB_OFFSET) -#define INTEGRATOR_SC_PCIENABLE (INTEGRATOR_SC_BASE + INTEGRATOR_SC_PCIENABLE_OFFSET) -#define INTEGRATOR_SC_LOCK (INTEGRATOR_SC_BASE + INTEGRATOR_SC_LOCK_OFFSET) - -#define INTEGRATOR_SC_OSC_SYS_10MHz 0x20 -#define INTEGRATOR_SC_OSC_SYS_15MHz 0x34 -#define INTEGRATOR_SC_OSC_SYS_20MHz 0x48 -#define INTEGRATOR_SC_OSC_SYS_25MHz 0x5C -#define INTEGRATOR_SC_OSC_SYS_33MHz 0x7C -#define INTEGRATOR_SC_OSC_SYS_MASK 0xFF - -#define INTEGRATOR_SC_OSC_PCI_25MHz 0x100 -#define INTEGRATOR_SC_OSC_PCI_33MHz 0x0 -#define INTEGRATOR_SC_OSC_PCI_MASK 0x100 - -#define INTEGRATOR_SC_CTRL_SOFTRST (1 << 0) -#define INTEGRATOR_SC_CTRL_nFLVPPEN (1 << 1) -#define INTEGRATOR_SC_CTRL_nFLWP (1 << 2) -#define INTEGRATOR_SC_CTRL_URTS0 (1 << 4) -#define INTEGRATOR_SC_CTRL_UDTR0 (1 << 5) -#define INTEGRATOR_SC_CTRL_URTS1 (1 << 6) -#define INTEGRATOR_SC_CTRL_UDTR1 (1 << 7) - -/* - * External Bus Interface - */ -#define INTEGRATOR_EBI_BASE 0x12000000 - -#define INTEGRATOR_EBI_CSR0_OFFSET 0x00 -#define INTEGRATOR_EBI_CSR1_OFFSET 0x04 -#define INTEGRATOR_EBI_CSR2_OFFSET 0x08 -#define INTEGRATOR_EBI_CSR3_OFFSET 0x0C -#define INTEGRATOR_EBI_LOCK_OFFSET 0x20 - -#define INTEGRATOR_EBI_CSR0 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR0_OFFSET) -#define INTEGRATOR_EBI_CSR1 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) -#define INTEGRATOR_EBI_CSR2 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR2_OFFSET) -#define INTEGRATOR_EBI_CSR3 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR3_OFFSET) -#define INTEGRATOR_EBI_LOCK (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) - -#define INTEGRATOR_EBI_8_BIT 0x00 -#define INTEGRATOR_EBI_16_BIT 0x01 -#define INTEGRATOR_EBI_32_BIT 0x02 -#define INTEGRATOR_EBI_WRITE_ENABLE 0x04 -#define INTEGRATOR_EBI_SYNC 0x08 -#define INTEGRATOR_EBI_WS_2 0x00 -#define INTEGRATOR_EBI_WS_3 0x10 -#define INTEGRATOR_EBI_WS_4 0x20 -#define INTEGRATOR_EBI_WS_5 0x30 -#define INTEGRATOR_EBI_WS_6 0x40 -#define INTEGRATOR_EBI_WS_7 0x50 -#define INTEGRATOR_EBI_WS_8 0x60 -#define INTEGRATOR_EBI_WS_9 0x70 -#define INTEGRATOR_EBI_WS_10 0x80 -#define INTEGRATOR_EBI_WS_11 0x90 -#define INTEGRATOR_EBI_WS_12 0xA0 -#define INTEGRATOR_EBI_WS_13 0xB0 -#define INTEGRATOR_EBI_WS_14 0xC0 -#define INTEGRATOR_EBI_WS_15 0xD0 -#define INTEGRATOR_EBI_WS_16 0xE0 -#define INTEGRATOR_EBI_WS_17 0xF0 - - -#define INTEGRATOR_CT_BASE 0x13000000 /* Counter/Timers */ -#define INTEGRATOR_IC_BASE 0x14000000 /* Interrupt Controller */ -#define INTEGRATOR_RTC_BASE 0x15000000 /* Real Time Clock */ -#define INTEGRATOR_UART0_BASE 0x16000000 /* UART 0 */ -#define INTEGRATOR_UART1_BASE 0x17000000 /* UART 1 */ -#define INTEGRATOR_KBD_BASE 0x18000000 /* Keyboard */ -#define INTEGRATOR_MOUSE_BASE 0x19000000 /* Mouse */ - -/* - * LED's & Switches - */ -#define INTEGRATOR_DBG_ALPHA_OFFSET 0x00 -#define INTEGRATOR_DBG_LEDS_OFFSET 0x04 -#define INTEGRATOR_DBG_SWITCH_OFFSET 0x08 - -#define INTEGRATOR_DBG_BASE 0x1A000000 -#define INTEGRATOR_DBG_ALPHA (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_ALPHA_OFFSET) -#define INTEGRATOR_DBG_LEDS (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_LEDS_OFFSET) -#define INTEGRATOR_DBG_SWITCH (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET) - -#define INTEGRATOR_AP_GPIO_BASE 0x1B000000 /* GPIO */ - -#define INTEGRATOR_CP_MMC_BASE 0x1C000000 /* MMC */ -#define INTEGRATOR_CP_AACI_BASE 0x1D000000 /* AACI */ -#define INTEGRATOR_CP_ETH_BASE 0xC8000000 /* Ethernet */ -#define INTEGRATOR_CP_GPIO_BASE 0xC9000000 /* GPIO */ -#define INTEGRATOR_CP_SIC_BASE 0xCA000000 /* SIC */ -#define INTEGRATOR_CP_CTL_BASE 0xCB000000 /* CP system control */ - -/* PS2 Keyboard interface */ -#define KMI0_BASE INTEGRATOR_KBD_BASE - -/* PS2 Mouse interface */ -#define KMI1_BASE INTEGRATOR_MOUSE_BASE - -/* - * Integrator Interrupt Controllers - * - * - * Offsets from interrupt controller base - * - * System Controller interrupt controller base is - * - * INTEGRATOR_IC_BASE + (header_number << 6) - * - * Core Module interrupt controller base is - * - * INTEGRATOR_HDR_IC - */ -#define IRQ_STATUS 0 -#define IRQ_RAW_STATUS 0x04 -#define IRQ_ENABLE 0x08 -#define IRQ_ENABLE_SET 0x08 -#define IRQ_ENABLE_CLEAR 0x0C - -#define INT_SOFT_SET 0x10 -#define INT_SOFT_CLEAR 0x14 - -#define FIQ_STATUS 0x20 -#define FIQ_RAW_STATUS 0x24 -#define FIQ_ENABLE 0x28 -#define FIQ_ENABLE_SET 0x28 -#define FIQ_ENABLE_CLEAR 0x2C - - -/* - * LED's - */ -#define GREEN_LED 0x01 -#define YELLOW_LED 0x02 -#define RED_LED 0x04 -#define GREEN_LED_2 0x08 -#define ALL_LEDS 0x0F - -#define LED_BANK INTEGRATOR_DBG_LEDS - -/* - * Timer definitions - * - * Only use timer 1 & 2 - * (both run at 24MHz and will need the clock divider set to 16). - * - * Timer 0 runs at bus frequency - */ -#define INTEGRATOR_TIMER0_BASE INTEGRATOR_CT_BASE -#define INTEGRATOR_TIMER1_BASE (INTEGRATOR_CT_BASE + 0x100) -#define INTEGRATOR_TIMER2_BASE (INTEGRATOR_CT_BASE + 0x200) - -#define INTEGRATOR_CSR_BASE 0x10000000 -#define INTEGRATOR_CSR_SIZE 0x10000000 - -#endif /* INTEGRATOR_HARDWARE_H */ diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c deleted file mode 100644 index 58b02cbbea72..000000000000 --- a/arch/arm/mach-integrator/integrator_ap.c +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/arch/arm/mach-integrator/integrator_ap.c - * - * Copyright (C) 2000-2003 Deep Blue Solutions Ltd - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "hardware.h" -#include "cm.h" -#include "common.h" - -/* Regmap to the AP system controller */ -static struct regmap *ap_syscon_map; - -/* - * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx - * is the (PA >> 12). - * - * Setup a VA for the Integrator interrupt controller (for header #0, - * just for now). - */ -#define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE) - -/* - * Logical Physical - * f1400000 14000000 Interrupt controller - * f1600000 16000000 UART 0 - */ - -static struct map_desc ap_io_desc[] __initdata __maybe_unused = { - { - .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), - .length = SZ_4K, - .type = MT_DEVICE - } -}; - -static void __init ap_map_io(void) -{ - iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc)); -} - -#ifdef CONFIG_PM -static unsigned long ic_irq_enable; - -static int irq_suspend(void) -{ - ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE); - return 0; -} - -static void irq_resume(void) -{ - /* disable all irq sources */ - cm_clear_irqs(); - writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); - writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); - - writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET); -} -#else -#define irq_suspend NULL -#define irq_resume NULL -#endif - -static struct syscore_ops irq_syscore_ops = { - .suspend = irq_suspend, - .resume = irq_resume, -}; - -static int __init irq_syscore_init(void) -{ - register_syscore_ops(&irq_syscore_ops); - - return 0; -} - -device_initcall(irq_syscore_init); - -/* - * For the PL010 found in the Integrator/AP some of the UART control is - * implemented in the system controller and accessed using a callback - * from the driver. - */ -static void integrator_uart_set_mctrl(struct amba_device *dev, - void __iomem *base, unsigned int mctrl) -{ - unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask; - u32 phybase = dev->res.start; - int ret; - - if (phybase == INTEGRATOR_UART0_BASE) { - /* UART0 */ - rts_mask = 1 << 4; - dtr_mask = 1 << 5; - } else { - /* UART1 */ - rts_mask = 1 << 6; - dtr_mask = 1 << 7; - } - - if (mctrl & TIOCM_RTS) - ctrlc |= rts_mask; - else - ctrls |= rts_mask; - - if (mctrl & TIOCM_DTR) - ctrlc |= dtr_mask; - else - ctrls |= dtr_mask; - - ret = regmap_write(ap_syscon_map, - INTEGRATOR_SC_CTRLS_OFFSET, - ctrls); - if (ret) - pr_err("MODEM: unable to write PL010 UART CTRLS\n"); - - ret = regmap_write(ap_syscon_map, - INTEGRATOR_SC_CTRLC_OFFSET, - ctrlc); - if (ret) - pr_err("MODEM: unable to write PL010 UART CRTLC\n"); -} - -struct amba_pl010_data ap_uart_data = { - .set_mctrl = integrator_uart_set_mctrl, -}; - -void __init ap_init_early(void) -{ -} - -static void __init ap_init_irq_of(void) -{ - cm_init(); - irqchip_init(); -} - -/* For the Device Tree, add in the UART callbacks as AUXDATA */ -static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE, - "uart0", &ap_uart_data), - OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE, - "uart1", &ap_uart_data), - { /* sentinel */ }, -}; - -static const struct of_device_id ap_syscon_match[] = { - { .compatible = "arm,integrator-ap-syscon"}, - { }, -}; - -static void __init ap_init_of(void) -{ - struct device_node *syscon; - - of_platform_default_populate(NULL, ap_auxdata_lookup, NULL); - - syscon = of_find_matching_node(NULL, ap_syscon_match); - if (!syscon) - return; - ap_syscon_map = syscon_node_to_regmap(syscon); - if (IS_ERR(ap_syscon_map)) { - pr_crit("could not find Integrator/AP system controller\n"); - return; - } -} - -static const char * ap_dt_board_compat[] = { - "arm,integrator-ap", - NULL, -}; - -DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") - .reserve = integrator_reserve, - .map_io = ap_map_io, - .init_early = ap_init_early, - .init_irq = ap_init_irq_of, - .init_machine = ap_init_of, - .dt_compat = ap_dt_board_compat, -MACHINE_END diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c deleted file mode 100644 index b7eb4038798b..000000000000 --- a/arch/arm/mach-integrator/integrator_cp.c +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-integrator/integrator_cp.c - * - * Copyright (C) 2003 Deep Blue Solutions Ltd - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "hardware.h" -#include "cm.h" -#include "common.h" - -/* Base address to the core module header */ -static struct regmap *cm_map; -/* Base address to the CP controller */ -static void __iomem *intcp_con_base; - -#define CM_COUNTER_OFFSET 0x28 - -/* - * Logical Physical - * f1400000 14000000 Interrupt controller - * f1600000 16000000 UART 0 - * fca00000 ca000000 SIC - */ - -static struct map_desc intcp_io_desc[] __initdata __maybe_unused = { - { - .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE), - .length = SZ_4K, - .type = MT_DEVICE - } -}; - -static void __init intcp_map_io(void) -{ - iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); -} - -/* - * It seems that the card insertion interrupt remains active after - * we've acknowledged it. We therefore ignore the interrupt, and - * rely on reading it from the SIC. This also means that we must - * clear the latched interrupt. - */ -static unsigned int mmc_status(struct device *dev) -{ - unsigned int status = readl(__io_address(0xca000000 + 4)); - writel(8, intcp_con_base + 8); - - return status & 8; -} - -static struct mmci_platform_data mmc_data = { - .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = mmc_status, -}; - -static u64 notrace intcp_read_sched_clock(void) -{ - unsigned int val; - - /* MMIO so discard return code */ - regmap_read(cm_map, CM_COUNTER_OFFSET, &val); - return val; -} - -static void __init intcp_init_early(void) -{ - cm_map = syscon_regmap_lookup_by_compatible("arm,core-module-integrator"); - if (IS_ERR(cm_map)) - return; - sched_clock_register(intcp_read_sched_clock, 32, 24000000); -} - -static void __init intcp_init_irq_of(void) -{ - cm_init(); - irqchip_init(); -} - -/* - * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA - * and enforce the bus names since these are used for clock lookups. - */ -static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE, - "mmci", &mmc_data), - { /* sentinel */ }, -}; - -static const struct of_device_id intcp_syscon_match[] = { - { .compatible = "arm,integrator-cp-syscon"}, - { }, -}; - -static void __init intcp_init_of(void) -{ - struct device_node *cpcon; - - cpcon = of_find_matching_node(NULL, intcp_syscon_match); - if (!cpcon) - return; - - intcp_con_base = of_iomap(cpcon, 0); - if (!intcp_con_base) - return; - - of_platform_default_populate(NULL, intcp_auxdata_lookup, NULL); -} - -static const char * intcp_dt_board_compat[] = { - "arm,integrator-cp", - NULL, -}; - -DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") - .reserve = integrator_reserve, - .map_io = intcp_map_io, - .init_early = intcp_init_early, - .init_irq = intcp_init_irq_of, - .init_machine = intcp_init_of, - .dt_compat = intcp_dt_board_compat, -MACHINE_END diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig deleted file mode 100644 index a4c36024b5e8..000000000000 --- a/arch/arm/mach-realview/Kconfig +++ /dev/null @@ -1,103 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -menuconfig ARCH_REALVIEW - bool "ARM Ltd. RealView family" - depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7 - select ARM_AMBA - select ARM_GIC - select ARM_TIMER_SP804 - select CLK_SP810 - select GPIO_PL061 if GPIOLIB - select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if SMP - select HAVE_PATA_PLATFORM - select HAVE_TCM - select CLK_ICST - select MACH_REALVIEW_EB if ARCH_MULTI_V5 - select MFD_SYSCON - select PLAT_VERSATILE - select POWER_RESET - select POWER_RESET_VERSATILE - select POWER_SUPPLY - select SOC_REALVIEW - help - This enables support for ARM Ltd RealView boards. - -if ARCH_REALVIEW - -config MACH_REALVIEW_EB - bool "Support RealView(R) Emulation Baseboard" - select ARM_GIC - select CPU_ARM926T if ARCH_MULTI_V5 - help - Include support for the ARM(R) RealView(R) Emulation Baseboard - platform. On an ARMv5 kernel, this will include support for - the ARM926EJ-S core tile, while on an ARMv6/v7 kernel, at least - one of the ARM1136, ARM1176, ARM11MPCore or Cortex-A9MPCore - core tile options should be enabled. - -config REALVIEW_EB_ARM1136 - bool "Support ARM1136J(F)-S Tile" - depends on MACH_REALVIEW_EB && ARCH_MULTI_V6 - select CPU_V6 - help - Enable support for the ARM1136 tile fitted to the - Realview(R) Emulation Baseboard platform. - -config REALVIEW_EB_ARM1176 - bool "Support ARM1176JZ(F)-S Tile" - depends on MACH_REALVIEW_EB && ARCH_MULTI_V6 - help - Enable support for the ARM1176 tile fitted to the - Realview(R) Emulation Baseboard platform. - -config REALVIEW_EB_A9MP - bool "Support Multicore Cortex-A9 Tile" - depends on MACH_REALVIEW_EB && ARCH_MULTI_V7 - help - Enable support for the Cortex-A9MPCore tile fitted to the - Realview(R) Emulation Baseboard platform. - -config REALVIEW_EB_ARM11MP - bool "Support ARM11MPCore Tile" - depends on MACH_REALVIEW_EB && ARCH_MULTI_V6 - select HAVE_SMP - help - Enable support for the ARM11MPCore tile fitted to the Realview(R) - Emulation Baseboard platform. - -config MACH_REALVIEW_PB11MP - bool "Support RealView(R) Platform Baseboard for ARM11MPCore" - depends on ARCH_MULTI_V6 - select HAVE_SMP - help - Include support for the ARM(R) RealView(R) Platform Baseboard for - the ARM11MPCore. This platform has an on-board ARM11MPCore and has - support for PCI-E and Compact Flash. - -# ARMv6 CPU without K extensions, but does have the new exclusive ops -config MACH_REALVIEW_PB1176 - bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S" - depends on ARCH_MULTI_V6 - select CPU_V6 - select HAVE_TCM - help - Include support for the ARM(R) RealView(R) Platform Baseboard for - ARM1176JZF-S. - -config MACH_REALVIEW_PBA8 - bool "Support RealView(R) Platform Baseboard for Cortex(tm)-A8 platform" - depends on ARCH_MULTI_V7 - help - Include support for the ARM(R) RealView Platform Baseboard for - Cortex(tm)-A8. This platform has an on-board Cortex-A8 and has - support for PCI-E and Compact Flash. - -config MACH_REALVIEW_PBX - bool "Support RealView(R) Platform Baseboard Explore for Cortex-A9" - depends on ARCH_MULTI_V7 - select ZONE_DMA - help - Include support for the ARM(R) RealView(R) Platform Baseboard - Explore. - -endif diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile deleted file mode 100644 index e259091591b8..000000000000 --- a/arch/arm/mach-realview/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the linux kernel. -# -ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-versatile/include - -obj-y += realview-dt.o -obj-$(CONFIG_SMP) += platsmp-dt.o diff --git a/arch/arm/mach-realview/platsmp-dt.c b/arch/arm/mach-realview/platsmp-dt.c deleted file mode 100644 index 5ae783767a5d..000000000000 --- a/arch/arm/mach-realview/platsmp-dt.c +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2015 Linus Walleij - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 - -static const struct of_device_id realview_scu_match[] = { - { .compatible = "arm,arm11mp-scu", }, - { .compatible = "arm,cortex-a9-scu", }, - { .compatible = "arm,cortex-a5-scu", }, - { } -}; - -static const struct of_device_id realview_syscon_match[] = { - { .compatible = "arm,core-module-integrator", }, - { .compatible = "arm,realview-eb-syscon", }, - { .compatible = "arm,realview-pb11mp-syscon", }, - { .compatible = "arm,realview-pbx-syscon", }, - { }, -}; - -static void __init realview_smp_prepare_cpus(unsigned int max_cpus) -{ - struct device_node *np; - void __iomem *scu_base; - struct regmap *map; - unsigned int ncores; - int i; - - np = of_find_matching_node(NULL, realview_scu_match); - if (!np) { - pr_err("PLATSMP: No SCU base address\n"); - return; - } - scu_base = of_iomap(np, 0); - of_node_put(np); - if (!scu_base) { - pr_err("PLATSMP: No SCU remap\n"); - return; - } - - scu_enable(scu_base); - ncores = scu_get_core_count(scu_base); - pr_info("SCU: %d cores detected\n", ncores); - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); - iounmap(scu_base); - - /* The syscon contains the magic SMP start address registers */ - np = of_find_matching_node(NULL, realview_syscon_match); - if (!np) { - pr_err("PLATSMP: No syscon match\n"); - return; - } - map = syscon_node_to_regmap(np); - if (IS_ERR(map)) { - pr_err("PLATSMP: No syscon regmap\n"); - return; - } - /* Put the boot address in this magic register */ - regmap_write(map, REALVIEW_SYS_FLAGSSET_OFFSET, - __pa_symbol(versatile_secondary_startup)); -} - -#ifdef CONFIG_HOTPLUG_CPU -static void realview_cpu_die(unsigned int cpu) -{ - return versatile_immitation_cpu_die(cpu, 0x20); -} -#endif - -static const struct smp_operations realview_dt_smp_ops __initconst = { - .smp_prepare_cpus = realview_smp_prepare_cpus, - .smp_secondary_init = versatile_secondary_init, - .smp_boot_secondary = versatile_boot_secondary, -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = realview_cpu_die, -#endif -}; -CPU_METHOD_OF_DECLARE(realview_smp, "arm,realview-smp", &realview_dt_smp_ops); diff --git a/arch/arm/mach-realview/realview-dt.c b/arch/arm/mach-realview/realview-dt.c deleted file mode 100644 index feab66080ba2..000000000000 --- a/arch/arm/mach-realview/realview-dt.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2014 Linaro Ltd. - * - * Author: Linus Walleij - */ -#include -#include -#include - -static const char *const realview_dt_platform_compat[] __initconst = { - "arm,realview-eb", - "arm,realview-pb1176", - "arm,realview-pb11mp", - "arm,realview-pba8", - "arm,realview-pbx", - NULL, -}; - -DT_MACHINE_START(REALVIEW_DT, "ARM RealView Machine (Device Tree Support)") -#ifdef CONFIG_ZONE_DMA - .dma_zone_size = SZ_256M, -#endif - .dt_compat = realview_dt_platform_compat, - .l2c_aux_val = 0x0, - .l2c_aux_mask = ~0x0, -MACHINE_END diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig index f78a1d358031..94b492c12e8d 100644 --- a/arch/arm/mach-versatile/Kconfig +++ b/arch/arm/mach-versatile/Kconfig @@ -16,3 +16,311 @@ config ARCH_VERSATILE help This enables support for ARM Ltd Versatile board. +menuconfig ARCH_INTEGRATOR + bool "ARM Ltd. Integrator family" + depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6 + select ARM_AMBA + select CMA + select DMA_CMA + select HAVE_TCM + select CLK_ICST + select MFD_SYSCON + select PLAT_VERSATILE + select POWER_RESET + select POWER_RESET_VERSATILE + select POWER_SUPPLY + select SOC_INTEGRATOR_CM + select VERSATILE_FPGA_IRQ + help + Support for ARM's Integrator platform. + +if ARCH_INTEGRATOR + +config ARCH_INTEGRATOR_AP + bool "Support Integrator/AP and Integrator/PP2 platforms" + select INTEGRATOR_AP_TIMER + select SERIAL_AMBA_PL010 if TTY + select SERIAL_AMBA_PL010_CONSOLE if TTY + select SOC_BUS + help + Include support for the ARM(R) Integrator/AP and + Integrator/PP2 platforms. + +config INTEGRATOR_IMPD1 + bool "Include support for Integrator/IM-PD1" + depends on ARCH_INTEGRATOR_AP + select ARM_VIC + select GPIO_PL061 + select GPIOLIB + select REGULATOR + select REGULATOR_FIXED_VOLTAGE + help + The IM-PD1 is an add-on logic module for the Integrator which + allows ARM(R) Ltd PrimeCells to be developed and evaluated. + The IM-PD1 can be found on the Integrator/PP2 platform. + +config INTEGRATOR_CM720T + bool "Integrator/CM720T core module" + depends on ARCH_INTEGRATOR_AP + depends on ARCH_MULTI_V4T + select CPU_ARM720T + +config INTEGRATOR_CM920T + bool "Integrator/CM920T core module" + depends on ARCH_INTEGRATOR_AP + depends on ARCH_MULTI_V4T + select CPU_ARM920T + +config INTEGRATOR_CM922T_XA10 + bool "Integrator/CM922T-XA10 core module" + depends on ARCH_MULTI_V4T + depends on ARCH_INTEGRATOR_AP + select CPU_ARM922T + +config INTEGRATOR_CM926EJS + bool "Integrator/CM926EJ-S core module" + depends on ARCH_INTEGRATOR_AP + depends on ARCH_MULTI_V5 + select CPU_ARM926T + +config INTEGRATOR_CM10200E_REV0 + bool "Integrator/CM10200E rev.0 core module" + depends on ARCH_INTEGRATOR_AP && n + depends on ARCH_MULTI_V5 + select CPU_ARM1020 + +config INTEGRATOR_CM10200E + bool "Integrator/CM10200E core module" + depends on ARCH_INTEGRATOR_AP && n + depends on ARCH_MULTI_V5 + select CPU_ARM1020E + +config INTEGRATOR_CM10220E + bool "Integrator/CM10220E core module" + depends on ARCH_INTEGRATOR_AP + depends on ARCH_MULTI_V5 + select CPU_ARM1022 + +config INTEGRATOR_CM1026EJS + bool "Integrator/CM1026EJ-S core module" + depends on ARCH_INTEGRATOR_AP + depends on ARCH_MULTI_V5 + select CPU_ARM1026 + +config INTEGRATOR_CM1136JFS + bool "Integrator/CM1136JF-S core module" + depends on ARCH_INTEGRATOR_AP + depends on ARCH_MULTI_V6 + select CPU_V6 + +config ARCH_INTEGRATOR_CP + bool "Support Integrator/CP platform" + depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 + select ARM_TIMER_SP804 + select SERIAL_AMBA_PL011 if TTY + select SERIAL_AMBA_PL011_CONSOLE if TTY + select SOC_BUS + help + Include support for the ARM(R) Integrator CP platform. + +config INTEGRATOR_CT926 + bool "Integrator/CT926 (ARM926EJ-S) core tile" + depends on ARCH_INTEGRATOR_CP + depends on ARCH_MULTI_V5 + select CPU_ARM926T + +config INTEGRATOR_CTB36 + bool "Integrator/CTB36 (ARM1136JF-S) core tile" + depends on ARCH_INTEGRATOR_CP + depends on ARCH_MULTI_V6 + select CPU_V6 + +config ARCH_CINTEGRATOR + depends on ARCH_INTEGRATOR_CP + def_bool y + +endif + +menuconfig ARCH_REALVIEW + bool "ARM Ltd. RealView family" + depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7 + select ARM_AMBA + select ARM_GIC + select ARM_TIMER_SP804 + select CLK_SP810 + select GPIO_PL061 if GPIOLIB + select HAVE_ARM_SCU if SMP + select HAVE_ARM_TWD if SMP + select HAVE_PATA_PLATFORM + select HAVE_TCM + select CLK_ICST + select MACH_REALVIEW_EB if ARCH_MULTI_V5 + select MFD_SYSCON + select PLAT_VERSATILE + select POWER_RESET + select POWER_RESET_VERSATILE + select POWER_SUPPLY + select SOC_REALVIEW + help + This enables support for ARM Ltd RealView boards. + +if ARCH_REALVIEW + +config MACH_REALVIEW_EB + bool "Support RealView(R) Emulation Baseboard" + select ARM_GIC + select CPU_ARM926T if ARCH_MULTI_V5 + help + Include support for the ARM(R) RealView(R) Emulation Baseboard + platform. On an ARMv5 kernel, this will include support for + the ARM926EJ-S core tile, while on an ARMv6/v7 kernel, at least + one of the ARM1136, ARM1176, ARM11MPCore or Cortex-A9MPCore + core tile options should be enabled. + +config REALVIEW_EB_ARM1136 + bool "Support ARM1136J(F)-S Tile" + depends on MACH_REALVIEW_EB && ARCH_MULTI_V6 + select CPU_V6 + help + Enable support for the ARM1136 tile fitted to the + Realview(R) Emulation Baseboard platform. + +config REALVIEW_EB_ARM1176 + bool "Support ARM1176JZ(F)-S Tile" + depends on MACH_REALVIEW_EB && ARCH_MULTI_V6 + help + Enable support for the ARM1176 tile fitted to the + Realview(R) Emulation Baseboard platform. + +config REALVIEW_EB_A9MP + bool "Support Multicore Cortex-A9 Tile" + depends on MACH_REALVIEW_EB && ARCH_MULTI_V7 + help + Enable support for the Cortex-A9MPCore tile fitted to the + Realview(R) Emulation Baseboard platform. + +config REALVIEW_EB_ARM11MP + bool "Support ARM11MPCore Tile" + depends on MACH_REALVIEW_EB && ARCH_MULTI_V6 + select HAVE_SMP + help + Enable support for the ARM11MPCore tile fitted to the Realview(R) + Emulation Baseboard platform. + +config MACH_REALVIEW_PB11MP + bool "Support RealView(R) Platform Baseboard for ARM11MPCore" + depends on ARCH_MULTI_V6 + select HAVE_SMP + help + Include support for the ARM(R) RealView(R) Platform Baseboard for + the ARM11MPCore. This platform has an on-board ARM11MPCore and has + support for PCI-E and Compact Flash. + +# ARMv6 CPU without K extensions, but does have the new exclusive ops +config MACH_REALVIEW_PB1176 + bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S" + depends on ARCH_MULTI_V6 + select CPU_V6 + select HAVE_TCM + help + Include support for the ARM(R) RealView(R) Platform Baseboard for + ARM1176JZF-S. + +config MACH_REALVIEW_PBA8 + bool "Support RealView(R) Platform Baseboard for Cortex(tm)-A8 platform" + depends on ARCH_MULTI_V7 + help + Include support for the ARM(R) RealView Platform Baseboard for + Cortex(tm)-A8. This platform has an on-board Cortex-A8 and has + support for PCI-E and Compact Flash. + +config MACH_REALVIEW_PBX + bool "Support RealView(R) Platform Baseboard Explore for Cortex-A9" + depends on ARCH_MULTI_V7 + select ZONE_DMA + help + Include support for the ARM(R) RealView(R) Platform Baseboard + Explore. + +endif + +menuconfig ARCH_VEXPRESS + bool "ARM Ltd. Versatile Express family" + depends on ARCH_MULTI_V7 + select ARCH_SUPPORTS_BIG_ENDIAN + select ARM_AMBA + select ARM_GIC + select ARM_GLOBAL_TIMER + select ARM_TIMER_SP804 + select GPIOLIB + select HAVE_ARM_SCU if SMP + select HAVE_ARM_TWD if SMP + select HAVE_PATA_PLATFORM + select CLK_ICST + select NO_IOPORT_MAP + select PLAT_VERSATILE + select POWER_RESET + select POWER_RESET_VEXPRESS + select POWER_SUPPLY + select REGULATOR if MMC_ARMMMCI + select REGULATOR_FIXED_VOLTAGE if REGULATOR + select VEXPRESS_CONFIG + help + This option enables support for systems using Cortex processor based + ARM core and logic (FPGA) tiles on the Versatile Express motherboard, + for example: + + - CoreTile Express A5x2 (V2P-CA5s) + - CoreTile Express A9x4 (V2P-CA9) + - CoreTile Express A15x2 (V2P-CA15) + - LogicTile Express 13MG (V2F-2XV6) with A5, A7, A9 or A15 SMMs + (Soft Macrocell Models) + - Versatile Express RTSMs (Models) + + You must boot using a Flattened Device Tree in order to use these + platforms. The traditional (ATAGs) boot method is not usable on + these boards with this option. + +if ARCH_VEXPRESS + +config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA + bool "Enable A5 and A9 only errata work-arounds" + default y + select ARM_ERRATA_643719 if SMP + select ARM_ERRATA_720789 + select PL310_ERRATA_753970 if CACHE_L2X0 + help + Provides common dependencies for Versatile Express platforms + based on Cortex-A5 and Cortex-A9 processors. In order to + build a working kernel, you must also enable relevant core + tile support or Flattened Device Tree based support options. + +config ARCH_VEXPRESS_DCSCB + bool "Dual Cluster System Control Block (DCSCB) support" + depends on MCPM + select ARM_CCI400_PORT_CTRL + help + Support for the Dual Cluster System Configuration Block (DCSCB). + This is needed to provide CPU and cluster power management + on RTSM implementing big.LITTLE. + +config ARCH_VEXPRESS_SPC + bool "Versatile Express Serial Power Controller (SPC)" + select PM_OPP + help + The TC2 (A15x2 A7x3) versatile express core tile integrates a logic + block called Serial Power Controller (SPC) that provides the interface + between the dual cluster test-chip and the M3 microcontroller that + carries out power management. + +config ARCH_VEXPRESS_TC2_PM + bool "Versatile Express TC2 power management" + depends on MCPM + select ARM_CCI400_PORT_CTRL + select ARCH_VEXPRESS_SPC + select ARM_CPU_SUSPEND + help + Support for CPU and cluster power management on Versatile Express + with a TC2 (A15x2 A7x3) big.LITTLE core tile. + +endif diff --git a/arch/arm/mach-versatile/Makefile b/arch/arm/mach-versatile/Makefile index 2b907718d467..27d712bcf1af 100644 --- a/arch/arm/mach-versatile/Makefile +++ b/arch/arm/mach-versatile/Makefile @@ -3,4 +3,34 @@ # Makefile for the linux kernel. # -obj-y := versatile_dt.o +# versatile +obj-$(CONFIG_ARCH_VERSATILE) += versatile.o + +# integrator +obj-$(CONFIG_ARCH_INTEGRATOR) += integrator.o +obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o +obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o + +# realview +obj-$(CONFIG_ARCH_REALVIEW) += realview.o + +# vexpress +obj-$(CONFIG_ARCH_VEXPRESS) := v2m.o +obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o +CFLAGS_dcscb.o += -march=armv7-a +CFLAGS_REMOVE_dcscb.o = -pg +obj-$(CONFIG_ARCH_VEXPRESS_SPC) += spc.o +CFLAGS_REMOVE_spc.o = -pg +obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o +CFLAGS_tc2_pm.o += -march=armv7-a +CFLAGS_REMOVE_tc2_pm.o = -pg + +# mps2 +obj-$(CONFIG_ARCH_MPS2) += v2m-mps2.o + +ifdef CONFIG_SMP +obj-y += headsmp.o platsmp.o +obj-$(CONFIG_ARCH_REALVIEW) += platsmp-realview.o +obj-$(CONFIG_ARCH_VEXPRESS) += platsmp-vexpress.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +endif diff --git a/arch/arm/mach-versatile/Makefile.boot b/arch/arm/mach-versatile/Makefile.boot new file mode 100644 index 000000000000..cec195d4fcba --- /dev/null +++ b/arch/arm/mach-versatile/Makefile.boot @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Empty file waiting for deletion once Makefile.boot isn't needed any more. +# Patch waits for application at +# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 . diff --git a/arch/arm/mach-versatile/dcscb.c b/arch/arm/mach-versatile/dcscb.c new file mode 100644 index 000000000000..866270e7f271 --- /dev/null +++ b/arch/arm/mach-versatile/dcscb.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * dcscb.c - Dual Cluster System Configuration Block + * + * Created by: Nicolas Pitre, May 2012 + * Copyright: (C) 2012-2013 Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "vexpress.h" + +#define RST_HOLD0 0x0 +#define RST_HOLD1 0x4 +#define SYS_SWRESET 0x8 +#define RST_STAT0 0xc +#define RST_STAT1 0x10 +#define EAG_CFG_R 0x20 +#define EAG_CFG_W 0x24 +#define KFC_CFG_R 0x28 +#define KFC_CFG_W 0x2c +#define DCS_CFG_R 0x30 + +static void __iomem *dcscb_base; +static int dcscb_allcpus_mask[2]; + +static int dcscb_cpu_powerup(unsigned int cpu, unsigned int cluster) +{ + unsigned int rst_hold, cpumask = (1 << cpu); + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + if (cluster >= 2 || !(cpumask & dcscb_allcpus_mask[cluster])) + return -EINVAL; + + rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); + rst_hold &= ~(cpumask | (cpumask << 4)); + writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); + return 0; +} + +static int dcscb_cluster_powerup(unsigned int cluster) +{ + unsigned int rst_hold; + + pr_debug("%s: cluster %u\n", __func__, cluster); + if (cluster >= 2) + return -EINVAL; + + /* remove cluster reset and add individual CPU's reset */ + rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); + rst_hold &= ~(1 << 8); + rst_hold |= dcscb_allcpus_mask[cluster]; + writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); + return 0; +} + +static void dcscb_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) +{ + unsigned int rst_hold; + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + BUG_ON(cluster >= 2 || !((1 << cpu) & dcscb_allcpus_mask[cluster])); + + rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); + rst_hold |= (1 << cpu); + writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); +} + +static void dcscb_cluster_powerdown_prepare(unsigned int cluster) +{ + unsigned int rst_hold; + + pr_debug("%s: cluster %u\n", __func__, cluster); + BUG_ON(cluster >= 2); + + rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); + rst_hold |= (1 << 8); + writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); +} + +static void dcscb_cpu_cache_disable(void) +{ + /* Disable and flush the local CPU cache. */ + v7_exit_coherency_flush(louis); +} + +static void dcscb_cluster_cache_disable(void) +{ + /* Flush all cache levels for this cluster. */ + v7_exit_coherency_flush(all); + + /* + * A full outer cache flush could be needed at this point + * on platforms with such a cache, depending on where the + * outer cache sits. In some cases the notion of a "last + * cluster standing" would need to be implemented if the + * outer cache is shared across clusters. In any case, when + * the outer cache needs flushing, there is no concurrent + * access to the cache controller to worry about and no + * special locking besides what is already provided by the + * MCPM state machinery is needed. + */ + + /* + * Disable cluster-level coherency by masking + * incoming snoops and DVM messages: + */ + cci_disable_port_by_cpu(read_cpuid_mpidr()); +} + +static const struct mcpm_platform_ops dcscb_power_ops = { + .cpu_powerup = dcscb_cpu_powerup, + .cluster_powerup = dcscb_cluster_powerup, + .cpu_powerdown_prepare = dcscb_cpu_powerdown_prepare, + .cluster_powerdown_prepare = dcscb_cluster_powerdown_prepare, + .cpu_cache_disable = dcscb_cpu_cache_disable, + .cluster_cache_disable = dcscb_cluster_cache_disable, +}; + +extern void dcscb_power_up_setup(unsigned int affinity_level); + +static int __init dcscb_init(void) +{ + struct device_node *node; + unsigned int cfg; + int ret; + + if (!cci_probed()) + return -ENODEV; + + node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb"); + if (!node) + return -ENODEV; + dcscb_base = of_iomap(node, 0); + if (!dcscb_base) + return -EADDRNOTAVAIL; + cfg = readl_relaxed(dcscb_base + DCS_CFG_R); + dcscb_allcpus_mask[0] = (1 << (((cfg >> 16) >> (0 << 2)) & 0xf)) - 1; + dcscb_allcpus_mask[1] = (1 << (((cfg >> 16) >> (1 << 2)) & 0xf)) - 1; + + ret = mcpm_platform_register(&dcscb_power_ops); + if (!ret) + ret = mcpm_sync_init(dcscb_power_up_setup); + if (ret) { + iounmap(dcscb_base); + return ret; + } + + pr_info("VExpress DCSCB support installed\n"); + + /* + * Future entries into the kernel can now go + * through the cluster entry vectors. + */ + vexpress_flags_set(__pa_symbol(mcpm_entry_point)); + + return 0; +} + +early_initcall(dcscb_init); diff --git a/arch/arm/mach-versatile/dcscb_setup.S b/arch/arm/mach-versatile/dcscb_setup.S new file mode 100644 index 000000000000..92d1fd9d7f6a --- /dev/null +++ b/arch/arm/mach-versatile/dcscb_setup.S @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Created by: Dave Martin, 2012-06-22 + * Copyright: (C) 2012-2013 Linaro Limited + */ + +#include + + +ENTRY(dcscb_power_up_setup) + + cmp r0, #0 @ check affinity level + beq 2f + +/* + * Enable cluster-level coherency, in preparation for turning on the MMU. + * The ACTLR SMP bit does not need to be set here, because cpu_resume() + * already restores that. + * + * A15/A7 may not require explicit L2 invalidation on reset, dependent + * on hardware integration decisions. + * For now, this code assumes that L2 is either already invalidated, + * or invalidation is not required. + */ + + b cci_enable_port_for_self + +2: @ Implementation-specific local CPU setup operations should go here, + @ if any. In this case, there is nothing to do. + + bx lr + +ENDPROC(dcscb_power_up_setup) diff --git a/arch/arm/mach-versatile/headsmp.S b/arch/arm/mach-versatile/headsmp.S new file mode 100644 index 000000000000..99c32db412ae --- /dev/null +++ b/arch/arm/mach-versatile/headsmp.S @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2003 ARM Limited + * All Rights Reserved + */ +#include +#include +#include + +/* + * Realview/Versatile Express specific entry point for secondary CPUs. + * This provides a "holding pen" into which all secondary cores are held + * until we're ready for them to initialise. + */ +ENTRY(versatile_secondary_startup) + ARM_BE8(setend be) + mrc p15, 0, r0, c0, c0, 5 + bic r0, #0xff000000 + adr r4, 1f + ldmia r4, {r5, r6} + sub r4, r4, r5 + add r6, r6, r4 +pen: ldr r7, [r6] + cmp r7, r0 + bne pen + + /* + * we've been released from the holding pen: secondary_stack + * should now contain the SVC stack for this core + */ + b secondary_startup + + .align +1: .long . + .long versatile_cpu_release +ENDPROC(versatile_secondary_startup) diff --git a/arch/arm/mach-versatile/hotplug.c b/arch/arm/mach-versatile/hotplug.c new file mode 100644 index 000000000000..5a152175578b --- /dev/null +++ b/arch/arm/mach-versatile/hotplug.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This hotplug implementation is _specific_ to the situation found on + * ARM development platforms where there is _no_ possibility of actually + * taking a CPU offline, resetting it, or otherwise. Real platforms must + * NOT copy this code. + */ +#include +#include +#include + +#include +#include + +#include "platsmp.h" + +static inline void versatile_immitation_enter_lowpower(unsigned int actrl_mask) +{ + unsigned int v; + + asm volatile( + "mcr p15, 0, %1, c7, c5, 0\n" + " mcr p15, 0, %1, c7, c10, 4\n" + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" + " bic %0, %0, %3\n" + " mcr p15, 0, %0, c1, c0, 1\n" + " mrc p15, 0, %0, c1, c0, 0\n" + " bic %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "r" (0), "Ir" (CR_C), "Ir" (actrl_mask) + : "cc"); +} + +static inline void versatile_immitation_leave_lowpower(unsigned int actrl_mask) +{ + unsigned int v; + + asm volatile( + "mrc p15, 0, %0, c1, c0, 0\n" + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" + " orr %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (CR_C), "Ir" (actrl_mask) + : "cc"); +} + +static inline void versatile_immitation_do_lowpower(unsigned int cpu, int *spurious) +{ + /* + * there is no power-control hardware on this platform, so all + * we can do is put the core into WFI; this is safe as the calling + * code will have already disabled interrupts. + * + * This code should not be used outside Versatile platforms. + */ + for (;;) { + wfi(); + + if (versatile_cpu_release == cpu_logical_map(cpu)) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * Getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * Just note it happening - when we're woken, we can report + * its occurrence. + */ + (*spurious)++; + } +} + +/* + * platform-specific code to shutdown a CPU. + * This code supports immitation-style CPU hotplug for Versatile/Realview/ + * Versatile Express platforms that are unable to do real CPU hotplug. + */ +void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask) +{ + int spurious = 0; + + versatile_immitation_enter_lowpower(actrl_mask); + versatile_immitation_do_lowpower(cpu, &spurious); + versatile_immitation_leave_lowpower(actrl_mask); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} diff --git a/arch/arm/mach-versatile/integrator-cm.h b/arch/arm/mach-versatile/integrator-cm.h new file mode 100644 index 000000000000..f09ea18a50f8 --- /dev/null +++ b/arch/arm/mach-versatile/integrator-cm.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * access the core module control register. + */ +u32 cm_get(void); +void cm_control(u32, u32); + +struct device_node; +void cm_init(void); +void cm_clear_irqs(void); + +#define CM_CTRL_LED (1 << 0) +#define CM_CTRL_nMBDET (1 << 1) +#define CM_CTRL_REMAP (1 << 2) + +/* + * Integrator/AP,PP2 specific + */ +#define CM_CTRL_HIGHVECTORS (1 << 4) +#define CM_CTRL_BIGENDIAN (1 << 5) +#define CM_CTRL_FASTBUS (1 << 6) +#define CM_CTRL_SYNC (1 << 7) + +/* + * ARM926/946/966 Integrator/CP specific + */ +#define CM_CTRL_LCDBIASEN (1 << 8) +#define CM_CTRL_LCDBIASUP (1 << 9) +#define CM_CTRL_LCDBIASDN (1 << 10) +#define CM_CTRL_LCDMUXSEL_MASK (7 << 11) +#define CM_CTRL_LCDMUXSEL_GENLCD (1 << 11) +#define CM_CTRL_LCDMUXSEL_VGA565_TFT555 (2 << 11) +#define CM_CTRL_LCDMUXSEL_SHARPLCD (3 << 11) +#define CM_CTRL_LCDMUXSEL_VGA555_TFT555 (4 << 11) +#define CM_CTRL_LCDEN0 (1 << 14) +#define CM_CTRL_LCDEN1 (1 << 15) +#define CM_CTRL_STATIC1 (1 << 16) +#define CM_CTRL_STATIC2 (1 << 17) +#define CM_CTRL_STATIC (1 << 18) +#define CM_CTRL_n24BITEN (1 << 19) +#define CM_CTRL_EBIWP (1 << 20) diff --git a/arch/arm/mach-versatile/integrator-hardware.h b/arch/arm/mach-versatile/integrator-hardware.h new file mode 100644 index 000000000000..81ce09e3ad45 --- /dev/null +++ b/arch/arm/mach-versatile/integrator-hardware.h @@ -0,0 +1,336 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * This file contains the hardware definitions of the Integrator. + * + * Copyright (C) 1998-1999 ARM Limited. + */ +#ifndef INTEGRATOR_HARDWARE_H +#define INTEGRATOR_HARDWARE_H + +/* + * Where in virtual memory the IO devices (timers, system controllers + * and so on) + */ +#define IO_BASE 0xF0000000 // VA of IO +#define IO_SIZE 0x0B000000 // How much? +#define IO_START INTEGRATOR_HDR_BASE // PA of IO + +/* macro to get at IO space when running virtually */ +#define IO_ADDRESS(x) (((x) & 0x000fffff) | (((x) >> 4) & 0x0ff00000) | IO_BASE) +#define __io_address(n) ((void __iomem *)IO_ADDRESS(n)) + +/* + * Integrator memory map + */ +#define INTEGRATOR_BOOT_ROM_LO 0x00000000 +#define INTEGRATOR_BOOT_ROM_HI 0x20000000 +#define INTEGRATOR_BOOT_ROM_BASE INTEGRATOR_BOOT_ROM_HI /* Normal position */ +#define INTEGRATOR_BOOT_ROM_SIZE SZ_512K + +/* + * New Core Modules have different amounts of SSRAM, the amount of SSRAM + * fitted can be found in HDR_STAT. + * + * The symbol INTEGRATOR_SSRAM_SIZE is kept, however this now refers to + * the minimum amount of SSRAM fitted on any core module. + * + * New Core Modules also alias the SSRAM. + * + */ +#define INTEGRATOR_SSRAM_BASE 0x00000000 +#define INTEGRATOR_SSRAM_ALIAS_BASE 0x10800000 +#define INTEGRATOR_SSRAM_SIZE SZ_256K + +#define INTEGRATOR_FLASH_BASE 0x24000000 +#define INTEGRATOR_FLASH_SIZE SZ_32M + +#define INTEGRATOR_MBRD_SSRAM_BASE 0x28000000 +#define INTEGRATOR_MBRD_SSRAM_SIZE SZ_512K + +/* + * SDRAM is a SIMM therefore the size is not known. + */ +#define INTEGRATOR_SDRAM_BASE 0x00040000 + +#define INTEGRATOR_SDRAM_ALIAS_BASE 0x80000000 +#define INTEGRATOR_HDR0_SDRAM_BASE 0x80000000 +#define INTEGRATOR_HDR1_SDRAM_BASE 0x90000000 +#define INTEGRATOR_HDR2_SDRAM_BASE 0xA0000000 +#define INTEGRATOR_HDR3_SDRAM_BASE 0xB0000000 + +/* + * Logic expansion modules + * + */ +#define INTEGRATOR_LOGIC_MODULES_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE0_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE1_BASE 0xD0000000 +#define INTEGRATOR_LOGIC_MODULE2_BASE 0xE0000000 +#define INTEGRATOR_LOGIC_MODULE3_BASE 0xF0000000 + +/* + * Integrator header card registers + */ +#define INTEGRATOR_HDR_ID_OFFSET 0x00 +#define INTEGRATOR_HDR_PROC_OFFSET 0x04 +#define INTEGRATOR_HDR_OSC_OFFSET 0x08 +#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C +#define INTEGRATOR_HDR_STAT_OFFSET 0x10 +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 +#define INTEGRATOR_HDR_SDRAM_OFFSET 0x20 +#define INTEGRATOR_HDR_INIT_OFFSET 0x24 /* CM9x6 */ +#define INTEGRATOR_HDR_IC_OFFSET 0x40 +#define INTEGRATOR_HDR_SPDBASE_OFFSET 0x100 +#define INTEGRATOR_HDR_SPDTOP_OFFSET 0x200 + +#define INTEGRATOR_HDR_BASE 0x10000000 +#define INTEGRATOR_HDR_ID (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_ID_OFFSET) +#define INTEGRATOR_HDR_PROC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_PROC_OFFSET) +#define INTEGRATOR_HDR_OSC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_OSC_OFFSET) +#define INTEGRATOR_HDR_CTRL (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_CTRL_OFFSET) +#define INTEGRATOR_HDR_STAT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_STAT_OFFSET) +#define INTEGRATOR_HDR_LOCK (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_LOCK_OFFSET) +#define INTEGRATOR_HDR_SDRAM (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SDRAM_OFFSET) +#define INTEGRATOR_HDR_INIT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_INIT_OFFSET) +#define INTEGRATOR_HDR_IC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_IC_OFFSET) +#define INTEGRATOR_HDR_SPDBASE (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDBASE_OFFSET) +#define INTEGRATOR_HDR_SPDTOP (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDTOP_OFFSET) + +#define INTEGRATOR_HDR_CTRL_LED 0x01 +#define INTEGRATOR_HDR_CTRL_MBRD_DETECH 0x02 +#define INTEGRATOR_HDR_CTRL_REMAP 0x04 +#define INTEGRATOR_HDR_CTRL_RESET 0x08 +#define INTEGRATOR_HDR_CTRL_HIGHVECTORS 0x10 +#define INTEGRATOR_HDR_CTRL_BIG_ENDIAN 0x20 +#define INTEGRATOR_HDR_CTRL_FASTBUS 0x40 +#define INTEGRATOR_HDR_CTRL_SYNC 0x80 + +#define INTEGRATOR_HDR_OSC_CORE_10MHz 0x102 +#define INTEGRATOR_HDR_OSC_CORE_15MHz 0x107 +#define INTEGRATOR_HDR_OSC_CORE_20MHz 0x10C +#define INTEGRATOR_HDR_OSC_CORE_25MHz 0x111 +#define INTEGRATOR_HDR_OSC_CORE_30MHz 0x116 +#define INTEGRATOR_HDR_OSC_CORE_35MHz 0x11B +#define INTEGRATOR_HDR_OSC_CORE_40MHz 0x120 +#define INTEGRATOR_HDR_OSC_CORE_45MHz 0x125 +#define INTEGRATOR_HDR_OSC_CORE_50MHz 0x12A +#define INTEGRATOR_HDR_OSC_CORE_55MHz 0x12F +#define INTEGRATOR_HDR_OSC_CORE_60MHz 0x134 +#define INTEGRATOR_HDR_OSC_CORE_65MHz 0x139 +#define INTEGRATOR_HDR_OSC_CORE_70MHz 0x13E +#define INTEGRATOR_HDR_OSC_CORE_75MHz 0x143 +#define INTEGRATOR_HDR_OSC_CORE_80MHz 0x148 +#define INTEGRATOR_HDR_OSC_CORE_85MHz 0x14D +#define INTEGRATOR_HDR_OSC_CORE_90MHz 0x152 +#define INTEGRATOR_HDR_OSC_CORE_95MHz 0x157 +#define INTEGRATOR_HDR_OSC_CORE_100MHz 0x15C +#define INTEGRATOR_HDR_OSC_CORE_105MHz 0x161 +#define INTEGRATOR_HDR_OSC_CORE_110MHz 0x166 +#define INTEGRATOR_HDR_OSC_CORE_115MHz 0x16B +#define INTEGRATOR_HDR_OSC_CORE_120MHz 0x170 +#define INTEGRATOR_HDR_OSC_CORE_125MHz 0x175 +#define INTEGRATOR_HDR_OSC_CORE_130MHz 0x17A +#define INTEGRATOR_HDR_OSC_CORE_135MHz 0x17F +#define INTEGRATOR_HDR_OSC_CORE_140MHz 0x184 +#define INTEGRATOR_HDR_OSC_CORE_145MHz 0x189 +#define INTEGRATOR_HDR_OSC_CORE_150MHz 0x18E +#define INTEGRATOR_HDR_OSC_CORE_155MHz 0x193 +#define INTEGRATOR_HDR_OSC_CORE_160MHz 0x198 +#define INTEGRATOR_HDR_OSC_CORE_MASK 0x7FF + +#define INTEGRATOR_HDR_OSC_MEM_10MHz 0x10C000 +#define INTEGRATOR_HDR_OSC_MEM_15MHz 0x116000 +#define INTEGRATOR_HDR_OSC_MEM_20MHz 0x120000 +#define INTEGRATOR_HDR_OSC_MEM_25MHz 0x12A000 +#define INTEGRATOR_HDR_OSC_MEM_30MHz 0x134000 +#define INTEGRATOR_HDR_OSC_MEM_33MHz 0x13A000 +#define INTEGRATOR_HDR_OSC_MEM_40MHz 0x148000 +#define INTEGRATOR_HDR_OSC_MEM_50MHz 0x15C000 +#define INTEGRATOR_HDR_OSC_MEM_60MHz 0x170000 +#define INTEGRATOR_HDR_OSC_MEM_66MHz 0x17C000 +#define INTEGRATOR_HDR_OSC_MEM_MASK 0x7FF000 + +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM7x0 0x0 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x0 0x0800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x6 0x1000000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM10x00 0x1800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_MASK 0x1800000 + +#define INTEGRATOR_HDR_SDRAM_SPD_OK (1 << 5) + +/* + * Integrator system registers + */ + +/* + * System Controller + */ +#define INTEGRATOR_SC_ID_OFFSET 0x00 +#define INTEGRATOR_SC_OSC_OFFSET 0x04 +#define INTEGRATOR_SC_CTRLS_OFFSET 0x08 +#define INTEGRATOR_SC_CTRLC_OFFSET 0x0C +#define INTEGRATOR_SC_DEC_OFFSET 0x10 +#define INTEGRATOR_SC_ARB_OFFSET 0x14 +#define INTEGRATOR_SC_LOCK_OFFSET 0x1C + +#define INTEGRATOR_SC_BASE 0x11000000 +#define INTEGRATOR_SC_ID (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ID_OFFSET) +#define INTEGRATOR_SC_OSC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_OSC_OFFSET) +#define INTEGRATOR_SC_CTRLS (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET) +#define INTEGRATOR_SC_CTRLC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET) +#define INTEGRATOR_SC_DEC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_DEC_OFFSET) +#define INTEGRATOR_SC_ARB (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ARB_OFFSET) +#define INTEGRATOR_SC_PCIENABLE (INTEGRATOR_SC_BASE + INTEGRATOR_SC_PCIENABLE_OFFSET) +#define INTEGRATOR_SC_LOCK (INTEGRATOR_SC_BASE + INTEGRATOR_SC_LOCK_OFFSET) + +#define INTEGRATOR_SC_OSC_SYS_10MHz 0x20 +#define INTEGRATOR_SC_OSC_SYS_15MHz 0x34 +#define INTEGRATOR_SC_OSC_SYS_20MHz 0x48 +#define INTEGRATOR_SC_OSC_SYS_25MHz 0x5C +#define INTEGRATOR_SC_OSC_SYS_33MHz 0x7C +#define INTEGRATOR_SC_OSC_SYS_MASK 0xFF + +#define INTEGRATOR_SC_OSC_PCI_25MHz 0x100 +#define INTEGRATOR_SC_OSC_PCI_33MHz 0x0 +#define INTEGRATOR_SC_OSC_PCI_MASK 0x100 + +#define INTEGRATOR_SC_CTRL_SOFTRST (1 << 0) +#define INTEGRATOR_SC_CTRL_nFLVPPEN (1 << 1) +#define INTEGRATOR_SC_CTRL_nFLWP (1 << 2) +#define INTEGRATOR_SC_CTRL_URTS0 (1 << 4) +#define INTEGRATOR_SC_CTRL_UDTR0 (1 << 5) +#define INTEGRATOR_SC_CTRL_URTS1 (1 << 6) +#define INTEGRATOR_SC_CTRL_UDTR1 (1 << 7) + +/* + * External Bus Interface + */ +#define INTEGRATOR_EBI_BASE 0x12000000 + +#define INTEGRATOR_EBI_CSR0_OFFSET 0x00 +#define INTEGRATOR_EBI_CSR1_OFFSET 0x04 +#define INTEGRATOR_EBI_CSR2_OFFSET 0x08 +#define INTEGRATOR_EBI_CSR3_OFFSET 0x0C +#define INTEGRATOR_EBI_LOCK_OFFSET 0x20 + +#define INTEGRATOR_EBI_CSR0 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR0_OFFSET) +#define INTEGRATOR_EBI_CSR1 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) +#define INTEGRATOR_EBI_CSR2 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR2_OFFSET) +#define INTEGRATOR_EBI_CSR3 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR3_OFFSET) +#define INTEGRATOR_EBI_LOCK (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) + +#define INTEGRATOR_EBI_8_BIT 0x00 +#define INTEGRATOR_EBI_16_BIT 0x01 +#define INTEGRATOR_EBI_32_BIT 0x02 +#define INTEGRATOR_EBI_WRITE_ENABLE 0x04 +#define INTEGRATOR_EBI_SYNC 0x08 +#define INTEGRATOR_EBI_WS_2 0x00 +#define INTEGRATOR_EBI_WS_3 0x10 +#define INTEGRATOR_EBI_WS_4 0x20 +#define INTEGRATOR_EBI_WS_5 0x30 +#define INTEGRATOR_EBI_WS_6 0x40 +#define INTEGRATOR_EBI_WS_7 0x50 +#define INTEGRATOR_EBI_WS_8 0x60 +#define INTEGRATOR_EBI_WS_9 0x70 +#define INTEGRATOR_EBI_WS_10 0x80 +#define INTEGRATOR_EBI_WS_11 0x90 +#define INTEGRATOR_EBI_WS_12 0xA0 +#define INTEGRATOR_EBI_WS_13 0xB0 +#define INTEGRATOR_EBI_WS_14 0xC0 +#define INTEGRATOR_EBI_WS_15 0xD0 +#define INTEGRATOR_EBI_WS_16 0xE0 +#define INTEGRATOR_EBI_WS_17 0xF0 + + +#define INTEGRATOR_CT_BASE 0x13000000 /* Counter/Timers */ +#define INTEGRATOR_IC_BASE 0x14000000 /* Interrupt Controller */ +#define INTEGRATOR_RTC_BASE 0x15000000 /* Real Time Clock */ +#define INTEGRATOR_UART0_BASE 0x16000000 /* UART 0 */ +#define INTEGRATOR_UART1_BASE 0x17000000 /* UART 1 */ +#define INTEGRATOR_KBD_BASE 0x18000000 /* Keyboard */ +#define INTEGRATOR_MOUSE_BASE 0x19000000 /* Mouse */ + +/* + * LED's & Switches + */ +#define INTEGRATOR_DBG_ALPHA_OFFSET 0x00 +#define INTEGRATOR_DBG_LEDS_OFFSET 0x04 +#define INTEGRATOR_DBG_SWITCH_OFFSET 0x08 + +#define INTEGRATOR_DBG_BASE 0x1A000000 +#define INTEGRATOR_DBG_ALPHA (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_ALPHA_OFFSET) +#define INTEGRATOR_DBG_LEDS (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_LEDS_OFFSET) +#define INTEGRATOR_DBG_SWITCH (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET) + +#define INTEGRATOR_AP_GPIO_BASE 0x1B000000 /* GPIO */ + +#define INTEGRATOR_CP_MMC_BASE 0x1C000000 /* MMC */ +#define INTEGRATOR_CP_AACI_BASE 0x1D000000 /* AACI */ +#define INTEGRATOR_CP_ETH_BASE 0xC8000000 /* Ethernet */ +#define INTEGRATOR_CP_GPIO_BASE 0xC9000000 /* GPIO */ +#define INTEGRATOR_CP_SIC_BASE 0xCA000000 /* SIC */ +#define INTEGRATOR_CP_CTL_BASE 0xCB000000 /* CP system control */ + +/* PS2 Keyboard interface */ +#define KMI0_BASE INTEGRATOR_KBD_BASE + +/* PS2 Mouse interface */ +#define KMI1_BASE INTEGRATOR_MOUSE_BASE + +/* + * Integrator Interrupt Controllers + * + * + * Offsets from interrupt controller base + * + * System Controller interrupt controller base is + * + * INTEGRATOR_IC_BASE + (header_number << 6) + * + * Core Module interrupt controller base is + * + * INTEGRATOR_HDR_IC + */ +#define IRQ_STATUS 0 +#define IRQ_RAW_STATUS 0x04 +#define IRQ_ENABLE 0x08 +#define IRQ_ENABLE_SET 0x08 +#define IRQ_ENABLE_CLEAR 0x0C + +#define INT_SOFT_SET 0x10 +#define INT_SOFT_CLEAR 0x14 + +#define FIQ_STATUS 0x20 +#define FIQ_RAW_STATUS 0x24 +#define FIQ_ENABLE 0x28 +#define FIQ_ENABLE_SET 0x28 +#define FIQ_ENABLE_CLEAR 0x2C + + +/* + * LED's + */ +#define GREEN_LED 0x01 +#define YELLOW_LED 0x02 +#define RED_LED 0x04 +#define GREEN_LED_2 0x08 +#define ALL_LEDS 0x0F + +#define LED_BANK INTEGRATOR_DBG_LEDS + +/* + * Timer definitions + * + * Only use timer 1 & 2 + * (both run at 24MHz and will need the clock divider set to 16). + * + * Timer 0 runs at bus frequency + */ +#define INTEGRATOR_TIMER0_BASE INTEGRATOR_CT_BASE +#define INTEGRATOR_TIMER1_BASE (INTEGRATOR_CT_BASE + 0x100) +#define INTEGRATOR_TIMER2_BASE (INTEGRATOR_CT_BASE + 0x200) + +#define INTEGRATOR_CSR_BASE 0x10000000 +#define INTEGRATOR_CSR_SIZE 0x10000000 + +#endif /* INTEGRATOR_HARDWARE_H */ diff --git a/arch/arm/mach-versatile/integrator.c b/arch/arm/mach-versatile/integrator.c new file mode 100644 index 000000000000..fdf9c4db08a7 --- /dev/null +++ b/arch/arm/mach-versatile/integrator.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "integrator-hardware.h" +#include "integrator-cm.h" +#include "integrator.h" + +static DEFINE_RAW_SPINLOCK(cm_lock); +static void __iomem *cm_base; + +/** + * cm_get - get the value from the CM_CTRL register + */ +u32 cm_get(void) +{ + return readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET); +} + +/** + * cm_control - update the CM_CTRL register. + * @mask: bits to change + * @set: bits to set + */ +void cm_control(u32 mask, u32 set) +{ + unsigned long flags; + u32 val; + + raw_spin_lock_irqsave(&cm_lock, flags); + val = readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET) & ~mask; + writel(val | set, cm_base + INTEGRATOR_HDR_CTRL_OFFSET); + raw_spin_unlock_irqrestore(&cm_lock, flags); +} + +void cm_clear_irqs(void) +{ + /* disable core module IRQs */ + writel(0xffffffffU, cm_base + INTEGRATOR_HDR_IC_OFFSET + + IRQ_ENABLE_CLEAR); +} + +static const struct of_device_id cm_match[] = { + { .compatible = "arm,core-module-integrator"}, + { }, +}; + +void cm_init(void) +{ + struct device_node *cm = of_find_matching_node(NULL, cm_match); + + if (!cm) { + pr_crit("no core module node found in device tree\n"); + return; + } + cm_base = of_iomap(cm, 0); + if (!cm_base) { + pr_crit("could not remap core module\n"); + return; + } + cm_clear_irqs(); +} + +/* + * We need to stop things allocating the low memory; ideally we need a + * better implementation of GFP_DMA which does not assume that DMA-able + * memory starts at zero. + */ +void __init integrator_reserve(void) +{ + memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); +} diff --git a/arch/arm/mach-versatile/integrator.h b/arch/arm/mach-versatile/integrator.h new file mode 100644 index 000000000000..f053aeebeb7a --- /dev/null +++ b/arch/arm/mach-versatile/integrator.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include +extern struct amba_pl010_data ap_uart_data; +void integrator_init_early(void); +int integrator_init(bool is_cp); +void integrator_reserve(void); diff --git a/arch/arm/mach-versatile/integrator_ap.c b/arch/arm/mach-versatile/integrator_ap.c new file mode 100644 index 000000000000..44a69cc69376 --- /dev/null +++ b/arch/arm/mach-versatile/integrator_ap.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "integrator-hardware.h" +#include "integrator-cm.h" +#include "integrator.h" + +/* Regmap to the AP system controller */ +static struct regmap *ap_syscon_map; + +/* + * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx + * is the (PA >> 12). + * + * Setup a VA for the Integrator interrupt controller (for header #0, + * just for now). + */ +#define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE) + +/* + * Logical Physical + * f1400000 14000000 Interrupt controller + * f1600000 16000000 UART 0 + */ + +static struct map_desc ap_io_desc[] __initdata __maybe_unused = { + { + .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + } +}; + +static void __init ap_map_io(void) +{ + iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc)); +} + +#ifdef CONFIG_PM +static unsigned long ic_irq_enable; + +static int irq_suspend(void) +{ + ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE); + return 0; +} + +static void irq_resume(void) +{ + /* disable all irq sources */ + cm_clear_irqs(); + writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); + writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); + + writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET); +} +#else +#define irq_suspend NULL +#define irq_resume NULL +#endif + +static struct syscore_ops irq_syscore_ops = { + .suspend = irq_suspend, + .resume = irq_resume, +}; + +static int __init irq_syscore_init(void) +{ + register_syscore_ops(&irq_syscore_ops); + + return 0; +} + +device_initcall(irq_syscore_init); + +/* + * For the PL010 found in the Integrator/AP some of the UART control is + * implemented in the system controller and accessed using a callback + * from the driver. + */ +static void integrator_uart_set_mctrl(struct amba_device *dev, + void __iomem *base, unsigned int mctrl) +{ + unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask; + u32 phybase = dev->res.start; + int ret; + + if (phybase == INTEGRATOR_UART0_BASE) { + /* UART0 */ + rts_mask = 1 << 4; + dtr_mask = 1 << 5; + } else { + /* UART1 */ + rts_mask = 1 << 6; + dtr_mask = 1 << 7; + } + + if (mctrl & TIOCM_RTS) + ctrlc |= rts_mask; + else + ctrls |= rts_mask; + + if (mctrl & TIOCM_DTR) + ctrlc |= dtr_mask; + else + ctrls |= dtr_mask; + + ret = regmap_write(ap_syscon_map, + INTEGRATOR_SC_CTRLS_OFFSET, + ctrls); + if (ret) + pr_err("MODEM: unable to write PL010 UART CTRLS\n"); + + ret = regmap_write(ap_syscon_map, + INTEGRATOR_SC_CTRLC_OFFSET, + ctrlc); + if (ret) + pr_err("MODEM: unable to write PL010 UART CRTLC\n"); +} + +struct amba_pl010_data ap_uart_data = { + .set_mctrl = integrator_uart_set_mctrl, +}; + +void __init ap_init_early(void) +{ +} + +static void __init ap_init_irq_of(void) +{ + cm_init(); + irqchip_init(); +} + +/* For the Device Tree, add in the UART callbacks as AUXDATA */ +static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE, + "uart0", &ap_uart_data), + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE, + "uart1", &ap_uart_data), + { /* sentinel */ }, +}; + +static const struct of_device_id ap_syscon_match[] = { + { .compatible = "arm,integrator-ap-syscon"}, + { }, +}; + +static void __init ap_init_of(void) +{ + struct device_node *syscon; + + of_platform_default_populate(NULL, ap_auxdata_lookup, NULL); + + syscon = of_find_matching_node(NULL, ap_syscon_match); + if (!syscon) + return; + ap_syscon_map = syscon_node_to_regmap(syscon); + if (IS_ERR(ap_syscon_map)) { + pr_crit("could not find Integrator/AP system controller\n"); + return; + } +} + +static const char * ap_dt_board_compat[] = { + "arm,integrator-ap", + NULL, +}; + +DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") + .reserve = integrator_reserve, + .map_io = ap_map_io, + .init_early = ap_init_early, + .init_irq = ap_init_irq_of, + .init_machine = ap_init_of, + .dt_compat = ap_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-versatile/integrator_cp.c b/arch/arm/mach-versatile/integrator_cp.c new file mode 100644 index 000000000000..2ed4ded56b3f --- /dev/null +++ b/arch/arm/mach-versatile/integrator_cp.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2003 Deep Blue Solutions Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "integrator-hardware.h" +#include "integrator-cm.h" +#include "integrator.h" + +/* Base address to the core module header */ +static struct regmap *cm_map; +/* Base address to the CP controller */ +static void __iomem *intcp_con_base; + +#define CM_COUNTER_OFFSET 0x28 + +/* + * Logical Physical + * f1400000 14000000 Interrupt controller + * f1600000 16000000 UART 0 + * fca00000 ca000000 SIC + */ + +static struct map_desc intcp_io_desc[] __initdata __maybe_unused = { + { + .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = IO_ADDRESS(INTEGRATOR_CP_SIC_BASE), + .pfn = __phys_to_pfn(INTEGRATOR_CP_SIC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + } +}; + +static void __init intcp_map_io(void) +{ + iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); +} + +/* + * It seems that the card insertion interrupt remains active after + * we've acknowledged it. We therefore ignore the interrupt, and + * rely on reading it from the SIC. This also means that we must + * clear the latched interrupt. + */ +static unsigned int mmc_status(struct device *dev) +{ + unsigned int status = readl(__io_address(0xca000000 + 4)); + writel(8, intcp_con_base + 8); + + return status & 8; +} + +static struct mmci_platform_data mmc_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +static u64 notrace intcp_read_sched_clock(void) +{ + unsigned int val; + + /* MMIO so discard return code */ + regmap_read(cm_map, CM_COUNTER_OFFSET, &val); + return val; +} + +static void __init intcp_init_early(void) +{ + cm_map = syscon_regmap_lookup_by_compatible("arm,core-module-integrator"); + if (IS_ERR(cm_map)) + return; + sched_clock_register(intcp_read_sched_clock, 32, 24000000); +} + +static void __init intcp_init_irq_of(void) +{ + cm_init(); + irqchip_init(); +} + +/* + * For the Device Tree, add in the UART, MMC and CLCD specifics as AUXDATA + * and enforce the bus names since these are used for clock lookups. + */ +static struct of_dev_auxdata intcp_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_CP_MMC_BASE, + "mmci", &mmc_data), + { /* sentinel */ }, +}; + +static const struct of_device_id intcp_syscon_match[] = { + { .compatible = "arm,integrator-cp-syscon"}, + { }, +}; + +static void __init intcp_init_of(void) +{ + struct device_node *cpcon; + + cpcon = of_find_matching_node(NULL, intcp_syscon_match); + if (!cpcon) + return; + + intcp_con_base = of_iomap(cpcon, 0); + if (!intcp_con_base) + return; + + of_platform_default_populate(NULL, intcp_auxdata_lookup, NULL); +} + +static const char * intcp_dt_board_compat[] = { + "arm,integrator-cp", + NULL, +}; + +DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") + .reserve = integrator_reserve, + .map_io = intcp_map_io, + .init_early = intcp_init_early, + .init_irq = intcp_init_irq_of, + .init_machine = intcp_init_of, + .dt_compat = intcp_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-versatile/platsmp-realview.c b/arch/arm/mach-versatile/platsmp-realview.c new file mode 100644 index 000000000000..5d363385c801 --- /dev/null +++ b/arch/arm/mach-versatile/platsmp-realview.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2015 Linus Walleij + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "platsmp.h" + +#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 + +static const struct of_device_id realview_scu_match[] = { + { .compatible = "arm,arm11mp-scu", }, + { .compatible = "arm,cortex-a9-scu", }, + { .compatible = "arm,cortex-a5-scu", }, + { } +}; + +static const struct of_device_id realview_syscon_match[] = { + { .compatible = "arm,core-module-integrator", }, + { .compatible = "arm,realview-eb-syscon", }, + { .compatible = "arm,realview-pb11mp-syscon", }, + { .compatible = "arm,realview-pbx-syscon", }, + { }, +}; + +static void __init realview_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *np; + void __iomem *scu_base; + struct regmap *map; + unsigned int ncores; + int i; + + np = of_find_matching_node(NULL, realview_scu_match); + if (!np) { + pr_err("PLATSMP: No SCU base address\n"); + return; + } + scu_base = of_iomap(np, 0); + of_node_put(np); + if (!scu_base) { + pr_err("PLATSMP: No SCU remap\n"); + return; + } + + scu_enable(scu_base); + ncores = scu_get_core_count(scu_base); + pr_info("SCU: %d cores detected\n", ncores); + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + iounmap(scu_base); + + /* The syscon contains the magic SMP start address registers */ + np = of_find_matching_node(NULL, realview_syscon_match); + if (!np) { + pr_err("PLATSMP: No syscon match\n"); + return; + } + map = syscon_node_to_regmap(np); + if (IS_ERR(map)) { + pr_err("PLATSMP: No syscon regmap\n"); + return; + } + /* Put the boot address in this magic register */ + regmap_write(map, REALVIEW_SYS_FLAGSSET_OFFSET, + __pa_symbol(versatile_secondary_startup)); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void realview_cpu_die(unsigned int cpu) +{ + return versatile_immitation_cpu_die(cpu, 0x20); +} +#endif + +static const struct smp_operations realview_dt_smp_ops __initconst = { + .smp_prepare_cpus = realview_smp_prepare_cpus, + .smp_secondary_init = versatile_secondary_init, + .smp_boot_secondary = versatile_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = realview_cpu_die, +#endif +}; +CPU_METHOD_OF_DECLARE(realview_smp, "arm,realview-smp", &realview_dt_smp_ops); diff --git a/arch/arm/mach-versatile/platsmp-vexpress.c b/arch/arm/mach-versatile/platsmp-vexpress.c new file mode 100644 index 000000000000..1ee3c45e71c9 --- /dev/null +++ b/arch/arm/mach-versatile/platsmp-vexpress.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "platsmp.h" +#include "vexpress.h" + +bool __init vexpress_smp_init_ops(void) +{ +#ifdef CONFIG_MCPM + int cpu; + struct device_node *cpu_node, *cci_node; + + /* + * The best way to detect a multi-cluster configuration + * is to detect if the kernel can take over CCI ports + * control. Loop over possible CPUs and check if CCI + * port control is available. + * Override the default vexpress_smp_ops if so. + */ + for_each_possible_cpu(cpu) { + bool available; + + cpu_node = of_get_cpu_node(cpu, NULL); + if (WARN(!cpu_node, "Missing cpu device node!")) + return false; + + cci_node = of_parse_phandle(cpu_node, "cci-control-port", 0); + available = cci_node && of_device_is_available(cci_node); + of_node_put(cci_node); + of_node_put(cpu_node); + + if (!available) + return false; + } + + mcpm_smp_set_ops(); + return true; +#else + return false; +#endif +} + +static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = { + { .compatible = "arm,cortex-a5-scu", }, + { .compatible = "arm,cortex-a9-scu", }, + {} +}; + +static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *scu = of_find_matching_node(NULL, + vexpress_smp_dt_scu_match); + + if (scu) + scu_enable(of_iomap(scu, 0)); + + /* + * Write the address of secondary startup into the + * system-wide flags register. The boot monitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. + */ + vexpress_flags_set(__pa_symbol(versatile_secondary_startup)); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void vexpress_cpu_die(unsigned int cpu) +{ + versatile_immitation_cpu_die(cpu, 0x40); +} +#endif + +const struct smp_operations vexpress_smp_dt_ops __initconst = { + .smp_prepare_cpus = vexpress_smp_dt_prepare_cpus, + .smp_secondary_init = versatile_secondary_init, + .smp_boot_secondary = versatile_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = vexpress_cpu_die, +#endif +}; diff --git a/arch/arm/mach-versatile/platsmp.c b/arch/arm/mach-versatile/platsmp.c new file mode 100644 index 000000000000..fa7378321e23 --- /dev/null +++ b/arch/arm/mach-versatile/platsmp.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This code is specific to the hardware found on ARM Realview and + * Versatile Express platforms where the CPUs are unable to be individually + * woken, and where there is no way to hot-unplug CPUs. Real platforms + * should not copy this code. + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "platsmp.h" + +/* + * versatile_cpu_release controls the release of CPUs from the holding + * pen in headsmp.S, which exists because we are not always able to + * control the release of individual CPUs from the board firmware. + * Production platforms do not need this. + */ +volatile int versatile_cpu_release = -1; + +/* + * Write versatile_cpu_release in a way that is guaranteed to be visible to + * all observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +static void versatile_write_cpu_release(int val) +{ + versatile_cpu_release = val; + smp_wmb(); + sync_cache_w(&versatile_cpu_release); +} + +/* + * versatile_lock exists to avoid running the loops_per_jiffy delay loop + * calibrations on the secondary CPU while the requesting CPU is using + * the limited-bandwidth bus - which affects the calibration value. + * Production platforms do not need this. + */ +static DEFINE_RAW_SPINLOCK(versatile_lock); + +void versatile_secondary_init(unsigned int cpu) +{ + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + versatile_write_cpu_release(-1); + + /* + * Synchronise with the boot thread. + */ + raw_spin_lock(&versatile_lock); + raw_spin_unlock(&versatile_lock); +} + +int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + + /* + * Set synchronisation state between this boot processor + * and the secondary one + */ + raw_spin_lock(&versatile_lock); + + /* + * This is really belt and braces; we hold unintended secondary + * CPUs in the holding pen until we're ready for them. However, + * since we haven't sent them a soft interrupt, they shouldn't + * be there. + */ + versatile_write_cpu_release(cpu_logical_map(cpu)); + + /* + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (versatile_cpu_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + raw_spin_unlock(&versatile_lock); + + return versatile_cpu_release != -1 ? -ENOSYS : 0; +} diff --git a/arch/arm/mach-versatile/platsmp.h b/arch/arm/mach-versatile/platsmp.h new file mode 100644 index 000000000000..171a0ab72220 --- /dev/null +++ b/arch/arm/mach-versatile/platsmp.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2011 ARM Ltd. + * All Rights Reserved + */ +extern volatile int versatile_cpu_release; + +extern void versatile_secondary_startup(void); +extern void versatile_secondary_init(unsigned int cpu); +extern int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle); +void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask); diff --git a/arch/arm/mach-versatile/realview.c b/arch/arm/mach-versatile/realview.c new file mode 100644 index 000000000000..feab66080ba2 --- /dev/null +++ b/arch/arm/mach-versatile/realview.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Linus Walleij + */ +#include +#include +#include + +static const char *const realview_dt_platform_compat[] __initconst = { + "arm,realview-eb", + "arm,realview-pb1176", + "arm,realview-pb11mp", + "arm,realview-pba8", + "arm,realview-pbx", + NULL, +}; + +DT_MACHINE_START(REALVIEW_DT, "ARM RealView Machine (Device Tree Support)") +#ifdef CONFIG_ZONE_DMA + .dma_zone_size = SZ_256M, +#endif + .dt_compat = realview_dt_platform_compat, + .l2c_aux_val = 0x0, + .l2c_aux_mask = ~0x0, +MACHINE_END diff --git a/arch/arm/mach-versatile/spc.c b/arch/arm/mach-versatile/spc.c new file mode 100644 index 000000000000..1da11bdb1dfb --- /dev/null +++ b/arch/arm/mach-versatile/spc.c @@ -0,0 +1,598 @@ +/* + * Versatile Express Serial Power Controller (SPC) support + * + * Copyright (C) 2013 ARM Ltd. + * + * Authors: Sudeep KarkadaNagesha + * Achin Gupta + * Lorenzo Pieralisi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "spc.h" + +#define SPCLOG "vexpress-spc: " + +#define PERF_LVL_A15 0x00 +#define PERF_REQ_A15 0x04 +#define PERF_LVL_A7 0x08 +#define PERF_REQ_A7 0x0c +#define COMMS 0x10 +#define COMMS_REQ 0x14 +#define PWC_STATUS 0x18 +#define PWC_FLAG 0x1c + +/* SPC wake-up IRQs status and mask */ +#define WAKE_INT_MASK 0x24 +#define WAKE_INT_RAW 0x28 +#define WAKE_INT_STAT 0x2c +/* SPC power down registers */ +#define A15_PWRDN_EN 0x30 +#define A7_PWRDN_EN 0x34 +/* SPC per-CPU mailboxes */ +#define A15_BX_ADDR0 0x68 +#define A7_BX_ADDR0 0x78 + +/* SPC CPU/cluster reset statue */ +#define STANDBYWFI_STAT 0x3c +#define STANDBYWFI_STAT_A15_CPU_MASK(cpu) (1 << (cpu)) +#define STANDBYWFI_STAT_A7_CPU_MASK(cpu) (1 << (3 + (cpu))) + +/* SPC system config interface registers */ +#define SYSCFG_WDATA 0x70 +#define SYSCFG_RDATA 0x74 + +/* A15/A7 OPP virtual register base */ +#define A15_PERFVAL_BASE 0xC10 +#define A7_PERFVAL_BASE 0xC30 + +/* Config interface control bits */ +#define SYSCFG_START BIT(31) +#define SYSCFG_SCC (6 << 20) +#define SYSCFG_STAT (14 << 20) + +/* wake-up interrupt masks */ +#define GBL_WAKEUP_INT_MSK (0x3 << 10) + +/* TC2 static dual-cluster configuration */ +#define MAX_CLUSTERS 2 + +/* + * Even though the SPC takes max 3-5 ms to complete any OPP/COMMS + * operation, the operation could start just before jiffie is about + * to be incremented. So setting timeout value of 20ms = 2jiffies@100Hz + */ +#define TIMEOUT_US 20000 + +#define MAX_OPPS 8 +#define CA15_DVFS 0 +#define CA7_DVFS 1 +#define SPC_SYS_CFG 2 +#define STAT_COMPLETE(type) ((1 << 0) << (type << 2)) +#define STAT_ERR(type) ((1 << 1) << (type << 2)) +#define RESPONSE_MASK(type) (STAT_COMPLETE(type) | STAT_ERR(type)) + +struct ve_spc_opp { + unsigned long freq; + unsigned long u_volt; +}; + +struct ve_spc_drvdata { + void __iomem *baseaddr; + /* + * A15s cluster identifier + * It corresponds to A15 processors MPIDR[15:8] bitfield + */ + u32 a15_clusid; + uint32_t cur_rsp_mask; + uint32_t cur_rsp_stat; + struct semaphore sem; + struct completion done; + struct ve_spc_opp *opps[MAX_CLUSTERS]; + int num_opps[MAX_CLUSTERS]; +}; + +static struct ve_spc_drvdata *info; + +static inline bool cluster_is_a15(u32 cluster) +{ + return cluster == info->a15_clusid; +} + +/** + * ve_spc_global_wakeup_irq() + * + * Function to set/clear global wakeup IRQs. Not protected by locking since + * it might be used in code paths where normal cacheable locks are not + * working. Locking must be provided by the caller to ensure atomicity. + * + * @set: if true, global wake-up IRQs are set, if false they are cleared + */ +void ve_spc_global_wakeup_irq(bool set) +{ + u32 reg; + + reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK); + + if (set) + reg |= GBL_WAKEUP_INT_MSK; + else + reg &= ~GBL_WAKEUP_INT_MSK; + + writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK); +} + +/** + * ve_spc_cpu_wakeup_irq() + * + * Function to set/clear per-CPU wake-up IRQs. Not protected by locking since + * it might be used in code paths where normal cacheable locks are not + * working. Locking must be provided by the caller to ensure atomicity. + * + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * @cpu: mpidr[7:0] bitfield describing cpu affinity level + * @set: if true, wake-up IRQs are set, if false they are cleared + */ +void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set) +{ + u32 mask, reg; + + if (cluster >= MAX_CLUSTERS) + return; + + mask = BIT(cpu); + + if (!cluster_is_a15(cluster)) + mask <<= 4; + + reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK); + + if (set) + reg |= mask; + else + reg &= ~mask; + + writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK); +} + +/** + * ve_spc_set_resume_addr() - set the jump address used for warm boot + * + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * @cpu: mpidr[7:0] bitfield describing cpu affinity level + * @addr: physical resume address + */ +void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr) +{ + void __iomem *baseaddr; + + if (cluster >= MAX_CLUSTERS) + return; + + if (cluster_is_a15(cluster)) + baseaddr = info->baseaddr + A15_BX_ADDR0 + (cpu << 2); + else + baseaddr = info->baseaddr + A7_BX_ADDR0 + (cpu << 2); + + writel_relaxed(addr, baseaddr); +} + +/** + * ve_spc_powerdown() + * + * Function to enable/disable cluster powerdown. Not protected by locking + * since it might be used in code paths where normal cacheable locks are not + * working. Locking must be provided by the caller to ensure atomicity. + * + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * @enable: if true enables powerdown, if false disables it + */ +void ve_spc_powerdown(u32 cluster, bool enable) +{ + u32 pwdrn_reg; + + if (cluster >= MAX_CLUSTERS) + return; + + pwdrn_reg = cluster_is_a15(cluster) ? A15_PWRDN_EN : A7_PWRDN_EN; + writel_relaxed(enable, info->baseaddr + pwdrn_reg); +} + +static u32 standbywfi_cpu_mask(u32 cpu, u32 cluster) +{ + return cluster_is_a15(cluster) ? + STANDBYWFI_STAT_A15_CPU_MASK(cpu) + : STANDBYWFI_STAT_A7_CPU_MASK(cpu); +} + +/** + * ve_spc_cpu_in_wfi(u32 cpu, u32 cluster) + * + * @cpu: mpidr[7:0] bitfield describing CPU affinity level within cluster + * @cluster: mpidr[15:8] bitfield describing cluster affinity level + * + * @return: non-zero if and only if the specified CPU is in WFI + * + * Take care when interpreting the result of this function: a CPU might + * be in WFI temporarily due to idle, and is not necessarily safely + * parked. + */ +int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster) +{ + int ret; + u32 mask = standbywfi_cpu_mask(cpu, cluster); + + if (cluster >= MAX_CLUSTERS) + return 1; + + ret = readl_relaxed(info->baseaddr + STANDBYWFI_STAT); + + pr_debug("%s: PCFGREG[0x%X] = 0x%08X, mask = 0x%X\n", + __func__, STANDBYWFI_STAT, ret, mask); + + return ret & mask; +} + +static int ve_spc_get_performance(int cluster, u32 *freq) +{ + struct ve_spc_opp *opps = info->opps[cluster]; + u32 perf_cfg_reg = 0; + u32 perf; + + perf_cfg_reg = cluster_is_a15(cluster) ? PERF_LVL_A15 : PERF_LVL_A7; + + perf = readl_relaxed(info->baseaddr + perf_cfg_reg); + if (perf >= info->num_opps[cluster]) + return -EINVAL; + + opps += perf; + *freq = opps->freq; + + return 0; +} + +/* find closest match to given frequency in OPP table */ +static int ve_spc_round_performance(int cluster, u32 freq) +{ + int idx, max_opp = info->num_opps[cluster]; + struct ve_spc_opp *opps = info->opps[cluster]; + u32 fmin = 0, fmax = ~0, ftmp; + + freq /= 1000; /* OPP entries in kHz */ + for (idx = 0; idx < max_opp; idx++, opps++) { + ftmp = opps->freq; + if (ftmp >= freq) { + if (ftmp <= fmax) + fmax = ftmp; + } else { + if (ftmp >= fmin) + fmin = ftmp; + } + } + if (fmax != ~0) + return fmax * 1000; + else + return fmin * 1000; +} + +static int ve_spc_find_performance_index(int cluster, u32 freq) +{ + int idx, max_opp = info->num_opps[cluster]; + struct ve_spc_opp *opps = info->opps[cluster]; + + for (idx = 0; idx < max_opp; idx++, opps++) + if (opps->freq == freq) + break; + return (idx == max_opp) ? -EINVAL : idx; +} + +static int ve_spc_waitforcompletion(int req_type) +{ + int ret = wait_for_completion_interruptible_timeout( + &info->done, usecs_to_jiffies(TIMEOUT_US)); + if (ret == 0) + ret = -ETIMEDOUT; + else if (ret > 0) + ret = info->cur_rsp_stat & STAT_COMPLETE(req_type) ? 0 : -EIO; + return ret; +} + +static int ve_spc_set_performance(int cluster, u32 freq) +{ + u32 perf_cfg_reg; + int ret, perf, req_type; + + if (cluster_is_a15(cluster)) { + req_type = CA15_DVFS; + perf_cfg_reg = PERF_LVL_A15; + } else { + req_type = CA7_DVFS; + perf_cfg_reg = PERF_LVL_A7; + } + + perf = ve_spc_find_performance_index(cluster, freq); + + if (perf < 0) + return perf; + + if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) + return -ETIME; + + init_completion(&info->done); + info->cur_rsp_mask = RESPONSE_MASK(req_type); + + writel(perf, info->baseaddr + perf_cfg_reg); + ret = ve_spc_waitforcompletion(req_type); + + info->cur_rsp_mask = 0; + up(&info->sem); + + return ret; +} + +static int ve_spc_read_sys_cfg(int func, int offset, uint32_t *data) +{ + int ret; + + if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) + return -ETIME; + + init_completion(&info->done); + info->cur_rsp_mask = RESPONSE_MASK(SPC_SYS_CFG); + + /* Set the control value */ + writel(SYSCFG_START | func | offset >> 2, info->baseaddr + COMMS); + ret = ve_spc_waitforcompletion(SPC_SYS_CFG); + + if (ret == 0) + *data = readl(info->baseaddr + SYSCFG_RDATA); + + info->cur_rsp_mask = 0; + up(&info->sem); + + return ret; +} + +static irqreturn_t ve_spc_irq_handler(int irq, void *data) +{ + struct ve_spc_drvdata *drv_data = data; + uint32_t status = readl_relaxed(drv_data->baseaddr + PWC_STATUS); + + if (info->cur_rsp_mask & status) { + info->cur_rsp_stat = status; + complete(&drv_data->done); + } + + return IRQ_HANDLED; +} + +/* + * +--------------------------+ + * | 31 20 | 19 0 | + * +--------------------------+ + * | m_volt | freq(kHz) | + * +--------------------------+ + */ +#define MULT_FACTOR 20 +#define VOLT_SHIFT 20 +#define FREQ_MASK (0xFFFFF) +static int ve_spc_populate_opps(uint32_t cluster) +{ + uint32_t data = 0, off, ret, idx; + struct ve_spc_opp *opps; + + opps = kcalloc(MAX_OPPS, sizeof(*opps), GFP_KERNEL); + if (!opps) + return -ENOMEM; + + info->opps[cluster] = opps; + + off = cluster_is_a15(cluster) ? A15_PERFVAL_BASE : A7_PERFVAL_BASE; + for (idx = 0; idx < MAX_OPPS; idx++, off += 4, opps++) { + ret = ve_spc_read_sys_cfg(SYSCFG_SCC, off, &data); + if (!ret) { + opps->freq = (data & FREQ_MASK) * MULT_FACTOR; + opps->u_volt = (data >> VOLT_SHIFT) * 1000; + } else { + break; + } + } + info->num_opps[cluster] = idx; + + return ret; +} + +static int ve_init_opp_table(struct device *cpu_dev) +{ + int cluster; + int idx, ret = 0, max_opp; + struct ve_spc_opp *opps; + + cluster = topology_physical_package_id(cpu_dev->id); + cluster = cluster < 0 ? 0 : cluster; + + max_opp = info->num_opps[cluster]; + opps = info->opps[cluster]; + + for (idx = 0; idx < max_opp; idx++, opps++) { + ret = dev_pm_opp_add(cpu_dev, opps->freq * 1000, opps->u_volt); + if (ret) { + dev_warn(cpu_dev, "failed to add opp %lu %lu\n", + opps->freq, opps->u_volt); + return ret; + } + } + return ret; +} + +int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid, int irq) +{ + int ret; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->baseaddr = baseaddr; + info->a15_clusid = a15_clusid; + + if (irq <= 0) { + pr_err(SPCLOG "Invalid IRQ %d\n", irq); + kfree(info); + return -EINVAL; + } + + init_completion(&info->done); + + readl_relaxed(info->baseaddr + PWC_STATUS); + + ret = request_irq(irq, ve_spc_irq_handler, IRQF_TRIGGER_HIGH + | IRQF_ONESHOT, "vexpress-spc", info); + if (ret) { + pr_err(SPCLOG "IRQ %d request failed\n", irq); + kfree(info); + return -ENODEV; + } + + sema_init(&info->sem, 1); + /* + * Multi-cluster systems may need this data when non-coherent, during + * cluster power-up/power-down. Make sure driver info reaches main + * memory. + */ + sync_cache_w(info); + sync_cache_w(&info); + + return 0; +} + +struct clk_spc { + struct clk_hw hw; + int cluster; +}; + +#define to_clk_spc(spc) container_of(spc, struct clk_spc, hw) +static unsigned long spc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_spc *spc = to_clk_spc(hw); + u32 freq; + + if (ve_spc_get_performance(spc->cluster, &freq)) + return -EIO; + + return freq * 1000; +} + +static long spc_round_rate(struct clk_hw *hw, unsigned long drate, + unsigned long *parent_rate) +{ + struct clk_spc *spc = to_clk_spc(hw); + + return ve_spc_round_performance(spc->cluster, drate); +} + +static int spc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_spc *spc = to_clk_spc(hw); + + return ve_spc_set_performance(spc->cluster, rate / 1000); +} + +static struct clk_ops clk_spc_ops = { + .recalc_rate = spc_recalc_rate, + .round_rate = spc_round_rate, + .set_rate = spc_set_rate, +}; + +static struct clk *ve_spc_clk_register(struct device *cpu_dev) +{ + struct clk_init_data init; + struct clk_spc *spc; + + spc = kzalloc(sizeof(*spc), GFP_KERNEL); + if (!spc) + return ERR_PTR(-ENOMEM); + + spc->hw.init = &init; + spc->cluster = topology_physical_package_id(cpu_dev->id); + + spc->cluster = spc->cluster < 0 ? 0 : spc->cluster; + + init.name = dev_name(cpu_dev); + init.ops = &clk_spc_ops; + init.flags = CLK_GET_RATE_NOCACHE; + init.num_parents = 0; + + return devm_clk_register(cpu_dev, &spc->hw); +} + +static int __init ve_spc_clk_init(void) +{ + int cpu, cluster; + struct clk *clk; + bool init_opp_table[MAX_CLUSTERS] = { false }; + + if (!info) + return 0; /* Continue only if SPC is initialised */ + + if (ve_spc_populate_opps(0) || ve_spc_populate_opps(1)) { + pr_err("failed to build OPP table\n"); + return -ENODEV; + } + + for_each_possible_cpu(cpu) { + struct device *cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_warn("failed to get cpu%d device\n", cpu); + continue; + } + clk = ve_spc_clk_register(cpu_dev); + if (IS_ERR(clk)) { + pr_warn("failed to register cpu%d clock\n", cpu); + continue; + } + if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) { + pr_warn("failed to register cpu%d clock lookup\n", cpu); + continue; + } + + cluster = topology_physical_package_id(cpu_dev->id); + if (init_opp_table[cluster]) + continue; + + if (ve_init_opp_table(cpu_dev)) + pr_warn("failed to initialise cpu%d opp table\n", cpu); + else if (dev_pm_opp_set_sharing_cpus(cpu_dev, + topology_core_cpumask(cpu_dev->id))) + pr_warn("failed to mark OPPs shared for cpu%d\n", cpu); + else + init_opp_table[cluster] = true; + } + + platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0); + return 0; +} +device_initcall(ve_spc_clk_init); diff --git a/arch/arm/mach-versatile/spc.h b/arch/arm/mach-versatile/spc.h new file mode 100644 index 000000000000..288569fdfcb9 --- /dev/null +++ b/arch/arm/mach-versatile/spc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * + * Copyright (C) 2012 ARM Limited + */ + + +#ifndef __SPC_H_ +#define __SPC_H_ + +int __init ve_spc_init(void __iomem *base, u32 a15_clusid, int irq); +void ve_spc_global_wakeup_irq(bool set); +void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); +void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); +void ve_spc_powerdown(u32 cluster, bool enable); +int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster); + +#endif diff --git a/arch/arm/mach-versatile/tc2_pm.c b/arch/arm/mach-versatile/tc2_pm.c new file mode 100644 index 000000000000..0fe78da0c109 --- /dev/null +++ b/arch/arm/mach-versatile/tc2_pm.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Created by: Nicolas Pitre, October 2012 + * Copyright: (C) 2012-2013 Linaro Limited + * + * Some portions of this file were originally written by Achin Gupta + * Copyright: (C) 2012 ARM Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "spc.h" + +/* SCC conf registers */ +#define RESET_CTRL 0x018 +#define RESET_A15_NCORERESET(cpu) (1 << (2 + (cpu))) +#define RESET_A7_NCORERESET(cpu) (1 << (16 + (cpu))) + +#define A15_CONF 0x400 +#define A7_CONF 0x500 +#define SYS_INFO 0x700 +#define SPC_BASE 0xb00 + +static void __iomem *scc; + +#define TC2_CLUSTERS 2 +#define TC2_MAX_CPUS_PER_CLUSTER 3 + +static unsigned int tc2_nr_cpus[TC2_CLUSTERS]; + +static int tc2_pm_cpu_powerup(unsigned int cpu, unsigned int cluster) +{ + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) + return -EINVAL; + ve_spc_set_resume_addr(cluster, cpu, + __pa_symbol(mcpm_entry_point)); + ve_spc_cpu_wakeup_irq(cluster, cpu, true); + return 0; +} + +static int tc2_pm_cluster_powerup(unsigned int cluster) +{ + pr_debug("%s: cluster %u\n", __func__, cluster); + if (cluster >= TC2_CLUSTERS) + return -EINVAL; + ve_spc_powerdown(cluster, false); + return 0; +} + +static void tc2_pm_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) +{ + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); + ve_spc_cpu_wakeup_irq(cluster, cpu, true); + /* + * If the CPU is committed to power down, make sure + * the power controller will be in charge of waking it + * up upon IRQ, ie IRQ lines are cut from GIC CPU IF + * to the CPU by disabling the GIC CPU IF to prevent wfi + * from completing execution behind power controller back + */ + gic_cpu_if_down(0); +} + +static void tc2_pm_cluster_powerdown_prepare(unsigned int cluster) +{ + pr_debug("%s: cluster %u\n", __func__, cluster); + BUG_ON(cluster >= TC2_CLUSTERS); + ve_spc_powerdown(cluster, true); + ve_spc_global_wakeup_irq(true); +} + +static void tc2_pm_cpu_cache_disable(void) +{ + v7_exit_coherency_flush(louis); +} + +static void tc2_pm_cluster_cache_disable(void) +{ + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) { + /* + * On the Cortex-A15 we need to disable + * L2 prefetching before flushing the cache. + */ + asm volatile( + "mcr p15, 1, %0, c15, c0, 3 \n\t" + "isb \n\t" + "dsb " + : : "r" (0x400) ); + } + + v7_exit_coherency_flush(all); + cci_disable_port_by_cpu(read_cpuid_mpidr()); +} + +static int tc2_core_in_reset(unsigned int cpu, unsigned int cluster) +{ + u32 mask = cluster ? + RESET_A7_NCORERESET(cpu) + : RESET_A15_NCORERESET(cpu); + + return !(readl_relaxed(scc + RESET_CTRL) & mask); +} + +#define POLL_MSEC 10 +#define TIMEOUT_MSEC 1000 + +static int tc2_pm_wait_for_powerdown(unsigned int cpu, unsigned int cluster) +{ + unsigned tries; + + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); + + for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; ++tries) { + pr_debug("%s(cpu=%u, cluster=%u): RESET_CTRL = 0x%08X\n", + __func__, cpu, cluster, + readl_relaxed(scc + RESET_CTRL)); + + /* + * We need the CPU to reach WFI, but the power + * controller may put the cluster in reset and + * power it off as soon as that happens, before + * we have a chance to see STANDBYWFI. + * + * So we need to check for both conditions: + */ + if (tc2_core_in_reset(cpu, cluster) || + ve_spc_cpu_in_wfi(cpu, cluster)) + return 0; /* success: the CPU is halted */ + + /* Otherwise, wait and retry: */ + msleep(POLL_MSEC); + } + + return -ETIMEDOUT; /* timeout */ +} + +static void tc2_pm_cpu_suspend_prepare(unsigned int cpu, unsigned int cluster) +{ + ve_spc_set_resume_addr(cluster, cpu, __pa_symbol(mcpm_entry_point)); +} + +static void tc2_pm_cpu_is_up(unsigned int cpu, unsigned int cluster) +{ + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); + ve_spc_cpu_wakeup_irq(cluster, cpu, false); + ve_spc_set_resume_addr(cluster, cpu, 0); +} + +static void tc2_pm_cluster_is_up(unsigned int cluster) +{ + pr_debug("%s: cluster %u\n", __func__, cluster); + BUG_ON(cluster >= TC2_CLUSTERS); + ve_spc_powerdown(cluster, false); + ve_spc_global_wakeup_irq(false); +} + +static const struct mcpm_platform_ops tc2_pm_power_ops = { + .cpu_powerup = tc2_pm_cpu_powerup, + .cluster_powerup = tc2_pm_cluster_powerup, + .cpu_suspend_prepare = tc2_pm_cpu_suspend_prepare, + .cpu_powerdown_prepare = tc2_pm_cpu_powerdown_prepare, + .cluster_powerdown_prepare = tc2_pm_cluster_powerdown_prepare, + .cpu_cache_disable = tc2_pm_cpu_cache_disable, + .cluster_cache_disable = tc2_pm_cluster_cache_disable, + .wait_for_powerdown = tc2_pm_wait_for_powerdown, + .cpu_is_up = tc2_pm_cpu_is_up, + .cluster_is_up = tc2_pm_cluster_is_up, +}; + +/* + * Enable cluster-level coherency, in preparation for turning on the MMU. + */ +static void __naked tc2_pm_power_up_setup(unsigned int affinity_level) +{ + asm volatile (" \n" +" cmp r0, #1 \n" +" bxne lr \n" +" b cci_enable_port_for_self "); +} + +static int __init tc2_pm_init(void) +{ + unsigned int mpidr, cpu, cluster; + int ret, irq; + u32 a15_cluster_id, a7_cluster_id, sys_info; + struct device_node *np; + + /* + * The power management-related features are hidden behind + * SCC registers. We need to extract runtime information like + * cluster ids and number of CPUs really available in clusters. + */ + np = of_find_compatible_node(NULL, NULL, + "arm,vexpress-scc,v2p-ca15_a7"); + scc = of_iomap(np, 0); + if (!scc) + return -ENODEV; + + a15_cluster_id = readl_relaxed(scc + A15_CONF) & 0xf; + a7_cluster_id = readl_relaxed(scc + A7_CONF) & 0xf; + if (a15_cluster_id >= TC2_CLUSTERS || a7_cluster_id >= TC2_CLUSTERS) + return -EINVAL; + + sys_info = readl_relaxed(scc + SYS_INFO); + tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; + tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; + + irq = irq_of_parse_and_map(np, 0); + + /* + * A subset of the SCC registers is also used to communicate + * with the SPC (power controller). We need to be able to + * drive it very early in the boot process to power up + * processors, so we initialize the SPC driver here. + */ + ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id, irq); + if (ret) + return ret; + + if (!cci_probed()) + return -ENODEV; + + mpidr = read_cpuid_mpidr(); + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); + if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) { + pr_err("%s: boot CPU is out of bound!\n", __func__); + return -EINVAL; + } + + ret = mcpm_platform_register(&tc2_pm_power_ops); + if (!ret) { + mcpm_sync_init(tc2_pm_power_up_setup); + /* test if we can (re)enable the CCI on our own */ + BUG_ON(mcpm_loopback(tc2_pm_cluster_cache_disable) != 0); + pr_info("TC2 power management initialized\n"); + } + return ret; +} + +early_initcall(tc2_pm_init); diff --git a/arch/arm/mach-versatile/v2m-mps2.c b/arch/arm/mach-versatile/v2m-mps2.c new file mode 100644 index 000000000000..5b50d8e95cd7 --- /dev/null +++ b/arch/arm/mach-versatile/v2m-mps2.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2015 ARM Limited + * + * Author: Vladimir Murzin + */ + +#include + +static const char *const mps2_compat[] __initconst = { + "arm,mps2", + NULL +}; + +DT_MACHINE_START(MPS2DT, "MPS2 (Device Tree Support)") + .dt_compat = mps2_compat, +MACHINE_END diff --git a/arch/arm/mach-versatile/v2m.c b/arch/arm/mach-versatile/v2m.c new file mode 100644 index 000000000000..79afdf2a90b6 --- /dev/null +++ b/arch/arm/mach-versatile/v2m.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include "vexpress.h" + +#define SYS_FLAGSSET 0x030 +#define SYS_FLAGSCLR 0x034 + +void vexpress_flags_set(u32 data) +{ + static void __iomem *base; + + if (!base) { + struct device_node *node = of_find_compatible_node(NULL, NULL, + "arm,vexpress-sysreg"); + + base = of_iomap(node, 0); + } + + if (WARN_ON(!base)) + return; + + writel(~0, base + SYS_FLAGSCLR); + writel(data, base + SYS_FLAGSSET); +} + +static const char * const v2m_dt_match[] __initconst = { + "arm,vexpress", + NULL, +}; + +DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") + .dt_compat = v2m_dt_match, + .l2c_aux_val = 0x00400000, + .l2c_aux_mask = 0xfe0fffff, + .smp = smp_ops(vexpress_smp_dt_ops), + .smp_init = smp_init_ops(vexpress_smp_init_ops), +MACHINE_END diff --git a/arch/arm/mach-versatile/versatile.c b/arch/arm/mach-versatile/versatile.c new file mode 100644 index 000000000000..02ba68abe533 --- /dev/null +++ b/arch/arm/mach-versatile/versatile.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Versatile board support using the device tree + * + * Copyright (C) 2010 Secret Lab Technologies Ltd. + * Copyright (C) 2009 Jeremy Kerr + * Copyright (C) 2004 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* macro to get at MMIO space when running virtually */ +#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) +#define __io_address(n) ((void __iomem __force *)IO_ADDRESS(n)) + +/* + * ------------------------------------------------------------------------ + * Versatile Registers + * ------------------------------------------------------------------------ + */ +#define VERSATILE_SYS_PCICTL_OFFSET 0x44 +#define VERSATILE_SYS_MCI_OFFSET 0x48 + +/* + * VERSATILE peripheral addresses + */ +#define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */ +#define VERSATILE_MMCI1_BASE 0x1000B000 /* MMC Interface */ +#define VERSATILE_SCTL_BASE 0x101E0000 /* System controller */ + +/* + * System controller bit assignment + */ +#define VERSATILE_REFCLK 0 +#define VERSATILE_TIMCLK 1 + +#define VERSATILE_TIMER1_EnSel 15 +#define VERSATILE_TIMER2_EnSel 17 +#define VERSATILE_TIMER3_EnSel 19 +#define VERSATILE_TIMER4_EnSel 21 + +static void __iomem *versatile_sys_base; + +unsigned int mmc_status(struct device *dev) +{ + struct amba_device *adev = container_of(dev, struct amba_device, dev); + u32 mask; + + if (adev->res.start == VERSATILE_MMCI0_BASE) + mask = 1; + else + mask = 2; + + return readl(versatile_sys_base + VERSATILE_SYS_MCI_OFFSET) & mask; +} + +static struct mmci_platform_data mmc0_plat_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +static struct mmci_platform_data mmc1_plat_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .status = mmc_status, +}; + +/* + * Lookup table for attaching a specific name and platform_data pointer to + * devices as they get created by of_platform_populate(). Ideally this table + * would not exist, but the current clock implementation depends on some devices + * having a specific name. + */ +struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data), + OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", &mmc1_plat_data), + {} +}; + +static struct map_desc versatile_io_desc[] __initdata __maybe_unused = { + { + .virtual = IO_ADDRESS(VERSATILE_SCTL_BASE), + .pfn = __phys_to_pfn(VERSATILE_SCTL_BASE), + .length = SZ_4K * 9, + .type = MT_DEVICE + } +}; + +static void __init versatile_map_io(void) +{ + debug_ll_io_init(); + iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); +} + +static void __init versatile_init_early(void) +{ + u32 val; + + /* + * set clock frequency: + * VERSATILE_REFCLK is 32KHz + * VERSATILE_TIMCLK is 1MHz + */ + val = readl(__io_address(VERSATILE_SCTL_BASE)); + writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | + (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | + (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | + (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val, + __io_address(VERSATILE_SCTL_BASE)); +} + +static void __init versatile_dt_pci_init(void) +{ + u32 val; + struct device_node *np; + struct property *newprop; + + np = of_find_compatible_node(NULL, NULL, "arm,versatile-pci"); + if (!np) + return; + + /* Check if PCI backplane is detected */ + val = readl(versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET); + if (val & 1) { + /* + * Enable PCI accesses. Note that the documentaton is + * inconsistent whether or not this is needed, but the old + * driver had it so we will keep it. + */ + writel(1, versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET); + goto out_put_node; + } + + newprop = kzalloc(sizeof(*newprop), GFP_KERNEL); + if (!newprop) + goto out_put_node; + + newprop->name = kstrdup("status", GFP_KERNEL); + newprop->value = kstrdup("disabled", GFP_KERNEL); + newprop->length = sizeof("disabled"); + of_update_property(np, newprop); + + pr_info("Not plugged into PCI backplane!\n"); + +out_put_node: + of_node_put(np); +} + +static void __init versatile_dt_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "arm,core-module-versatile"); + if (np) + versatile_sys_base = of_iomap(np, 0); + WARN_ON(!versatile_sys_base); + + versatile_dt_pci_init(); + + of_platform_default_populate(NULL, versatile_auxdata_lookup, NULL); +} + +static const char *const versatile_dt_match[] __initconst = { + "arm,versatile-ab", + "arm,versatile-pb", + NULL, +}; + +DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)") + .map_io = versatile_map_io, + .init_early = versatile_init_early, + .init_machine = versatile_dt_init, + .dt_compat = versatile_dt_match, +MACHINE_END diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c deleted file mode 100644 index 02ba68abe533..000000000000 --- a/arch/arm/mach-versatile/versatile_dt.c +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Versatile board support using the device tree - * - * Copyright (C) 2010 Secret Lab Technologies Ltd. - * Copyright (C) 2009 Jeremy Kerr - * Copyright (C) 2004 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* macro to get at MMIO space when running virtually */ -#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) -#define __io_address(n) ((void __iomem __force *)IO_ADDRESS(n)) - -/* - * ------------------------------------------------------------------------ - * Versatile Registers - * ------------------------------------------------------------------------ - */ -#define VERSATILE_SYS_PCICTL_OFFSET 0x44 -#define VERSATILE_SYS_MCI_OFFSET 0x48 - -/* - * VERSATILE peripheral addresses - */ -#define VERSATILE_MMCI0_BASE 0x10005000 /* MMC interface */ -#define VERSATILE_MMCI1_BASE 0x1000B000 /* MMC Interface */ -#define VERSATILE_SCTL_BASE 0x101E0000 /* System controller */ - -/* - * System controller bit assignment - */ -#define VERSATILE_REFCLK 0 -#define VERSATILE_TIMCLK 1 - -#define VERSATILE_TIMER1_EnSel 15 -#define VERSATILE_TIMER2_EnSel 17 -#define VERSATILE_TIMER3_EnSel 19 -#define VERSATILE_TIMER4_EnSel 21 - -static void __iomem *versatile_sys_base; - -unsigned int mmc_status(struct device *dev) -{ - struct amba_device *adev = container_of(dev, struct amba_device, dev); - u32 mask; - - if (adev->res.start == VERSATILE_MMCI0_BASE) - mask = 1; - else - mask = 2; - - return readl(versatile_sys_base + VERSATILE_SYS_MCI_OFFSET) & mask; -} - -static struct mmci_platform_data mmc0_plat_data = { - .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = mmc_status, -}; - -static struct mmci_platform_data mmc1_plat_data = { - .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = mmc_status, -}; - -/* - * Lookup table for attaching a specific name and platform_data pointer to - * devices as they get created by of_platform_populate(). Ideally this table - * would not exist, but the current clock implementation depends on some devices - * having a specific name. - */ -struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data), - OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", &mmc1_plat_data), - {} -}; - -static struct map_desc versatile_io_desc[] __initdata __maybe_unused = { - { - .virtual = IO_ADDRESS(VERSATILE_SCTL_BASE), - .pfn = __phys_to_pfn(VERSATILE_SCTL_BASE), - .length = SZ_4K * 9, - .type = MT_DEVICE - } -}; - -static void __init versatile_map_io(void) -{ - debug_ll_io_init(); - iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc)); -} - -static void __init versatile_init_early(void) -{ - u32 val; - - /* - * set clock frequency: - * VERSATILE_REFCLK is 32KHz - * VERSATILE_TIMCLK is 1MHz - */ - val = readl(__io_address(VERSATILE_SCTL_BASE)); - writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | - (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | - (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | - (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val, - __io_address(VERSATILE_SCTL_BASE)); -} - -static void __init versatile_dt_pci_init(void) -{ - u32 val; - struct device_node *np; - struct property *newprop; - - np = of_find_compatible_node(NULL, NULL, "arm,versatile-pci"); - if (!np) - return; - - /* Check if PCI backplane is detected */ - val = readl(versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET); - if (val & 1) { - /* - * Enable PCI accesses. Note that the documentaton is - * inconsistent whether or not this is needed, but the old - * driver had it so we will keep it. - */ - writel(1, versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET); - goto out_put_node; - } - - newprop = kzalloc(sizeof(*newprop), GFP_KERNEL); - if (!newprop) - goto out_put_node; - - newprop->name = kstrdup("status", GFP_KERNEL); - newprop->value = kstrdup("disabled", GFP_KERNEL); - newprop->length = sizeof("disabled"); - of_update_property(np, newprop); - - pr_info("Not plugged into PCI backplane!\n"); - -out_put_node: - of_node_put(np); -} - -static void __init versatile_dt_init(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "arm,core-module-versatile"); - if (np) - versatile_sys_base = of_iomap(np, 0); - WARN_ON(!versatile_sys_base); - - versatile_dt_pci_init(); - - of_platform_default_populate(NULL, versatile_auxdata_lookup, NULL); -} - -static const char *const versatile_dt_match[] __initconst = { - "arm,versatile-ab", - "arm,versatile-pb", - NULL, -}; - -DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)") - .map_io = versatile_map_io, - .init_early = versatile_init_early, - .init_machine = versatile_dt_init, - .dt_compat = versatile_dt_match, -MACHINE_END diff --git a/arch/arm/mach-versatile/vexpress.h b/arch/arm/mach-versatile/vexpress.h new file mode 100644 index 000000000000..bda78675c55d --- /dev/null +++ b/arch/arm/mach-versatile/vexpress.h @@ -0,0 +1,4 @@ +bool vexpress_smp_init_ops(void); +void vexpress_flags_set(u32 data); + +extern const struct smp_operations vexpress_smp_dt_ops; diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig deleted file mode 100644 index 2e6aff5a0f17..000000000000 --- a/arch/arm/mach-vexpress/Kconfig +++ /dev/null @@ -1,81 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -menuconfig ARCH_VEXPRESS - bool "ARM Ltd. Versatile Express family" - depends on ARCH_MULTI_V7 - select ARCH_SUPPORTS_BIG_ENDIAN - select ARM_AMBA - select ARM_GIC - select ARM_GLOBAL_TIMER - select ARM_TIMER_SP804 - select GPIOLIB - select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if SMP - select HAVE_PATA_PLATFORM - select CLK_ICST - select NO_IOPORT_MAP - select PLAT_VERSATILE - select POWER_RESET - select POWER_RESET_VEXPRESS - select POWER_SUPPLY - select REGULATOR if MMC_ARMMMCI - select REGULATOR_FIXED_VOLTAGE if REGULATOR - select VEXPRESS_CONFIG - help - This option enables support for systems using Cortex processor based - ARM core and logic (FPGA) tiles on the Versatile Express motherboard, - for example: - - - CoreTile Express A5x2 (V2P-CA5s) - - CoreTile Express A9x4 (V2P-CA9) - - CoreTile Express A15x2 (V2P-CA15) - - LogicTile Express 13MG (V2F-2XV6) with A5, A7, A9 or A15 SMMs - (Soft Macrocell Models) - - Versatile Express RTSMs (Models) - - You must boot using a Flattened Device Tree in order to use these - platforms. The traditional (ATAGs) boot method is not usable on - these boards with this option. - -if ARCH_VEXPRESS - -config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA - bool "Enable A5 and A9 only errata work-arounds" - default y - select ARM_ERRATA_643719 if SMP - select ARM_ERRATA_720789 - select PL310_ERRATA_753970 if CACHE_L2X0 - help - Provides common dependencies for Versatile Express platforms - based on Cortex-A5 and Cortex-A9 processors. In order to - build a working kernel, you must also enable relevant core - tile support or Flattened Device Tree based support options. - -config ARCH_VEXPRESS_DCSCB - bool "Dual Cluster System Control Block (DCSCB) support" - depends on MCPM - select ARM_CCI400_PORT_CTRL - help - Support for the Dual Cluster System Configuration Block (DCSCB). - This is needed to provide CPU and cluster power management - on RTSM implementing big.LITTLE. - -config ARCH_VEXPRESS_SPC - bool "Versatile Express Serial Power Controller (SPC)" - select PM_OPP - help - The TC2 (A15x2 A7x3) versatile express core tile integrates a logic - block called Serial Power Controller (SPC) that provides the interface - between the dual cluster test-chip and the M3 microcontroller that - carries out power management. - -config ARCH_VEXPRESS_TC2_PM - bool "Versatile Express TC2 power management" - depends on MCPM - select ARM_CCI400_PORT_CTRL - select ARCH_VEXPRESS_SPC - select ARM_CPU_SUSPEND - help - Support for CPU and cluster power management on Versatile Express - with a TC2 (A15x2 A7x3) big.LITTLE core tile. - -endif diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile deleted file mode 100644 index 3651a1ed0f2b..000000000000 --- a/arch/arm/mach-vexpress/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the linux kernel. -# -ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := \ - -I$(srctree)/arch/arm/plat-versatile/include - -obj-$(CONFIG_ARCH_VEXPRESS) := v2m.o -obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o -CFLAGS_dcscb.o += -march=armv7-a -CFLAGS_REMOVE_dcscb.o = -pg -obj-$(CONFIG_ARCH_VEXPRESS_SPC) += spc.o -CFLAGS_REMOVE_spc.o = -pg -obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o -CFLAGS_tc2_pm.o += -march=armv7-a -CFLAGS_REMOVE_tc2_pm.o = -pg -obj-$(CONFIG_SMP) += platsmp.o - -obj-$(CONFIG_ARCH_MPS2) += v2m-mps2.o diff --git a/arch/arm/mach-vexpress/Makefile.boot b/arch/arm/mach-vexpress/Makefile.boot deleted file mode 100644 index cec195d4fcba..000000000000 --- a/arch/arm/mach-vexpress/Makefile.boot +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Empty file waiting for deletion once Makefile.boot isn't needed any more. -# Patch waits for application at -# http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7889/1 . diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h deleted file mode 100644 index bda78675c55d..000000000000 --- a/arch/arm/mach-vexpress/core.h +++ /dev/null @@ -1,4 +0,0 @@ -bool vexpress_smp_init_ops(void); -void vexpress_flags_set(u32 data); - -extern const struct smp_operations vexpress_smp_dt_ops; diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c deleted file mode 100644 index a0554d7d04f7..000000000000 --- a/arch/arm/mach-vexpress/dcscb.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-vexpress/dcscb.c - Dual Cluster System Configuration Block - * - * Created by: Nicolas Pitre, May 2012 - * Copyright: (C) 2012-2013 Linaro Limited - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "core.h" - -#define RST_HOLD0 0x0 -#define RST_HOLD1 0x4 -#define SYS_SWRESET 0x8 -#define RST_STAT0 0xc -#define RST_STAT1 0x10 -#define EAG_CFG_R 0x20 -#define EAG_CFG_W 0x24 -#define KFC_CFG_R 0x28 -#define KFC_CFG_W 0x2c -#define DCS_CFG_R 0x30 - -static void __iomem *dcscb_base; -static int dcscb_allcpus_mask[2]; - -static int dcscb_cpu_powerup(unsigned int cpu, unsigned int cluster) -{ - unsigned int rst_hold, cpumask = (1 << cpu); - - pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - if (cluster >= 2 || !(cpumask & dcscb_allcpus_mask[cluster])) - return -EINVAL; - - rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); - rst_hold &= ~(cpumask | (cpumask << 4)); - writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); - return 0; -} - -static int dcscb_cluster_powerup(unsigned int cluster) -{ - unsigned int rst_hold; - - pr_debug("%s: cluster %u\n", __func__, cluster); - if (cluster >= 2) - return -EINVAL; - - /* remove cluster reset and add individual CPU's reset */ - rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); - rst_hold &= ~(1 << 8); - rst_hold |= dcscb_allcpus_mask[cluster]; - writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); - return 0; -} - -static void dcscb_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) -{ - unsigned int rst_hold; - - pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - BUG_ON(cluster >= 2 || !((1 << cpu) & dcscb_allcpus_mask[cluster])); - - rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); - rst_hold |= (1 << cpu); - writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); -} - -static void dcscb_cluster_powerdown_prepare(unsigned int cluster) -{ - unsigned int rst_hold; - - pr_debug("%s: cluster %u\n", __func__, cluster); - BUG_ON(cluster >= 2); - - rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); - rst_hold |= (1 << 8); - writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); -} - -static void dcscb_cpu_cache_disable(void) -{ - /* Disable and flush the local CPU cache. */ - v7_exit_coherency_flush(louis); -} - -static void dcscb_cluster_cache_disable(void) -{ - /* Flush all cache levels for this cluster. */ - v7_exit_coherency_flush(all); - - /* - * A full outer cache flush could be needed at this point - * on platforms with such a cache, depending on where the - * outer cache sits. In some cases the notion of a "last - * cluster standing" would need to be implemented if the - * outer cache is shared across clusters. In any case, when - * the outer cache needs flushing, there is no concurrent - * access to the cache controller to worry about and no - * special locking besides what is already provided by the - * MCPM state machinery is needed. - */ - - /* - * Disable cluster-level coherency by masking - * incoming snoops and DVM messages: - */ - cci_disable_port_by_cpu(read_cpuid_mpidr()); -} - -static const struct mcpm_platform_ops dcscb_power_ops = { - .cpu_powerup = dcscb_cpu_powerup, - .cluster_powerup = dcscb_cluster_powerup, - .cpu_powerdown_prepare = dcscb_cpu_powerdown_prepare, - .cluster_powerdown_prepare = dcscb_cluster_powerdown_prepare, - .cpu_cache_disable = dcscb_cpu_cache_disable, - .cluster_cache_disable = dcscb_cluster_cache_disable, -}; - -extern void dcscb_power_up_setup(unsigned int affinity_level); - -static int __init dcscb_init(void) -{ - struct device_node *node; - unsigned int cfg; - int ret; - - if (!cci_probed()) - return -ENODEV; - - node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb"); - if (!node) - return -ENODEV; - dcscb_base = of_iomap(node, 0); - if (!dcscb_base) - return -EADDRNOTAVAIL; - cfg = readl_relaxed(dcscb_base + DCS_CFG_R); - dcscb_allcpus_mask[0] = (1 << (((cfg >> 16) >> (0 << 2)) & 0xf)) - 1; - dcscb_allcpus_mask[1] = (1 << (((cfg >> 16) >> (1 << 2)) & 0xf)) - 1; - - ret = mcpm_platform_register(&dcscb_power_ops); - if (!ret) - ret = mcpm_sync_init(dcscb_power_up_setup); - if (ret) { - iounmap(dcscb_base); - return ret; - } - - pr_info("VExpress DCSCB support installed\n"); - - /* - * Future entries into the kernel can now go - * through the cluster entry vectors. - */ - vexpress_flags_set(__pa_symbol(mcpm_entry_point)); - - return 0; -} - -early_initcall(dcscb_init); diff --git a/arch/arm/mach-vexpress/dcscb_setup.S b/arch/arm/mach-vexpress/dcscb_setup.S deleted file mode 100644 index 0614b2ebd354..000000000000 --- a/arch/arm/mach-vexpress/dcscb_setup.S +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/include/asm/dcscb_setup.S - * - * Created by: Dave Martin, 2012-06-22 - * Copyright: (C) 2012-2013 Linaro Limited - */ - -#include - - -ENTRY(dcscb_power_up_setup) - - cmp r0, #0 @ check affinity level - beq 2f - -/* - * Enable cluster-level coherency, in preparation for turning on the MMU. - * The ACTLR SMP bit does not need to be set here, because cpu_resume() - * already restores that. - * - * A15/A7 may not require explicit L2 invalidation on reset, dependent - * on hardware integration decisions. - * For now, this code assumes that L2 is either already invalidated, - * or invalidation is not required. - */ - - b cci_enable_port_for_self - -2: @ Implementation-specific local CPU setup operations should go here, - @ if any. In this case, there is nothing to do. - - bx lr - -ENDPROC(dcscb_power_up_setup) diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c deleted file mode 100644 index 99c93124aa68..000000000000 --- a/arch/arm/mach-vexpress/platsmp.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-vexpress/platsmp.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "core.h" - -bool __init vexpress_smp_init_ops(void) -{ -#ifdef CONFIG_MCPM - int cpu; - struct device_node *cpu_node, *cci_node; - - /* - * The best way to detect a multi-cluster configuration - * is to detect if the kernel can take over CCI ports - * control. Loop over possible CPUs and check if CCI - * port control is available. - * Override the default vexpress_smp_ops if so. - */ - for_each_possible_cpu(cpu) { - bool available; - - cpu_node = of_get_cpu_node(cpu, NULL); - if (WARN(!cpu_node, "Missing cpu device node!")) - return false; - - cci_node = of_parse_phandle(cpu_node, "cci-control-port", 0); - available = cci_node && of_device_is_available(cci_node); - of_node_put(cci_node); - of_node_put(cpu_node); - - if (!available) - return false; - } - - mcpm_smp_set_ops(); - return true; -#else - return false; -#endif -} - -static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = { - { .compatible = "arm,cortex-a5-scu", }, - { .compatible = "arm,cortex-a9-scu", }, - {} -}; - -static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus) -{ - struct device_node *scu = of_find_matching_node(NULL, - vexpress_smp_dt_scu_match); - - if (scu) - scu_enable(of_iomap(scu, 0)); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The boot monitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ - vexpress_flags_set(__pa_symbol(versatile_secondary_startup)); -} - -#ifdef CONFIG_HOTPLUG_CPU -static void vexpress_cpu_die(unsigned int cpu) -{ - versatile_immitation_cpu_die(cpu, 0x40); -} -#endif - -const struct smp_operations vexpress_smp_dt_ops __initconst = { - .smp_prepare_cpus = vexpress_smp_dt_prepare_cpus, - .smp_secondary_init = versatile_secondary_init, - .smp_boot_secondary = versatile_boot_secondary, -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = vexpress_cpu_die, -#endif -}; diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c deleted file mode 100644 index 1da11bdb1dfb..000000000000 --- a/arch/arm/mach-vexpress/spc.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Versatile Express Serial Power Controller (SPC) support - * - * Copyright (C) 2013 ARM Ltd. - * - * Authors: Sudeep KarkadaNagesha - * Achin Gupta - * Lorenzo Pieralisi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "spc.h" - -#define SPCLOG "vexpress-spc: " - -#define PERF_LVL_A15 0x00 -#define PERF_REQ_A15 0x04 -#define PERF_LVL_A7 0x08 -#define PERF_REQ_A7 0x0c -#define COMMS 0x10 -#define COMMS_REQ 0x14 -#define PWC_STATUS 0x18 -#define PWC_FLAG 0x1c - -/* SPC wake-up IRQs status and mask */ -#define WAKE_INT_MASK 0x24 -#define WAKE_INT_RAW 0x28 -#define WAKE_INT_STAT 0x2c -/* SPC power down registers */ -#define A15_PWRDN_EN 0x30 -#define A7_PWRDN_EN 0x34 -/* SPC per-CPU mailboxes */ -#define A15_BX_ADDR0 0x68 -#define A7_BX_ADDR0 0x78 - -/* SPC CPU/cluster reset statue */ -#define STANDBYWFI_STAT 0x3c -#define STANDBYWFI_STAT_A15_CPU_MASK(cpu) (1 << (cpu)) -#define STANDBYWFI_STAT_A7_CPU_MASK(cpu) (1 << (3 + (cpu))) - -/* SPC system config interface registers */ -#define SYSCFG_WDATA 0x70 -#define SYSCFG_RDATA 0x74 - -/* A15/A7 OPP virtual register base */ -#define A15_PERFVAL_BASE 0xC10 -#define A7_PERFVAL_BASE 0xC30 - -/* Config interface control bits */ -#define SYSCFG_START BIT(31) -#define SYSCFG_SCC (6 << 20) -#define SYSCFG_STAT (14 << 20) - -/* wake-up interrupt masks */ -#define GBL_WAKEUP_INT_MSK (0x3 << 10) - -/* TC2 static dual-cluster configuration */ -#define MAX_CLUSTERS 2 - -/* - * Even though the SPC takes max 3-5 ms to complete any OPP/COMMS - * operation, the operation could start just before jiffie is about - * to be incremented. So setting timeout value of 20ms = 2jiffies@100Hz - */ -#define TIMEOUT_US 20000 - -#define MAX_OPPS 8 -#define CA15_DVFS 0 -#define CA7_DVFS 1 -#define SPC_SYS_CFG 2 -#define STAT_COMPLETE(type) ((1 << 0) << (type << 2)) -#define STAT_ERR(type) ((1 << 1) << (type << 2)) -#define RESPONSE_MASK(type) (STAT_COMPLETE(type) | STAT_ERR(type)) - -struct ve_spc_opp { - unsigned long freq; - unsigned long u_volt; -}; - -struct ve_spc_drvdata { - void __iomem *baseaddr; - /* - * A15s cluster identifier - * It corresponds to A15 processors MPIDR[15:8] bitfield - */ - u32 a15_clusid; - uint32_t cur_rsp_mask; - uint32_t cur_rsp_stat; - struct semaphore sem; - struct completion done; - struct ve_spc_opp *opps[MAX_CLUSTERS]; - int num_opps[MAX_CLUSTERS]; -}; - -static struct ve_spc_drvdata *info; - -static inline bool cluster_is_a15(u32 cluster) -{ - return cluster == info->a15_clusid; -} - -/** - * ve_spc_global_wakeup_irq() - * - * Function to set/clear global wakeup IRQs. Not protected by locking since - * it might be used in code paths where normal cacheable locks are not - * working. Locking must be provided by the caller to ensure atomicity. - * - * @set: if true, global wake-up IRQs are set, if false they are cleared - */ -void ve_spc_global_wakeup_irq(bool set) -{ - u32 reg; - - reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK); - - if (set) - reg |= GBL_WAKEUP_INT_MSK; - else - reg &= ~GBL_WAKEUP_INT_MSK; - - writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK); -} - -/** - * ve_spc_cpu_wakeup_irq() - * - * Function to set/clear per-CPU wake-up IRQs. Not protected by locking since - * it might be used in code paths where normal cacheable locks are not - * working. Locking must be provided by the caller to ensure atomicity. - * - * @cluster: mpidr[15:8] bitfield describing cluster affinity level - * @cpu: mpidr[7:0] bitfield describing cpu affinity level - * @set: if true, wake-up IRQs are set, if false they are cleared - */ -void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set) -{ - u32 mask, reg; - - if (cluster >= MAX_CLUSTERS) - return; - - mask = BIT(cpu); - - if (!cluster_is_a15(cluster)) - mask <<= 4; - - reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK); - - if (set) - reg |= mask; - else - reg &= ~mask; - - writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK); -} - -/** - * ve_spc_set_resume_addr() - set the jump address used for warm boot - * - * @cluster: mpidr[15:8] bitfield describing cluster affinity level - * @cpu: mpidr[7:0] bitfield describing cpu affinity level - * @addr: physical resume address - */ -void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr) -{ - void __iomem *baseaddr; - - if (cluster >= MAX_CLUSTERS) - return; - - if (cluster_is_a15(cluster)) - baseaddr = info->baseaddr + A15_BX_ADDR0 + (cpu << 2); - else - baseaddr = info->baseaddr + A7_BX_ADDR0 + (cpu << 2); - - writel_relaxed(addr, baseaddr); -} - -/** - * ve_spc_powerdown() - * - * Function to enable/disable cluster powerdown. Not protected by locking - * since it might be used in code paths where normal cacheable locks are not - * working. Locking must be provided by the caller to ensure atomicity. - * - * @cluster: mpidr[15:8] bitfield describing cluster affinity level - * @enable: if true enables powerdown, if false disables it - */ -void ve_spc_powerdown(u32 cluster, bool enable) -{ - u32 pwdrn_reg; - - if (cluster >= MAX_CLUSTERS) - return; - - pwdrn_reg = cluster_is_a15(cluster) ? A15_PWRDN_EN : A7_PWRDN_EN; - writel_relaxed(enable, info->baseaddr + pwdrn_reg); -} - -static u32 standbywfi_cpu_mask(u32 cpu, u32 cluster) -{ - return cluster_is_a15(cluster) ? - STANDBYWFI_STAT_A15_CPU_MASK(cpu) - : STANDBYWFI_STAT_A7_CPU_MASK(cpu); -} - -/** - * ve_spc_cpu_in_wfi(u32 cpu, u32 cluster) - * - * @cpu: mpidr[7:0] bitfield describing CPU affinity level within cluster - * @cluster: mpidr[15:8] bitfield describing cluster affinity level - * - * @return: non-zero if and only if the specified CPU is in WFI - * - * Take care when interpreting the result of this function: a CPU might - * be in WFI temporarily due to idle, and is not necessarily safely - * parked. - */ -int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster) -{ - int ret; - u32 mask = standbywfi_cpu_mask(cpu, cluster); - - if (cluster >= MAX_CLUSTERS) - return 1; - - ret = readl_relaxed(info->baseaddr + STANDBYWFI_STAT); - - pr_debug("%s: PCFGREG[0x%X] = 0x%08X, mask = 0x%X\n", - __func__, STANDBYWFI_STAT, ret, mask); - - return ret & mask; -} - -static int ve_spc_get_performance(int cluster, u32 *freq) -{ - struct ve_spc_opp *opps = info->opps[cluster]; - u32 perf_cfg_reg = 0; - u32 perf; - - perf_cfg_reg = cluster_is_a15(cluster) ? PERF_LVL_A15 : PERF_LVL_A7; - - perf = readl_relaxed(info->baseaddr + perf_cfg_reg); - if (perf >= info->num_opps[cluster]) - return -EINVAL; - - opps += perf; - *freq = opps->freq; - - return 0; -} - -/* find closest match to given frequency in OPP table */ -static int ve_spc_round_performance(int cluster, u32 freq) -{ - int idx, max_opp = info->num_opps[cluster]; - struct ve_spc_opp *opps = info->opps[cluster]; - u32 fmin = 0, fmax = ~0, ftmp; - - freq /= 1000; /* OPP entries in kHz */ - for (idx = 0; idx < max_opp; idx++, opps++) { - ftmp = opps->freq; - if (ftmp >= freq) { - if (ftmp <= fmax) - fmax = ftmp; - } else { - if (ftmp >= fmin) - fmin = ftmp; - } - } - if (fmax != ~0) - return fmax * 1000; - else - return fmin * 1000; -} - -static int ve_spc_find_performance_index(int cluster, u32 freq) -{ - int idx, max_opp = info->num_opps[cluster]; - struct ve_spc_opp *opps = info->opps[cluster]; - - for (idx = 0; idx < max_opp; idx++, opps++) - if (opps->freq == freq) - break; - return (idx == max_opp) ? -EINVAL : idx; -} - -static int ve_spc_waitforcompletion(int req_type) -{ - int ret = wait_for_completion_interruptible_timeout( - &info->done, usecs_to_jiffies(TIMEOUT_US)); - if (ret == 0) - ret = -ETIMEDOUT; - else if (ret > 0) - ret = info->cur_rsp_stat & STAT_COMPLETE(req_type) ? 0 : -EIO; - return ret; -} - -static int ve_spc_set_performance(int cluster, u32 freq) -{ - u32 perf_cfg_reg; - int ret, perf, req_type; - - if (cluster_is_a15(cluster)) { - req_type = CA15_DVFS; - perf_cfg_reg = PERF_LVL_A15; - } else { - req_type = CA7_DVFS; - perf_cfg_reg = PERF_LVL_A7; - } - - perf = ve_spc_find_performance_index(cluster, freq); - - if (perf < 0) - return perf; - - if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) - return -ETIME; - - init_completion(&info->done); - info->cur_rsp_mask = RESPONSE_MASK(req_type); - - writel(perf, info->baseaddr + perf_cfg_reg); - ret = ve_spc_waitforcompletion(req_type); - - info->cur_rsp_mask = 0; - up(&info->sem); - - return ret; -} - -static int ve_spc_read_sys_cfg(int func, int offset, uint32_t *data) -{ - int ret; - - if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) - return -ETIME; - - init_completion(&info->done); - info->cur_rsp_mask = RESPONSE_MASK(SPC_SYS_CFG); - - /* Set the control value */ - writel(SYSCFG_START | func | offset >> 2, info->baseaddr + COMMS); - ret = ve_spc_waitforcompletion(SPC_SYS_CFG); - - if (ret == 0) - *data = readl(info->baseaddr + SYSCFG_RDATA); - - info->cur_rsp_mask = 0; - up(&info->sem); - - return ret; -} - -static irqreturn_t ve_spc_irq_handler(int irq, void *data) -{ - struct ve_spc_drvdata *drv_data = data; - uint32_t status = readl_relaxed(drv_data->baseaddr + PWC_STATUS); - - if (info->cur_rsp_mask & status) { - info->cur_rsp_stat = status; - complete(&drv_data->done); - } - - return IRQ_HANDLED; -} - -/* - * +--------------------------+ - * | 31 20 | 19 0 | - * +--------------------------+ - * | m_volt | freq(kHz) | - * +--------------------------+ - */ -#define MULT_FACTOR 20 -#define VOLT_SHIFT 20 -#define FREQ_MASK (0xFFFFF) -static int ve_spc_populate_opps(uint32_t cluster) -{ - uint32_t data = 0, off, ret, idx; - struct ve_spc_opp *opps; - - opps = kcalloc(MAX_OPPS, sizeof(*opps), GFP_KERNEL); - if (!opps) - return -ENOMEM; - - info->opps[cluster] = opps; - - off = cluster_is_a15(cluster) ? A15_PERFVAL_BASE : A7_PERFVAL_BASE; - for (idx = 0; idx < MAX_OPPS; idx++, off += 4, opps++) { - ret = ve_spc_read_sys_cfg(SYSCFG_SCC, off, &data); - if (!ret) { - opps->freq = (data & FREQ_MASK) * MULT_FACTOR; - opps->u_volt = (data >> VOLT_SHIFT) * 1000; - } else { - break; - } - } - info->num_opps[cluster] = idx; - - return ret; -} - -static int ve_init_opp_table(struct device *cpu_dev) -{ - int cluster; - int idx, ret = 0, max_opp; - struct ve_spc_opp *opps; - - cluster = topology_physical_package_id(cpu_dev->id); - cluster = cluster < 0 ? 0 : cluster; - - max_opp = info->num_opps[cluster]; - opps = info->opps[cluster]; - - for (idx = 0; idx < max_opp; idx++, opps++) { - ret = dev_pm_opp_add(cpu_dev, opps->freq * 1000, opps->u_volt); - if (ret) { - dev_warn(cpu_dev, "failed to add opp %lu %lu\n", - opps->freq, opps->u_volt); - return ret; - } - } - return ret; -} - -int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid, int irq) -{ - int ret; - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->baseaddr = baseaddr; - info->a15_clusid = a15_clusid; - - if (irq <= 0) { - pr_err(SPCLOG "Invalid IRQ %d\n", irq); - kfree(info); - return -EINVAL; - } - - init_completion(&info->done); - - readl_relaxed(info->baseaddr + PWC_STATUS); - - ret = request_irq(irq, ve_spc_irq_handler, IRQF_TRIGGER_HIGH - | IRQF_ONESHOT, "vexpress-spc", info); - if (ret) { - pr_err(SPCLOG "IRQ %d request failed\n", irq); - kfree(info); - return -ENODEV; - } - - sema_init(&info->sem, 1); - /* - * Multi-cluster systems may need this data when non-coherent, during - * cluster power-up/power-down. Make sure driver info reaches main - * memory. - */ - sync_cache_w(info); - sync_cache_w(&info); - - return 0; -} - -struct clk_spc { - struct clk_hw hw; - int cluster; -}; - -#define to_clk_spc(spc) container_of(spc, struct clk_spc, hw) -static unsigned long spc_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_spc *spc = to_clk_spc(hw); - u32 freq; - - if (ve_spc_get_performance(spc->cluster, &freq)) - return -EIO; - - return freq * 1000; -} - -static long spc_round_rate(struct clk_hw *hw, unsigned long drate, - unsigned long *parent_rate) -{ - struct clk_spc *spc = to_clk_spc(hw); - - return ve_spc_round_performance(spc->cluster, drate); -} - -static int spc_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_spc *spc = to_clk_spc(hw); - - return ve_spc_set_performance(spc->cluster, rate / 1000); -} - -static struct clk_ops clk_spc_ops = { - .recalc_rate = spc_recalc_rate, - .round_rate = spc_round_rate, - .set_rate = spc_set_rate, -}; - -static struct clk *ve_spc_clk_register(struct device *cpu_dev) -{ - struct clk_init_data init; - struct clk_spc *spc; - - spc = kzalloc(sizeof(*spc), GFP_KERNEL); - if (!spc) - return ERR_PTR(-ENOMEM); - - spc->hw.init = &init; - spc->cluster = topology_physical_package_id(cpu_dev->id); - - spc->cluster = spc->cluster < 0 ? 0 : spc->cluster; - - init.name = dev_name(cpu_dev); - init.ops = &clk_spc_ops; - init.flags = CLK_GET_RATE_NOCACHE; - init.num_parents = 0; - - return devm_clk_register(cpu_dev, &spc->hw); -} - -static int __init ve_spc_clk_init(void) -{ - int cpu, cluster; - struct clk *clk; - bool init_opp_table[MAX_CLUSTERS] = { false }; - - if (!info) - return 0; /* Continue only if SPC is initialised */ - - if (ve_spc_populate_opps(0) || ve_spc_populate_opps(1)) { - pr_err("failed to build OPP table\n"); - return -ENODEV; - } - - for_each_possible_cpu(cpu) { - struct device *cpu_dev = get_cpu_device(cpu); - if (!cpu_dev) { - pr_warn("failed to get cpu%d device\n", cpu); - continue; - } - clk = ve_spc_clk_register(cpu_dev); - if (IS_ERR(clk)) { - pr_warn("failed to register cpu%d clock\n", cpu); - continue; - } - if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) { - pr_warn("failed to register cpu%d clock lookup\n", cpu); - continue; - } - - cluster = topology_physical_package_id(cpu_dev->id); - if (init_opp_table[cluster]) - continue; - - if (ve_init_opp_table(cpu_dev)) - pr_warn("failed to initialise cpu%d opp table\n", cpu); - else if (dev_pm_opp_set_sharing_cpus(cpu_dev, - topology_core_cpumask(cpu_dev->id))) - pr_warn("failed to mark OPPs shared for cpu%d\n", cpu); - else - init_opp_table[cluster] = true; - } - - platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0); - return 0; -} -device_initcall(ve_spc_clk_init); diff --git a/arch/arm/mach-vexpress/spc.h b/arch/arm/mach-vexpress/spc.h deleted file mode 100644 index 288569fdfcb9..000000000000 --- a/arch/arm/mach-vexpress/spc.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * - * Copyright (C) 2012 ARM Limited - */ - - -#ifndef __SPC_H_ -#define __SPC_H_ - -int __init ve_spc_init(void __iomem *base, u32 a15_clusid, int irq); -void ve_spc_global_wakeup_irq(bool set); -void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); -void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); -void ve_spc_powerdown(u32 cluster, bool enable); -int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster); - -#endif diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c deleted file mode 100644 index e96c42ae3602..000000000000 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ /dev/null @@ -1,263 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * arch/arm/mach-vexpress/tc2_pm.c - TC2 power management support - * - * Created by: Nicolas Pitre, October 2012 - * Copyright: (C) 2012-2013 Linaro Limited - * - * Some portions of this file were originally written by Achin Gupta - * Copyright: (C) 2012 ARM Limited - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "spc.h" - -/* SCC conf registers */ -#define RESET_CTRL 0x018 -#define RESET_A15_NCORERESET(cpu) (1 << (2 + (cpu))) -#define RESET_A7_NCORERESET(cpu) (1 << (16 + (cpu))) - -#define A15_CONF 0x400 -#define A7_CONF 0x500 -#define SYS_INFO 0x700 -#define SPC_BASE 0xb00 - -static void __iomem *scc; - -#define TC2_CLUSTERS 2 -#define TC2_MAX_CPUS_PER_CLUSTER 3 - -static unsigned int tc2_nr_cpus[TC2_CLUSTERS]; - -static int tc2_pm_cpu_powerup(unsigned int cpu, unsigned int cluster) -{ - pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) - return -EINVAL; - ve_spc_set_resume_addr(cluster, cpu, - __pa_symbol(mcpm_entry_point)); - ve_spc_cpu_wakeup_irq(cluster, cpu, true); - return 0; -} - -static int tc2_pm_cluster_powerup(unsigned int cluster) -{ - pr_debug("%s: cluster %u\n", __func__, cluster); - if (cluster >= TC2_CLUSTERS) - return -EINVAL; - ve_spc_powerdown(cluster, false); - return 0; -} - -static void tc2_pm_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) -{ - pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); - ve_spc_cpu_wakeup_irq(cluster, cpu, true); - /* - * If the CPU is committed to power down, make sure - * the power controller will be in charge of waking it - * up upon IRQ, ie IRQ lines are cut from GIC CPU IF - * to the CPU by disabling the GIC CPU IF to prevent wfi - * from completing execution behind power controller back - */ - gic_cpu_if_down(0); -} - -static void tc2_pm_cluster_powerdown_prepare(unsigned int cluster) -{ - pr_debug("%s: cluster %u\n", __func__, cluster); - BUG_ON(cluster >= TC2_CLUSTERS); - ve_spc_powerdown(cluster, true); - ve_spc_global_wakeup_irq(true); -} - -static void tc2_pm_cpu_cache_disable(void) -{ - v7_exit_coherency_flush(louis); -} - -static void tc2_pm_cluster_cache_disable(void) -{ - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) { - /* - * On the Cortex-A15 we need to disable - * L2 prefetching before flushing the cache. - */ - asm volatile( - "mcr p15, 1, %0, c15, c0, 3 \n\t" - "isb \n\t" - "dsb " - : : "r" (0x400) ); - } - - v7_exit_coherency_flush(all); - cci_disable_port_by_cpu(read_cpuid_mpidr()); -} - -static int tc2_core_in_reset(unsigned int cpu, unsigned int cluster) -{ - u32 mask = cluster ? - RESET_A7_NCORERESET(cpu) - : RESET_A15_NCORERESET(cpu); - - return !(readl_relaxed(scc + RESET_CTRL) & mask); -} - -#define POLL_MSEC 10 -#define TIMEOUT_MSEC 1000 - -static int tc2_pm_wait_for_powerdown(unsigned int cpu, unsigned int cluster) -{ - unsigned tries; - - pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); - - for (tries = 0; tries < TIMEOUT_MSEC / POLL_MSEC; ++tries) { - pr_debug("%s(cpu=%u, cluster=%u): RESET_CTRL = 0x%08X\n", - __func__, cpu, cluster, - readl_relaxed(scc + RESET_CTRL)); - - /* - * We need the CPU to reach WFI, but the power - * controller may put the cluster in reset and - * power it off as soon as that happens, before - * we have a chance to see STANDBYWFI. - * - * So we need to check for both conditions: - */ - if (tc2_core_in_reset(cpu, cluster) || - ve_spc_cpu_in_wfi(cpu, cluster)) - return 0; /* success: the CPU is halted */ - - /* Otherwise, wait and retry: */ - msleep(POLL_MSEC); - } - - return -ETIMEDOUT; /* timeout */ -} - -static void tc2_pm_cpu_suspend_prepare(unsigned int cpu, unsigned int cluster) -{ - ve_spc_set_resume_addr(cluster, cpu, __pa_symbol(mcpm_entry_point)); -} - -static void tc2_pm_cpu_is_up(unsigned int cpu, unsigned int cluster) -{ - pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - BUG_ON(cluster >= TC2_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_CLUSTER); - ve_spc_cpu_wakeup_irq(cluster, cpu, false); - ve_spc_set_resume_addr(cluster, cpu, 0); -} - -static void tc2_pm_cluster_is_up(unsigned int cluster) -{ - pr_debug("%s: cluster %u\n", __func__, cluster); - BUG_ON(cluster >= TC2_CLUSTERS); - ve_spc_powerdown(cluster, false); - ve_spc_global_wakeup_irq(false); -} - -static const struct mcpm_platform_ops tc2_pm_power_ops = { - .cpu_powerup = tc2_pm_cpu_powerup, - .cluster_powerup = tc2_pm_cluster_powerup, - .cpu_suspend_prepare = tc2_pm_cpu_suspend_prepare, - .cpu_powerdown_prepare = tc2_pm_cpu_powerdown_prepare, - .cluster_powerdown_prepare = tc2_pm_cluster_powerdown_prepare, - .cpu_cache_disable = tc2_pm_cpu_cache_disable, - .cluster_cache_disable = tc2_pm_cluster_cache_disable, - .wait_for_powerdown = tc2_pm_wait_for_powerdown, - .cpu_is_up = tc2_pm_cpu_is_up, - .cluster_is_up = tc2_pm_cluster_is_up, -}; - -/* - * Enable cluster-level coherency, in preparation for turning on the MMU. - */ -static void __naked tc2_pm_power_up_setup(unsigned int affinity_level) -{ - asm volatile (" \n" -" cmp r0, #1 \n" -" bxne lr \n" -" b cci_enable_port_for_self "); -} - -static int __init tc2_pm_init(void) -{ - unsigned int mpidr, cpu, cluster; - int ret, irq; - u32 a15_cluster_id, a7_cluster_id, sys_info; - struct device_node *np; - - /* - * The power management-related features are hidden behind - * SCC registers. We need to extract runtime information like - * cluster ids and number of CPUs really available in clusters. - */ - np = of_find_compatible_node(NULL, NULL, - "arm,vexpress-scc,v2p-ca15_a7"); - scc = of_iomap(np, 0); - if (!scc) - return -ENODEV; - - a15_cluster_id = readl_relaxed(scc + A15_CONF) & 0xf; - a7_cluster_id = readl_relaxed(scc + A7_CONF) & 0xf; - if (a15_cluster_id >= TC2_CLUSTERS || a7_cluster_id >= TC2_CLUSTERS) - return -EINVAL; - - sys_info = readl_relaxed(scc + SYS_INFO); - tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; - tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; - - irq = irq_of_parse_and_map(np, 0); - - /* - * A subset of the SCC registers is also used to communicate - * with the SPC (power controller). We need to be able to - * drive it very early in the boot process to power up - * processors, so we initialize the SPC driver here. - */ - ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id, irq); - if (ret) - return ret; - - if (!cci_probed()) - return -ENODEV; - - mpidr = read_cpuid_mpidr(); - cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); - cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); - pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); - if (cluster >= TC2_CLUSTERS || cpu >= tc2_nr_cpus[cluster]) { - pr_err("%s: boot CPU is out of bound!\n", __func__); - return -EINVAL; - } - - ret = mcpm_platform_register(&tc2_pm_power_ops); - if (!ret) { - mcpm_sync_init(tc2_pm_power_up_setup); - /* test if we can (re)enable the CCI on our own */ - BUG_ON(mcpm_loopback(tc2_pm_cluster_cache_disable) != 0); - pr_info("TC2 power management initialized\n"); - } - return ret; -} - -early_initcall(tc2_pm_init); diff --git a/arch/arm/mach-vexpress/v2m-mps2.c b/arch/arm/mach-vexpress/v2m-mps2.c deleted file mode 100644 index 5b50d8e95cd7..000000000000 --- a/arch/arm/mach-vexpress/v2m-mps2.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2015 ARM Limited - * - * Author: Vladimir Murzin - */ - -#include - -static const char *const mps2_compat[] __initconst = { - "arm,mps2", - NULL -}; - -DT_MACHINE_START(MPS2DT, "MPS2 (Device Tree Support)") - .dt_compat = mps2_compat, -MACHINE_END diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c deleted file mode 100644 index ffe7c7a85ae9..000000000000 --- a/arch/arm/mach-vexpress/v2m.c +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - -#include "core.h" - -#define SYS_FLAGSSET 0x030 -#define SYS_FLAGSCLR 0x034 - -void vexpress_flags_set(u32 data) -{ - static void __iomem *base; - - if (!base) { - struct device_node *node = of_find_compatible_node(NULL, NULL, - "arm,vexpress-sysreg"); - - base = of_iomap(node, 0); - } - - if (WARN_ON(!base)) - return; - - writel(~0, base + SYS_FLAGSCLR); - writel(data, base + SYS_FLAGSSET); -} - -static const char * const v2m_dt_match[] __initconst = { - "arm,vexpress", - NULL, -}; - -DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") - .dt_compat = v2m_dt_match, - .l2c_aux_val = 0x00400000, - .l2c_aux_mask = 0xfe0fffff, - .smp = smp_ops(vexpress_smp_dt_ops), - .smp_init = smp_init_ops(vexpress_smp_init_ops), -MACHINE_END diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile deleted file mode 100644 index 5de44a57c4de..000000000000 --- a/arch/arm/plat-versatile/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include - -obj-$(CONFIG_SMP) += headsmp.o platsmp.o -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/plat-versatile/headsmp.S b/arch/arm/plat-versatile/headsmp.S deleted file mode 100644 index 09d9fc30c8ca..000000000000 --- a/arch/arm/plat-versatile/headsmp.S +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/arm/plat-versatile/headsmp.S - * - * Copyright (c) 2003 ARM Limited - * All Rights Reserved - */ -#include -#include -#include - -/* - * Realview/Versatile Express specific entry point for secondary CPUs. - * This provides a "holding pen" into which all secondary cores are held - * until we're ready for them to initialise. - */ -ENTRY(versatile_secondary_startup) - ARM_BE8(setend be) - mrc p15, 0, r0, c0, c0, 5 - bic r0, #0xff000000 - adr r4, 1f - ldmia r4, {r5, r6} - sub r4, r4, r5 - add r6, r6, r4 -pen: ldr r7, [r6] - cmp r7, r0 - bne pen - - /* - * we've been released from the holding pen: secondary_stack - * should now contain the SVC stack for this core - */ - b secondary_startup - - .align -1: .long . - .long versatile_cpu_release -ENDPROC(versatile_secondary_startup) diff --git a/arch/arm/plat-versatile/hotplug.c b/arch/arm/plat-versatile/hotplug.c deleted file mode 100644 index 2e9dca38bec0..000000000000 --- a/arch/arm/plat-versatile/hotplug.c +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This hotplug implementation is _specific_ to the situation found on - * ARM development platforms where there is _no_ possibility of actually - * taking a CPU offline, resetting it, or otherwise. Real platforms must - * NOT copy this code. - */ -#include -#include -#include - -#include -#include - -#include - -static inline void versatile_immitation_enter_lowpower(unsigned int actrl_mask) -{ - unsigned int v; - - asm volatile( - "mcr p15, 0, %1, c7, c5, 0\n" - " mcr p15, 0, %1, c7, c10, 4\n" - /* - * Turn off coherency - */ - " mrc p15, 0, %0, c1, c0, 1\n" - " bic %0, %0, %3\n" - " mcr p15, 0, %0, c1, c0, 1\n" - " mrc p15, 0, %0, c1, c0, 0\n" - " bic %0, %0, %2\n" - " mcr p15, 0, %0, c1, c0, 0\n" - : "=&r" (v) - : "r" (0), "Ir" (CR_C), "Ir" (actrl_mask) - : "cc"); -} - -static inline void versatile_immitation_leave_lowpower(unsigned int actrl_mask) -{ - unsigned int v; - - asm volatile( - "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, %1\n" - " mcr p15, 0, %0, c1, c0, 0\n" - " mrc p15, 0, %0, c1, c0, 1\n" - " orr %0, %0, %2\n" - " mcr p15, 0, %0, c1, c0, 1\n" - : "=&r" (v) - : "Ir" (CR_C), "Ir" (actrl_mask) - : "cc"); -} - -static inline void versatile_immitation_do_lowpower(unsigned int cpu, int *spurious) -{ - /* - * there is no power-control hardware on this platform, so all - * we can do is put the core into WFI; this is safe as the calling - * code will have already disabled interrupts. - * - * This code should not be used outside Versatile platforms. - */ - for (;;) { - wfi(); - - if (versatile_cpu_release == cpu_logical_map(cpu)) { - /* - * OK, proper wakeup, we're done - */ - break; - } - - /* - * Getting here, means that we have come out of WFI without - * having been woken up - this shouldn't happen - * - * Just note it happening - when we're woken, we can report - * its occurrence. - */ - (*spurious)++; - } -} - -/* - * platform-specific code to shutdown a CPU. - * This code supports immitation-style CPU hotplug for Versatile/Realview/ - * Versatile Express platforms that are unable to do real CPU hotplug. - */ -void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask) -{ - int spurious = 0; - - versatile_immitation_enter_lowpower(actrl_mask); - versatile_immitation_do_lowpower(cpu, &spurious); - versatile_immitation_leave_lowpower(actrl_mask); - - if (spurious) - pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); -} diff --git a/arch/arm/plat-versatile/include/plat/platsmp.h b/arch/arm/plat-versatile/include/plat/platsmp.h deleted file mode 100644 index 500605f48b80..000000000000 --- a/arch/arm/plat-versatile/include/plat/platsmp.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/arm/plat-versatile/include/plat/platsmp.h - * - * Copyright (C) 2011 ARM Ltd. - * All Rights Reserved - */ -extern volatile int versatile_cpu_release; - -extern void versatile_secondary_startup(void); -extern void versatile_secondary_init(unsigned int cpu); -extern int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle); -void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask); diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c deleted file mode 100644 index 3567296cec2a..000000000000 --- a/arch/arm/plat-versatile/platsmp.c +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/plat-versatile/platsmp.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This code is specific to the hardware found on ARM Realview and - * Versatile Express platforms where the CPUs are unable to be individually - * woken, and where there is no way to hot-unplug CPUs. Real platforms - * should not copy this code. - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -/* - * versatile_cpu_release controls the release of CPUs from the holding - * pen in headsmp.S, which exists because we are not always able to - * control the release of individual CPUs from the board firmware. - * Production platforms do not need this. - */ -volatile int versatile_cpu_release = -1; - -/* - * Write versatile_cpu_release in a way that is guaranteed to be visible to - * all observers, irrespective of whether they're taking part in coherency - * or not. This is necessary for the hotplug code to work reliably. - */ -static void versatile_write_cpu_release(int val) -{ - versatile_cpu_release = val; - smp_wmb(); - sync_cache_w(&versatile_cpu_release); -} - -/* - * versatile_lock exists to avoid running the loops_per_jiffy delay loop - * calibrations on the secondary CPU while the requesting CPU is using - * the limited-bandwidth bus - which affects the calibration value. - * Production platforms do not need this. - */ -static DEFINE_RAW_SPINLOCK(versatile_lock); - -void versatile_secondary_init(unsigned int cpu) -{ - /* - * let the primary processor know we're out of the - * pen, then head off into the C entry point - */ - versatile_write_cpu_release(-1); - - /* - * Synchronise with the boot thread. - */ - raw_spin_lock(&versatile_lock); - raw_spin_unlock(&versatile_lock); -} - -int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) -{ - unsigned long timeout; - - /* - * Set synchronisation state between this boot processor - * and the secondary one - */ - raw_spin_lock(&versatile_lock); - - /* - * This is really belt and braces; we hold unintended secondary - * CPUs in the holding pen until we're ready for them. However, - * since we haven't sent them a soft interrupt, they shouldn't - * be there. - */ - versatile_write_cpu_release(cpu_logical_map(cpu)); - - /* - * Send the secondary CPU a soft interrupt, thereby causing - * the boot monitor to read the system wide flags register, - * and branch to the address found there. - */ - arch_send_wakeup_ipi_mask(cpumask_of(cpu)); - - timeout = jiffies + (1 * HZ); - while (time_before(jiffies, timeout)) { - smp_rmb(); - if (versatile_cpu_release == -1) - break; - - udelay(10); - } - - /* - * now the secondary core is starting up let it run its - * calibrations, then wait for it to finish - */ - raw_spin_unlock(&versatile_lock); - - return versatile_cpu_release != -1 ? -ENOSYS : 0; -} -- cgit v1.2.3-59-g8ed1b