• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-cns3xxx/
1/*
2 * Copyright 1999 - 2003 ARM Limited
3 * Copyright 2000 Deep Blue Solutions Ltd
4 * Copyright 2008 Cavium Networks
5 *
6 * This file is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, Version 2, as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/clockchips.h>
14#include <linux/io.h>
15#include <asm/mach/map.h>
16#include <asm/mach/time.h>
17#include <asm/mach/irq.h>
18#include <asm/hardware/gic.h>
19#include <mach/cns3xxx.h>
20#include "core.h"
21
22static struct map_desc cns3xxx_io_desc[] __initdata = {
23	{
24		.virtual	= CNS3XXX_TC11MP_TWD_BASE_VIRT,
25		.pfn		= __phys_to_pfn(CNS3XXX_TC11MP_TWD_BASE),
26		.length		= SZ_4K,
27		.type		= MT_DEVICE,
28	}, {
29		.virtual	= CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT,
30		.pfn		= __phys_to_pfn(CNS3XXX_TC11MP_GIC_CPU_BASE),
31		.length		= SZ_4K,
32		.type		= MT_DEVICE,
33	}, {
34		.virtual	= CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT,
35		.pfn		= __phys_to_pfn(CNS3XXX_TC11MP_GIC_DIST_BASE),
36		.length		= SZ_4K,
37		.type		= MT_DEVICE,
38	}, {
39		.virtual	= CNS3XXX_TIMER1_2_3_BASE_VIRT,
40		.pfn		= __phys_to_pfn(CNS3XXX_TIMER1_2_3_BASE),
41		.length		= SZ_4K,
42		.type		= MT_DEVICE,
43	}, {
44		.virtual	= CNS3XXX_GPIOA_BASE_VIRT,
45		.pfn		= __phys_to_pfn(CNS3XXX_GPIOA_BASE),
46		.length		= SZ_4K,
47		.type		= MT_DEVICE,
48	}, {
49		.virtual	= CNS3XXX_GPIOB_BASE_VIRT,
50		.pfn		= __phys_to_pfn(CNS3XXX_GPIOB_BASE),
51		.length		= SZ_4K,
52		.type		= MT_DEVICE,
53	}, {
54		.virtual	= CNS3XXX_MISC_BASE_VIRT,
55		.pfn		= __phys_to_pfn(CNS3XXX_MISC_BASE),
56		.length		= SZ_4K,
57		.type		= MT_DEVICE,
58	}, {
59		.virtual	= CNS3XXX_PM_BASE_VIRT,
60		.pfn		= __phys_to_pfn(CNS3XXX_PM_BASE),
61		.length		= SZ_4K,
62		.type		= MT_DEVICE,
63	},
64};
65
66void __init cns3xxx_map_io(void)
67{
68	iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc));
69}
70
71/* used by entry-macro.S */
72void __iomem *gic_cpu_base_addr;
73
74void __init cns3xxx_init_irq(void)
75{
76	gic_cpu_base_addr = __io(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT);
77	gic_dist_init(0, __io(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT), 29);
78	gic_cpu_init(0, gic_cpu_base_addr);
79}
80
81void cns3xxx_power_off(void)
82{
83	u32 __iomem *pm_base = __io(CNS3XXX_PM_BASE_VIRT);
84	u32 clkctrl;
85
86	printk(KERN_INFO "powering system down...\n");
87
88	clkctrl = readl(pm_base + PM_SYS_CLK_CTRL_OFFSET);
89	clkctrl &= 0xfffff1ff;
90	clkctrl |= (0x5 << 9);		/* Hibernate */
91	writel(clkctrl, pm_base + PM_SYS_CLK_CTRL_OFFSET);
92
93}
94
95/*
96 * Timer
97 */
98static void __iomem *cns3xxx_tmr1;
99
100static void cns3xxx_timer_set_mode(enum clock_event_mode mode,
101				   struct clock_event_device *clk)
102{
103	unsigned long ctrl = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
104	int pclk = cns3xxx_cpu_clock() / 8;
105	int reload;
106
107	switch (mode) {
108	case CLOCK_EVT_MODE_PERIODIC:
109		reload = pclk * 20 / (3 * HZ) * 0x25000;
110		writel(reload, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
111		ctrl |= (1 << 0) | (1 << 2) | (1 << 9);
112		break;
113	case CLOCK_EVT_MODE_ONESHOT:
114		/* period set, and timer enabled in 'next_event' hook */
115		ctrl |= (1 << 2) | (1 << 9);
116		break;
117	case CLOCK_EVT_MODE_UNUSED:
118	case CLOCK_EVT_MODE_SHUTDOWN:
119	default:
120		ctrl = 0;
121	}
122
123	writel(ctrl, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
124}
125
126static int cns3xxx_timer_set_next_event(unsigned long evt,
127					struct clock_event_device *unused)
128{
129	unsigned long ctrl = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
130
131	writel(evt, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
132	writel(ctrl | (1 << 0), cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
133
134	return 0;
135}
136
137static struct clock_event_device cns3xxx_tmr1_clockevent = {
138	.name		= "cns3xxx timer1",
139	.shift		= 8,
140	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
141	.set_mode	= cns3xxx_timer_set_mode,
142	.set_next_event	= cns3xxx_timer_set_next_event,
143	.rating		= 350,
144	.cpumask	= cpu_all_mask,
145};
146
147static void __init cns3xxx_clockevents_init(unsigned int timer_irq)
148{
149	cns3xxx_tmr1_clockevent.irq = timer_irq;
150	cns3xxx_tmr1_clockevent.mult =
151		div_sc((cns3xxx_cpu_clock() >> 3) * 1000000, NSEC_PER_SEC,
152		       cns3xxx_tmr1_clockevent.shift);
153	cns3xxx_tmr1_clockevent.max_delta_ns =
154		clockevent_delta2ns(0xffffffff, &cns3xxx_tmr1_clockevent);
155	cns3xxx_tmr1_clockevent.min_delta_ns =
156		clockevent_delta2ns(0xf, &cns3xxx_tmr1_clockevent);
157
158	clockevents_register_device(&cns3xxx_tmr1_clockevent);
159}
160
161/*
162 * IRQ handler for the timer
163 */
164static irqreturn_t cns3xxx_timer_interrupt(int irq, void *dev_id)
165{
166	struct clock_event_device *evt = &cns3xxx_tmr1_clockevent;
167	u32 __iomem *stat = cns3xxx_tmr1 + TIMER1_2_INTERRUPT_STATUS_OFFSET;
168	u32 val;
169
170	/* Clear the interrupt */
171	val = readl(stat);
172	writel(val & ~(1 << 2), stat);
173
174	evt->event_handler(evt);
175
176	return IRQ_HANDLED;
177}
178
179static struct irqaction cns3xxx_timer_irq = {
180	.name		= "timer",
181	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
182	.handler	= cns3xxx_timer_interrupt,
183};
184
185/*
186 * Set up the clock source and clock events devices
187 */
188static void __init __cns3xxx_timer_init(unsigned int timer_irq)
189{
190	u32 val;
191	u32 irq_mask;
192
193	/*
194	 * Initialise to a known state (all timers off)
195	 */
196
197	/* disable timer1 and timer2 */
198	writel(0, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
199	/* stop free running timer3 */
200	writel(0, cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
201
202	/* timer1 */
203	writel(0x5C800, cns3xxx_tmr1 + TIMER1_COUNTER_OFFSET);
204	writel(0x5C800, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
205
206	writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V1_OFFSET);
207	writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V2_OFFSET);
208
209	/* mask irq, non-mask timer1 overflow */
210	irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
211	irq_mask &= ~(1 << 2);
212	irq_mask |= 0x03;
213	writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
214
215	/* down counter */
216	val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
217	val |= (1 << 9);
218	writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
219
220	/* timer2 */
221	writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V1_OFFSET);
222	writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V2_OFFSET);
223
224	/* mask irq */
225	irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
226	irq_mask |= ((1 << 3) | (1 << 4) | (1 << 5));
227	writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
228
229	/* down counter */
230	val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
231	val |= (1 << 10);
232	writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
233
234	/* Make irqs happen for the system timer */
235	setup_irq(timer_irq, &cns3xxx_timer_irq);
236
237	cns3xxx_clockevents_init(timer_irq);
238}
239
240static void __init cns3xxx_timer_init(void)
241{
242	cns3xxx_tmr1 = __io(CNS3XXX_TIMER1_2_3_BASE_VIRT);
243
244	__cns3xxx_timer_init(IRQ_CNS3XXX_TIMER0);
245}
246
247struct sys_timer cns3xxx_timer = {
248	.init = cns3xxx_timer_init,
249};
250