add clock, earlycon

This commit is contained in:
haru 2022-06-30 19:18:23 +09:00
parent f3080542ae
commit 5605892411
7 changed files with 339 additions and 17 deletions

View File

@ -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>;
}; };

View File

@ -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.

View File

@ -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,
}, },

View File

@ -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

View File

@ -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

View 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);

View 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);