Rename mipsIRQ.S to int-handler to match the kernel naming convention, implement...
[openwrt.git] / target / linux / brcm63xx-2.6 / files / arch / mips / bcm963xx / board.c
1 /*
2 <:copyright-gpl 
3  Copyright 2002 Broadcom Corp. All Rights Reserved. 
4  
5  This program is free software; you can distribute it and/or modify it 
6  under the terms of the GNU General Public License (Version 2) as 
7  published by the Free Software Foundation. 
8  
9  This program is distributed in the hope it will be useful, but WITHOUT 
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
11  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
12  for more details. 
13  
14  You should have received a copy of the GNU General Public License along 
15  with this program; if not, write to the Free Software Foundation, Inc., 
16  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
17 :>
18 */
19
20 /* Includes. */
21 #include <linux/version.h>
22 #include <linux/init.h>
23 #include <linux/fs.h>
24 #include <linux/interrupt.h>
25 #include <linux/capability.h>
26 #include <linux/slab.h>
27 #include <linux/errno.h>
28 #include <linux/module.h>
29 #include <linux/pagemap.h>
30 #include <asm/uaccess.h>
31 #include <linux/wait.h>
32 #include <linux/poll.h>
33 #include <linux/sched.h>
34 #include <linux/list.h>
35 #include <linux/if.h>
36 #include <linux/spinlock.h>
37
38 #include <bcm_map_part.h>
39 #include <board.h>
40 #include <bcmTag.h>
41 #include "boardparms.h"
42 #include "bcm_intr.h"
43 #include "board.h"
44 #include "bcm_map_part.h"
45
46 static DEFINE_SPINLOCK(board_lock);
47
48 /* Typedefs. */
49 #if defined (NON_CONSECUTIVE_MAC)
50 // used to be the last octet. Now changed to the first 5 bits of the the forth octet
51 // to reduced the duplicated MAC addresses.
52 #define CHANGED_OCTET   3
53 #define SHIFT_BITS      3
54 #else
55 #define CHANGED_OCTET   1
56 #define SHIFT_BITS      0
57 #endif
58
59 typedef struct
60 {
61     unsigned long ulId;
62     char chInUse;
63     char chReserved[3];
64 } MAC_ADDR_INFO, *PMAC_ADDR_INFO;
65
66 typedef struct
67 {
68     unsigned long ulSdramSize;
69     unsigned long ulPsiSize;
70     unsigned long ulNumMacAddrs;
71     unsigned long ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN];
72     MAC_ADDR_INFO MacAddrs[1];
73 } NVRAM_INFO, *PNVRAM_INFO;
74
75 typedef struct
76 {
77     unsigned long eventmask;    
78 } BOARD_IOC, *PBOARD_IOC;
79
80
81 /*Dyinggasp callback*/
82 typedef void (*cb_dgasp_t)(void *arg);
83 typedef struct _CB_DGASP__LIST
84 {
85     struct list_head list;
86     char name[IFNAMSIZ];
87     cb_dgasp_t cb_dgasp_fn;
88     void *context;
89 }CB_DGASP_LIST , *PCB_DGASP_LIST;
90
91
92 static LED_MAP_PAIR LedMapping[] =
93 {   // led name     Initial state       physical pin (ledMask)
94     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
95     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
96     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
97     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
98     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},
99     {kLedEnd,       kLedStateOff,       0, 0, 0, 0}, 
100     {kLedEnd,       kLedStateOff,       0, 0, 0, 0}, 
101     {kLedEnd,       kLedStateOff,       0, 0, 0, 0},     
102     {kLedEnd,       kLedStateOff,       0, 0, 0, 0} // NOTE: kLedEnd has to be at the end.
103 };
104
105 /* Externs. */
106 extern struct file fastcall *fget_light(unsigned int fd, int *fput_needed);
107 extern unsigned int nr_free_pages (void);
108 extern const char *get_system_type(void);
109 extern void kerSysFlashInit(void);
110 extern unsigned long get_nvram_start_addr(void);
111 extern unsigned long get_scratch_pad_start_addr(void);
112 extern unsigned long getMemorySize(void);
113 extern void __init boardLedInit(PLED_MAP_PAIR);
114 extern void boardLedCtrl(BOARD_LED_NAME, BOARD_LED_STATE);
115 extern void kerSysLedRegisterHandler( BOARD_LED_NAME ledName,
116     HANDLE_LED_FUNC ledHwFunc, int ledFailType );
117
118 /* Prototypes. */
119 void __init InitNvramInfo( void );
120
121 /* DyingGasp function prototype */
122 static void __init kerSysDyingGaspMapIntr(void);
123 static irqreturn_t kerSysDyingGaspIsr(int irq, void * dev_id);
124 static void __init kerSysInitDyingGaspHandler( void );
125 static void __exit kerSysDeinitDyingGaspHandler( void );
126 /* -DyingGasp function prototype - */
127
128 static PNVRAM_INFO g_pNvramInfo = NULL;
129 static int g_ledInitialized = 0;
130 static CB_DGASP_LIST *g_cb_dgasp_list_head = NULL;
131
132 static int g_wakeup_monitor = 0;
133 static struct file *g_monitor_file = NULL;
134 static struct task_struct *g_monitor_task = NULL;
135 static unsigned int (*g_orig_fop_poll)
136     (struct file *, struct poll_table_struct *) = NULL;
137
138 void kerSysMipsSoftReset(void)
139 {
140     if (PERF->RevID == 0x634800A1) {
141         typedef void (*FNPTR) (void);
142         FNPTR bootaddr = (FNPTR) FLASH_BASE;
143         int i;
144
145         /* Disable interrupts. */
146         //cli();
147         spin_lock_irq(&board_lock);
148         
149         /* Reset all blocks. */
150         PERF->BlockSoftReset &= ~BSR_ALL_BLOCKS;
151         for( i = 0; i < 1000000; i++ )
152             ;
153         PERF->BlockSoftReset |= BSR_ALL_BLOCKS;
154         /* Jump to the power on address. */
155         (*bootaddr) ();
156     }
157     else
158         PERF->pll_control |= SOFT_RESET;    // soft reset mips
159 }
160
161
162 int kerSysGetMacAddress( unsigned char *pucaMacAddr, unsigned long ulId )
163 {
164     int nRet = 0;
165     PMAC_ADDR_INFO pMai = NULL;
166     PMAC_ADDR_INFO pMaiFreeNoId = NULL;
167     PMAC_ADDR_INFO pMaiFreeId = NULL;
168     unsigned long i = 0, ulIdxNoId = 0, ulIdxId = 0, shiftedIdx = 0;
169
170     /* CMO -- Fix le problème avec les adresses mac que l'on n'arrive pas
171      *  * à relire plusieurs fois */
172     /* inv_xde */
173 #if 0
174     if (boot_loader_type == BOOT_CFE)
175       memcpy( pucaMacAddr, g_pNvramInfo->ucaBaseMacAddr,
176               NVRAM_MAC_ADDRESS_LEN );
177     else {
178 #endif
179       pucaMacAddr[0] = 0x00;
180       pucaMacAddr[1] = 0x07;
181       pucaMacAddr[2] = 0x3A;
182       pucaMacAddr[3] = 0xFF;
183       pucaMacAddr[4] = 0xFF;
184       pucaMacAddr[5] = 0xFF;
185 #if 0
186     }
187 #endif
188
189     return nRet;
190 } /* kerSysGetMacAddr */
191
192 int kerSysReleaseMacAddress( unsigned char *pucaMacAddr )
193 {
194     int nRet = -EINVAL;
195     unsigned long ulIdx = 0;
196     int idx = (pucaMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET] -
197         g_pNvramInfo->ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET]);
198
199     // if overflow 255 (negitive), add 256 to have the correct index
200     if (idx < 0)
201         idx += 256;
202     ulIdx = (unsigned long) (idx >> SHIFT_BITS);
203
204     if( ulIdx < g_pNvramInfo->ulNumMacAddrs )
205     {
206         PMAC_ADDR_INFO pMai = &g_pNvramInfo->MacAddrs[ulIdx];
207         if( pMai->chInUse == 1 )
208         {
209             pMai->chInUse = 0;
210             nRet = 0;
211         }
212     }
213
214     return( nRet );
215 } /* kerSysReleaseMacAddr */
216
217 int kerSysGetSdramSize( void )
218 {
219   if (boot_loader_type == BOOT_CFE) {
220     return( (int) g_pNvramInfo->ulSdramSize );
221   }
222   else {
223     printk("kerSysGetSdramSize : 0x%08X\n", (int)getMemorySize() + 0x00040000);
224     return((int)getMemorySize() + 0x00040000);
225   }
226 } /* kerSysGetSdramSize */
227
228
229 void kerSysLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState)
230 {
231     if (g_ledInitialized)
232       boardLedCtrl(ledName, ledState);
233 }
234
235 unsigned int kerSysMonitorPollHook( struct file *f, struct poll_table_struct *t)
236 {
237     int mask = (*g_orig_fop_poll) (f, t);
238
239     if( g_wakeup_monitor == 1 && g_monitor_file == f )
240     {
241         /* If g_wakeup_monitor is non-0, the user mode application needs to
242          * return from a blocking select function.  Return POLLPRI which will
243          * cause the select to return with the exception descriptor set.
244          */
245         mask |= POLLPRI;
246         g_wakeup_monitor = 0;
247     }
248
249     return( mask );
250 }
251
252 /* Put the user mode application that monitors link state on a run queue. */
253 void kerSysWakeupMonitorTask( void )
254 {
255     g_wakeup_monitor = 1;
256     if( g_monitor_task )
257         wake_up_process( g_monitor_task );
258 }
259
260 //<<JUNHON, 2004/09/15, get reset button status , tim hou , 05/04/12
261 int kerSysGetResetHold(void)
262 {
263         unsigned short gpio;
264
265         if( BpGetPressAndHoldResetGpio( &gpio ) == BP_SUCCESS )
266         {
267     unsigned long gpio_mask = GPIO_NUM_TO_MASK(gpio);
268     volatile unsigned long *gpio_reg = &GPIO->GPIOio;
269
270     if( (gpio & ~BP_ACTIVE_MASK) >= 32 )
271     {
272         gpio_mask = GPIO_NUM_TO_MASK_HIGH(gpio);
273         gpio_reg = &GPIO->GPIOio_high;
274     }
275         //printk("gpio=%04x,gpio_mask=%04x,gpio_reg=%04x\n",gpio,gpio_mask,*gpio_reg);
276         if(*gpio_reg & gpio_mask)  //press down
277                 return RESET_BUTTON_UP;
278         }
279         return RESET_BUTTON_PRESSDOWN;
280 }
281 //<<JUNHON, 2004/09/15
282
283 /***************************************************************************
284  * Dying gasp ISR and functions.
285  ***************************************************************************/
286 #define KERSYS_DBG      printk
287
288 #if defined(CONFIG_BCM96345)
289 #define CYCLE_PER_US    70
290 #elif defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)
291 /* The BCM6348 cycles per microsecond is really variable since the BCM6348
292  * MIPS speed can vary depending on the PLL settings.  However, an appoximate
293  * value of 120 will still work OK for the test being done.
294  */
295 #define CYCLE_PER_US    120
296 #endif
297 #define DG_GLITCH_TO    (100*CYCLE_PER_US)
298  
299 static void __init kerSysDyingGaspMapIntr()
300 {
301     unsigned long ulIntr;
302         
303 #if defined(CONFIG_BCM96348) || defined(_BCM96348_) || defined(CONFIG_BCM96338) || defined(_BCM96338_)
304     if( BpGetAdslDyingGaspExtIntr( &ulIntr ) == BP_SUCCESS ) {
305                 BcmHalMapInterrupt((FN_HANDLER)kerSysDyingGaspIsr, 0, INTERRUPT_ID_DG);
306                 BcmHalInterruptEnable( INTERRUPT_ID_DG );
307     }
308 #elif defined(CONFIG_BCM96345) || defined(_BCM96345_)
309     if( BpGetAdslDyingGaspExtIntr( &ulIntr ) == BP_SUCCESS ) {
310         ulIntr += INTERRUPT_ID_EXTERNAL_0;
311         BcmHalMapInterrupt((FN_HANDLER)kerSysDyingGaspIsr, 0, ulIntr);
312         BcmHalInterruptEnable( ulIntr );
313     }
314 #endif
315
316
317
318 void kerSysSetWdTimer(ulong timeUs)
319 {
320         TIMER->WatchDogDefCount = timeUs * (FPERIPH/1000000);
321         TIMER->WatchDogCtl = 0xFF00;
322         TIMER->WatchDogCtl = 0x00FF;
323 }
324
325 ulong kerSysGetCycleCount(void)
326 {
327     ulong cnt; 
328 #ifdef _WIN32_WCE
329     cnt = 0;
330 #else
331     __asm volatile("mfc0 %0, $9":"=d"(cnt));
332 #endif
333     return(cnt); 
334 }
335
336 static Bool kerSysDyingGaspCheckPowerLoss(void)
337 {
338     ulong clk0;
339     ulong ulIntr;
340
341     ulIntr = 0;
342     clk0 = kerSysGetCycleCount();
343
344     UART->Data = 'D';
345     UART->Data = '%';
346     UART->Data = 'G';
347
348 #if defined(CONFIG_BCM96345)
349     BpGetAdslDyingGaspExtIntr( &ulIntr );
350
351     do {
352         ulong clk1;
353         
354         clk1 = kerSysGetCycleCount();           /* time cleared */
355         /* wait a little to get new reading */
356         while ((kerSysGetCycleCount()-clk1) < CYCLE_PER_US*2)
357             ;
358     } while ((0 == (PERF->ExtIrqCfg & (1 << (ulIntr + EI_STATUS_SHFT)))) && ((kerSysGetCycleCount() - clk0) < DG_GLITCH_TO));
359
360     if (PERF->ExtIrqCfg & (1 << (ulIntr + EI_STATUS_SHFT))) {   /* power glitch */
361         BcmHalInterruptEnable( ulIntr + INTERRUPT_ID_EXTERNAL_0);
362         KERSYS_DBG(" - Power glitch detected. Duration: %ld us\n", (kerSysGetCycleCount() - clk0)/CYCLE_PER_US);
363         return 0;
364     }
365 #elif (defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)) && !defined(VXWORKS)
366     do {
367         ulong clk1;
368         
369         clk1 = kerSysGetCycleCount();           /* time cleared */
370         /* wait a little to get new reading */
371         while ((kerSysGetCycleCount()-clk1) < CYCLE_PER_US*2)
372             ;
373      } while ((PERF->IrqStatus & (1 << (INTERRUPT_ID_DG - INTERNAL_ISR_TABLE_OFFSET))) && ((kerSysGetCycleCount() - clk0) < DG_GLITCH_TO));
374
375     if (!(PERF->IrqStatus & (1 << (INTERRUPT_ID_DG - INTERNAL_ISR_TABLE_OFFSET)))) {
376         BcmHalInterruptEnable( INTERRUPT_ID_DG );
377         KERSYS_DBG(" - Power glitch detected. Duration: %ld us\n", (kerSysGetCycleCount() - clk0)/CYCLE_PER_US);
378         return 0;
379     }
380 #endif
381     return 1;
382 }
383
384 static void kerSysDyingGaspShutdown( void )
385 {
386     kerSysSetWdTimer(1000000);
387 #if defined(CONFIG_BCM96345)
388     PERF->blkEnables &= ~(EMAC_CLK_EN | USB_CLK_EN | CPU_CLK_EN);
389 #elif defined(CONFIG_BCM96348)
390     PERF->blkEnables &= ~(EMAC_CLK_EN | USBS_CLK_EN | USBH_CLK_EN | SAR_CLK_EN);
391 #endif
392 }
393
394 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
395 static irqreturn_t kerSysDyingGaspIsr(int irq, void * dev_id)
396 #else
397 static unsigned int kerSysDyingGaspIsr(void)
398 #endif
399 {       
400     struct list_head *pos;
401     CB_DGASP_LIST *tmp, *dsl = NULL;    
402
403     if (kerSysDyingGaspCheckPowerLoss()) {        
404
405         /* first to turn off everything other than dsl */        
406         list_for_each(pos, &g_cb_dgasp_list_head->list) {       
407             tmp = list_entry(pos, CB_DGASP_LIST, list);
408             if(strncmp(tmp->name, "dsl", 3)) {
409                 (tmp->cb_dgasp_fn)(tmp->context); 
410             }else {
411                 dsl = tmp;                      
412             }       
413         }  
414         
415         /* now send dgasp */
416         if(dsl)
417             (dsl->cb_dgasp_fn)(dsl->context); 
418
419         /* reset and shutdown system */
420         kerSysDyingGaspShutdown();
421     }
422 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
423 return( IRQ_HANDLED );
424 #else
425     return( 1 );
426 #endif
427 }
428
429 static void __init kerSysInitDyingGaspHandler( void )
430 {
431     CB_DGASP_LIST *new_node;
432
433     if( g_cb_dgasp_list_head != NULL) {
434         printk("Error: kerSysInitDyingGaspHandler: list head is not null\n");
435         return; 
436     }
437     new_node= (CB_DGASP_LIST *)kmalloc(sizeof(CB_DGASP_LIST), GFP_KERNEL);
438     memset(new_node, 0x00, sizeof(CB_DGASP_LIST));
439     INIT_LIST_HEAD(&new_node->list);    
440     g_cb_dgasp_list_head = new_node; 
441                 
442 } /* kerSysInitDyingGaspHandler */
443
444 static void __exit kerSysDeinitDyingGaspHandler( void )
445 {
446     struct list_head *pos;
447     CB_DGASP_LIST *tmp; 
448         
449     if(g_cb_dgasp_list_head == NULL)
450         return;
451         
452     list_for_each(pos, &g_cb_dgasp_list_head->list) {           
453         tmp = list_entry(pos, CB_DGASP_LIST, list);
454         list_del(pos);
455         kfree(tmp);
456     }       
457
458     kfree(g_cb_dgasp_list_head);        
459     g_cb_dgasp_list_head = NULL;
460     
461 } /* kerSysDeinitDyingGaspHandler */
462
463 void kerSysRegisterDyingGaspHandler(char *devname, void *cbfn, void *context)
464 {
465     CB_DGASP_LIST *new_node;
466
467     if( g_cb_dgasp_list_head == NULL) {
468         printk("Error: kerSysRegisterDyingGaspHandler: list head is null\n");   
469         return;    
470     }
471     
472     if( devname == NULL || cbfn == NULL ) {
473         printk("Error: kerSysRegisterDyingGaspHandler: register info not enough (%s,%x,%x)\n", devname, (unsigned int)cbfn, (unsigned int)context);             
474         return;
475     }
476        
477     new_node= (CB_DGASP_LIST *)kmalloc(sizeof(CB_DGASP_LIST), GFP_KERNEL);
478     memset(new_node, 0x00, sizeof(CB_DGASP_LIST));    
479     INIT_LIST_HEAD(&new_node->list);
480     strncpy(new_node->name, devname, IFNAMSIZ);
481     new_node->cb_dgasp_fn = (cb_dgasp_t)cbfn;
482     new_node->context = context;
483     list_add(&new_node->list, &g_cb_dgasp_list_head->list);
484     
485     printk("dgasp: kerSysRegisterDyingGaspHandler: %s registered \n", devname);
486                 
487 } /* kerSysRegisterDyingGaspHandler */
488
489 void kerSysDeregisterDyingGaspHandler(char *devname)
490 {
491     struct list_head *pos;
492     CB_DGASP_LIST *tmp;    
493     
494     if(g_cb_dgasp_list_head == NULL) {
495         printk("Error: kerSysDeregisterDyingGaspHandler: list head is null\n");
496         return; 
497     }
498
499     if(devname == NULL) {
500         printk("Error: kerSysDeregisterDyingGaspHandler: devname is null\n");
501         return; 
502     }
503     
504     printk("kerSysDeregisterDyingGaspHandler: %s is deregistering\n", devname);
505
506     list_for_each(pos, &g_cb_dgasp_list_head->list) {           
507         tmp = list_entry(pos, CB_DGASP_LIST, list);
508         if(!strcmp(tmp->name, devname)) {
509             list_del(pos);
510             kfree(tmp);
511             printk("kerSysDeregisterDyingGaspHandler: %s is deregistered\n", devname);
512             return;
513         }
514     }   
515     printk("kerSysDeregisterDyingGaspHandler: %s not (de)registered\n", devname);
516         
517 } /* kerSysDeregisterDyingGaspHandler */
518
519 //EXPORT_SYMBOL(kerSysNvRamGet);
520 EXPORT_SYMBOL(kerSysGetMacAddress);
521 EXPORT_SYMBOL(kerSysReleaseMacAddress);
522 EXPORT_SYMBOL(kerSysGetSdramSize);
523 EXPORT_SYMBOL(kerSysLedCtrl);
524 EXPORT_SYMBOL(kerSysGetResetHold);
525 EXPORT_SYMBOL(kerSysLedRegisterHwHandler);
526 EXPORT_SYMBOL(BpGetBoardIds);
527 EXPORT_SYMBOL(BpGetSdramSize);
528 EXPORT_SYMBOL(BpGetPsiSize);
529 EXPORT_SYMBOL(BpGetEthernetMacInfo);
530 EXPORT_SYMBOL(BpGetRj11InnerOuterPairGpios);
531 EXPORT_SYMBOL(BpGetPressAndHoldResetGpio);
532 EXPORT_SYMBOL(BpGetVoipResetGpio);
533 EXPORT_SYMBOL(BpGetVoipIntrGpio);
534 EXPORT_SYMBOL(BpGetPcmciaResetGpio);
535 EXPORT_SYMBOL(BpGetRtsCtsUartGpios);
536 EXPORT_SYMBOL(BpGetAdslLedGpio);
537 EXPORT_SYMBOL(BpGetAdslFailLedGpio);
538 EXPORT_SYMBOL(BpGetWirelessLedGpio);
539 EXPORT_SYMBOL(BpGetUsbLedGpio);
540 EXPORT_SYMBOL(BpGetHpnaLedGpio);
541 EXPORT_SYMBOL(BpGetWanDataLedGpio);
542 EXPORT_SYMBOL(BpGetPppLedGpio);
543 EXPORT_SYMBOL(BpGetPppFailLedGpio);
544 EXPORT_SYMBOL(BpGetVoipLedGpio);
545 EXPORT_SYMBOL(BpGetWirelessExtIntr);
546 EXPORT_SYMBOL(BpGetAdslDyingGaspExtIntr);
547 EXPORT_SYMBOL(BpGetVoipExtIntr);
548 EXPORT_SYMBOL(BpGetHpnaExtIntr);
549 EXPORT_SYMBOL(BpGetHpnaChipSelect);
550 EXPORT_SYMBOL(BpGetVoipChipSelect);
551 EXPORT_SYMBOL(BpGetWirelessSesBtnGpio);
552 EXPORT_SYMBOL(BpGetWirelessSesExtIntr);
553 EXPORT_SYMBOL(BpGetWirelessSesLedGpio);
554 EXPORT_SYMBOL(kerSysRegisterDyingGaspHandler);
555 EXPORT_SYMBOL(kerSysDeregisterDyingGaspHandler);
556 EXPORT_SYMBOL(kerSysGetCycleCount);
557 EXPORT_SYMBOL(kerSysSetWdTimer);
558 EXPORT_SYMBOL(kerSysWakeupMonitorTask);
559