3 Copyright 2002 Broadcom Corp. All Rights Reserved.
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.
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
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.
21 #include <linux/version.h>
22 #include <linux/init.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>
36 #include <linux/spinlock.h>
38 #include <bcm_map_part.h>
41 #include "boardparms.h"
44 #include "bcm_map_part.h"
46 static DEFINE_SPINLOCK(board_lock
);
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
55 #define CHANGED_OCTET 1
64 } MAC_ADDR_INFO
, *PMAC_ADDR_INFO
;
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
;
77 unsigned long eventmask
;
78 } BOARD_IOC
, *PBOARD_IOC
;
81 /*Dyinggasp callback*/
82 typedef void (*cb_dgasp_t
)(void *arg
);
83 typedef struct _CB_DGASP__LIST
85 struct list_head list
;
87 cb_dgasp_t cb_dgasp_fn
;
89 }CB_DGASP_LIST
, *PCB_DGASP_LIST
;
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.
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
);
119 void __init
InitNvramInfo( void );
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 - */
128 static PNVRAM_INFO g_pNvramInfo
= NULL
;
129 static int g_ledInitialized
= 0;
130 static CB_DGASP_LIST
*g_cb_dgasp_list_head
= NULL
;
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
;
138 void kerSysMipsSoftReset(void)
140 if (PERF
->RevID
== 0x634800A1) {
141 typedef void (*FNPTR
) (void);
142 FNPTR bootaddr
= (FNPTR
) FLASH_BASE
;
145 /* Disable interrupts. */
147 spin_lock_irq(&board_lock
);
149 /* Reset all blocks. */
150 PERF
->BlockSoftReset
&= ~BSR_ALL_BLOCKS
;
151 for( i
= 0; i
< 1000000; i
++ )
153 PERF
->BlockSoftReset
|= BSR_ALL_BLOCKS
;
154 /* Jump to the power on address. */
158 PERF
->pll_control
|= SOFT_RESET
; // soft reset mips
162 int kerSysGetMacAddress( unsigned char *pucaMacAddr
, unsigned long ulId
)
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;
170 /* CMO -- Fix le problème avec les adresses mac que l'on n'arrive pas
171 * * Ã relire plusieurs fois */
174 if (boot_loader_type
== BOOT_CFE
)
175 memcpy( pucaMacAddr
, g_pNvramInfo
->ucaBaseMacAddr
,
176 NVRAM_MAC_ADDRESS_LEN
);
179 pucaMacAddr
[0] = 0x00;
180 pucaMacAddr
[1] = 0x07;
181 pucaMacAddr
[2] = 0x3A;
182 pucaMacAddr
[3] = 0xFF;
183 pucaMacAddr
[4] = 0xFF;
184 pucaMacAddr
[5] = 0xFF;
190 } /* kerSysGetMacAddr */
192 int kerSysReleaseMacAddress( unsigned char *pucaMacAddr
)
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
]);
199 // if overflow 255 (negitive), add 256 to have the correct index
202 ulIdx
= (unsigned long) (idx
>> SHIFT_BITS
);
204 if( ulIdx
< g_pNvramInfo
->ulNumMacAddrs
)
206 PMAC_ADDR_INFO pMai
= &g_pNvramInfo
->MacAddrs
[ulIdx
];
207 if( pMai
->chInUse
== 1 )
215 } /* kerSysReleaseMacAddr */
217 int kerSysGetSdramSize( void )
219 if (boot_loader_type
== BOOT_CFE
) {
220 return( (int) g_pNvramInfo
->ulSdramSize
);
223 printk("kerSysGetSdramSize : 0x%08X\n", (int)getMemorySize() + 0x00040000);
224 return((int)getMemorySize() + 0x00040000);
226 } /* kerSysGetSdramSize */
229 void kerSysLedCtrl(BOARD_LED_NAME ledName
, BOARD_LED_STATE ledState
)
231 if (g_ledInitialized
)
232 boardLedCtrl(ledName
, ledState
);
235 unsigned int kerSysMonitorPollHook( struct file
*f
, struct poll_table_struct
*t
)
237 int mask
= (*g_orig_fop_poll
) (f
, t
);
239 if( g_wakeup_monitor
== 1 && g_monitor_file
== f
)
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.
246 g_wakeup_monitor
= 0;
252 /* Put the user mode application that monitors link state on a run queue. */
253 void kerSysWakeupMonitorTask( void )
255 g_wakeup_monitor
= 1;
257 wake_up_process( g_monitor_task
);
260 //<<JUNHON, 2004/09/15, get reset button status , tim hou , 05/04/12
261 int kerSysGetResetHold(void)
265 if( BpGetPressAndHoldResetGpio( &gpio
) == BP_SUCCESS
)
267 unsigned long gpio_mask
= GPIO_NUM_TO_MASK(gpio
);
268 volatile unsigned long *gpio_reg
= &GPIO
->GPIOio
;
270 if( (gpio
& ~BP_ACTIVE_MASK
) >= 32 )
272 gpio_mask
= GPIO_NUM_TO_MASK_HIGH(gpio
);
273 gpio_reg
= &GPIO
->GPIOio_high
;
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
;
279 return RESET_BUTTON_PRESSDOWN
;
281 //<<JUNHON, 2004/09/15
283 /***************************************************************************
284 * Dying gasp ISR and functions.
285 ***************************************************************************/
286 #define KERSYS_DBG printk
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.
295 #define CYCLE_PER_US 120
297 #define DG_GLITCH_TO (100*CYCLE_PER_US)
299 static void __init
kerSysDyingGaspMapIntr()
301 unsigned long ulIntr
;
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
);
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
);
318 void kerSysSetWdTimer(ulong timeUs
)
320 TIMER
->WatchDogDefCount
= timeUs
* (FPERIPH
/1000000);
321 TIMER
->WatchDogCtl
= 0xFF00;
322 TIMER
->WatchDogCtl
= 0x00FF;
325 ulong
kerSysGetCycleCount(void)
331 __asm
volatile("mfc0 %0, $9":"=d"(cnt
));
336 static Bool
kerSysDyingGaspCheckPowerLoss(void)
342 clk0
= kerSysGetCycleCount();
348 #if defined(CONFIG_BCM96345)
349 BpGetAdslDyingGaspExtIntr( &ulIntr
);
354 clk1
= kerSysGetCycleCount(); /* time cleared */
355 /* wait a little to get new reading */
356 while ((kerSysGetCycleCount()-clk1
) < CYCLE_PER_US
*2)
358 } while ((0 == (PERF
->ExtIrqCfg
& (1 << (ulIntr
+ EI_STATUS_SHFT
)))) && ((kerSysGetCycleCount() - clk0
) < DG_GLITCH_TO
));
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
);
365 #elif (defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)) && !defined(VXWORKS)
369 clk1
= kerSysGetCycleCount(); /* time cleared */
370 /* wait a little to get new reading */
371 while ((kerSysGetCycleCount()-clk1
) < CYCLE_PER_US
*2)
373 } while ((PERF
->IrqStatus
& (1 << (INTERRUPT_ID_DG
- INTERNAL_ISR_TABLE_OFFSET
))) && ((kerSysGetCycleCount() - clk0
) < DG_GLITCH_TO
));
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
);
384 static void kerSysDyingGaspShutdown( void )
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
);
394 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
395 static irqreturn_t
kerSysDyingGaspIsr(int irq
, void * dev_id
)
397 static unsigned int kerSysDyingGaspIsr(void)
400 struct list_head
*pos
;
401 CB_DGASP_LIST
*tmp
, *dsl
= NULL
;
403 if (kerSysDyingGaspCheckPowerLoss()) {
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
);
417 (dsl
->cb_dgasp_fn
)(dsl
->context
);
419 /* reset and shutdown system */
420 kerSysDyingGaspShutdown();
422 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
423 return( IRQ_HANDLED
);
429 static void __init
kerSysInitDyingGaspHandler( void )
431 CB_DGASP_LIST
*new_node
;
433 if( g_cb_dgasp_list_head
!= NULL
) {
434 printk("Error: kerSysInitDyingGaspHandler: list head is not null\n");
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
;
442 } /* kerSysInitDyingGaspHandler */
444 static void __exit
kerSysDeinitDyingGaspHandler( void )
446 struct list_head
*pos
;
449 if(g_cb_dgasp_list_head
== NULL
)
452 list_for_each(pos
, &g_cb_dgasp_list_head
->list
) {
453 tmp
= list_entry(pos
, CB_DGASP_LIST
, list
);
458 kfree(g_cb_dgasp_list_head
);
459 g_cb_dgasp_list_head
= NULL
;
461 } /* kerSysDeinitDyingGaspHandler */
463 void kerSysRegisterDyingGaspHandler(char *devname
, void *cbfn
, void *context
)
465 CB_DGASP_LIST
*new_node
;
467 if( g_cb_dgasp_list_head
== NULL
) {
468 printk("Error: kerSysRegisterDyingGaspHandler: list head is null\n");
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
);
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
);
485 printk("dgasp: kerSysRegisterDyingGaspHandler: %s registered \n", devname
);
487 } /* kerSysRegisterDyingGaspHandler */
489 void kerSysDeregisterDyingGaspHandler(char *devname
)
491 struct list_head
*pos
;
494 if(g_cb_dgasp_list_head
== NULL
) {
495 printk("Error: kerSysDeregisterDyingGaspHandler: list head is null\n");
499 if(devname
== NULL
) {
500 printk("Error: kerSysDeregisterDyingGaspHandler: devname is null\n");
504 printk("kerSysDeregisterDyingGaspHandler: %s is deregistering\n", devname
);
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
)) {
511 printk("kerSysDeregisterDyingGaspHandler: %s is deregistered\n", devname
);
515 printk("kerSysDeregisterDyingGaspHandler: %s not (de)registered\n", devname
);
517 } /* kerSysDeregisterDyingGaspHandler */
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
);