Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform changes from Arnd Bergmann: "New and updated SoC support, notable changes include: - bcm: brcmstb SMP support initial iproc/cygnus support - exynos: Exynos4415 SoC support PMU and suspend support for Exynos5420 PMU support for Exynos3250 pm related maintenance - imx: new LS1021A SoC support vybrid 610 global timer support - integrator: convert to using multiplatform configuration - mediatek: earlyprintk support for mt8127/mt8135 - meson: meson8 soc and l2 cache controller support - mvebu: Armada 38x CPU hotplug support drop support for prerelease Armada 375 Z1 stepping extended suspend support, now works on Armada 370/XP - omap: hwmod related maintenance prcm cleanup - pxa: initial pxa27x DT handling - rockchip: SMP support for rk3288 add cpu frequency scaling support - shmobile: r8a7740 power domain support various small restart, timer, pci apmu changes - sunxi: Allwinner A80 (sun9i) earlyprintk support - ux500: power domain support Overall, a significant chunk of changes, coming mostly from the usual suspects: omap, shmobile, samsung and mvebu, all of which already contain a lot of platform specific code in arch/arm" * tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (187 commits) ARM: mvebu: use the cpufreq-dt platform_data for independent clocks soc: integrator: Add terminating entry for integrator_cm_match ARM: mvebu: add SDRAM controller description for Armada XP ARM: mvebu: adjust mbus controller description on Armada 370/XP ARM: mvebu: add suspend/resume DT information for Armada XP GP ARM: mvebu: synchronize secondary CPU clocks on resume ARM: mvebu: make sure MMU is disabled in armada_370_xp_cpu_resume ARM: mvebu: Armada XP GP specific suspend/resume code ARM: mvebu: reserve the first 10 KB of each memory bank for suspend/resume ARM: mvebu: implement suspend/resume support for Armada XP clk: mvebu: add suspend/resume for gatable clocks bus: mvebu-mbus: provide a mechanism to save SDRAM window configuration bus: mvebu-mbus: suspend/resume support clocksource: time-armada-370-xp: add suspend/resume support irqchip: armada-370-xp: Add suspend/resume support ARM: add lolevel debug support for asm9260 ARM: add mach-asm9260 ARM: EXYNOS: use u8 for val[] in struct exynos_pmu_conf power: reset: imx-snvs-poweroff: add power off driver for i.mx6 ARM: imx: temporarily remove CONFIG_SOC_FSL from LS1021A ...
This commit is contained in:
@@ -32,6 +32,7 @@ config ARMADA_370_XP_TIMER
|
||||
|
||||
config MESON6_TIMER
|
||||
bool
|
||||
select CLKSRC_MMIO
|
||||
|
||||
config ORION_TIMER
|
||||
select CLKSRC_OF
|
||||
|
@@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
|
||||
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
|
||||
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
|
||||
obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
|
||||
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
|
||||
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
/*
|
||||
* Timer block registers.
|
||||
@@ -223,6 +224,28 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = {
|
||||
.notifier_call = armada_370_xp_timer_cpu_notify,
|
||||
};
|
||||
|
||||
static u32 timer0_ctrl_reg, timer0_local_ctrl_reg;
|
||||
|
||||
static int armada_370_xp_timer_suspend(void)
|
||||
{
|
||||
timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF);
|
||||
timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void armada_370_xp_timer_resume(void)
|
||||
{
|
||||
writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
|
||||
writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
|
||||
writel(timer0_ctrl_reg, timer_base + TIMER_CTRL_OFF);
|
||||
writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF);
|
||||
}
|
||||
|
||||
struct syscore_ops armada_370_xp_timer_syscore_ops = {
|
||||
.suspend = armada_370_xp_timer_suspend,
|
||||
.resume = armada_370_xp_timer_resume,
|
||||
};
|
||||
|
||||
static void __init armada_370_xp_timer_common_init(struct device_node *np)
|
||||
{
|
||||
u32 clr = 0, set = 0;
|
||||
@@ -285,6 +308,8 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
|
||||
/* Immediately configure the timer on the boot CPU */
|
||||
if (!res)
|
||||
armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
|
||||
|
||||
register_syscore_ops(&armada_370_xp_timer_syscore_ops);
|
||||
}
|
||||
|
||||
static void __init armada_xp_timer_init(struct device_node *np)
|
||||
|
210
drivers/clocksource/timer-integrator-ap.c
Normal file
210
drivers/clocksource/timer-integrator-ap.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Integrator/AP timer driver
|
||||
* Copyright (C) 2000-2003 Deep Blue Solutions Ltd
|
||||
* Copyright (c) 2014, Linaro Limited
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <asm/hardware/arm_timer.h>
|
||||
|
||||
static void __iomem * sched_clk_base;
|
||||
|
||||
static u64 notrace integrator_read_sched_clock(void)
|
||||
{
|
||||
return -readl(sched_clk_base + TIMER_VALUE);
|
||||
}
|
||||
|
||||
static void integrator_clocksource_init(unsigned long inrate,
|
||||
void __iomem *base)
|
||||
{
|
||||
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
|
||||
unsigned long rate = inrate;
|
||||
|
||||
if (rate >= 1500000) {
|
||||
rate /= 16;
|
||||
ctrl |= TIMER_CTRL_DIV16;
|
||||
}
|
||||
|
||||
writel(0xffff, base + TIMER_LOAD);
|
||||
writel(ctrl, base + TIMER_CTRL);
|
||||
|
||||
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
|
||||
rate, 200, 16, clocksource_mmio_readl_down);
|
||||
|
||||
sched_clk_base = base;
|
||||
sched_clock_register(integrator_read_sched_clock, 16, rate);
|
||||
}
|
||||
|
||||
static unsigned long timer_reload;
|
||||
static void __iomem * clkevt_base;
|
||||
|
||||
/*
|
||||
* IRQ handler for the timer
|
||||
*/
|
||||
static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = dev_id;
|
||||
|
||||
/* clear the interrupt */
|
||||
writel(1, clkevt_base + TIMER_INTCLR);
|
||||
|
||||
evt->event_handler(evt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
|
||||
{
|
||||
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
|
||||
|
||||
/* Disable timer */
|
||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
/* Enable the timer and start the periodic tick */
|
||||
writel(timer_reload, clkevt_base + TIMER_LOAD);
|
||||
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
|
||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
/* Leave the timer disabled, .set_next_event will enable it */
|
||||
ctrl &= ~TIMER_CTRL_PERIODIC;
|
||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
default:
|
||||
/* Just leave in disabled state */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
|
||||
{
|
||||
unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
|
||||
|
||||
writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
||||
writel(next, clkevt_base + TIMER_LOAD);
|
||||
writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clock_event_device integrator_clockevent = {
|
||||
.name = "timer1",
|
||||
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_mode = clkevt_set_mode,
|
||||
.set_next_event = clkevt_set_next_event,
|
||||
.rating = 300,
|
||||
};
|
||||
|
||||
static struct irqaction integrator_timer_irq = {
|
||||
.name = "timer",
|
||||
.flags = IRQF_TIMER | IRQF_IRQPOLL,
|
||||
.handler = integrator_timer_interrupt,
|
||||
.dev_id = &integrator_clockevent,
|
||||
};
|
||||
|
||||
static void integrator_clockevent_init(unsigned long inrate,
|
||||
void __iomem *base, int irq)
|
||||
{
|
||||
unsigned long rate = inrate;
|
||||
unsigned int ctrl = 0;
|
||||
|
||||
clkevt_base = base;
|
||||
/* Calculate and program a divisor */
|
||||
if (rate > 0x100000 * HZ) {
|
||||
rate /= 256;
|
||||
ctrl |= TIMER_CTRL_DIV256;
|
||||
} else if (rate > 0x10000 * HZ) {
|
||||
rate /= 16;
|
||||
ctrl |= TIMER_CTRL_DIV16;
|
||||
}
|
||||
timer_reload = rate / HZ;
|
||||
writel(ctrl, clkevt_base + TIMER_CTRL);
|
||||
|
||||
setup_irq(irq, &integrator_timer_irq);
|
||||
clockevents_config_and_register(&integrator_clockevent,
|
||||
rate,
|
||||
1,
|
||||
0xffffU);
|
||||
}
|
||||
|
||||
static void __init integrator_ap_timer_init_of(struct device_node *node)
|
||||
{
|
||||
const char *path;
|
||||
void __iomem *base;
|
||||
int err;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
unsigned long rate;
|
||||
struct device_node *pri_node;
|
||||
struct device_node *sec_node;
|
||||
|
||||
base = of_io_request_and_map(node, 0, "integrator-timer");
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
clk = of_clk_get(node, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("No clock for %s\n", node->name);
|
||||
return;
|
||||
}
|
||||
clk_prepare_enable(clk);
|
||||
rate = clk_get_rate(clk);
|
||||
writel(0, base + TIMER_CTRL);
|
||||
|
||||
err = of_property_read_string(of_aliases,
|
||||
"arm,timer-primary", &path);
|
||||
if (WARN_ON(err))
|
||||
return;
|
||||
pri_node = of_find_node_by_path(path);
|
||||
err = of_property_read_string(of_aliases,
|
||||
"arm,timer-secondary", &path);
|
||||
if (WARN_ON(err))
|
||||
return;
|
||||
sec_node = of_find_node_by_path(path);
|
||||
|
||||
if (node == pri_node) {
|
||||
/* The primary timer lacks IRQ, use as clocksource */
|
||||
integrator_clocksource_init(rate, base);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node == sec_node) {
|
||||
/* The secondary timer will drive the clock event */
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
integrator_clockevent_init(rate, base, irq);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("Timer @%p unused\n", base);
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
|
||||
integrator_ap_timer_init_of);
|
Fai riferimento in un nuovo problema
Block a user