1/*
2 * Copyright 2006, Broadcom Corporation
3 * All Rights Reserved.
4 *
5 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
9 *
10 * $Id: time.c,v 1.1.1.1 2008/10/15 03:26:06 james26_jang Exp $
11 */
12#include <linux/config.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <linux/serial_reg.h>
17#include <linux/interrupt.h>
18#include <asm/addrspace.h>
19#include <asm/io.h>
20#include <asm/time.h>
21
22#include <typedefs.h>
23#include <osl.h>
24#include <bcmutils.h>
25#include <bcmnvram.h>
26#include <sbconfig.h>
27#include <sbextif.h>
28#include <sbchipc.h>
29#include <sbutils.h>
30#include <hndmips.h>
31#include <mipsinc.h>
32#include <hndcpu.h>
33#include <bcmdevs.h>
34
35/* Global SB handle */
36extern void *bcm947xx_sbh;
37extern spinlock_t bcm947xx_sbh_lock;
38
39/* Convenience */
40#define sbh bcm947xx_sbh
41#define sbh_lock bcm947xx_sbh_lock
42
43extern int panic_timeout;
44static int watchdog = 0;
45static u8 *mcr = NULL;
46
47void __init
48bcm947xx_time_init(void)
49{
50	unsigned int hz;
51	extifregs_t *eir;
52
53	/*
54	 * Use deterministic values for initial counter interrupt
55	 * so that calibrate delay avoids encountering a counter wrap.
56	 */
57	write_c0_count(0);
58	write_c0_compare(0xffff);
59
60	if (!(hz = sb_cpu_clock(sbh)))
61		hz = 100000000;
62
63	printk("CPU: BCM%04x rev %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh),
64	       (hz + 500000) / 1000000);
65
66	/* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
67	mips_counter_frequency = hz / 2;
68
69	/* Set watchdog interval in ms */
70	watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0);
71
72	/* Please set the watchdog to 3 sec if it is less than 3 but not equal to 0 */
73	if (watchdog > 0) {
74		if (watchdog < 3000)
75			watchdog = 3000;
76	}
77
78	/* Set panic timeout in seconds */
79	panic_timeout = watchdog / 1000;
80
81	/* Setup blink */
82	if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
83		sbconfig_t *sb = (sbconfig_t *)((unsigned int) eir + SBCONFIGOFF);
84		unsigned long base = EXTIF_CFGIF_BASE(sb_base(readl(&sb->sbadmatch1)));
85		mcr = (u8 *) ioremap_nocache(base + UART_MCR, 1);
86	}
87}
88
89#ifdef CONFIG_HND_BMIPS3300_PROF
90extern bool hndprofiling;
91#ifdef CONFIG_MIPS64
92typedef u_int64_t sbprof_pc;
93#else
94typedef u_int32_t sbprof_pc;
95#endif
96extern void sbprof_cpu_intr(sbprof_pc restartpc);
97#endif	/* CONFIG_HND_BMIPS3300_PROF */
98
99static void
100bcm947xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
101{
102#ifdef CONFIG_HND_BMIPS3300_PROF
103	/*
104	 * Are there any ExcCode or other mean(s) to determine what has caused
105	 * the timer interrupt? For now simply stop the normal timer proc if
106	 * count register is less than compare register.
107	 */
108	if (hndprofiling) {
109		sbprof_cpu_intr(regs->cp0_epc +
110		                ((regs->cp0_cause >> (CAUSEB_BD - 2)) & 4));
111		if (read_c0_count() < read_c0_compare())
112			return;
113	}
114#endif	/* CONFIG_HND_BMIPS3300_PROF */
115
116	/* Generic MIPS timer code */
117	timer_interrupt(irq, dev_id, regs);
118
119	/* Set the watchdog timer to reset after the specified number of ms */
120	if (watchdog > 0) {
121		if (sb_chip(sbh) == BCM5354_CHIP_ID)
122			sb_watchdog(sbh, WATCHDOG_CLOCK_5354 / 1000 * watchdog);
123		else
124			sb_watchdog(sbh, WATCHDOG_CLOCK / 1000 * watchdog);
125	}
126
127#ifdef	CONFIG_HWSIM
128	(*((int *)0xa0000f1c))++;
129#else
130	/* Blink one of the LEDs in the external UART */
131	if (mcr && !(jiffies % (HZ/2)))
132		writeb(readb(mcr) ^ UART_MCR_OUT2, mcr);
133#endif
134}
135
136static struct irqaction bcm947xx_timer_irqaction = {
137	bcm947xx_timer_interrupt,
138	SA_INTERRUPT,
139	0,
140	"timer",
141	NULL,
142	NULL
143};
144
145void __init
146bcm947xx_timer_setup(struct irqaction *irq)
147{
148	/* Enable the timer interrupt */
149	setup_irq(7, &bcm947xx_timer_irqaction);
150}
151
152#define CFE_UPDATE 1            // added by Chen-I for mac/regulation update
153
154#ifdef CFE_UPDATE
155void bcm947xx_watchdog_disable(void)
156{
157        watchdog=0;
158        sb_watchdog(sbh, 0);
159}
160#endif
161
162