add clock, earlycon
This commit is contained in:
parent
f3080542ae
commit
5605892411
@ -7,8 +7,12 @@
|
|||||||
model = "Cavium Celestial CNC1800L";
|
model = "Cavium Celestial CNC1800L";
|
||||||
compatible = "cavium,cnc1800l";
|
compatible = "cavium,cnc1800l";
|
||||||
|
|
||||||
|
aliases {
|
||||||
|
serial0 = &uart0;
|
||||||
|
};
|
||||||
|
|
||||||
chosen {
|
chosen {
|
||||||
stdout-path = "/uart@801f1000:115200";
|
stdout-path = "serial0:115200n8";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -24,7 +28,6 @@
|
|||||||
cpu {
|
cpu {
|
||||||
compatible = "arm,arm1176jzf";
|
compatible = "arm,arm1176jzf";
|
||||||
device_type = "cpu";
|
device_type = "cpu";
|
||||||
// clocks = <&timer0>;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,29 +52,31 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
timer0: timer@801e2000 {
|
timer0: timer@801e2000 {
|
||||||
compatible = "snps,dw-apb-timer";
|
compatible = "snps,dw-apb-timer-cnc1800l";
|
||||||
interrupts = <10>;
|
|
||||||
reg = <0x801e2000 0x100>;
|
reg = <0x801e2000 0x100>;
|
||||||
clocks = <&timclk>, <&pclk>;
|
clocks = <&pclk>;
|
||||||
clock-names = "timer", "pclk";
|
};
|
||||||
// clock-frequency = <94500000>;
|
|
||||||
// #clock-cells = <1>;
|
timer1: timer@80270000 {
|
||||||
|
compatible = "cavium,cnc1800l-timer";
|
||||||
|
reg = <0x80270000 0x100>;
|
||||||
|
clocks = <&timclk>;
|
||||||
|
interrupts = <4>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
watchdog0: wd@801e1000 {
|
watchdog0: wd@801e1000 {
|
||||||
compatible = "snps,dw-wdt";
|
compatible = "snps,dw-wdt";
|
||||||
reg = <0x801e1000 0x100>;
|
reg = <0x801e1000 0x100>;
|
||||||
interrupts = <0>;
|
interrupts = <0>;
|
||||||
clocks = <&pclk>;
|
clocks = <&pclk>;
|
||||||
// resets = <&rst WDT0_RESET>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
uart0: uart@801f1000 {
|
uart0: serial@801f1000 {
|
||||||
compatible = "ns8250";
|
compatible = "snps,dw-apb-uart";
|
||||||
reg = <0x801f1000 0x100>;
|
reg = <0x801f1000 0x100>;
|
||||||
clock-frequency = <47250000>;
|
reg-io-width = <1>;
|
||||||
|
clocks = <&pclk>;
|
||||||
interrupts = <12>;
|
interrupts = <12>;
|
||||||
reg-shift = <2>;
|
reg-shift = <2>;
|
||||||
};
|
};
|
||||||
|
@ -2,9 +2,9 @@ config MACH_CELESTIAL
|
|||||||
bool "Celestial CNC1800L"
|
bool "Celestial CNC1800L"
|
||||||
depends on ARCH_MULTI_V6
|
depends on ARCH_MULTI_V6
|
||||||
select DW_APB_ICTL
|
select DW_APB_ICTL
|
||||||
select DW_APB_TIMER
|
|
||||||
select DW_APB_TIMER_OF
|
|
||||||
select SERIAL_8250
|
select SERIAL_8250
|
||||||
select SERIAL_8250_CONSOLE
|
select SERIAL_8250_CONSOLE
|
||||||
|
select CNC1800L_TIMER
|
||||||
|
select CNC1800L_APBTIMER
|
||||||
help
|
help
|
||||||
Support for Cavium CNC1800L Soc.
|
Support for Cavium CNC1800L Soc.
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
#define CNC1800L_VIRT_UART0 0xfec00000
|
#define CNC1800L_VIRT_UART0 0xfec00000
|
||||||
|
|
||||||
static struct map_desc cnc1800l_of_io_desc[] __initdata = {
|
static struct map_desc cnc1800l_of_io_desc[] __initdata = {
|
||||||
#ifdef CONFIG_DEBUG_UART_8250
|
#ifdef CONFIG_DEBUG_CELESTIAL_UART
|
||||||
{
|
{
|
||||||
.virtual = CNC1800L_VIRT_UART0,
|
.virtual = CNC1800L_VIRT_UART0,
|
||||||
.pfn = __phys_to_pfn(CNC1800L_VIRT_UART0),
|
.pfn = __phys_to_pfn(0x801f1000),
|
||||||
.length = SZ_4K,
|
.length = SZ_4K,
|
||||||
.type = MT_DEVICE,
|
.type = MT_DEVICE,
|
||||||
},
|
},
|
||||||
|
@ -178,6 +178,21 @@ config ASM9260_TIMER
|
|||||||
help
|
help
|
||||||
Enables support for the ASM9260 timer.
|
Enables support for the ASM9260 timer.
|
||||||
|
|
||||||
|
config CNC1800L_TIMER
|
||||||
|
bool "CNC1800L timer driver" if COMPILE_TEST
|
||||||
|
select CLKSRC_MMIO
|
||||||
|
select TIMER_OF
|
||||||
|
help
|
||||||
|
Enables support for the CNC1800L timer.
|
||||||
|
|
||||||
|
config CNC1800L_APBTIMER
|
||||||
|
bool "CNC1800L Synopsys APB timer driver" if COMPILE_TEST
|
||||||
|
select CLKSRC_MMIO
|
||||||
|
select TIMER_OF
|
||||||
|
help
|
||||||
|
Enables support for the CNC1800L APB timer.
|
||||||
|
|
||||||
|
|
||||||
config CLKSRC_NOMADIK_MTU
|
config CLKSRC_NOMADIK_MTU
|
||||||
bool "Nomakdik clocksource driver" if COMPILE_TEST
|
bool "Nomakdik clocksource driver" if COMPILE_TEST
|
||||||
depends on ARM
|
depends on ARM
|
||||||
|
@ -58,6 +58,9 @@ obj-$(CONFIG_MILBEAUT_TIMER) += timer-milbeaut.o
|
|||||||
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
|
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
|
||||||
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
|
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
|
||||||
obj-$(CONFIG_RDA_TIMER) += timer-rda.o
|
obj-$(CONFIG_RDA_TIMER) += timer-rda.o
|
||||||
|
obj-$(CONFIG_CNC1800L_TIMER) += cnc1800l_timer.o
|
||||||
|
obj-$(CONFIG_CNC1800L_APBTIMER) += cnc1800l_apbtimer.o
|
||||||
|
|
||||||
|
|
||||||
obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
|
obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
|
||||||
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
|
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
|
||||||
|
121
drivers/clocksource/cnc1800l_apbtimer.c
Normal file
121
drivers/clocksource/cnc1800l_apbtimer.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/clocksource.h>
|
||||||
|
#include <linux/clockchips.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* arch/arm/mach-celestial/include/mach/time.h
|
||||||
|
*
|
||||||
|
* This file contains the hardware definitions of the Celestial Platform.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Celestial Semiconductor
|
||||||
|
* Copyright (C) 2011 Cavium
|
||||||
|
|
||||||
|
* Author: Xaodong Fan <xiaodong.fan@caviumneworks.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define APB_TIMER_1_LOADCOUNT 0
|
||||||
|
#define APB_TIMER_1_CUR_VAL 0x04
|
||||||
|
#define APB_TIMER_1_CTRL 0x08
|
||||||
|
#define APB_TIMER_1_EOI 0x0c
|
||||||
|
#define APB_TIMER_1_INT_STATUS 0x10
|
||||||
|
|
||||||
|
#define APB_TIMER_2_LOADCOUNT 0x14
|
||||||
|
#define APB_TIMER_2_CUR_VAL 0x18
|
||||||
|
#define APB_TIMER_2_CTRL 0x1C
|
||||||
|
#define APB_TIMER_2_EOI 0x20
|
||||||
|
#define APB_TIMER_2_INT_STATUS 0x24
|
||||||
|
|
||||||
|
#define APB_TIMERS_INT_STATUS 0xA0
|
||||||
|
#define APB_TIMERS_EOI 0xA4
|
||||||
|
#define APB_TIMERS_RAW_INT_STATUS 0xA8
|
||||||
|
|
||||||
|
|
||||||
|
#define APB_TIMER_CTL_ENABLE (1 <<0)
|
||||||
|
#define APB_TIMER_CTL_PERIODIC (1<<1)
|
||||||
|
#define APB_TIMER_CTL_INTMASK (1<<2)
|
||||||
|
|
||||||
|
|
||||||
|
static void __iomem *cncat_base;
|
||||||
|
|
||||||
|
static u64 cnc1800l_apbtimer_read(struct clocksource *cs){
|
||||||
|
volatile unsigned int timeval_high,timeval_high2, timeval;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
raw_local_irq_save(flags);
|
||||||
|
timeval_high = readw(cncat_base + APB_TIMER_1_CUR_VAL + 2);
|
||||||
|
timeval = readw(cncat_base + APB_TIMER_1_CUR_VAL);
|
||||||
|
timeval_high2 = readw(cncat_base + APB_TIMER_1_CUR_VAL + 2);
|
||||||
|
if(timeval_high2 != timeval_high){
|
||||||
|
timeval = timeval_high2 << 16 | readw(cncat_base + APB_TIMER_1_CUR_VAL);
|
||||||
|
}else{
|
||||||
|
timeval = timeval_high << 16 | timeval;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_local_irq_restore(flags);
|
||||||
|
|
||||||
|
return ((u32)0xffffffff - timeval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clocksource cnc1800l_clksrc = {
|
||||||
|
.name = "cnc_clocksource",
|
||||||
|
.shift = 27,
|
||||||
|
.rating = 300,
|
||||||
|
.read = cnc1800l_apbtimer_read,
|
||||||
|
.mask = CLOCKSOURCE_MASK(32),
|
||||||
|
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init cnc1800l_apbtimer_init(struct device_node *np)
|
||||||
|
{
|
||||||
|
struct clk *clk;
|
||||||
|
int ret;
|
||||||
|
unsigned long rate,u;
|
||||||
|
|
||||||
|
cncat_base = of_io_request_and_map(np, 0, np->name);
|
||||||
|
if (IS_ERR(cncat_base)) {
|
||||||
|
pr_err("%pOFn: unable to map resource\n", np);
|
||||||
|
return PTR_ERR(cncat_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
clk = of_clk_get(np, 0);
|
||||||
|
if (IS_ERR(clk)) {
|
||||||
|
pr_err("Failed to get clk!\n");
|
||||||
|
return PTR_ERR(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(clk);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to enable clk!\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
rate = clk_get_rate(clk);
|
||||||
|
|
||||||
|
writel_relaxed(u & (~APB_TIMER_CTL_ENABLE),cncat_base + APB_TIMER_1_CTRL);
|
||||||
|
writew_relaxed(0xffff,cncat_base + APB_TIMER_1_LOADCOUNT);
|
||||||
|
writew_relaxed(0xffff,cncat_base + APB_TIMER_1_LOADCOUNT + 2);
|
||||||
|
|
||||||
|
u = readl(cncat_base + APB_TIMER_1_CTRL);
|
||||||
|
writel_relaxed((u | APB_TIMER_CTL_INTMASK) & (~APB_TIMER_CTL_PERIODIC),cncat_base + APB_TIMER_1_CTRL);
|
||||||
|
|
||||||
|
clocksource_register_hz(&cnc1800l_clksrc,rate);
|
||||||
|
|
||||||
|
u = readl(cncat_base + APB_TIMER_1_CTRL);
|
||||||
|
writel_relaxed(u | APB_TIMER_CTL_ENABLE | APB_TIMER_CTL_INTMASK | APB_TIMER_CTL_PERIODIC, cncat_base + APB_TIMER_1_CTRL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
TIMER_OF_DECLARE(cnc1800l_apbtimer, "snps,dw-apb-timer-cnc1800l", cnc1800l_apbtimer_init);
|
178
drivers/clocksource/cnc1800l_timer.c
Normal file
178
drivers/clocksource/cnc1800l_timer.c
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/clocksource.h>
|
||||||
|
#include <linux/clockchips.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* arch/arm/mach-celestial/include/mach/time.h
|
||||||
|
*
|
||||||
|
* This file contains the hardware definitions of the Celestial Platform.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Celestial Semiconductor
|
||||||
|
* Copyright (C) 2011 Cavium
|
||||||
|
|
||||||
|
* Author: Xaodong Fan <xiaodong.fan@caviumneworks.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define TIMER_PRE_LOAD_0 0x0
|
||||||
|
#define TIMER_PRE_LOAD_1 0x4
|
||||||
|
#define TIMER_THRESHOLD_0 0x8
|
||||||
|
#define TIMER_THRESHOLD_1 0xc
|
||||||
|
#define TIMER_MODE 0x10
|
||||||
|
#define TIMER_INTR_EN 0x14
|
||||||
|
#define TIMER_INTR_CLR 0x18
|
||||||
|
#define TIMER_ENABLE 0x1c
|
||||||
|
#define TIMER_CURRENT_VAL_0 0x20
|
||||||
|
#define TIMER_CURRENT_VAL_1 0x24
|
||||||
|
#define TIMER_INTR_STATUS 0x28
|
||||||
|
#define TIMER_INTR_RAW_STATUS 0x2c
|
||||||
|
|
||||||
|
static void __iomem *cnct_base;
|
||||||
|
static unsigned long cnct_reload;
|
||||||
|
|
||||||
|
static int cnc1800l_timer_set_next_event(unsigned long delta,
|
||||||
|
struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
if(delta == 0){
|
||||||
|
return -ETIME;
|
||||||
|
}
|
||||||
|
raw_local_irq_save(flags);
|
||||||
|
|
||||||
|
writel_relaxed(0,cnct_base + TIMER_ENABLE);
|
||||||
|
writel_relaxed(0x7,cnct_base +TIMER_INTR_CLR);
|
||||||
|
writel_relaxed(0x0,cnct_base +TIMER_INTR_CLR);
|
||||||
|
|
||||||
|
writel_relaxed(delta,cnct_base + TIMER_THRESHOLD_0);
|
||||||
|
writel_relaxed(0,cnct_base + TIMER_PRE_LOAD_0);
|
||||||
|
|
||||||
|
writel_relaxed(0x1,cnct_base + TIMER_MODE);
|
||||||
|
writel_relaxed(0x1,cnct_base + TIMER_INTR_EN);
|
||||||
|
writel_relaxed(0x1,cnct_base + TIMER_ENABLE);
|
||||||
|
|
||||||
|
raw_local_irq_restore(flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cnc1800l_timer_shutdown(struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
writel_relaxed(0x0, cnct_base + TIMER_ENABLE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cnc1800l_timer_set_periodic(struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
raw_local_irq_save(flags);
|
||||||
|
|
||||||
|
writel_relaxed(0,cnct_base + TIMER_ENABLE);
|
||||||
|
writel_relaxed(cnct_reload,cnct_base + TIMER_THRESHOLD_0);
|
||||||
|
writel_relaxed(0,cnct_base + TIMER_PRE_LOAD_0);
|
||||||
|
writel_relaxed(0,cnct_base + TIMER_MODE);
|
||||||
|
writel_relaxed(0x1,cnct_base + TIMER_INTR_EN);
|
||||||
|
writel_relaxed(0x1,cnct_base + TIMER_ENABLE);
|
||||||
|
|
||||||
|
raw_local_irq_restore(flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cnc1800l_timer_set_oneshot(struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
raw_local_irq_save(flags);
|
||||||
|
|
||||||
|
writel_relaxed(0x7, cnct_base + TIMER_INTR_CLR);
|
||||||
|
writel_relaxed(0x0, cnct_base + TIMER_INTR_CLR);
|
||||||
|
writel_relaxed(0x0,cnct_base + TIMER_ENABLE);
|
||||||
|
|
||||||
|
raw_local_irq_restore(flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct clock_event_device event_dev = {
|
||||||
|
.name = "cnc1800l-timer",
|
||||||
|
.rating = 400,
|
||||||
|
.features = CLOCK_EVT_FEAT_PERIODIC |
|
||||||
|
CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
.shift = 32,
|
||||||
|
.set_next_event = cnc1800l_timer_set_next_event,
|
||||||
|
.set_state_shutdown = cnc1800l_timer_shutdown,
|
||||||
|
.set_state_periodic = cnc1800l_timer_set_periodic,
|
||||||
|
.set_state_oneshot = cnc1800l_timer_set_oneshot,
|
||||||
|
.tick_resume = cnc1800l_timer_shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
|
static irqreturn_t cnc1800l_timer_interrupt(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct clock_event_device *evt = dev_id;
|
||||||
|
|
||||||
|
writel_relaxed(0x1,cnct_base + TIMER_INTR_CLR);
|
||||||
|
writel_relaxed(0x0,cnct_base + TIMER_INTR_CLR);
|
||||||
|
|
||||||
|
evt->event_handler(evt);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init cnc1800l_timer_init(struct device_node *np)
|
||||||
|
{
|
||||||
|
int irq;
|
||||||
|
struct clk *clk;
|
||||||
|
int ret;
|
||||||
|
unsigned long rate;
|
||||||
|
|
||||||
|
cnct_base = of_io_request_and_map(np, 0, np->name);
|
||||||
|
if (IS_ERR(cnct_base)) {
|
||||||
|
pr_err("%pOFn: unable to map resource\n", np);
|
||||||
|
return PTR_ERR(cnct_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
clk = of_clk_get(np, 0);
|
||||||
|
if (IS_ERR(clk)) {
|
||||||
|
pr_err("Failed to get clk!\n");
|
||||||
|
return PTR_ERR(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(clk);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to enable clk!\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq = irq_of_parse_and_map(np, 0);
|
||||||
|
ret = request_irq(irq, cnc1800l_timer_interrupt, IRQF_TIMER,
|
||||||
|
"cnc1800l-timer", &event_dev);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to setup irq!\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel_relaxed(0x0,cnct_base + TIMER_INTR_EN);
|
||||||
|
writel_relaxed(0x0,cnct_base + TIMER_ENABLE);
|
||||||
|
writel_relaxed(0x1,cnct_base + TIMER_INTR_CLR);
|
||||||
|
writel_relaxed(0x0,cnct_base + TIMER_INTR_CLR);
|
||||||
|
|
||||||
|
rate = clk_get_rate(clk);
|
||||||
|
|
||||||
|
cnct_reload = DIV_ROUND_CLOSEST(rate,HZ);
|
||||||
|
|
||||||
|
event_dev.cpumask = cpumask_of(0);
|
||||||
|
clockevents_config_and_register(&event_dev, rate, 0xf, 0xfffffffc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
TIMER_OF_DECLARE(cnc1800l_timer, "cavium,cnc1800l-timer",
|
||||||
|
cnc1800l_timer_init);
|
Loading…
x
Reference in New Issue
Block a user