1/* 2 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 * 16 * $Id: time.c,v 1.9 2009-07-17 06:23:12 $ 17 */ 18#include <linux/config.h> 19#include <linux/init.h> 20#include <linux/kernel.h> 21#include <linux/sched.h> 22#include <linux/serial_reg.h> 23#include <linux/interrupt.h> 24#include <asm/addrspace.h> 25#include <asm/io.h> 26#include <asm/time.h> 27 28#include <typedefs.h> 29#include <osl.h> 30#include <bcmutils.h> 31#include <bcmnvram.h> 32#include <hndsoc.h> 33#include <sbchipc.h> 34#include <siutils.h> 35#include <hndmips.h> 36#include <mipsinc.h> 37#include <hndcpu.h> 38#include <bcmdevs.h> 39 40#include <wps_led.h> /* Foxconn added, zacker, 07/04/2009 */ 41/* Global SB handle */ 42extern si_t *bcm947xx_sih; 43extern spinlock_t bcm947xx_sih_lock; 44 45/* Convenience */ 46#define sih bcm947xx_sih 47#define sih_lock bcm947xx_sih_lock 48 49#define WATCHDOG_MIN 3000 /* milliseconds */ 50extern int panic_timeout; 51extern int panic_on_oops; 52static uint32 watchdog = 0; /* Foxconn */ 53 54#ifndef CONFIG_HWSIM 55static u8 *mcr = NULL; 56#endif /* CONFIG_HWSIM */ 57 58/* Foxconn added start */ 59#define LED_BLINK_RATE_NORMAL 50 60#define LED_BLINK_RATE_QUICK 10 61 62int wps_led_pattern = 0; 63int wps_led_state = 0; 64 65/* foxconn added start, zacker, 09/17/2009, @wps_led */ 66int is_wl_secu_mode = 0; 67static int wps_led_is_on = 0; 68/* foxconn added end, zacker, 09/17/2009, @wps_led */ 69static int wps_led_state_old = 1; 70 71static si_t *gpio_sih; 72static int wps_led_init(void) 73{ 74 if (!(gpio_sih = si_kattach(SI_OSH))) 75 { 76 printk("%s failed!\n", __FUNCTION__); 77 return -ENODEV; 78 } 79 80 return 0; 81} 82 83static int gpio_control_normal(int pin, int value) 84{ 85 si_gpioreserve(gpio_sih, 1 << pin, GPIO_APP_PRIORITY); 86 si_gpioouten(gpio_sih, 1 << pin, 1 << pin, GPIO_APP_PRIORITY); 87 si_gpioout(gpio_sih, 1 << pin, value << pin, GPIO_APP_PRIORITY); 88 89 return 0; 90} 91 92#define GPIO_PIN(x) ((x) & 0x00FF) 93 94int gpio_led_on_off(int gpio, int value) 95{ 96 int pin = GPIO_PIN(gpio); 97 98 /* foxconn added start, zacker, 09/17/2009, @wps_led */ 99 if (gpio == WPS_LED_GPIO) 100 wps_led_is_on = !value; 101 /* foxconn added end, zacker, 09/17/2009, @wps_led */ 102 gpio_control_normal(pin, value); 103 104 return 0; 105} 106 107static void quick_blink2(void) 108{ 109 static int interrupt_count = -1; 110 111 interrupt_count++; 112 if (interrupt_count == LED_BLINK_RATE_QUICK * 2) 113 interrupt_count = 0; 114 115 if (interrupt_count == 0) 116 gpio_led_on_off(WPS_LED_GPIO, 0); 117 else if (interrupt_count == LED_BLINK_RATE_QUICK) 118 gpio_led_on_off(WPS_LED_GPIO, 1); 119} 120 121static void quick_blink(void) 122{ 123 /* foxconn modified start, zacker, 09/17/2009, @wps_led */ 124 //static int blink_interval = 3000; /* 30 seconds */ 125 static int blink_interval = 500; /* 5 seconds */ 126 /* foxconn modified end, zacker, 09/17/2009, @wps_led */ 127 static int interrupt_count = -1; 128 129 blink_interval--; 130 interrupt_count++; 131 if (interrupt_count == LED_BLINK_RATE_QUICK * 2) 132 interrupt_count = 0; 133 134 if (interrupt_count == 0) 135 gpio_led_on_off(WPS_LED_GPIO, 0); 136 else if (interrupt_count == LED_BLINK_RATE_QUICK) 137 gpio_led_on_off(WPS_LED_GPIO, 1); 138 139 if ( blink_interval <= 0 ) 140 { 141 /* foxconn modified start, zacker, 09/17/2009, @wps_led */ 142 //blink_interval = 3000; 143 blink_interval = 500; 144 /* foxconn modified end, zacker, 09/17/2009, @wps_led */ 145 wps_led_state = 0; 146 } 147} 148 149static int normal_blink(void) 150{ 151 static int interrupt_count = -1; 152 153 interrupt_count++; 154 if (interrupt_count == LED_BLINK_RATE_NORMAL * 2) 155 interrupt_count = 0; 156 157 if (interrupt_count == 0) 158 gpio_led_on_off(WPS_LED_GPIO, 0); 159 else if (interrupt_count == LED_BLINK_RATE_NORMAL) 160 gpio_led_on_off(WPS_LED_GPIO, 1); 161} 162 163static int wps_ap_lockdown_blink(void) 164{ 165 static int interrupt_count = -1; 166 167 interrupt_count++; 168 if (interrupt_count == LED_BLINK_RATE_QUICK * 10) 169 interrupt_count = 0; 170 171 if (interrupt_count == 0) 172 gpio_led_on_off(WPS_LED_GPIO, 0); 173 else if (interrupt_count == LED_BLINK_RATE_QUICK) 174 gpio_led_on_off(WPS_LED_GPIO, 1); 175} 176/* Foxconn added end */ 177 178/* Foxconn added start pling 02/26/2010 */ 179/* Add USB LED */ 180#if (defined INCLUDE_USB_LED) 181/* Foxconn modified start, Wins, 04/11/2011 */ 182#define GPIO_USB1_LED 8 /* USB1 LED. */ 183#define GPIO_USB2_LED 14 /* USB2 LED. */ 184#define LED_BLINK_RATE 5 185int usb1_pkt_cnt = 0; 186int usb2_pkt_cnt = 0; 187int usb1_led_state = 0; 188int usb2_led_state = 0; 189static int usb1_led_state_old = 1; 190static int usb2_led_state_old = 1; 191EXPORT_SYMBOL(usb1_pkt_cnt); 192EXPORT_SYMBOL(usb2_pkt_cnt); 193EXPORT_SYMBOL(usb1_led_state); 194EXPORT_SYMBOL(usb2_led_state); 195/* Foxconn modified end, Wins, 04/11/2011 */ 196 197static int gpio_on_off(int gpio_num, int on_off) 198{ 199 si_gpioreserve(gpio_sih, 1 << gpio_num, GPIO_APP_PRIORITY); 200 si_gpioouten(gpio_sih, 1 << gpio_num, 1 << gpio_num, GPIO_APP_PRIORITY); 201 si_gpioout(gpio_sih, 1 << gpio_num, on_off << gpio_num, GPIO_APP_PRIORITY); 202 return 0; 203} 204 205static int usb1_normal_blink(void) 206{ 207 static int interrupt_count1 = -1; 208 static int usb1_pkt_cnt_old = 0; 209 210 interrupt_count1++; 211 if (interrupt_count1 == LED_BLINK_RATE * 2) 212 interrupt_count1 = 0; 213 214 if (interrupt_count1 == 0){ 215 /*Foxconn, [MJ], turn off USB_Led. */ 216 gpio_on_off(GPIO_USB1_LED, 0); 217 } 218 else if (interrupt_count1 == LED_BLINK_RATE) 219 { 220 if (usb1_pkt_cnt != usb1_pkt_cnt_old) 221 { 222 usb1_pkt_cnt_old = usb1_pkt_cnt; 223 /*Foxconn, [MJ], turn on USB_Led. */ 224 gpio_on_off(GPIO_USB1_LED, 1); 225 //printk("<1> turn on USB_LED.\n"); 226 } 227 } 228 return 0; 229} 230 231static int usb2_normal_blink(void) 232{ 233 static int interrupt_count2 = -1; 234 static int usb2_pkt_cnt_old = 0; 235 236 interrupt_count2++; 237 if (interrupt_count2 == LED_BLINK_RATE * 2) 238 interrupt_count2 = 0; 239 240 if (interrupt_count2 == 0){ 241 /*Foxconn, [MJ], turn off USB_Led. */ 242 gpio_on_off(GPIO_USB2_LED, 0); 243 } 244 else if (interrupt_count2 == LED_BLINK_RATE) 245 { 246 if (usb2_pkt_cnt != usb2_pkt_cnt_old) 247 { 248 usb2_pkt_cnt_old = usb2_pkt_cnt; 249 /*Foxconn, [MJ], turn on USB_Led. */ 250 gpio_on_off(GPIO_USB2_LED, 1); 251 //printk("<1> turn on USB_LED.\n"); 252 } 253 } 254 return 0; 255} 256#endif 257/* Foxconn added end pling 02/26/2010 */ 258 259void __init 260bcm947xx_time_init(void) 261{ 262 unsigned int hz; 263 char cn[8]; 264 265 /* 266 * Use deterministic values for initial counter interrupt 267 * so that calibrate delay avoids encountering a counter wrap. 268 */ 269 write_c0_count(0); 270 write_c0_compare(0xffff); 271 272 if (!(hz = si_cpu_clock(sih))) 273 hz = 100000000; 274 275 bcm_chipname(sih->chip, cn, 8); 276 printk("CPU: BCM%s rev %d at %d MHz\n", cn, sih->chiprev, 277 (hz + 500000) / 1000000); 278 279 /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */ 280 mips_hpt_frequency = hz / 2; 281 282 /* Set watchdog interval in ms */ 283 watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0); 284 285 /* Ensure at least WATCHDOG_MIN */ 286 if ((watchdog > 0) && (watchdog < WATCHDOG_MIN)) 287 watchdog = WATCHDOG_MIN; 288 289 /* Set panic timeout in seconds */ 290 panic_timeout = watchdog / 1000; 291 panic_on_oops = watchdog / 1000; 292 /* Init WLAN LED */ 293 wps_led_init(); /* Foxconn added */ 294} 295 296#ifdef CONFIG_HND_BMIPS3300_PROF 297extern bool hndprofiling; 298#ifdef CONFIG_MIPS64 299typedef u_int64_t sbprof_pc; 300#else 301typedef u_int32_t sbprof_pc; 302#endif 303extern void sbprof_cpu_intr(sbprof_pc restartpc); 304#endif /* CONFIG_HND_BMIPS3300_PROF */ 305 306static irqreturn_t 307bcm947xx_timer_interrupt(int irq, void *dev_id) 308{ 309#ifdef CONFIG_HND_BMIPS3300_PROF 310 /* 311 * Are there any ExcCode or other mean(s) to determine what has caused 312 * the timer interrupt? For now simply stop the normal timer proc if 313 * count register is less than compare register. 314 */ 315 if (hndprofiling) { 316 sbprof_cpu_intr(read_c0_epc() + 317 ((read_c0_cause() >> (CAUSEB_BD - 2)) & 4)); 318 if (read_c0_count() < read_c0_compare()) 319 return (IRQ_HANDLED); 320 } 321#endif /* CONFIG_HND_BMIPS3300_PROF */ 322 323 /* Generic MIPS timer code */ 324 timer_interrupt(irq, dev_id); 325 326 /* Set the watchdog timer to reset after the specified number of ms */ 327 if (watchdog > 0) 328 si_watchdog_ms(sih, watchdog); 329 330#ifdef CONFIG_HWSIM 331 (*((int *)0xa0000f1c))++; 332#else 333 /* Blink one of the LEDs in the external UART */ 334 if (mcr && !(jiffies % (HZ/2))) 335 writeb(readb(mcr) ^ UART_MCR_OUT2, mcr); 336#endif 337 338 /* Foxconn added start */ 339 /* Blink LED depending of WPS status */ 340 if ( wps_led_state == 0 ) 341 { 342 if (wps_led_state_old != 0) 343 gpio_led_on_off(WPS_LED_GPIO, 1); 344 345 /* foxconn added start, zacker, 09/17/2009, @wps_led */ 346 if ((!is_wl_secu_mode) && wps_led_is_on) 347 gpio_led_on_off(WPS_LED_GPIO, 1); 348 349 if (is_wl_secu_mode && (!wps_led_is_on)) 350 gpio_led_on_off(WPS_LED_GPIO, 0); 351 /* foxconn added end, zacker, 09/17/2009, @wps_led */ 352 } 353 else 354 if (wps_led_state == 1) 355 { 356 normal_blink(); 357 } 358 else 359 if (wps_led_state == 2) 360 { 361 quick_blink(); 362 } 363 else 364 if (wps_led_state == 3) 365 { 366 quick_blink2(); 367 } 368 else 369 if (wps_led_state == 4) 370 { 371 wps_ap_lockdown_blink(); 372 } 373 374 wps_led_state_old = wps_led_state; 375 /* Foxconn added end */ 376 /* Foxconn added start pling 02/26/2010 */ 377 /* Blink USB LED if necessary */ 378#if (defined INCLUDE_USB_LED) 379 /* Foxconn modified start, Wins, 04/11/2011 */ 380 if (usb1_led_state) 381 { 382 usb1_normal_blink(); 383 } 384 else 385 { 386 if (usb1_led_state_old){ 387 /* Foxconn, [MJ], turn on USB1_Led. */ 388 gpio_on_off(GPIO_USB1_LED, 1); 389 } 390 } 391 usb1_led_state_old = usb1_led_state; 392 393 if (usb2_led_state) 394 { 395 usb2_normal_blink(); 396 } 397 else 398 { 399 if (usb2_led_state_old){ 400 /* Foxconn, [MJ], turn on USB2_Led. */ 401 gpio_on_off(GPIO_USB2_LED, 1); 402 } 403 } 404 usb2_led_state_old = usb2_led_state; 405 /* Foxconn modified end, Wins, 04/11/2011 */ 406#endif 407 /* Foxconn added end pling 02/26/2010 */ 408 409 return (IRQ_HANDLED); 410} 411 412static struct irqaction bcm947xx_timer_irqaction = { 413 bcm947xx_timer_interrupt, 414 IRQF_DISABLED, 415 { { 0 } }, 416 "timer", 417 NULL, 418 NULL, 419 0, 420 NULL 421}; 422 423void __init 424plat_timer_setup(struct irqaction *irq) 425{ 426 /* Enable the timer interrupt */ 427 setup_irq(7, &bcm947xx_timer_irqaction); 428} 429