X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/6e7905d2a36799482b283ad8e3f0f9fa520f09ac..d4aeb1b5c81c3adfa2db01e9a6eebf9ec5b6d35b:/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/board.c diff --git a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/board.c b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/board.c new file mode 100644 index 000000000..e54b96050 --- /dev/null +++ b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/board.c @@ -0,0 +1,559 @@ +/* +<:copyright-gpl + Copyright 2002 Broadcom Corp. All Rights Reserved. + + This program is free software; you can distribute it and/or modify it + under the terms of the GNU General Public License (Version 2) as + published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +:> +*/ + +/* Includes. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "boardparms.h" +#include "bcm_intr.h" +#include "board.h" +#include "bcm_map_part.h" + +static DEFINE_SPINLOCK(board_lock); + +/* Typedefs. */ +#if defined (NON_CONSECUTIVE_MAC) +// used to be the last octet. Now changed to the first 5 bits of the the forth octet +// to reduced the duplicated MAC addresses. +#define CHANGED_OCTET 3 +#define SHIFT_BITS 3 +#else +#define CHANGED_OCTET 1 +#define SHIFT_BITS 0 +#endif + +typedef struct +{ + unsigned long ulId; + char chInUse; + char chReserved[3]; +} MAC_ADDR_INFO, *PMAC_ADDR_INFO; + +typedef struct +{ + unsigned long ulSdramSize; + unsigned long ulPsiSize; + unsigned long ulNumMacAddrs; + unsigned long ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN]; + MAC_ADDR_INFO MacAddrs[1]; +} NVRAM_INFO, *PNVRAM_INFO; + +typedef struct +{ + unsigned long eventmask; +} BOARD_IOC, *PBOARD_IOC; + + +/*Dyinggasp callback*/ +typedef void (*cb_dgasp_t)(void *arg); +typedef struct _CB_DGASP__LIST +{ + struct list_head list; + char name[IFNAMSIZ]; + cb_dgasp_t cb_dgasp_fn; + void *context; +}CB_DGASP_LIST , *PCB_DGASP_LIST; + + +static LED_MAP_PAIR LedMapping[] = +{ // led name Initial state physical pin (ledMask) + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0}, + {kLedEnd, kLedStateOff, 0, 0, 0, 0} // NOTE: kLedEnd has to be at the end. +}; + +/* Externs. */ +extern struct file fastcall *fget_light(unsigned int fd, int *fput_needed); +extern unsigned int nr_free_pages (void); +extern const char *get_system_type(void); +extern void kerSysFlashInit(void); +extern unsigned long get_nvram_start_addr(void); +extern unsigned long get_scratch_pad_start_addr(void); +extern unsigned long getMemorySize(void); +extern void __init boardLedInit(PLED_MAP_PAIR); +extern void boardLedCtrl(BOARD_LED_NAME, BOARD_LED_STATE); +extern void kerSysLedRegisterHandler( BOARD_LED_NAME ledName, + HANDLE_LED_FUNC ledHwFunc, int ledFailType ); + +/* Prototypes. */ +void __init InitNvramInfo( void ); + +/* DyingGasp function prototype */ +static void __init kerSysDyingGaspMapIntr(void); +static irqreturn_t kerSysDyingGaspIsr(int irq, void * dev_id); +static void __init kerSysInitDyingGaspHandler( void ); +static void __exit kerSysDeinitDyingGaspHandler( void ); +/* -DyingGasp function prototype - */ + +static PNVRAM_INFO g_pNvramInfo = NULL; +static int g_ledInitialized = 0; +static CB_DGASP_LIST *g_cb_dgasp_list_head = NULL; + +static int g_wakeup_monitor = 0; +static struct file *g_monitor_file = NULL; +static struct task_struct *g_monitor_task = NULL; +static unsigned int (*g_orig_fop_poll) + (struct file *, struct poll_table_struct *) = NULL; + +void kerSysMipsSoftReset(void) +{ + if (PERF->RevID == 0x634800A1) { + typedef void (*FNPTR) (void); + FNPTR bootaddr = (FNPTR) FLASH_BASE; + int i; + + /* Disable interrupts. */ + //cli(); + spin_lock_irq(&board_lock); + + /* Reset all blocks. */ + PERF->BlockSoftReset &= ~BSR_ALL_BLOCKS; + for( i = 0; i < 1000000; i++ ) + ; + PERF->BlockSoftReset |= BSR_ALL_BLOCKS; + /* Jump to the power on address. */ + (*bootaddr) (); + } + else + PERF->pll_control |= SOFT_RESET; // soft reset mips +} + + +int kerSysGetMacAddress( unsigned char *pucaMacAddr, unsigned long ulId ) +{ + int nRet = 0; + PMAC_ADDR_INFO pMai = NULL; + PMAC_ADDR_INFO pMaiFreeNoId = NULL; + PMAC_ADDR_INFO pMaiFreeId = NULL; + unsigned long i = 0, ulIdxNoId = 0, ulIdxId = 0, shiftedIdx = 0; + + /* CMO -- Fix le problème avec les adresses mac que l'on n'arrive pas + * * à relire plusieurs fois */ + /* inv_xde */ +#if 0 + if (boot_loader_type == BOOT_CFE) + memcpy( pucaMacAddr, g_pNvramInfo->ucaBaseMacAddr, + NVRAM_MAC_ADDRESS_LEN ); + else { +#endif + pucaMacAddr[0] = 0x00; + pucaMacAddr[1] = 0x07; + pucaMacAddr[2] = 0x3A; + pucaMacAddr[3] = 0xFF; + pucaMacAddr[4] = 0xFF; + pucaMacAddr[5] = 0xFF; +#if 0 + } +#endif + + return nRet; +} /* kerSysGetMacAddr */ + +int kerSysReleaseMacAddress( unsigned char *pucaMacAddr ) +{ + int nRet = -EINVAL; + unsigned long ulIdx = 0; + int idx = (pucaMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET] - + g_pNvramInfo->ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET]); + + // if overflow 255 (negitive), add 256 to have the correct index + if (idx < 0) + idx += 256; + ulIdx = (unsigned long) (idx >> SHIFT_BITS); + + if( ulIdx < g_pNvramInfo->ulNumMacAddrs ) + { + PMAC_ADDR_INFO pMai = &g_pNvramInfo->MacAddrs[ulIdx]; + if( pMai->chInUse == 1 ) + { + pMai->chInUse = 0; + nRet = 0; + } + } + + return( nRet ); +} /* kerSysReleaseMacAddr */ + +int kerSysGetSdramSize( void ) +{ + if (boot_loader_type == BOOT_CFE) { + return( (int) g_pNvramInfo->ulSdramSize ); + } + else { + printk("kerSysGetSdramSize : 0x%08X\n", (int)getMemorySize() + 0x00040000); + return((int)getMemorySize() + 0x00040000); + } +} /* kerSysGetSdramSize */ + + +void kerSysLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState) +{ + if (g_ledInitialized) + boardLedCtrl(ledName, ledState); +} + +unsigned int kerSysMonitorPollHook( struct file *f, struct poll_table_struct *t) +{ + int mask = (*g_orig_fop_poll) (f, t); + + if( g_wakeup_monitor == 1 && g_monitor_file == f ) + { + /* If g_wakeup_monitor is non-0, the user mode application needs to + * return from a blocking select function. Return POLLPRI which will + * cause the select to return with the exception descriptor set. + */ + mask |= POLLPRI; + g_wakeup_monitor = 0; + } + + return( mask ); +} + +/* Put the user mode application that monitors link state on a run queue. */ +void kerSysWakeupMonitorTask( void ) +{ + g_wakeup_monitor = 1; + if( g_monitor_task ) + wake_up_process( g_monitor_task ); +} + +//<GPIOio; + + if( (gpio & ~BP_ACTIVE_MASK) >= 32 ) + { + gpio_mask = GPIO_NUM_TO_MASK_HIGH(gpio); + gpio_reg = &GPIO->GPIOio_high; + } + //printk("gpio=%04x,gpio_mask=%04x,gpio_reg=%04x\n",gpio,gpio_mask,*gpio_reg); + if(*gpio_reg & gpio_mask) //press down + return RESET_BUTTON_UP; + } + return RESET_BUTTON_PRESSDOWN; +} +//<WatchDogDefCount = timeUs * (FPERIPH/1000000); + TIMER->WatchDogCtl = 0xFF00; + TIMER->WatchDogCtl = 0x00FF; +} + +ulong kerSysGetCycleCount(void) +{ + ulong cnt; +#ifdef _WIN32_WCE + cnt = 0; +#else + __asm volatile("mfc0 %0, $9":"=d"(cnt)); +#endif + return(cnt); +} + +static Bool kerSysDyingGaspCheckPowerLoss(void) +{ + ulong clk0; + ulong ulIntr; + + ulIntr = 0; + clk0 = kerSysGetCycleCount(); + + UART->Data = 'D'; + UART->Data = '%'; + UART->Data = 'G'; + +#if defined(CONFIG_BCM96345) + BpGetAdslDyingGaspExtIntr( &ulIntr ); + + do { + ulong clk1; + + clk1 = kerSysGetCycleCount(); /* time cleared */ + /* wait a little to get new reading */ + while ((kerSysGetCycleCount()-clk1) < CYCLE_PER_US*2) + ; + } while ((0 == (PERF->ExtIrqCfg & (1 << (ulIntr + EI_STATUS_SHFT)))) && ((kerSysGetCycleCount() - clk0) < DG_GLITCH_TO)); + + if (PERF->ExtIrqCfg & (1 << (ulIntr + EI_STATUS_SHFT))) { /* power glitch */ + BcmHalInterruptEnable( ulIntr + INTERRUPT_ID_EXTERNAL_0); + KERSYS_DBG(" - Power glitch detected. Duration: %ld us\n", (kerSysGetCycleCount() - clk0)/CYCLE_PER_US); + return 0; + } +#elif (defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)) && !defined(VXWORKS) + do { + ulong clk1; + + clk1 = kerSysGetCycleCount(); /* time cleared */ + /* wait a little to get new reading */ + while ((kerSysGetCycleCount()-clk1) < CYCLE_PER_US*2) + ; + } while ((PERF->IrqStatus & (1 << (INTERRUPT_ID_DG - INTERNAL_ISR_TABLE_OFFSET))) && ((kerSysGetCycleCount() - clk0) < DG_GLITCH_TO)); + + if (!(PERF->IrqStatus & (1 << (INTERRUPT_ID_DG - INTERNAL_ISR_TABLE_OFFSET)))) { + BcmHalInterruptEnable( INTERRUPT_ID_DG ); + KERSYS_DBG(" - Power glitch detected. Duration: %ld us\n", (kerSysGetCycleCount() - clk0)/CYCLE_PER_US); + return 0; + } +#endif + return 1; +} + +static void kerSysDyingGaspShutdown( void ) +{ + kerSysSetWdTimer(1000000); +#if defined(CONFIG_BCM96345) + PERF->blkEnables &= ~(EMAC_CLK_EN | USB_CLK_EN | CPU_CLK_EN); +#elif defined(CONFIG_BCM96348) + PERF->blkEnables &= ~(EMAC_CLK_EN | USBS_CLK_EN | USBH_CLK_EN | SAR_CLK_EN); +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +static irqreturn_t kerSysDyingGaspIsr(int irq, void * dev_id) +#else +static unsigned int kerSysDyingGaspIsr(void) +#endif +{ + struct list_head *pos; + CB_DGASP_LIST *tmp, *dsl = NULL; + + if (kerSysDyingGaspCheckPowerLoss()) { + + /* first to turn off everything other than dsl */ + list_for_each(pos, &g_cb_dgasp_list_head->list) { + tmp = list_entry(pos, CB_DGASP_LIST, list); + if(strncmp(tmp->name, "dsl", 3)) { + (tmp->cb_dgasp_fn)(tmp->context); + }else { + dsl = tmp; + } + } + + /* now send dgasp */ + if(dsl) + (dsl->cb_dgasp_fn)(dsl->context); + + /* reset and shutdown system */ + kerSysDyingGaspShutdown(); + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +return( IRQ_HANDLED ); +#else + return( 1 ); +#endif +} + +static void __init kerSysInitDyingGaspHandler( void ) +{ + CB_DGASP_LIST *new_node; + + if( g_cb_dgasp_list_head != NULL) { + printk("Error: kerSysInitDyingGaspHandler: list head is not null\n"); + return; + } + new_node= (CB_DGASP_LIST *)kmalloc(sizeof(CB_DGASP_LIST), GFP_KERNEL); + memset(new_node, 0x00, sizeof(CB_DGASP_LIST)); + INIT_LIST_HEAD(&new_node->list); + g_cb_dgasp_list_head = new_node; + +} /* kerSysInitDyingGaspHandler */ + +static void __exit kerSysDeinitDyingGaspHandler( void ) +{ + struct list_head *pos; + CB_DGASP_LIST *tmp; + + if(g_cb_dgasp_list_head == NULL) + return; + + list_for_each(pos, &g_cb_dgasp_list_head->list) { + tmp = list_entry(pos, CB_DGASP_LIST, list); + list_del(pos); + kfree(tmp); + } + + kfree(g_cb_dgasp_list_head); + g_cb_dgasp_list_head = NULL; + +} /* kerSysDeinitDyingGaspHandler */ + +void kerSysRegisterDyingGaspHandler(char *devname, void *cbfn, void *context) +{ + CB_DGASP_LIST *new_node; + + if( g_cb_dgasp_list_head == NULL) { + printk("Error: kerSysRegisterDyingGaspHandler: list head is null\n"); + return; + } + + if( devname == NULL || cbfn == NULL ) { + printk("Error: kerSysRegisterDyingGaspHandler: register info not enough (%s,%x,%x)\n", devname, (unsigned int)cbfn, (unsigned int)context); + return; + } + + new_node= (CB_DGASP_LIST *)kmalloc(sizeof(CB_DGASP_LIST), GFP_KERNEL); + memset(new_node, 0x00, sizeof(CB_DGASP_LIST)); + INIT_LIST_HEAD(&new_node->list); + strncpy(new_node->name, devname, IFNAMSIZ); + new_node->cb_dgasp_fn = (cb_dgasp_t)cbfn; + new_node->context = context; + list_add(&new_node->list, &g_cb_dgasp_list_head->list); + + printk("dgasp: kerSysRegisterDyingGaspHandler: %s registered \n", devname); + +} /* kerSysRegisterDyingGaspHandler */ + +void kerSysDeregisterDyingGaspHandler(char *devname) +{ + struct list_head *pos; + CB_DGASP_LIST *tmp; + + if(g_cb_dgasp_list_head == NULL) { + printk("Error: kerSysDeregisterDyingGaspHandler: list head is null\n"); + return; + } + + if(devname == NULL) { + printk("Error: kerSysDeregisterDyingGaspHandler: devname is null\n"); + return; + } + + printk("kerSysDeregisterDyingGaspHandler: %s is deregistering\n", devname); + + list_for_each(pos, &g_cb_dgasp_list_head->list) { + tmp = list_entry(pos, CB_DGASP_LIST, list); + if(!strcmp(tmp->name, devname)) { + list_del(pos); + kfree(tmp); + printk("kerSysDeregisterDyingGaspHandler: %s is deregistered\n", devname); + return; + } + } + printk("kerSysDeregisterDyingGaspHandler: %s not (de)registered\n", devname); + +} /* kerSysDeregisterDyingGaspHandler */ + +//EXPORT_SYMBOL(kerSysNvRamGet); +EXPORT_SYMBOL(kerSysGetMacAddress); +EXPORT_SYMBOL(kerSysReleaseMacAddress); +EXPORT_SYMBOL(kerSysGetSdramSize); +EXPORT_SYMBOL(kerSysLedCtrl); +EXPORT_SYMBOL(kerSysGetResetHold); +EXPORT_SYMBOL(kerSysLedRegisterHwHandler); +EXPORT_SYMBOL(BpGetBoardIds); +EXPORT_SYMBOL(BpGetSdramSize); +EXPORT_SYMBOL(BpGetPsiSize); +EXPORT_SYMBOL(BpGetEthernetMacInfo); +EXPORT_SYMBOL(BpGetRj11InnerOuterPairGpios); +EXPORT_SYMBOL(BpGetPressAndHoldResetGpio); +EXPORT_SYMBOL(BpGetVoipResetGpio); +EXPORT_SYMBOL(BpGetVoipIntrGpio); +EXPORT_SYMBOL(BpGetPcmciaResetGpio); +EXPORT_SYMBOL(BpGetRtsCtsUartGpios); +EXPORT_SYMBOL(BpGetAdslLedGpio); +EXPORT_SYMBOL(BpGetAdslFailLedGpio); +EXPORT_SYMBOL(BpGetWirelessLedGpio); +EXPORT_SYMBOL(BpGetUsbLedGpio); +EXPORT_SYMBOL(BpGetHpnaLedGpio); +EXPORT_SYMBOL(BpGetWanDataLedGpio); +EXPORT_SYMBOL(BpGetPppLedGpio); +EXPORT_SYMBOL(BpGetPppFailLedGpio); +EXPORT_SYMBOL(BpGetVoipLedGpio); +EXPORT_SYMBOL(BpGetWirelessExtIntr); +EXPORT_SYMBOL(BpGetAdslDyingGaspExtIntr); +EXPORT_SYMBOL(BpGetVoipExtIntr); +EXPORT_SYMBOL(BpGetHpnaExtIntr); +EXPORT_SYMBOL(BpGetHpnaChipSelect); +EXPORT_SYMBOL(BpGetVoipChipSelect); +EXPORT_SYMBOL(BpGetWirelessSesBtnGpio); +EXPORT_SYMBOL(BpGetWirelessSesExtIntr); +EXPORT_SYMBOL(BpGetWirelessSesLedGpio); +EXPORT_SYMBOL(kerSysRegisterDyingGaspHandler); +EXPORT_SYMBOL(kerSysDeregisterDyingGaspHandler); +EXPORT_SYMBOL(kerSysGetCycleCount); +EXPORT_SYMBOL(kerSysSetWdTimer); +EXPORT_SYMBOL(kerSysWakeupMonitorTask); +