arm: Xilinx Zynq cleanup patches for v3.18
- PM support - Fix L2 useless setting -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iEYEABECAAYFAlQYGFwACgkQykllyylKDCFI/ACeMQecelDM7sN3pOXVDA8unho5 eqEAnjwQL/kw2p8jru1+t13V1SxThxKa =xfgX -----END PGP SIGNATURE----- Merge tag 'zynq-cleanup-for-3.18' of git://git.xilinx.com/linux-xlnx into next/soc Pull "arm: Xilinx Zynq cleanup patches for v3.18" from Michal Simek: - PM support - Fix L2 useless setting Signed-off-by: Arnd Bergmann <arnd@arndb.de> * tag 'zynq-cleanup-for-3.18' of git://git.xilinx.com/linux-xlnx: ARM: zynq: Remove useless L2C AUX setting ARM: zynq: Rename 'zynq_platform_cpu_die' ARM: zynq: Remove hotplug.c ARM: zynq: Synchronise zynq_cpu_die/kill ARM: zynq: cpuidle: Remove pointless code ARM: zynq: Remove invalidate cache for cpu die ARM: zynq: PM: Enable DDR clock stop ARM: zynq: DT: Add DDRC node Documentation: devicetree: Add binding for Synopsys DDR controller ARM: zynq: PM: Enable A9 internal clock gating feature
This commit is contained in:
commit
e36087998a
10 changed files with 207 additions and 63 deletions
|
@ -0,0 +1,11 @@
|
||||||
|
Binding for Synopsys IntelliDDR Multi Protocol Memory Controller
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should be 'xlnx,zynq-ddrc-a05'
|
||||||
|
- reg: Base address and size of the controllers memory area
|
||||||
|
|
||||||
|
Example:
|
||||||
|
memory-controller@f8006000 {
|
||||||
|
compatible = "xlnx,zynq-ddrc-a05";
|
||||||
|
reg = <0xf8006000 0x1000>;
|
||||||
|
};
|
|
@ -146,6 +146,11 @@
|
||||||
cache-level = <2>;
|
cache-level = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
memory-controller@f8006000 {
|
||||||
|
compatible = "xlnx,zynq-ddrc-a05";
|
||||||
|
reg = <0xf8006000 0x1000>;
|
||||||
|
} ;
|
||||||
|
|
||||||
uart0: serial@e0000000 {
|
uart0: serial@e0000000 {
|
||||||
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
|
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# Common support
|
# Common support
|
||||||
obj-y := common.o slcr.o
|
obj-y := common.o slcr.o pm.o
|
||||||
CFLAGS_REMOVE_hotplug.o =-march=armv6k
|
CFLAGS_REMOVE_hotplug.o =-march=armv6k
|
||||||
CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9
|
CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9
|
||||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
|
||||||
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
|
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
|
||||||
|
|
|
@ -98,6 +98,12 @@ static int __init zynq_get_revision(void)
|
||||||
return revision;
|
return revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init zynq_init_late(void)
|
||||||
|
{
|
||||||
|
zynq_core_pm_init();
|
||||||
|
zynq_pm_late_init();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zynq_init_machine - System specific initialization, intended to be
|
* zynq_init_machine - System specific initialization, intended to be
|
||||||
* called from board specific initialization.
|
* called from board specific initialization.
|
||||||
|
@ -198,12 +204,13 @@ static const char * const zynq_dt_match[] = {
|
||||||
|
|
||||||
DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
|
DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
|
||||||
/* 64KB way size, 8-way associativity, parity disabled */
|
/* 64KB way size, 8-way associativity, parity disabled */
|
||||||
.l2c_aux_val = 0x02000000,
|
.l2c_aux_val = 0x00000000,
|
||||||
.l2c_aux_mask = 0xf0ffffff,
|
.l2c_aux_mask = 0xffffffff,
|
||||||
.smp = smp_ops(zynq_smp_ops),
|
.smp = smp_ops(zynq_smp_ops),
|
||||||
.map_io = zynq_map_io,
|
.map_io = zynq_map_io,
|
||||||
.init_irq = zynq_irq_init,
|
.init_irq = zynq_irq_init,
|
||||||
.init_machine = zynq_init_machine,
|
.init_machine = zynq_init_machine,
|
||||||
|
.init_late = zynq_init_late,
|
||||||
.init_time = zynq_timer_init,
|
.init_time = zynq_timer_init,
|
||||||
.dt_compat = zynq_dt_match,
|
.dt_compat = zynq_dt_match,
|
||||||
.reserve = zynq_memory_init,
|
.reserve = zynq_memory_init,
|
||||||
|
|
|
@ -24,6 +24,8 @@ extern int zynq_early_slcr_init(void);
|
||||||
extern void zynq_slcr_system_reset(void);
|
extern void zynq_slcr_system_reset(void);
|
||||||
extern void zynq_slcr_cpu_stop(int cpu);
|
extern void zynq_slcr_cpu_stop(int cpu);
|
||||||
extern void zynq_slcr_cpu_start(int cpu);
|
extern void zynq_slcr_cpu_start(int cpu);
|
||||||
|
extern bool zynq_slcr_cpu_state_read(int cpu);
|
||||||
|
extern void zynq_slcr_cpu_state_write(int cpu, bool die);
|
||||||
extern u32 zynq_slcr_get_device_id(void);
|
extern u32 zynq_slcr_get_device_id(void);
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
@ -37,7 +39,17 @@ extern struct smp_operations zynq_smp_ops __initdata;
|
||||||
|
|
||||||
extern void __iomem *zynq_scu_base;
|
extern void __iomem *zynq_scu_base;
|
||||||
|
|
||||||
/* Hotplug */
|
void zynq_pm_late_init(void);
|
||||||
extern void zynq_platform_cpu_die(unsigned int cpu);
|
|
||||||
|
static inline void zynq_core_pm_init(void)
|
||||||
|
{
|
||||||
|
/* A9 clock gating */
|
||||||
|
asm volatile ("mrc p15, 0, r12, c15, c0, 0\n"
|
||||||
|
"orr r12, r12, #1\n"
|
||||||
|
"mcr p15, 0, r12, c15, c0, 0\n"
|
||||||
|
: /* no outputs */
|
||||||
|
: /* no inputs */
|
||||||
|
: "r12");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,50 +10,5 @@
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
#include <linux/kernel.h>
|
#include <asm/proc-fns.h>
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/smp.h>
|
|
||||||
|
|
||||||
#include <asm/cacheflush.h>
|
|
||||||
#include <asm/cp15.h>
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
static inline void zynq_cpu_enter_lowpower(void)
|
|
||||||
{
|
|
||||||
unsigned int v;
|
|
||||||
|
|
||||||
flush_cache_all();
|
|
||||||
asm volatile(
|
|
||||||
" mcr p15, 0, %1, c7, c5, 0\n"
|
|
||||||
" dsb\n"
|
|
||||||
/*
|
|
||||||
* Turn off coherency
|
|
||||||
*/
|
|
||||||
" mrc p15, 0, %0, c1, c0, 1\n"
|
|
||||||
" bic %0, %0, #0x40\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)
|
|
||||||
: "cc");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* platform-specific code to shutdown a CPU
|
|
||||||
*
|
|
||||||
* Called with IRQs disabled
|
|
||||||
*/
|
|
||||||
void zynq_platform_cpu_die(unsigned int cpu)
|
|
||||||
{
|
|
||||||
zynq_cpu_enter_lowpower();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
for (;;)
|
|
||||||
cpu_do_idle();
|
|
||||||
}
|
|
||||||
|
|
|
@ -112,20 +112,59 @@ static void __init zynq_smp_prepare_cpus(unsigned int max_cpus)
|
||||||
scu_enable(zynq_scu_base);
|
scu_enable(zynq_scu_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zynq_secondary_init - Initialize secondary CPU cores
|
||||||
|
* @cpu: CPU that is initialized
|
||||||
|
*
|
||||||
|
* This function is in the hotplug path. Don't move it into the
|
||||||
|
* init section!!
|
||||||
|
*/
|
||||||
|
static void zynq_secondary_init(unsigned int cpu)
|
||||||
|
{
|
||||||
|
zynq_core_pm_init();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_HOTPLUG_CPU
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
static int zynq_cpu_kill(unsigned cpu)
|
static int zynq_cpu_kill(unsigned cpu)
|
||||||
{
|
{
|
||||||
|
unsigned long timeout = jiffies + msecs_to_jiffies(50);
|
||||||
|
|
||||||
|
while (zynq_slcr_cpu_state_read(cpu))
|
||||||
|
if (time_after(jiffies, timeout))
|
||||||
|
return 0;
|
||||||
|
|
||||||
zynq_slcr_cpu_stop(cpu);
|
zynq_slcr_cpu_stop(cpu);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zynq_cpu_die - Let a CPU core die
|
||||||
|
* @cpu: Dying CPU
|
||||||
|
*
|
||||||
|
* Platform-specific code to shutdown a CPU.
|
||||||
|
* Called with IRQs disabled on the dying CPU.
|
||||||
|
*/
|
||||||
|
static void zynq_cpu_die(unsigned int cpu)
|
||||||
|
{
|
||||||
|
zynq_slcr_cpu_state_write(cpu, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
for (;;)
|
||||||
|
cpu_do_idle();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct smp_operations zynq_smp_ops __initdata = {
|
struct smp_operations zynq_smp_ops __initdata = {
|
||||||
.smp_init_cpus = zynq_smp_init_cpus,
|
.smp_init_cpus = zynq_smp_init_cpus,
|
||||||
.smp_prepare_cpus = zynq_smp_prepare_cpus,
|
.smp_prepare_cpus = zynq_smp_prepare_cpus,
|
||||||
.smp_boot_secondary = zynq_boot_secondary,
|
.smp_boot_secondary = zynq_boot_secondary,
|
||||||
|
.smp_secondary_init = zynq_secondary_init,
|
||||||
#ifdef CONFIG_HOTPLUG_CPU
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
.cpu_die = zynq_platform_cpu_die,
|
.cpu_die = zynq_cpu_die,
|
||||||
.cpu_kill = zynq_cpu_kill,
|
.cpu_kill = zynq_cpu_kill,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
83
arch/arm/mach-zynq/pm.c
Normal file
83
arch/arm/mach-zynq/pm.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Zynq power management
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 - 2014 Xilinx
|
||||||
|
*
|
||||||
|
* Sören Brinkmann <soren.brinkmann@xilinx.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/* register offsets */
|
||||||
|
#define DDRC_CTRL_REG1_OFFS 0x60
|
||||||
|
#define DDRC_DRAM_PARAM_REG3_OFFS 0x20
|
||||||
|
|
||||||
|
/* bitfields */
|
||||||
|
#define DDRC_CLOCKSTOP_MASK BIT(23)
|
||||||
|
#define DDRC_SELFREFRESH_MASK BIT(12)
|
||||||
|
|
||||||
|
static void __iomem *ddrc_base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zynq_pm_ioremap() - Create IO mappings
|
||||||
|
* @comp: DT compatible string
|
||||||
|
* Return: Pointer to the mapped memory or NULL.
|
||||||
|
*
|
||||||
|
* Remap the memory region for a compatible DT node.
|
||||||
|
*/
|
||||||
|
static void __iomem *zynq_pm_ioremap(const char *comp)
|
||||||
|
{
|
||||||
|
struct device_node *np;
|
||||||
|
void __iomem *base = NULL;
|
||||||
|
|
||||||
|
np = of_find_compatible_node(NULL, NULL, comp);
|
||||||
|
if (np) {
|
||||||
|
base = of_iomap(np, 0);
|
||||||
|
of_node_put(np);
|
||||||
|
} else {
|
||||||
|
pr_warn("%s: no compatible node found for '%s'\n", __func__,
|
||||||
|
comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zynq_pm_late_init() - Power management init
|
||||||
|
*
|
||||||
|
* Initialization of power management related featurs and infrastructure.
|
||||||
|
*/
|
||||||
|
void __init zynq_pm_late_init(void)
|
||||||
|
{
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
ddrc_base = zynq_pm_ioremap("xlnx,zynq-ddrc-a05");
|
||||||
|
if (!ddrc_base) {
|
||||||
|
pr_warn("%s: Unable to map DDRC IO memory.\n", __func__);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Enable DDRC clock stop feature. The HW takes care of
|
||||||
|
* entering/exiting the correct mode depending
|
||||||
|
* on activity state.
|
||||||
|
*/
|
||||||
|
reg = readl(ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
|
||||||
|
reg |= DDRC_CLOCKSTOP_MASK;
|
||||||
|
writel(reg, ddrc_base + DDRC_DRAM_PARAM_REG3_OFFS);
|
||||||
|
}
|
||||||
|
}
|
|
@ -138,6 +138,8 @@ void zynq_slcr_cpu_start(int cpu)
|
||||||
zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
|
zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
|
||||||
reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
|
reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
|
||||||
zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
|
zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
|
||||||
|
|
||||||
|
zynq_slcr_cpu_state_write(cpu, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,8 +156,47 @@ void zynq_slcr_cpu_stop(int cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zynq_slcr_init - Regular slcr driver init
|
* zynq_slcr_cpu_state - Read/write cpu state
|
||||||
|
* @cpu: cpu number
|
||||||
*
|
*
|
||||||
|
* SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
|
||||||
|
* 0 means cpu is running, 1 cpu is going to die.
|
||||||
|
*
|
||||||
|
* Return: true if cpu is running, false if cpu is going to die
|
||||||
|
*/
|
||||||
|
bool zynq_slcr_cpu_state_read(int cpu)
|
||||||
|
{
|
||||||
|
u32 state;
|
||||||
|
|
||||||
|
state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
|
||||||
|
state &= 1 << (31 - cpu);
|
||||||
|
|
||||||
|
return !state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zynq_slcr_cpu_state - Read/write cpu state
|
||||||
|
* @cpu: cpu number
|
||||||
|
* @die: cpu state - true if cpu is going to die
|
||||||
|
*
|
||||||
|
* SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
|
||||||
|
* 0 means cpu is running, 1 cpu is going to die.
|
||||||
|
*/
|
||||||
|
void zynq_slcr_cpu_state_write(int cpu, bool die)
|
||||||
|
{
|
||||||
|
u32 state, mask;
|
||||||
|
|
||||||
|
state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
|
||||||
|
mask = 1 << (31 - cpu);
|
||||||
|
if (die)
|
||||||
|
state |= mask;
|
||||||
|
else
|
||||||
|
state &= ~mask;
|
||||||
|
writel(state, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zynq_slcr_init - Regular slcr driver init
|
||||||
* Return: 0 on success, negative errno otherwise.
|
* Return: 0 on success, negative errno otherwise.
|
||||||
*
|
*
|
||||||
* Called early during boot from platform code to remap SLCR area.
|
* Called early during boot from platform code to remap SLCR area.
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/cpu_pm.h>
|
|
||||||
#include <linux/cpuidle.h>
|
#include <linux/cpuidle.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <asm/proc-fns.h>
|
#include <asm/proc-fns.h>
|
||||||
|
@ -38,15 +37,9 @@
|
||||||
static int zynq_enter_idle(struct cpuidle_device *dev,
|
static int zynq_enter_idle(struct cpuidle_device *dev,
|
||||||
struct cpuidle_driver *drv, int index)
|
struct cpuidle_driver *drv, int index)
|
||||||
{
|
{
|
||||||
/* Devices must be stopped here */
|
|
||||||
cpu_pm_enter();
|
|
||||||
|
|
||||||
/* Add code for DDR self refresh start */
|
/* Add code for DDR self refresh start */
|
||||||
cpu_do_idle();
|
cpu_do_idle();
|
||||||
|
|
||||||
/* Add code for DDR self refresh stop */
|
|
||||||
cpu_pm_exit();
|
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +52,7 @@ static struct cpuidle_driver zynq_idle_driver = {
|
||||||
.enter = zynq_enter_idle,
|
.enter = zynq_enter_idle,
|
||||||
.exit_latency = 10,
|
.exit_latency = 10,
|
||||||
.target_residency = 10000,
|
.target_residency = 10000,
|
||||||
.flags = CPUIDLE_FLAG_TIME_VALID |
|
.flags = CPUIDLE_FLAG_TIME_VALID,
|
||||||
CPUIDLE_FLAG_TIMER_STOP,
|
|
||||||
.name = "RAM_SR",
|
.name = "RAM_SR",
|
||||||
.desc = "WFI and RAM Self Refresh",
|
.desc = "WFI and RAM Self Refresh",
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Reference in a new issue