Initial commit; kernel source import

This commit is contained in:
Nathan
2025-04-06 23:50:55 -05:00
commit 25c6d769f4
45093 changed files with 18199410 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
config ARCH_MVEBU
bool "Marvell SOCs with Device Tree support" if ARCH_MULTI_V7
select CLKSRC_MMIO
select COMMON_CLK
select GENERIC_CLOCKEVENTS
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
select MULTI_IRQ_HANDLER
select PINCTRL
select PLAT_ORION
select SPARSE_IRQ
select CLKDEV_LOOKUP
select MVEBU_CLK_CORE
select MVEBU_CLK_CPU
select MVEBU_CLK_GATING
select MVEBU_MBUS
select ZONE_DMA if ARM_LPAE
select ARCH_REQUIRE_GPIOLIB
if ARCH_MVEBU
menu "Marvell SOC with device tree"
config MACH_ARMADA_370_XP
bool
select ARMADA_370_XP_TIMER
select HAVE_SMP
select CACHE_L2X0
select CPU_PJ4B
config MACH_ARMADA_370
bool "Marvell Armada 370 boards"
select MACH_ARMADA_370_XP
select PINCTRL_ARMADA_370
help
Say 'Y' here if you want your kernel to support boards based
on the Marvell Armada 370 SoC with device tree.
config MACH_ARMADA_XP
bool "Marvell Armada XP boards"
select MACH_ARMADA_370_XP
select PINCTRL_ARMADA_XP
help
Say 'Y' here if you want your kernel to support boards based
on the Marvell Armada XP SoC with device tree.
endmenu
endif

View File

@@ -0,0 +1,10 @@
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
-I$(srctree)/arch/arm/plat-orion/include
AFLAGS_coherency_ll.o := -Wa,-march=armv7-a
obj-y += system-controller.o
obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o
obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o

View File

@@ -0,0 +1,96 @@
/*
* Device Tree support for Armada 370 and XP platforms.
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/time-armada-370-xp.h>
#include <linux/clk/mvebu.h>
#include <linux/dma-mapping.h>
#include <linux/mbus.h>
#include <linux/irqchip.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include "armada-370-xp.h"
#include "common.h"
#include "coherency.h"
static struct map_desc armada_370_xp_io_desc[] __initdata = {
{
.virtual = (unsigned long) ARMADA_370_XP_REGS_VIRT_BASE,
.pfn = __phys_to_pfn(ARMADA_370_XP_REGS_PHYS_BASE),
.length = ARMADA_370_XP_REGS_SIZE,
.type = MT_DEVICE,
},
};
void __init armada_370_xp_map_io(void)
{
iotable_init(armada_370_xp_io_desc, ARRAY_SIZE(armada_370_xp_io_desc));
}
void __init armada_370_xp_timer_and_clk_init(void)
{
mvebu_clocks_init();
armada_370_xp_timer_init();
}
void __init armada_370_xp_init_early(void)
{
char *mbus_soc_name;
/*
* This initialization will be replaced by a DT-based
* initialization once the mvebu-mbus driver gains DT support.
*/
if (of_machine_is_compatible("marvell,armada370"))
mbus_soc_name = "marvell,armada370-mbus";
else
mbus_soc_name = "marvell,armadaxp-mbus";
mvebu_mbus_init(mbus_soc_name,
ARMADA_370_XP_MBUS_WINS_BASE,
ARMADA_370_XP_MBUS_WINS_SIZE,
ARMADA_370_XP_SDRAM_WINS_BASE,
ARMADA_370_XP_SDRAM_WINS_SIZE);
#ifdef CONFIG_CACHE_L2X0
l2x0_of_init(0, ~0UL);
#endif
}
static void __init armada_370_xp_dt_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
coherency_init();
}
static const char * const armada_370_xp_dt_compat[] = {
"marvell,armada-370-xp",
NULL,
};
DT_MACHINE_START(ARMADA_XP_DT, "Marvell Armada 370/XP (Device Tree)")
.smp = smp_ops(armada_xp_smp_ops),
.init_machine = armada_370_xp_dt_init,
.map_io = armada_370_xp_map_io,
.init_early = armada_370_xp_init_early,
.init_irq = irqchip_init,
.init_time = armada_370_xp_timer_and_clk_init,
.restart = mvebu_restart,
.dt_compat = armada_370_xp_dt_compat,
MACHINE_END

View File

@@ -0,0 +1,35 @@
/*
* Generic definitions for Marvell Armada_370_XP SoCs
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MACH_ARMADA_370_XP_H
#define __MACH_ARMADA_370_XP_H
#define ARMADA_370_XP_REGS_PHYS_BASE 0xd0000000
#define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfec00000)
#define ARMADA_370_XP_REGS_SIZE SZ_1M
/* These defines can go away once mvebu-mbus has a DT binding */
#define ARMADA_370_XP_MBUS_WINS_BASE (ARMADA_370_XP_REGS_PHYS_BASE + 0x20000)
#define ARMADA_370_XP_MBUS_WINS_SIZE 0x100
#define ARMADA_370_XP_SDRAM_WINS_BASE (ARMADA_370_XP_REGS_PHYS_BASE + 0x20180)
#define ARMADA_370_XP_SDRAM_WINS_SIZE 0x20
#ifdef CONFIG_SMP
#include <linux/cpumask.h>
void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq);
void armada_xp_mpic_smp_cpu_init(void);
#endif
#endif /* __MACH_ARMADA_370_XP_H */

View File

@@ -0,0 +1,155 @@
/*
* Coherency fabric (Aurora) support for Armada 370 and XP platforms.
*
* Copyright (C) 2012 Marvell
*
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory Clement <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada 370 and Armada XP SOCs have a coherency fabric which is
* responsible for ensuring hardware coherency between all CPUs and between
* CPUs and I/O masters. This file initializes the coherency fabric and
* supplies basic routines for configuring and controlling hardware coherency
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/smp.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <asm/smp_plat.h>
#include "armada-370-xp.h"
/*
* Some functions in this file are called very early during SMP
* initialization. At that time the device tree framework is not yet
* ready, and it is not possible to get the register address to
* ioremap it. That's why the pointer below is given with an initial
* value matching its virtual mapping
*/
static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
static void __iomem *coherency_cpu_base;
/* Coherency fabric registers */
#define COHERENCY_FABRIC_CFG_OFFSET 0x4
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
static struct of_device_id of_coherency_table[] = {
{.compatible = "marvell,coherency-fabric"},
{ /* end of list */ },
};
#ifdef CONFIG_SMP
int coherency_get_cpu_count(void)
{
int reg, cnt;
reg = readl(coherency_base + COHERENCY_FABRIC_CFG_OFFSET);
cnt = (reg & 0xF) + 1;
return cnt;
}
#endif
/* Function defined in coherency_ll.S */
int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id);
int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
{
if (!coherency_base) {
pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id);
pr_warn("Coherency fabric is not initialized\n");
return 1;
}
return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
}
static inline void mvebu_hwcc_sync_io_barrier(void)
{
writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
}
static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
struct dma_attrs *attrs)
{
if (dir != DMA_TO_DEVICE)
mvebu_hwcc_sync_io_barrier();
return pfn_to_dma(dev, page_to_pfn(page)) + offset;
}
static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
if (dir != DMA_TO_DEVICE)
mvebu_hwcc_sync_io_barrier();
}
static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir)
{
if (dir != DMA_TO_DEVICE)
mvebu_hwcc_sync_io_barrier();
}
static struct dma_map_ops mvebu_hwcc_dma_ops = {
.alloc = arm_dma_alloc,
.free = arm_dma_free,
.mmap = arm_dma_mmap,
.map_page = mvebu_hwcc_dma_map_page,
.unmap_page = mvebu_hwcc_dma_unmap_page,
.get_sgtable = arm_dma_get_sgtable,
.map_sg = arm_dma_map_sg,
.unmap_sg = arm_dma_unmap_sg,
.sync_single_for_cpu = mvebu_hwcc_dma_sync,
.sync_single_for_device = mvebu_hwcc_dma_sync,
.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
.sync_sg_for_device = arm_dma_sync_sg_for_device,
.set_dma_mask = arm_dma_set_mask,
};
static int mvebu_hwcc_platform_notifier(struct notifier_block *nb,
unsigned long event, void *__dev)
{
struct device *dev = __dev;
if (event != BUS_NOTIFY_ADD_DEVICE)
return NOTIFY_DONE;
set_dma_ops(dev, &mvebu_hwcc_dma_ops);
return NOTIFY_OK;
}
static struct notifier_block mvebu_hwcc_platform_nb = {
.notifier_call = mvebu_hwcc_platform_notifier,
};
int __init coherency_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, of_coherency_table);
if (np) {
pr_info("Initializing Coherency fabric\n");
coherency_base = of_iomap(np, 0);
coherency_cpu_base = of_iomap(np, 1);
set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
bus_register_notifier(&platform_bus_type,
&mvebu_hwcc_platform_nb);
}
return 0;
}

View File

@@ -0,0 +1,24 @@
/*
* arch/arm/mach-mvebu/include/mach/coherency.h
*
*
* Coherency fabric (Aurora) support for Armada 370 and XP platforms.
*
* Copyright (C) 2012 Marvell
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MACH_370_XP_COHERENCY_H
#define __MACH_370_XP_COHERENCY_H
#ifdef CONFIG_SMP
int coherency_get_cpu_count(void);
#endif
int set_cpu_coherent(int cpu_id, int smp_group_id);
int coherency_init(void);
#endif /* __MACH_370_XP_COHERENCY_H */

View File

@@ -0,0 +1,55 @@
/*
* Coherency fabric: low level functions
*
* Copyright (C) 2012 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* This file implements the assembly function to add a CPU to the
* coherency fabric. This function is called by each of the secondary
* CPUs during their early boot in an SMP kernel, this why this
* function have to callable from assembly. It can also be called by a
* primary CPU from C code during its boot.
*/
#include <linux/linkage.h>
#define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0
#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
.text
/*
* r0: Coherency fabric base register address
* r1: HW CPU id
*/
ENTRY(ll_set_cpu_coherent)
/* Create bit by cpu index */
mov r3, #(1 << 24)
lsl r1, r3, r1
/* Add CPU to SMP group - Atomic */
add r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET
1:
ldrex r2, [r3]
orr r2, r2, r1
strex r0, r2, [r3]
cmp r0, #0
bne 1b
/* Enable coherency on CPU - Atomic */
add r3, r3, #ARMADA_XP_CFB_CFG_REG_OFFSET
1:
ldrex r2, [r3]
orr r2, r2, r1
strex r0, r2, [r3]
cmp r0, #0
bne 1b
dsb
mov r0, #0
mov pc, lr
ENDPROC(ll_set_cpu_coherent)

View File

@@ -0,0 +1,28 @@
/*
* Core functions for Marvell System On Chip
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __ARCH_MVEBU_COMMON_H
#define __ARCH_MVEBU_COMMON_H
void mvebu_restart(char mode, const char *cmd);
void armada_370_xp_init_irq(void);
void armada_370_xp_handle_irq(struct pt_regs *regs);
void armada_xp_cpu_die(unsigned int cpu);
int armada_370_xp_coherency_init(void);
int armada_370_xp_pmsu_init(void);
void armada_xp_secondary_startup(void);
extern struct smp_operations armada_xp_smp_ops;
#endif

View File

@@ -0,0 +1,49 @@
/*
* SMP support: Entry point for secondary CPUs
*
* Copyright (C) 2012 Marvell
*
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* This file implements the assembly entry point for secondary CPUs in
* an SMP kernel. The only thing we need to do is to add the CPU to
* the coherency fabric by writing to 2 registers. Currently the base
* register addresses are hard coded due to the early initialisation
* problems.
*/
#include <linux/linkage.h>
#include <linux/init.h>
/*
* At this stage the secondary CPUs don't have acces yet to the MMU, so
* we have to provide physical addresses
*/
#define ARMADA_XP_CFB_BASE 0xD0020200
__CPUINIT
/*
* Armada XP specific entry point for secondary CPUs.
* We add the CPU to the coherency fabric and then jump to secondary
* startup
*/
ENTRY(armada_xp_secondary_startup)
/* Read CPU id */
mrc p15, 0, r1, c0, c0, 5
and r1, r1, #0xF
/* Add CPU to coherency fabric */
ldr r0, =ARMADA_XP_CFB_BASE
bl ll_set_cpu_coherent
b secondary_startup
ENDPROC(armada_xp_secondary_startup)

View File

@@ -0,0 +1,30 @@
/*
* Symmetric Multi Processing (SMP) support for Armada XP
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>
#include <asm/proc-fns.h>
/*
* platform-specific code to shutdown a CPU
*
* Called with IRQs disabled
*/
void __ref armada_xp_cpu_die(unsigned int cpu)
{
cpu_do_idle();
/* We should never return from idle */
panic("mvebu: cpu %d unexpectedly exit from shutdown\n", cpu);
}

View File

@@ -0,0 +1 @@
/* empty */

View File

@@ -0,0 +1,124 @@
/*
* Symmetric Multi Processing (SMP) support for Armada XP
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada XP SoC has 4 ARMv7 PJ4B CPUs running in full HW coherency
* This file implements the routines for preparing the SMP infrastructure
* and waking up the secondary CPUs
*/
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/mbus.h>
#include <asm/cacheflush.h>
#include <asm/smp_plat.h>
#include "common.h"
#include "armada-370-xp.h"
#include "pmsu.h"
#include "coherency.h"
void __init set_secondary_cpus_clock(void)
{
int thiscpu;
unsigned long rate;
struct clk *cpu_clk = NULL;
struct device_node *np = NULL;
thiscpu = smp_processor_id();
for_each_node_by_type(np, "cpu") {
int err;
int cpu;
err = of_property_read_u32(np, "reg", &cpu);
if (WARN_ON(err))
return;
if (cpu == thiscpu) {
cpu_clk = of_clk_get(np, 0);
break;
}
}
if (WARN_ON(IS_ERR(cpu_clk)))
return;
clk_prepare_enable(cpu_clk);
rate = clk_get_rate(cpu_clk);
/* set all the other CPU clk to the same rate than the boot CPU */
for_each_node_by_type(np, "cpu") {
int err;
int cpu;
err = of_property_read_u32(np, "reg", &cpu);
if (WARN_ON(err))
return;
if (cpu != thiscpu) {
cpu_clk = of_clk_get(np, 0);
clk_set_rate(cpu_clk, rate);
}
}
}
static void __cpuinit armada_xp_secondary_init(unsigned int cpu)
{
armada_xp_mpic_smp_cpu_init();
}
static int __cpuinit armada_xp_boot_secondary(unsigned int cpu,
struct task_struct *idle)
{
pr_info("Booting CPU %d\n", cpu);
armada_xp_boot_cpu(cpu, armada_xp_secondary_startup);
return 0;
}
static void __init armada_xp_smp_init_cpus(void)
{
unsigned int i, ncores;
ncores = coherency_get_cpu_count();
/* Limit possible CPUs to defconfig */
if (ncores > nr_cpu_ids) {
pr_warn("SMP: %d CPUs physically present. Only %d configured.",
ncores, nr_cpu_ids);
pr_warn("Clipping CPU count to %d\n", nr_cpu_ids);
ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
set_smp_cross_call(armada_mpic_send_doorbell);
}
void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
{
set_secondary_cpus_clock();
flush_cache_all();
set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
mvebu_mbus_add_window("bootrom", 0xfff00000, SZ_1M);
}
struct smp_operations armada_xp_smp_ops __initdata = {
.smp_init_cpus = armada_xp_smp_init_cpus,
.smp_prepare_cpus = armada_xp_smp_prepare_cpus,
.smp_secondary_init = armada_xp_secondary_init,
.smp_boot_secondary = armada_xp_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = armada_xp_cpu_die,
#endif
};

View File

@@ -0,0 +1,75 @@
/*
* Power Management Service Unit(PMSU) support for Armada 370/XP platforms.
*
* Copyright (C) 2012 Marvell
*
* Yehuda Yitschak <yehuday@marvell.com>
* Gregory Clement <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada 370 and Armada XP SOCs have a power management service
* unit which is responsible for powering down and waking up CPUs and
* other SOC units
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/smp.h>
#include <asm/smp_plat.h>
static void __iomem *pmsu_mp_base;
static void __iomem *pmsu_reset_base;
#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24)
#define PMSU_RESET_CTL_OFFSET(cpu) (cpu * 0x8)
static struct of_device_id of_pmsu_table[] = {
{.compatible = "marvell,armada-370-xp-pmsu"},
{ /* end of list */ },
};
#ifdef CONFIG_SMP
int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
{
int reg, hw_cpu;
if (!pmsu_mp_base || !pmsu_reset_base) {
pr_warn("Can't boot CPU. PMSU is uninitialized\n");
return 1;
}
hw_cpu = cpu_logical_map(cpu_id);
writel(virt_to_phys(boot_addr), pmsu_mp_base +
PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
/* Release CPU from reset by clearing reset bit*/
reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
reg &= (~0x1);
writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
return 0;
}
#endif
int __init armada_370_xp_pmsu_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, of_pmsu_table);
if (np) {
pr_info("Initializing Power Management Service Unit\n");
pmsu_mp_base = of_iomap(np, 0);
pmsu_reset_base = of_iomap(np, 1);
}
return 0;
}
early_initcall(armada_370_xp_pmsu_init);

View File

@@ -0,0 +1,16 @@
/*
* Power Management Service Unit (PMSU) support for Armada 370/XP platforms.
*
* Copyright (C) 2012 Marvell
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MACH_MVEBU_PMSU_H
#define __MACH_MVEBU_PMSU_H
int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
#endif /* __MACH_370_XP_PMSU_H */

View File

@@ -0,0 +1,105 @@
/*
* System controller support for Armada 370 and XP platforms.
*
* Copyright (C) 2012 Marvell
*
* Lior Amsalem <alior@marvell.com>
* Gregory CLEMENT <gregory.clement@free-electrons.com>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
* The Armada 370 and Armada XP SoCs both have a range of
* miscellaneous registers, that do not belong to a particular device,
* but rather provide system-level features. This basic
* system-controller driver provides a device tree binding for those
* registers, and implements utility functions offering various
* features related to those registers.
*
* For now, the feature set is limited to restarting the platform by a
* soft-reset, but it might be extended in the future.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/io.h>
static void __iomem *system_controller_base;
struct mvebu_system_controller {
u32 rstoutn_mask_offset;
u32 system_soft_reset_offset;
u32 rstoutn_mask_reset_out_en;
u32 system_soft_reset;
};
static struct mvebu_system_controller *mvebu_sc;
const struct mvebu_system_controller armada_370_xp_system_controller = {
.rstoutn_mask_offset = 0x60,
.system_soft_reset_offset = 0x64,
.rstoutn_mask_reset_out_en = 0x1,
.system_soft_reset = 0x1,
};
const struct mvebu_system_controller orion_system_controller = {
.rstoutn_mask_offset = 0x108,
.system_soft_reset_offset = 0x10c,
.rstoutn_mask_reset_out_en = 0x4,
.system_soft_reset = 0x1,
};
static struct of_device_id of_system_controller_table[] = {
{
.compatible = "marvell,orion-system-controller",
.data = (void *) &orion_system_controller,
}, {
.compatible = "marvell,armada-370-xp-system-controller",
.data = (void *) &armada_370_xp_system_controller,
},
{ /* end of list */ },
};
void mvebu_restart(char mode, const char *cmd)
{
if (!system_controller_base) {
pr_err("Cannot restart, system-controller not available: check the device tree\n");
} else {
/*
* Enable soft reset to assert RSTOUTn.
*/
writel(mvebu_sc->rstoutn_mask_reset_out_en,
system_controller_base +
mvebu_sc->rstoutn_mask_offset);
/*
* Assert soft reset.
*/
writel(mvebu_sc->system_soft_reset,
system_controller_base +
mvebu_sc->system_soft_reset_offset);
}
while (1)
;
}
static int __init mvebu_system_controller_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, of_system_controller_table);
if (np) {
const struct of_device_id *match =
of_match_node(of_system_controller_table, np);
BUG_ON(!match);
system_controller_base = of_iomap(np, 0);
mvebu_sc = (struct mvebu_system_controller *)match->data;
}
return 0;
}
arch_initcall(mvebu_system_controller_init);