diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/boot/dts/hi3620.dtsi | 168 | ||||
-rw-r--r-- | arch/arm/boot/dts/hi4511.dts | 41 | ||||
-rw-r--r-- | arch/arm/common/timer-sp.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/smp_twd.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-hs/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-hs/hs-dt.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-hs/localtimer.c | 252 | ||||
-rw-r--r-- | arch/arm/mm/init.c | 1 |
8 files changed, 435 insertions, 84 deletions
diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi index d27827d8d496..b243ff097b66 100644 --- a/arch/arm/boot/dts/hi3620.dtsi +++ b/arch/arm/boot/dts/hi3620.dtsi @@ -17,6 +17,81 @@ serial1 = &uart1; }; + intc: interrupt-controller@fc001000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + /* gic dist base, gic cpu base */ + reg = <0xfc001000 0x1000>, <0xfc000100 0x100>; + }; + + sysctrl@fc802000 { + compatible = "hisilicon,sysctrl"; + reg = <0xfc802000 0x1000>; + smp_reg = <0x31c>; + reboot_reg = <0x4>; + }; + + l2: l2-cache { + compatible = "arm,pl310-cache"; + reg = <0xfc100000 0x100000>; + interrupts = <0 15 4>; + cache-unified; + cache-level = <2>; + hisilicon,l2cache-aux = <0x30070000 0xf00f0000>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + device_type = "soc"; + interrupt-parent = <&intc>; + ranges; + + i2c0: i2c@fcb08000 { + compatible = "hisilicon,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfcb08000 0x1000>; + interrupts = <0 28 4>; + clocks = <&clk_i2c0>; + dmas = <&dma0 18 /* read channel */ + &dma0 19>; /* write channel */ + dma-names = "rx", "tx"; + status = "disabled"; + }; + + i2c1: i2c@fcb09000 { + compatible = "hisilicon,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfcb09000 0x1000>; + interrupts = <0 29 4>; + clocks = <&clk_i2c1>; + dmas = <&dma0 20 /* read channel */ + &dma0 21>; /* write channel */ + dma-names = "rx", "tx"; + status = "disabled"; + }; + + i2c2: i2c@fcb0c000 { + compatible = "hisilicon,designware-i2c"; + reg = <0xfcb0c000 0x1000>; + interrupts = <0 62 4>; + clocks = <&clk_i2c2>; + status = "disabled"; + }; + + i2c3: i2c@fcb0d000 { + compatible = "hisilicon,designware-i2c"; + reg = <0xfcb0d000 0x1000>; + interrupts = <0 63 4>; + clocks = <&clk_i2c3>; + status = "disabled"; + }; + amba { #address-cells = <1>; #size-cells = <1>; @@ -24,6 +99,14 @@ interrupt-parent = <&intc>; ranges; + timer@fc000600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xfc000600 0x20>; + interrupts = <1 13 0xf01>; + clocks = <&armpll0>; + //clocks = <&smp_twd>; + }; + pmctrl: pmctrl@fca08000 { compatible = "hisilicon,pmctrl"; reg = <0xfca08000 0x1000>; @@ -84,6 +167,14 @@ clock-frequency = <1600000000>; clock-output-names = "clk_armpll1"; }; + /* + smp_twd: smp_twd{ + compatible = "hisilicon,pll"; + #clock-cells = <0>; + clock-frequency = <1600000000>; + clocks = <&armpll0>; + }; + */ peripll: pll2 { compatible = "hisilicon,pll"; #clock-cells = <0>; @@ -577,23 +668,7 @@ status = "disabled"; }; - l2: l2-cache { - compatible = "arm,pl310-cache"; - reg = <0xfc100000 0x100000>; - interrupts = <0 15 4>; - cache-unified; - cache-level = <2>; - hisilicon,l2cache-aux = <0x30070000 0xf00f0000>; - }; - intc: interrupt-controller@fc001000 { - compatible = "arm,cortex-a9-gic"; - #interrupt-cells = <3>; - #address-cells = <0>; - interrupt-controller; - /* gic dist base, gic cpu base */ - reg = <0xfc001000 0x1000>, <0xfc000100 0x100>; - }; timer0: timer@fc800000 { compatible = "arm,sp804", "arm,primecell"; @@ -620,6 +695,19 @@ status = "disabled"; }; + localtimer: localtimer@fca01000 { + compatible = "hisilicon,local-timer"; + reg = <0xfc800000 0x0020>, /* timer00 */ + <0xfca01000 0x0020>, /* timer20 */ + <0xfca01020 0x0040>, /* timer21 */ + <0xfca02000 0x0020>; /* timer30 */ + /* timer20 & timer21 */ + interrupts = <0 0 4>, /* timer00 */ + <0 4 4>, /* timer20 */ + <0 5 4>, /* timer21 */ + <0 6 4>; /* timer30 */ + }; + timer2: timer@fca01000 { compatible = "arm,sp804", "arm,primecell"; reg = <0xfca01000 0x1000>; @@ -1072,12 +1160,6 @@ pinctrl-single,register-width = <32>; }; - sysctrl@fc802000 { - compatible = "hisilicon,sysctrl"; - reg = <0xfc802000 0x1000>; - smp_reg = <0x31c>; - reboot_reg = <0x4>; - }; dma0: dma@fcd02000 { compatible = "hisilicon,k3-dma-1.0"; @@ -1089,46 +1171,6 @@ status = "disable"; }; - i2c0: i2c@fcb08000 { - compatible = "hisilicon,designware-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0xfcb08000 0x1000>; - interrupts = <0 28 4>; - clocks = <&clk_i2c0>; - dmas = <&dma0 18 /* read channel */ - &dma0 19>; /* write channel */ - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2c1: i2c@fcb09000 { - compatible = "hisilicon,designware-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0xfcb09000 0x1000>; - interrupts = <0 29 4>; - clocks = <&clk_i2c1>; - dmas = <&dma0 20 /* read channel */ - &dma0 21>; /* write channel */ - dma-names = "rx", "tx"; - status = "disabled"; - }; - - i2c2: i2c@fcb0c000 { - compatible = "hisilicon,designware-i2c"; - reg = <0xfcb0c000 0x1000>; - interrupts = <0 62 4>; - clocks = <&clk_i2c2>; - status = "disabled"; - }; - - i2c3: i2c@fcb0d000 { - compatible = "hisilicon,designware-i2c"; - reg = <0xfcb0d000 0x1000>; - interrupts = <0 63 4>; - clocks = <&clk_i2c3>; - status = "disabled"; - }; + }; }; }; diff --git a/arch/arm/boot/dts/hi4511.dts b/arch/arm/boot/dts/hi4511.dts index 70a5c45bd8ee..46a6f5e3cc24 100644 --- a/arch/arm/boot/dts/hi4511.dts +++ b/arch/arm/boot/dts/hi4511.dts @@ -54,7 +54,28 @@ memory { reg = <0x00000000 0x20000000>; }; + + + soc { + i2c0: i2c@fcb08000 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>; + i2c_test: i2c_test@58 { + compatible = "hs,i2c_test_tpa2028"; + reg = <0x58>; + }; + }; + i2c1: i2c@fcb09000 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pmx_func &i2c1_cfg_func>; + bq24161: charger@6b { + compatible = "hs,i2c_test_bq24161"; + reg = <0x6b>; + }; + }; amba { timer0: timer@fc800000 { status = "ok"; @@ -810,25 +831,6 @@ }; }; - i2c0: i2c@fcb08000 { - status = "ok"; - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>; - i2c_test: i2c_test@58 { - compatible = "hs,i2c_test_tpa2028"; - reg = <0x58>; - }; - }; - - i2c1: i2c@fcb09000 { - status = "ok"; - pinctrl-names = "default"; - pinctrl-0 = <&i2c1_pmx_func &i2c1_cfg_func>; - bq24161: charger@6b { - compatible = "hs,i2c_test_bq24161"; - reg = <0x6b>; - }; - }; regulators { compatible = "hisilicon,hi6421-pmic"; @@ -1325,4 +1327,5 @@ }; }; /* end of regulators */ }; /* end of amba */ + }; }; diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 9d2d3ba339ff..44af4f670c4d 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -34,6 +34,7 @@ static long __init sp804_get_clock_rate(const char *name) struct clk *clk; long rate; int err; + printk("gzf %s\n", __func__); clk = clk_get_sys("sp804", name); if (IS_ERR(clk)) { diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 49f335d301ba..6821abfebba7 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -244,6 +244,8 @@ static struct clk *twd_get_clock(void) struct clk *clk; int err; + printk("gzf %s\n", __func__); + clk = clk_get_sys("smp_twd", NULL); if (IS_ERR(clk)) { pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk)); @@ -404,7 +406,7 @@ void __init twd_local_timer_of_register(void) err = -ENOMEM; goto out; } - + printk("gzf %s, twd_ppd=%d, twd_base=0x%x\n", __func__, twd_ppi, twd_base); err = twd_local_timer_common_register(); out: diff --git a/arch/arm/mach-hs/Makefile b/arch/arm/mach-hs/Makefile index 56bd1be58d20..0a942cbcb977 100644 --- a/arch/arm/mach-hs/Makefile +++ b/arch/arm/mach-hs/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_MACH_HS_DT) += hs-dt.o -obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_SMP) += platsmp.o #localtimer.o diff --git a/arch/arm/mach-hs/hs-dt.c b/arch/arm/mach-hs/hs-dt.c index 8394a26dc5c5..e9f46433da05 100644 --- a/arch/arm/mach-hs/hs-dt.c +++ b/arch/arm/mach-hs/hs-dt.c @@ -26,6 +26,7 @@ #include <asm/mach/time.h> #include <asm/smp_plat.h> #include <asm/proc-fns.h> +#include <asm/smp_twd.h> static void __iomem *hs_sctrl_base; static int hs_smp_reg; @@ -35,12 +36,19 @@ static void __init hs_map_io(void) { struct device_node *np; + printk("gzf %s\n", __func__); np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); hs_sctrl_base = of_iomap(np, 0); of_property_read_u32(np, "smp_reg", &hs_smp_reg); of_property_read_u32(np, "reset_reg", &hs_reset_reg); } +void __init kirkwood_init_early(void) +{ + printk("gzf %s\n", __func__); +// hs_map_io(); +} + void hs_set_cpu_jump(int cpu, void *jump_addr) { int offset = hs_smp_reg; @@ -51,6 +59,25 @@ void hs_set_cpu_jump(int cpu, void *jump_addr) writel(virt_to_phys(jump_addr), hs_sctrl_base + offset); } +/* enable timer bit */ +#define TIMER2_ENABLE_BIT 1<<3 +#define TIMER3_ENABLE_BIT 1<<4 + +void local_timer_clkenable(int cpu) +{ + unsigned long ctrl=0; + + if((cpu == 1)||(cpu == 2)){ + //BIT MAP, only bit 1 take effect. + ctrl = TIMER2_ENABLE_BIT; + writel(ctrl,(hs_sctrl_base+0x40)); + } + else if(cpu == 3){ + ctrl = TIMER3_ENABLE_BIT; + writel(ctrl,(hs_sctrl_base+0x40)); + } +} + static struct of_device_id hs_timer_match[] __initdata = { { .compatible = "arm,sp804", }, {} @@ -61,12 +88,19 @@ static struct clk_lookup sp804_lookup = { .clk = NULL, }; +static struct clk_lookup twd_lookup = { + .dev_id = "smp_twd", + .clk = NULL, +}; + extern void __init hs_init_clocks(void); +extern void __init hs_local_timer_of_register(void); static void __init hs_timer_init(void) { struct device_node *node = NULL; void __iomem *base; int irq; + printk("gzf %s\n", __func__); hs_init_clocks(); @@ -83,11 +117,25 @@ static void __init hs_timer_init(void) irq = irq_of_parse_and_map(node, 0); WARN_ON(!irq); + printk("irq=%d\n", irq); + sp804_lookup.clk = of_clk_get(node, 0); clkdev_add(&sp804_lookup); sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, "timer1"); sp804_clockevents_init(base, irq, "timer0"); + + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-twd-timer"); + if (node) { + twd_lookup.clk = of_clk_get(node, 0); + clkdev_add(&twd_lookup); + twd_local_timer_of_register(); + } + /* + else { + hs_local_timer_of_register(); + } + */ } static struct sys_timer hs_timer = { @@ -109,6 +157,7 @@ static void __init hs_irq_init(void) struct device_node *node; int ret; u32 data[2]; + printk("gzf %s\n", __func__); hs_map_io(); of_irq_init(hs_irq_match); @@ -142,6 +191,7 @@ static const char *hs_compat[] __initdata = { extern struct smp_operations hs_smp_ops; DT_MACHINE_START(HS_DT, "Hisilicon Hi36xx/Hi37xx (Flattened Device Tree)") /* Maintainer: Haojian Zhuang <haojian.zhuang@linaro.org> */ + .init_early = kirkwood_init_early, .smp = smp_ops(hs_smp_ops), .map_io = debug_ll_io_init, .init_irq = hs_irq_init, diff --git a/arch/arm/mach-hs/localtimer.c b/arch/arm/mach-hs/localtimer.c new file mode 100644 index 000000000000..187b198f75fe --- /dev/null +++ b/arch/arm/mach-hs/localtimer.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2012-2013 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/smp.h> +#include <linux/jiffies.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +#include <asm/hardware/timer-sp.h> +#include <asm/localtimer.h> + +static struct device_node *hs_timer_node; +static DEFINE_PER_CPU(bool, percpu_setup_called); +static struct clock_event_device __percpu **lt_evt; + +static long __init sp804_get_clock_rate(const char *name) +{ + struct clk *clk; + long rate; + int err; + + clk = clk_get_sys("sp804", name); + if (IS_ERR(clk)) { + pr_err("sp804: %s clock not found: %d\n", name, + (int)PTR_ERR(clk)); + return PTR_ERR(clk); + } + + err = clk_prepare(clk); + if (err) { + pr_err("sp804: %s clock failed to prepare: %d\n", name, err); + clk_put(clk); + return err; + } + + err = clk_enable(clk); + if (err) { + pr_err("sp804: %s clock failed to enable: %d\n", name, err); + clk_unprepare(clk); + clk_put(clk); + return err; + } + + rate = clk_get_rate(clk); + if (rate < 0) { + pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate); + clk_disable(clk); + clk_unprepare(clk); + clk_put(clk); + } + + return rate; +} + +static void __iomem *clkevt_base; +static unsigned long clkevt_reload; + +/* + * IRQ handler for the timer + */ +static irqreturn_t sp804_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 sp804_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; + + writel(ctrl, clkevt_base + TIMER_CTRL); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(clkevt_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl |= TIMER_CTRL_ONESHOT; + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + break; + } + + writel(ctrl, clkevt_base + TIMER_CTRL); +} + +static int sp804_set_next_event(unsigned long next, + struct clock_event_device *evt) +{ + unsigned long ctrl = readl(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 sp804_clockevent = { + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = sp804_set_mode, + .set_next_event = sp804_set_next_event, + .rating = 300, +}; + +static struct irqaction sp804_timer_irq = { + .name = "timer", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = sp804_timer_interrupt, + .dev_id = &sp804_clockevent, +}; + +void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, + const char *name) +{ + struct clock_event_device *evt = &sp804_clockevent; + long rate = sp804_get_clock_rate(name); + + if (rate < 0) + return; + + clkevt_base = base; + clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ); + evt->name = name; + evt->irq = irq; + evt->cpumask = cpu_possible_mask; + + setup_irq(irq, &sp804_timer_irq); + clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); +} + +static void hs_timer_stop(struct clock_event_device *clk) +{ + //remove_irq + printk("gzf %s, clk->irq=%d\n", __func__, clk->irq); +// hs_set_mode(CLOCK_EVT_MODE_UNUSED, clk); +// disable_percpu_irq(clk->irq); +} + +static unsigned char cpu_name[NR_CPUS][15]; + +/* + * Setup the local clock events for a CPU. + */ +static int __cpuinit hs_timer_setup(struct clock_event_device *clk) +{ + extern void local_timer_clkenable(int cpu); + struct clock_event_device **this_cpu_clk; + int cpu = smp_processor_id(), irq = 0; + void __iomem *base = NULL; + + printk("gzf %s cpu=%d \n", __func__, cpu); + if (cpu == 0) + return 0; + /* + * If the basic setup for this CPU has been done before don't + * bother with the below. + */ + if (per_cpu(percpu_setup_called, cpu)) { + printk("gzf %s already init \n", __func__); + return 0; + } + per_cpu(percpu_setup_called, cpu) = true; + + irq = irq_of_parse_and_map(hs_timer_node, cpu); + if (!irq) + return -EINVAL; + + base = of_iomap(hs_timer_node, cpu); + if (!base) + return -ENOMEM; + + snprintf(&cpu_name[cpu][0], 12, "localtimer%d", cpu); + + printk("base=0x%x, irq=%d, cpu_name[cpu][0]=%s", base, irq, cpu_name[cpu][0]); + clk->name = "local_timer"; + clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_C3STOP; + clk->rating = 350; + clk->set_mode = twd_set_mode; + clk->set_next_event = twd_set_next_event; + clk->irq = irq; + + this_cpu_clk = __this_cpu_ptr(lt_evt); + *this_cpu_clk = clk; + + clockevents_config_and_register(clk, twd_timer_rate, + 0xf, 0xffffffff); + local_timer_clkenable(cpu); + sp804_clockevents_init(base, irq, &cpu_name[cpu][0]); + irq_set_affinity(irq, cpumask_of(cpu)); + return 0; +} + +static struct local_timer_ops hs_lt_ops __cpuinitdata = { + .setup = hs_timer_setup, + .stop = hs_timer_stop, +}; + +#ifdef CONFIG_OF +const static struct of_device_id hs_of_match[] __initconst = { + { .compatible = "hisilicon,local-timer", }, + { }, +}; + +void __init hs_local_timer_of_register(void) +{ + int err; + + printk("gzf %s\n", __func__); + + hs_timer_node = of_find_matching_node(NULL, hs_of_match); + if (!hs_timer_node) + return; + + lt_evt = alloc_percpu(struct clock_event_device *); + if (!lt_evt) + return -ENOMEM; + + err = local_timer_register(&hs_lt_ops); + if (err) { + WARN(err, "hs_local_timer_of_register failed (%d)\n", err); + return; + } +} +#endif diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index ad722f1208a5..ccec7c377a9d 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -600,6 +600,7 @@ void __init mem_init(void) extern u32 itcm_end; #endif + printk("gzf %s\n", __func__); max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; /* this will put all unused low memory onto the freelists */ |