/****************************************************************************** Copyright (c) 2010 Lantiq Deutschland GmbH Am Campeon 3; 85579 Neubiberg, Germany For licensing information, see the file 'LICENSE' in the root folder of this software module. ******************************************************************************/ /*! \defgroup AMAZON_S_MEI Amazon-S MEI Driver Module \brief Amazon-S MEI driver module */ /*! \defgroup Internal Compile Parametere \ingroup AMAZON_S_MEI \brief exported functions for other driver use */ /*! \file amazon_s_mei_bsp.c \ingroup AMAZON_S_MEI \brief Amazon-S MEI driver file */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #define IFX_MEI_BSP #include "ifxmips_mei_interface.h" #include #define IFXMIPS_RCU_RST IFX_RCU_RST_REQ #define IFXMIPS_RCU_RST_REQ_ARC_JTAG IFX_RCU_RST_REQ_ARC_JTAG #define IFXMIPS_RCU_RST_REQ_DFE IFX_RCU_RST_REQ_DFE #define IFXMIPS_RCU_RST_REQ_AFE IFX_RCU_RST_REQ_AFE #define IFXMIPS_FUSE_BASE_ADDR IFX_FUSE_BASE_ADDR #define IFXMIPS_ICU_IM0_IER IFX_ICU_IM0_IER #define IFXMIPS_ICU_IM2_IER IFX_ICU_IM2_IER #define IFXMIPS_MEI_INT IFX_MEI_INT #define IFXMIPS_MEI_DYING_GASP_INT IFX_MEI_DYING_GASP_INT #define IFXMIPS_MEI_BASE_ADDR IFX_MEI_SPACE_ACCESS #define IFXMIPS_PMU_PWDCR IFX_PMU_PWDCR #define IFXMIPS_MPS_CHIPID IFX_MPS_CHIPID #define ifxmips_port_reserve_pin ifx_gpio_pin_reserve #define ifxmips_port_set_dir_in ifx_gpio_dir_in_set #define ifxmips_port_clear_altsel0 ifx_gpio_altsel0_set #define ifxmips_port_clear_altsel1 ifx_gpio_altsel1_clear #define ifxmips_port_set_open_drain ifx_gpio_open_drain_clear #define ifxmips_port_free_pin ifx_gpio_pin_free #define ifxmips_mask_and_ack_irq bsp_mask_and_ack_irq #define IFXMIPS_MPS_CHIPID_VERSION_GET IFX_MCD_CHIPID_VERSION_GET #define ifxmips_r32(reg) __raw_readl(reg) #define ifxmips_w32(val, reg) __raw_writel(val, reg) #define ifxmips_w32_mask(clear, set, reg) ifxmips_w32((ifxmips_r32(reg) & ~clear) | set, reg) #define IFX_MEI_EMSG(fmt, args...) printk(KERN_ERR "[%s %d]: " fmt,__FUNCTION__, __LINE__, ## args) #define IFX_MEI_DMSG(fmt, args...) printk(KERN_INFO "[%s %d]: " fmt,__FUNCTION__, __LINE__, ## args) #ifdef CONFIG_IFXMIPS_MEI_FW_LOOPBACK /*#define DFE_MEM_TEST*/ /*#define DFE_PING_TEST*/ #define DFE_ATM_LOOPBACK #ifdef DFE_PING_TEST #include "dsp_xmem_arb_rand_em.h" #endif #ifdef DFE_MEM_TEST #include "aai_mem_test.h" #endif #ifdef DFE_ATM_LOOPBACK #include #endif void dfe_loopback_irq_handler (DSL_DEV_Device_t *pDev); #endif /*CONFIG_AMAZON_S_MEI_FW_LOOPBACK*/ /*AVMac: AVM_VERSION_NUMBER*/ DSL_DEV_Version_t avm_bsp_mei_version = { major: 5, minor: 0, revision:0 }; DSL_DEV_Version_t bsp_mei_version = { major: 5, minor: 1, revision: 5 }; DSL_DEV_HwVersion_t bsp_chip_info; #ifndef MEI_DEBUG_DISABLE /* Initial debug level by module*/ MEI_DebugInfo_t g_MEI_DebugLevel[MEI_DBG_MOD_LAST] = { {"MEI_DBG_MOD_COM", MEI_DBG_ERR}, /* MEI_DBG_MOD_COM*/ {"MEI_DBG_MOD_CMV", MEI_DBG_ERR}, /* MEI_DBG_MOD_CMV*/ {"MEI_DBG_MOD_TST", MEI_DBG_ERR} /* MEI_DBG_MOD_TST*/ }; #endif /* #ifndef MEI_DEBUG_DISABLE*/ #define IFX_MEI_DEVNAME "ifx_mei" #define BSP_MAX_DEVICES 1 DSL_DEV_MeiError_t DSL_BSP_FWDownload( DSL_DEV_Device_t *, const char *, unsigned long, long *, long *); DSL_DEV_MeiError_t DSL_BSP_Showtime( DSL_DEV_Device_t *, DSL_uint32_t, DSL_uint32_t); DSL_DEV_MeiError_t DSL_BSP_ShowtimeExit( DSL_DEV_Device_t *); DSL_DEV_MeiError_t DSL_BSP_AdslLedInit( DSL_DEV_Device_t *, DSL_DEV_LedId_t, DSL_DEV_LedType_t, DSL_DEV_LedHandler_t); /*DSL_DEV_MeiError_t DSL_BSP_AdslLedSet( DSL_DEV_Device_t *, DSL_DEV_LedId_t, DSL_DEV_LedMode_t);*/ DSL_DEV_MeiError_t DSL_BSP_MemoryDebugAccess( DSL_DEV_Device_t *, DSL_BSP_MemoryAccessType_t, DSL_uint32_t, DSL_uint32_t*, DSL_uint32_t); DSL_DEV_MeiError_t DSL_BSP_SendCMV( DSL_DEV_Device_t *, u16 *, int, u16 *); int DSL_BSP_KernelIoctls( DSL_DEV_Device_t *, unsigned int, unsigned long); static DSL_DEV_MeiError_t IFX_MEI_RunAdslModem( DSL_DEV_Device_t *); static DSL_DEV_MeiError_t IFX_MEI_CpuModeSet( DSL_DEV_Device_t *, DSL_DEV_CpuMode_t); static DSL_DEV_MeiError_t IFX_MEI_DownloadBootCode( DSL_DEV_Device_t *); static DSL_DEV_MeiError_t IFX_MEI_ArcJtagEnable( DSL_DEV_Device_t *, int); static DSL_DEV_MeiError_t IFX_MEI_AdslMailboxIRQEnable( DSL_DEV_Device_t *, int); static int IFX_MEI_GetPage( DSL_DEV_Device_t *, u32, u32, u32, u32 *, u32 *); static int IFX_MEI_BarUpdate( DSL_DEV_Device_t *, int); static ssize_t IFX_MEI_Write( DSL_DRV_file_t *, const char *, size_t, loff_t *); static int IFX_MEI_UserIoctls( DSL_DRV_inode_t *, DSL_DRV_file_t *, unsigned int, unsigned long); static int IFX_MEI_Open( DSL_DRV_inode_t *, DSL_DRV_file_t *); static int IFX_MEI_Release( DSL_DRV_inode_t *, DSL_DRV_file_t *); void AMAZON_SE_MEI_ARC_MUX_Test(void); #ifdef CONFIG_PROC_FS static int IFX_MEI_ProcRead( struct file *, char *, size_t, loff_t *); static ssize_t IFX_MEI_ProcWrite( struct file *, const char *, size_t, loff_t *); #define MAX_PROC_ITEMS 12 #define MEI_DIRNAME "ifxmips_mei" static struct proc_dir_entry *meidir; static struct file_operations IFX_MEI_ProcOperations = { read : IFX_MEI_ProcRead, write : IFX_MEI_ProcWrite, }; /* total items to be monitored by /proc/mei*/ static reg_entry_t regs[BSP_MAX_DEVICES][MAX_PROC_ITEMS]; #define NUM_OF_REG_ENTRY (sizeof(regs[0])/sizeof(reg_entry_t)) #endif /* CONFIG_PROC_FS*/ void IFX_MEI_ARC_MUX_Test(void); static int adsl_dummy_ledcallback(void); int (*ifx_mei_atm_showtime_enter)(struct port_cell_info *, void *) = NULL; EXPORT_SYMBOL(ifx_mei_atm_showtime_enter); int (*ifx_mei_atm_showtime_exit)(void) = NULL; EXPORT_SYMBOL(ifx_mei_atm_showtime_exit); static int (*g_adsl_ledcallback)(void) = adsl_dummy_ledcallback; static unsigned int g_tx_link_rate[2] = {0}; static void *g_xdata_addr = NULL; /* holding swap pages*/ static u32 *mei_arc_swap_buff = NULL; extern void ifxmips_mask_and_ack_irq(unsigned int irq_nr); #define MEI_MASK_AND_ACK_IRQ ifxmips_mask_and_ack_irq static int dev_major = 105; static struct file_operations bsp_mei_operations = { owner : THIS_MODULE, open : IFX_MEI_Open, release : IFX_MEI_Release, write : IFX_MEI_Write, ioctl : IFX_MEI_UserIoctls, }; static DSL_DEV_Device_t dsl_devices[BSP_MAX_DEVICES]; static ifx_mei_device_private_t sDanube_Mei_Private[BSP_MAX_DEVICES]; /* To prevent xDATA_REGISTER allocation during very firmware download */ static int xdata_alloc = 0; static DSL_BSP_EventCallBack_t dsl_bsp_event_callback[DSL_BSP_CB_LAST + 1]; /** * Write a value to register * This function writes a value to danube register * * \param ul_address The address to write * \param ul_data The value to write * \ingroup Internal */ static void IFX_MEI_LongWordWrite( u32 ul_address, u32 ul_data) { IFX_MEI_WRITE_REGISTER_L (ul_data, ul_address); wmb(); return; } /** * Write a value to register * This function writes a value to danube register * * \param pDev the device pointer * \param ul_address The address to write * \param ul_data The value to write * \ingroup Internal */ static void IFX_MEI_LongWordWriteOffset( DSL_DEV_Device_t * pDev, u32 ul_address, u32 ul_data) { IFX_MEI_WRITE_REGISTER_L (ul_data, pDev->base_address + ul_address); wmb(); return; } /** * Read the danube register * This function read the value from danube register * * \param ul_address The address to write * \param pul_data Pointer to the data * \ingroup Internal */ static void IFX_MEI_LongWordRead( u32 ul_address, u32 * pul_data) { *pul_data = IFX_MEI_READ_REGISTER_L (ul_address); rmb(); return; } /** * Read the danube register * This function read the value from danube register * * \param pDev the device pointer * \param ul_address The address to write * \param pul_data Pointer to the data * \ingroup Internal */ static void IFX_MEI_LongWordReadOffset( DSL_DEV_Device_t * pDev, u32 ul_address, u32 * pul_data) { *pul_data = IFX_MEI_READ_REGISTER_L (pDev->base_address + ul_address); rmb(); return; } /** * Write several DWORD datas to ARC memory via ARC DMA interface * This function writes several DWORD datas to ARC memory via DMA interface. * * \param pDev the device pointer * \param destaddr The address to write * \param databuff Pointer to the data buffer * \param databuffsize Number of DWORDs to write * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_DMAWrite( DSL_DEV_Device_t * pDev, u32 destaddr, u32 * databuff, u32 databuffsize) { u32 *p = databuff; u32 temp; if (destaddr & 3) { return DSL_DEV_MEI_ERR_FAILURE; } /* Set the write transfer address*/ IFX_MEI_LongWordWriteOffset(pDev, ME_DX_AD, destaddr); /* Write the data pushed across DMA*/ while (databuffsize--) { temp = *p; if (destaddr == MEI_TO_ARC_MAILBOX) { MEI_HALF_WORD_SWAP (temp); } IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_DX_DATA, temp); p++; } return DSL_DEV_MEI_ERR_SUCCESS; } /** * Read several DWORD datas from ARC memory via ARC DMA interface * This function reads several DWORD datas from ARC memory via DMA interface. * * \param pDev the device pointer * \param srcaddr The address to read * \param databuff Pointer to the data buffer * \param databuffsize Number of DWORDs to read * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_DMARead( DSL_DEV_Device_t * pDev, u32 srcaddr, u32 * databuff, u32 databuffsize) { u32 *p = databuff; u32 temp; if (srcaddr & 3) { return DSL_DEV_MEI_ERR_FAILURE; } /* Set the read transfer address*/ IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_DX_AD, srcaddr); /* Read the data popped across DMA*/ while (databuffsize--) { IFX_MEI_LongWordReadOffset (pDev, (u32) ME_DX_DATA, &temp); if (databuff == (u32 *) DSL_DEV_PRIVATE(pDev)->CMV_RxMsg) { /* swap half word*/ MEI_HALF_WORD_SWAP (temp); } *p = temp; p++; } return DSL_DEV_MEI_ERR_SUCCESS; } /** * Switch the ARC control mode * This function switchs the ARC control mode to JTAG mode or MEI mode * * \param pDev the device pointer * \param mode The mode want to switch: JTAG_MASTER_MODE or MEI_MASTER_MODE. * \ingroup Internal */ static void IFX_MEI_ControlModeSet( DSL_DEV_Device_t * pDev, int mode) { u32 temp = 0x0; IFX_MEI_LongWordReadOffset(pDev, (u32) ME_DBG_MASTER, &temp); switch (mode) { case JTAG_MASTER_MODE: temp &= ~(HOST_MSTR); break; case MEI_MASTER_MODE: temp |= (HOST_MSTR); break; default: MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - IFX_MEI_ControlModeSet: unkonwn mode [%d]"MEI_CRLF, mode)); return; } IFX_MEI_LongWordWriteOffset (pDev, (u32) ME_DBG_MASTER, temp); } /** * Disable ARC to MEI interrupt * * \param pDev the device pointer * \ingroup Internal */ static void IFX_MEI_IRQDisable( DSL_DEV_Device_t * pDev) { IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_ARC2ME_MASK, 0x0); } /** * Eable ARC to MEI interrupt * * \param pDev the device pointer * \ingroup Internal */ static void IFX_MEI_IRQEnable( DSL_DEV_Device_t * pDev) { IFX_MEI_LongWordWriteOffset (pDev, (u32) ME_ARC2ME_MASK, MSGAV_EN); } /** * Poll for transaction complete signal * This function polls and waits for transaction complete signal. * * \param pDev the device pointer * \ingroup Internal */ static void meiPollForDbgDone( DSL_DEV_Device_t * pDev) { u32 query = 0; int i = 0; while (i < WHILE_DELAY) { IFX_MEI_LongWordReadOffset (pDev, (u32) ME_ARC2ME_STAT, &query); query &= (ARC_TO_MEI_DBG_DONE); if (query) { break; } i++; if (i == WHILE_DELAY) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - poll for DBG_DONE failed"MEI_CRLF)); } } /* to clear this interrupt*/ IFX_MEI_LongWordWriteOffset (pDev, (u32) ME_ARC2ME_STAT, ARC_TO_MEI_DBG_DONE); } /** * ARC Debug Memory Access for a single DWORD reading. * This function used for direct, address-based access to ARC memory. * * \param pDev the device pointer * \param DEC_mode ARC memory space to used * \param address Address to read * \param data Pointer to data * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t _IFX_MEI_DBGLongWordRead( DSL_DEV_Device_t * pDev, u32 DEC_mode, u32 address, u32 * data) { IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_DBG_DECODE, DEC_mode); IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_DBG_RD_AD, address); meiPollForDbgDone (pDev); IFX_MEI_LongWordReadOffset(pDev, (u32) ME_DBG_DATA, data); return DSL_DEV_MEI_ERR_SUCCESS; } /** * ARC Debug Memory Access for a single DWORD writing. * This function used for direct, address-based access to ARC memory. * * \param pDev the device pointer * \param DEC_mode ARC memory space to used * \param address The address to write * \param data The data to write * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t _IFX_MEI_DBGLongWordWrite( DSL_DEV_Device_t * pDev, u32 DEC_mode, u32 address, u32 data) { IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_DBG_DECODE, DEC_mode); IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_DBG_WR_AD, address); IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_DBG_DATA, data); meiPollForDbgDone (pDev); return DSL_DEV_MEI_ERR_SUCCESS; } /** * ARC Debug Memory Access for writing. * This function used for direct, address-based access to ARC memory. * * \param pDev the device pointer * \param destaddr The address to read * \param databuffer Pointer to data * \param databuffsize The number of DWORDs to read * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_DebugWrite( DSL_DEV_Device_t * pDev, u32 destaddr, u32 * databuff, u32 databuffsize) { u32 i; u32 temp = 0x0; u32 address = 0x0; u32 *buffer = 0x0; /* Open the debug port before DMP memory write*/ IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); /* For the requested length, write the address and write the data*/ address = destaddr; buffer = databuff; for (i = 0; i < databuffsize; i++) { temp = *buffer; _IFX_MEI_DBGLongWordWrite(pDev, ME_DBG_DECODE_DMP1_MASK, address, temp); address += 4; buffer++; } /* Close the debug port after DMP memory write*/ IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); return DSL_DEV_MEI_ERR_SUCCESS; } /** * ARC Debug Memory Access for reading. * This function used for direct, address-based access to ARC memory. * * \param pDev the device pointer * \param srcaddr The address to read * \param databuffer Pointer to data * \param databuffsize The number of DWORDs to read * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_DebugRead( DSL_DEV_Device_t * pDev, u32 srcaddr, u32 * databuff, u32 databuffsize) { u32 i; u32 temp = 0x0; u32 address = 0x0; u32 *buffer = 0x0; /* Open the debug port before DMP memory read*/ IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); /* For the requested length, write the address and read the data*/ address = srcaddr; buffer = databuff; for (i = 0; i < databuffsize; i++) { _IFX_MEI_DBGLongWordRead(pDev, ME_DBG_DECODE_DMP1_MASK, address, &temp); *buffer = temp; address += 4; buffer++; } /* Close the debug port after DMP memory read*/ IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); return DSL_DEV_MEI_ERR_SUCCESS; } /** * Send a message to ARC MailBox. * This function sends a message to ARC Mailbox via ARC DMA interface. * * \param pDev the device pointer * \param msgsrcbuffer Pointer to message. * \param msgsize The number of words to write. * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_MailboxWrite( DSL_DEV_Device_t * pDev, u16 * msgsrcbuffer, u16 msgsize) { int i; u32 arc_mailbox_status = 0x0; u32 temp = 0; DSL_DEV_MeiError_t meiMailboxError = DSL_DEV_MEI_ERR_SUCCESS; /* Write to mailbox*/ meiMailboxError = IFX_MEI_DMAWrite(pDev, MEI_TO_ARC_MAILBOX, (u32 *)msgsrcbuffer, msgsize / 2); meiMailboxError = IFX_MEI_DMAWrite(pDev, MEI_TO_ARC_MAILBOXR, (u32 *)(&temp), 1); /* Notify arc that mailbox write completed*/ DSL_DEV_PRIVATE(pDev)->cmv_waiting = 1; IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_ME2ARC_INT, MEI_TO_ARC_MSGAV); i = 0; /* wait for ARC to clear the bit*/ while (i < WHILE_DELAY) { IFX_MEI_LongWordReadOffset(pDev, (u32) ME_ME2ARC_INT, &arc_mailbox_status); if ((arc_mailbox_status & MEI_TO_ARC_MSGAV) != MEI_TO_ARC_MSGAV) break; i++; if (i == WHILE_DELAY) { MEI_DEBUG(MEI_DBG_MOD_CMV, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Timeout waiting for ARC to clear" "MEI2ARC_MSGAV MEI2ARC message size = %d DWORDs"MEI_CRLF, msgsize/2)); meiMailboxError = DSL_DEV_MEI_ERR_FAILURE; } } return meiMailboxError; } /** * Read a message from ARC MailBox. * This function reads a message from ARC Mailbox via ARC DMA interface. * * \param pDev the device pointer * \param msgsrcbuffer Pointer to message. * \param msgsize The number of words to read * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_MailboxRead( DSL_DEV_Device_t * pDev, u16 * msgdestbuffer, u16 msgsize) { DSL_DEV_MeiError_t meiMailboxError = DSL_DEV_MEI_ERR_SUCCESS; /* Read from mailbox*/ meiMailboxError = IFX_MEI_DMARead(pDev, ARC_TO_MEI_MAILBOX, (u32 *)msgdestbuffer, msgsize / 2); /* Notify arc that mailbox read completed*/ IFX_MEI_LongWordWriteOffset (pDev, (u32)ME_ARC2ME_STAT, ARC_TO_MEI_MSGAV); return meiMailboxError; } /** * Download boot pages to ARC. * This function downloads boot pages to ARC. * * \param pDev the device pointer * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_DownloadBootPages( DSL_DEV_Device_t * pDev) { int boot_loop; int page_size; u32 dest_addr; /* DMA the boot code page(s) */ for (boot_loop = 1; boot_loop < (DSL_DEV_PRIVATE(pDev)->img_hdr-> count); boot_loop++) { if ((DSL_DEV_PRIVATE(pDev)-> img_hdr->page[boot_loop].p_size) & BOOT_FLAG) { page_size = IFX_MEI_GetPage(pDev, boot_loop, GET_PROG, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr); if (page_size > 0) { IFX_MEI_DMAWrite(pDev, dest_addr, mei_arc_swap_buff, page_size); } } if ((DSL_DEV_PRIVATE(pDev)-> img_hdr->page[boot_loop].d_size) & BOOT_FLAG) { page_size = IFX_MEI_GetPage(pDev, boot_loop, GET_DATA, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr); if (page_size > 0) { IFX_MEI_DMAWrite(pDev, dest_addr, mei_arc_swap_buff, page_size); } } } return DSL_DEV_MEI_ERR_SUCCESS; } /** * Initial efuse rar. **/ static void IFX_MEI_FuseInit( DSL_DEV_Device_t * pDev) { u32 data = 0; IFX_MEI_DMAWrite(pDev, IRAM0_BASE, &data, 1); IFX_MEI_DMAWrite(pDev, IRAM0_BASE + 4, &data, 1); IFX_MEI_DMAWrite(pDev, IRAM1_BASE, &data, 1); IFX_MEI_DMAWrite(pDev, IRAM1_BASE + 4, &data, 1); IFX_MEI_DMAWrite(pDev, BRAM_BASE, &data, 1); IFX_MEI_DMAWrite(pDev, BRAM_BASE + 4, &data, 1); IFX_MEI_DMAWrite(pDev, ADSL_DILV_BASE, &data, 1); IFX_MEI_DMAWrite(pDev, ADSL_DILV_BASE + 4, &data, 1); } /** * efuse rar program **/ static void IFX_MEI_FuseProg( DSL_DEV_Device_t * pDev) { u32 reg_data, fuse_value; int i = 0; IFX_MEI_LongWordRead((u32) IFXMIPS_RCU_RST, ®_data); while ((reg_data & 0x10000000) == 0) { IFX_MEI_LongWordRead((u32) IFXMIPS_RCU_RST, ®_data); i++; /* 0x4000 translate to about 16 ms@111M, so should be enough */ if (i == 0x4000) return; } /* STEP a: Prepare memory for external accesses*/ /* Write fuse_en bit24*/ IFX_MEI_LongWordRead((u32) IFXMIPS_RCU_RST, ®_data); IFX_MEI_LongWordWrite((u32) IFXMIPS_RCU_RST, reg_data | (1 << 24)); IFX_MEI_FuseInit (pDev); for (i = 0; i < 4; i++) { IFX_MEI_LongWordRead((u32) (IFXMIPS_FUSE_BASE_ADDR) + i * 4, &fuse_value); switch (fuse_value & 0xF0000) { case 0x80000: reg_data = ((fuse_value & RX_DILV_ADDR_BIT_MASK) | (RX_DILV_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, ADSL_DILV_BASE, ®_data, 1); break; case 0x90000: reg_data = ((fuse_value & RX_DILV_ADDR_BIT_MASK) | (RX_DILV_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, ADSL_DILV_BASE + 4, ®_data, 1); break; case 0xA0000: reg_data = ((fuse_value & IRAM0_ADDR_BIT_MASK) | (IRAM0_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, IRAM0_BASE, ®_data, 1); break; case 0xB0000: reg_data = ((fuse_value & IRAM0_ADDR_BIT_MASK) | (IRAM0_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, IRAM0_BASE + 4, ®_data, 1); break; case 0xC0000: reg_data = ((fuse_value & IRAM1_ADDR_BIT_MASK) | (IRAM1_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, IRAM1_BASE, ®_data, 1); break; case 0xD0000: reg_data = ((fuse_value & IRAM1_ADDR_BIT_MASK) | (IRAM1_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, IRAM1_BASE + 4, ®_data, 1); break; case 0xE0000: reg_data = ((fuse_value & BRAM_ADDR_BIT_MASK) | (BRAM_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, BRAM_BASE, ®_data, 1); break; case 0xF0000: reg_data = ((fuse_value & BRAM_ADDR_BIT_MASK) | (BRAM_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite(pDev, BRAM_BASE + 4, ®_data, 1); break; /* PPE efuse*/ default: break; } } IFX_MEI_LongWordRead((u32) IFXMIPS_RCU_RST, ®_data); IFX_MEI_LongWordWrite((u32) IFXMIPS_RCU_RST, reg_data & ~(1 << 24)); IFX_MEI_LongWordRead((u32) IFXMIPS_RCU_RST, ®_data); } /** * Enable DFE Clock * This function enables DFE Clock * * \param pDev the device pointer * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_EnableCLK( DSL_DEV_Device_t * pDev) { u32 arc_debug_data = 0; IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); /*enable ac_clk signal*/ _IFX_MEI_DBGLongWordRead(pDev, ME_DBG_DECODE_DMP1_MASK, CRI_CCR0, &arc_debug_data); arc_debug_data |= ACL_CLK_MODE_ENABLE; _IFX_MEI_DBGLongWordWrite(pDev, ME_DBG_DECODE_DMP1_MASK, CRI_CCR0, arc_debug_data); IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); return DSL_DEV_MEI_ERR_SUCCESS; } /** * Halt the ARC. * This function halts the ARC. * * \param pDev the device pointer * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_HaltArc( DSL_DEV_Device_t * pDev) { u32 arc_debug_data = 0x0; /* Switch arc control from JTAG mode to MEI mode*/ IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); _IFX_MEI_DBGLongWordRead(pDev, MEI_DEBUG_DEC_AUX_MASK, ARC_DEBUG, &arc_debug_data); arc_debug_data |= ARC_DEBUG_HALT; _IFX_MEI_DBGLongWordWrite(pDev, MEI_DEBUG_DEC_AUX_MASK, ARC_DEBUG, arc_debug_data); /* Switch arc control from MEI mode to JTAG mode*/ IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); MEI_WAIT (10); return DSL_DEV_MEI_ERR_SUCCESS; } /** * Run the ARC. * This function runs the ARC. * * \param pDev the device pointer * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_RunArc( DSL_DEV_Device_t * pDev) { u32 arc_debug_data = 0x0; /* Switch arc control from JTAG mode to MEI mode- write '1' to bit0*/ IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); _IFX_MEI_DBGLongWordRead(pDev, MEI_DEBUG_DEC_AUX_MASK, AUX_STATUS, &arc_debug_data); /* Write debug data reg with content AND with 0xFDFFFFFF (halt bit cleared)*/ arc_debug_data &= ~ARC_AUX_HALT; _IFX_MEI_DBGLongWordWrite(pDev, MEI_DEBUG_DEC_AUX_MASK, AUX_STATUS, arc_debug_data); /* Switch arc control from MEI mode to JTAG mode- write '0' to bit0*/ IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); /* Enable mask for arc codeswap interrupts*/ IFX_MEI_IRQEnable(pDev); return DSL_DEV_MEI_ERR_SUCCESS; } /** * Reset the ARC. * This function resets the ARC. * * \param pDev the device pointer * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_ResetARC( DSL_DEV_Device_t * pDev) { u32 arc_debug_data = 0; IFX_MEI_HaltArc(pDev); /* From conceptual point of view minimum delay of 20 ms is necessary after halt of ARC. However during investigations within context of HDT00225573 issue (a-se compact board issue with ahb access) it turned out that 30 ms needs to be used. */ MEI_WAIT(30); /* reset RCU */ IFX_MEI_LongWordRead((u32)IFXMIPS_RCU_RST, &arc_debug_data); IFX_MEI_LongWordWrite((u32)IFXMIPS_RCU_RST, arc_debug_data | IFXMIPS_RCU_RST_REQ_DFE | IFXMIPS_RCU_RST_REQ_AFE); /* From conceptual point of view minimum delay of 10 ms is necessary after halt of ARC. However during investigations within context of HDT00225573 issue (a-se compact board issue with ahb access) it turned out that 30 ms needs to be used. */ MEI_WAIT(30); IFX_MEI_IRQDisable(pDev); IFX_MEI_EnableCLK(pDev); #if 0 /* reset part of PPE*/ *(unsigned long *) (BSP_PPE32_SRST) = 0xC30; *(unsigned long *) (BSP_PPE32_SRST) = 0xFFF; #endif DSL_DEV_PRIVATE(pDev)->modem_ready = 0; return DSL_DEV_MEI_ERR_SUCCESS; } DSL_DEV_MeiError_t DSL_BSP_Showtime( DSL_DEV_Device_t * dev, DSL_uint32_t rate_fast, DSL_uint32_t rate_intl) { struct port_cell_info port_cell = {0}; MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"SHOWTIME entry with Datarate US intl = %d, fast = %d"MEI_CRLF, (int)rate_intl, (int)rate_fast)); if (rate_fast) { g_tx_link_rate[0] = rate_fast / (53 * 8); } if ( rate_intl ) { g_tx_link_rate[1] = rate_intl / (53 * 8); } if (g_tx_link_rate[0] == 0 && g_tx_link_rate[1] == 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - SHOWTIME Datarate update failed"MEI_CRLF)); } if (ifx_mei_atm_showtime_enter) { port_cell.port_num = 2; port_cell.tx_link_rate[0] = g_tx_link_rate[0]; port_cell.tx_link_rate[1] = g_tx_link_rate[1]; ifx_mei_atm_showtime_enter(&port_cell, g_xdata_addr); } else { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - no hookup from xTM driver to set cell rate" MEI_CRLF)); } return DSL_DEV_MEI_ERR_SUCCESS; } DSL_DEV_MeiError_t DSL_BSP_ShowtimeExit( DSL_DEV_Device_t *dev) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"SHOWTIME exit." MEI_CRLF)); if (ifx_mei_atm_showtime_exit) { ifx_mei_atm_showtime_exit(); } else { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - no hookup from xTM driver to signal showtime exit" MEI_CRLF)); } return DSL_DEV_MEI_ERR_SUCCESS; } /** * Reset/halt/run the DFE. * This function provide operations to reset/halt/run the DFE. * * \param pDev the device pointer * \param mode which operation want to do * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_CpuModeSet( DSL_DEV_Device_t *pDev, DSL_DEV_CpuMode_t mode) { DSL_DEV_MeiError_t err_ret = DSL_DEV_MEI_ERR_FAILURE; switch (mode) { case DSL_CPU_HALT: err_ret = IFX_MEI_HaltArc(pDev); break; case DSL_CPU_RUN: err_ret = IFX_MEI_RunArc(pDev); break; case DSL_CPU_RESET: err_ret = IFX_MEI_ResetARC(pDev); break; default: break; } return err_ret; } /** * Accress DFE memory. * This function provide a way to access DFE memory; * * \param pDev the device pointer * \param type read or write * \param destaddr destination address * \param databuff pointer to hold data * \param databuffsize size want to read/write * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ DSL_DEV_MeiError_t DSL_BSP_MemoryDebugAccess( DSL_DEV_Device_t * pDev, DSL_BSP_MemoryAccessType_t type, DSL_uint32_t destaddr, DSL_uint32_t *databuff, DSL_uint32_t databuffsize) { DSL_DEV_MeiError_t meierr = DSL_DEV_MEI_ERR_SUCCESS; switch (type) { case DSL_BSP_MEMORY_READ: meierr = IFX_MEI_DebugRead(pDev, (u32)destaddr, (u32*)databuff, (u32)databuffsize); break; case DSL_BSP_MEMORY_WRITE: meierr = IFX_MEI_DebugWrite(pDev, (u32)destaddr, (u32*)databuff, (u32)databuffsize); break; } return DSL_DEV_MEI_ERR_SUCCESS; } /** * Download boot code to ARC. * This function downloads boot code to ARC. * * \param pDev the device pointer * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_DownloadBootCode( DSL_DEV_Device_t *pDev) { IFX_MEI_IRQDisable(pDev); IFX_MEI_EnableCLK(pDev); /* program fuse rar*/ IFX_MEI_FuseProg(pDev); IFX_MEI_DownloadBootPages (pDev); return DSL_DEV_MEI_ERR_SUCCESS; } /** * Enable Jtag debugger interface * This function setups mips gpio to enable jtag debugger * * \param pDev the device pointer * \param enable enable or disable * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_ArcJtagEnable( DSL_DEV_Device_t *dev, int enable) { int meierr=0; u32 reg_data; switch (enable) { case 1: /* reserve gpio 9, 10, 11, 14, 19 for ARC JTAG*/ ifxmips_port_reserve_pin (0, 9); ifxmips_port_reserve_pin (0, 10); ifxmips_port_reserve_pin (0, 11); ifxmips_port_reserve_pin (0, 14); ifxmips_port_reserve_pin (1, 3); ifxmips_port_set_dir_in(0, 11); ifxmips_port_clear_altsel0(0, 11); ifxmips_port_clear_altsel1(0, 11); ifxmips_port_set_open_drain(0, 11); /* enable ARC JTAG*/ IFX_MEI_LongWordRead ((u32) IFXMIPS_RCU_RST, ®_data); IFX_MEI_LongWordWrite ((u32) IFXMIPS_RCU_RST, reg_data | IFXMIPS_RCU_RST_REQ_ARC_JTAG); break; case 0: default: /* reserve gpio 9, 10, 11, 14, 19 for ARC JTAG*/ meierr = ifxmips_port_free_pin(0, 9); if (meierr < 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Reserve GPIO 9 Fail"MEI_CRLF)); goto jtag_end; } meierr = ifxmips_port_free_pin(0, 10); if (meierr < 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Reserve GPIO 10 Fail"MEI_CRLF)); goto jtag_end; } meierr = ifxmips_port_free_pin(0, 11); if (meierr < 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Reserve GPIO 11 Fail"MEI_CRLF)); goto jtag_end; } meierr = ifxmips_port_free_pin(0, 14); if (meierr < 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Reserve GPIO 14 Fail"MEI_CRLF)); goto jtag_end; } meierr = ifxmips_port_free_pin(1, 3); if (meierr < 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Reserve GPIO 19 Fail"MEI_CRLF)); goto jtag_end; } break; } jtag_end: if (meierr) { return DSL_DEV_MEI_ERR_FAILURE; } return DSL_DEV_MEI_ERR_SUCCESS; } /** * Enable DFE to MIPS interrupt * This function enable DFE to MIPS interrupt * * \param pDev the device pointer * \param enable enable or disable * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_AdslMailboxIRQEnable( DSL_DEV_Device_t *pDev, int enable) { DSL_DEV_MeiError_t meierr; switch (enable) { case 0: meierr = DSL_DEV_MEI_ERR_SUCCESS; IFX_MEI_IRQDisable(pDev); break; case 1: IFX_MEI_IRQEnable(pDev); meierr = DSL_DEV_MEI_ERR_SUCCESS; break; default: meierr = DSL_DEV_MEI_ERR_FAILURE; break; } return meierr; } /** * Get the modem status * This function return the modem status * * \param pDev the device pointer * \return 1: modem ready 0: not ready * \ingroup Internal */ static int IFX_MEI_IsModemReady( DSL_DEV_Device_t *pDev) { return DSL_DEV_PRIVATE(pDev)->modem_ready; } DSL_DEV_MeiError_t DSL_BSP_AdslLedInit( DSL_DEV_Device_t * dev, DSL_DEV_LedId_t led_number, DSL_DEV_LedType_t type, DSL_DEV_LedHandler_t handler) { #if 0 struct led_config_param param; if (led_number == DSL_LED_LINK_ID && type == DSL_LED_LINK_TYPE && handler == /*DSL_LED_HD_CPU*/DSL_LED_HD_FW) { param.operation_mask = CONFIG_OPERATION_UPDATE_SOURCE; param.led = 0x01; param.source = 0x01; /* bsp_led_config (¶m);*/ } else if (led_number == DSL_LED_DATA_ID && type == DSL_LED_DATA_TYPE && (handler == DSL_LED_HD_FW)) { param.operation_mask = CONFIG_OPERATION_UPDATE_SOURCE; param.led = 0x02; param.source = 0x02; /* bsp_led_config (¶m);*/ } #endif return DSL_DEV_MEI_ERR_SUCCESS; } #if 0 DSL_DEV_MeiError_t DSL_BSP_AdslLedSet( DSL_DEV_Device_t * dev, DSL_DEV_LedId_t led_number, DSL_DEV_LedMode_t mode) { printk(KERN_INFO "[%s %d]: mode = %#x, led_number = %d\n", __func__, __LINE__, mode, led_number); switch (mode) { case DSL_LED_OFF: switch (led_number) { case DSL_LED_LINK_ID: #ifdef CONFIG_BSP_LED bsp_led_set_blink(1, 0); bsp_led_set_data(1, 0); #endif break; case DSL_LED_DATA_ID: #ifdef CONFIG_BSP_LED bsp_led_set_blink(0, 0); bsp_led_set_data(0, 0); #endif break; } break; case DSL_LED_FLASH: switch (led_number) { case DSL_LED_LINK_ID: #ifdef CONFIG_BSP_LED bsp_led_set_blink(1, 1); /* data*/ #endif break; case DSL_LED_DATA_ID: #ifdef CONFIG_BSP_LED bsp_led_set_blink(0, 1); /* data*/ #endif break; } break; case DSL_LED_ON: switch (led_number) { case DSL_LED_LINK_ID: #ifdef CONFIG_BSP_LED bsp_led_set_blink(1, 0); bsp_led_set_data(1, 1); #endif break; case DSL_LED_DATA_ID: #ifdef CONFIG_BSP_LED bsp_led_set_blink(0, 0); bsp_led_set_data(0, 1); #endif break; } break; } return DSL_DEV_MEI_ERR_SUCCESS; } #endif /** * Compose a message. * This function compose a message from opcode, group, address, index, size, and data * * \param opcode The message opcode * \param group The message group number * \param address The message address. * \param index The message index. * \param size The number of words to read/write. * \param data The pointer to data. * \param CMVMSG The pointer to message buffer. * \ingroup Internal */ void makeCMV( u8 opcode, u8 group, u16 address, u16 index, int size, u16 * data, u16 *CMVMSG) { memset (CMVMSG, 0, MSG_LENGTH * 2); CMVMSG[0] = (opcode << 4) + (size & 0xf); CMVMSG[1] = (((index == 0) ? 0 : 1) << 7) + (group & 0x7f); CMVMSG[2] = address; CMVMSG[3] = index; if (opcode == H2D_CMV_WRITE) { memcpy (CMVMSG + 4, data, size * 2); } return; } /** * Send a message to ARC and read the response * This function sends a message to arc, waits the response, and reads the responses. * * \param pDev the device pointer * \param request Pointer to the request * \param reply Wait reply or not. * \param response Pointer to the response * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ DSL_DEV_MeiError_t DSL_BSP_SendCMV( DSL_DEV_Device_t *pDev, u16 *request, int reply, u16 *response) { DSL_DEV_MeiError_t meierror; #if defined(BSP_PORT_RTEMS) int delay_counter = 0; #else int mboxTimeoutCnt = 0; #endif if (MEI_MUTEX_LOCK (DSL_DEV_PRIVATE(pDev)->mei_cmv_sema)) { return -ERESTARTSYS; } DSL_DEV_PRIVATE(pDev)->cmv_reply = reply; memset(DSL_DEV_PRIVATE(pDev)->CMV_RxMsg, 0, sizeof (DSL_DEV_PRIVATE(pDev)-> CMV_RxMsg)); DSL_DEV_PRIVATE(pDev)->arcmsgav = 0; meierror = IFX_MEI_MailboxWrite(pDev, request, MSG_LENGTH); if (meierror != DSL_DEV_MEI_ERR_SUCCESS) { DSL_DEV_PRIVATE(pDev)->cmv_waiting = 0; DSL_DEV_PRIVATE(pDev)->arcmsgav = 0; MEI_DEBUG(MEI_DBG_MOD_CMV, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Mailbox write failed, resetting ARC..."MEI_CRLF)); IFX_MEI_ResetARC(pDev); MEI_MUTEX_UNLOCK(DSL_DEV_PRIVATE(pDev)->mei_cmv_sema); return meierror; } else { DSL_DEV_PRIVATE(pDev)->cmv_count++; } if (DSL_DEV_PRIVATE(pDev)->cmv_reply == NO_REPLY) { MEI_MUTEX_UNLOCK (DSL_DEV_PRIVATE(pDev)->mei_cmv_sema); return DSL_DEV_MEI_ERR_SUCCESS; } #if !defined(BSP_PORT_RTEMS) #if 0 if (DSL_DEV_PRIVATE(pDev)->arcmsgav == 0) { MEI_WAIT_EVENT_TIMEOUT(DSL_DEV_PRIVATE(pDev)->wait_queue_arcmsgav, CMV_TIMEOUT); } #else /* Some kind of a workaround to get "clean" system reboot*/ mboxTimeoutCnt = CMV_TIMEOUT / MBOX_POLL_PERIOD_MS; while ((DSL_DEV_PRIVATE(pDev)->arcmsgav == 0) && (mboxTimeoutCnt > 0)) { MEI_WAIT_EVENT_TIMEOUT(DSL_DEV_PRIVATE(pDev)->wait_queue_arcmsgav, MBOX_POLL_PERIOD_MS); mboxTimeoutCnt--; if (signal_pending(current)) /* Wait till getting CMV response*/ mboxTimeoutCnt = CMV_TIMEOUT / MBOX_POLL_PERIOD_MS; } #endif #else while (DSL_DEV_PRIVATE(pDev)->arcmsgav == 0 && delay_counter < CMV_TIMEOUT / 5) { MEI_WAIT (5); delay_counter++; } #endif DSL_DEV_PRIVATE(pDev)->cmv_waiting = 0; if (DSL_DEV_PRIVATE(pDev)->arcmsgav == 0) { /*CMV_timeout*/ DSL_DEV_PRIVATE(pDev)->arcmsgav = 0; MEI_DEBUG(MEI_DBG_MOD_CMV, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - CMV send failed, mailbox timeout"MEI_CRLF)); MEI_MUTEX_UNLOCK (DSL_DEV_PRIVATE(pDev)->mei_cmv_sema); return DSL_DEV_MEI_ERR_MAILBOX_TIMEOUT; } else { DSL_DEV_PRIVATE(pDev)->arcmsgav = 0; DSL_DEV_PRIVATE(pDev)->reply_count++; memcpy(response, DSL_DEV_PRIVATE(pDev)->CMV_RxMsg, MSG_LENGTH * 2); MEI_MUTEX_UNLOCK(DSL_DEV_PRIVATE(pDev)->mei_cmv_sema); return DSL_DEV_MEI_ERR_SUCCESS; } MEI_MUTEX_UNLOCK(DSL_DEV_PRIVATE(pDev)->mei_cmv_sema); return DSL_DEV_MEI_ERR_SUCCESS; } /** * Reset the ARC, download boot codes, and run the ARC. * This function resets the ARC, downloads boot codes to ARC, and runs the ARC. * * \param pDev the device pointer * \return DSL_DEV_MEI_ERR_SUCCESS or DSL_DEV_MEI_ERR_FAILURE * \ingroup Internal */ static DSL_DEV_MeiError_t IFX_MEI_RunAdslModem( DSL_DEV_Device_t *pDev) { int nSize = 0, idx = 0; uint32_t im0_register, im2_register; if (mei_arc_swap_buff == NULL) { mei_arc_swap_buff = (u32 *) kmalloc(MAXSWAPSIZE * 4, GFP_KERNEL); if (mei_arc_swap_buff == NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - no memory for the codeswap buffer"MEI_CRLF)); return DSL_DEV_MEI_ERR_FAILURE; } MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Codeswap buffer created, size=%dK, location=0x%X"MEI_CRLF, ksize(mei_arc_swap_buff)/1024, mei_arc_swap_buff)); } DSL_DEV_PRIVATE(pDev)->img_hdr = (ARC_IMG_HDR *) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[0].address; if ((DSL_DEV_PRIVATE(pDev)->img_hdr->count) * sizeof (ARC_SWP_PAGE_HDR) > SDRAM_SEGMENT_SIZE) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - firmware header size is bigger than 64K segment size" MEI_CRLF)); return DSL_DEV_MEI_ERR_FAILURE; } /* check image size*/ for (idx = 0; idx < MAX_BAR_REGISTERS; idx++) { nSize += DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].nCopy; } if (nSize != DSL_DEV_PRIVATE(pDev)->image_size) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - firmware download is not completed," " Please download firmware again"MEI_CRLF)); return DSL_DEV_MEI_ERR_FAILURE; } /* TODO: check crc*/ IFX_MEI_ResetARC(pDev); IFX_MEI_HaltArc(pDev); IFX_MEI_BarUpdate(pDev, DSL_DEV_PRIVATE(pDev)->nBar); IFX_MEI_DownloadBootCode(pDev); im0_register = (*IFXMIPS_ICU_IM0_IER) & (1 << 20); im2_register = (*IFXMIPS_ICU_IM2_IER) & (1 << 20); /* Turn off irq */ #ifdef CONFIG_IFXMIPS_AMAZON_SE disable_irq(IFXMIPS_USB_OC_INT0); disable_irq(IFXMIPS_USB_OC_INT2); #elif defined(CONFIG_IFXMIPS_AR9) disable_irq(IFXMIPS_USB_OC_INT0); disable_irq(IFXMIPS_USB_OC_INT2); #elif defined(CONFIG_IFXMIPS_DANUBE) disable_irq(IFXMIPS_USB_OC_INT); #endif disable_irq(pDev->nIrq[IFX_DYING_GASP]); IFX_MEI_RunArc(pDev); MEI_WAIT_EVENT_TIMEOUT(DSL_DEV_PRIVATE(pDev)->wait_queue_modemready, 1000); #ifdef CONFIG_IFXMIPS_AMAZON_SE MEI_MASK_AND_ACK_IRQ(IFXMIPS_USB_OC_INT0); MEI_MASK_AND_ACK_IRQ(IFXMIPS_USB_OC_INT2); #elif defined(CONFIG_IFXMIPS_AMAZON_S) MEI_MASK_AND_ACK_IRQ(IFXMIPS_USB_OC_INT0); MEI_MASK_AND_ACK_IRQ(IFXMIPS_USB_OC_INT2); #elif defined(CONFIG_IFXMIPS_DANUBE) MEI_MASK_AND_ACK_IRQ(IFXMIPS_USB_OC_INT); #endif MEI_MASK_AND_ACK_IRQ(pDev->nIrq[IFX_DYING_GASP]); /* Re-enable irq */ enable_irq(pDev->nIrq[IFX_DYING_GASP]); *IFXMIPS_ICU_IM0_IER |= im0_register; *IFXMIPS_ICU_IM2_IER |= im2_register; if (DSL_DEV_PRIVATE(pDev)->modem_ready != 1) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Modem failed to be ready"MEI_CRLF)); return DSL_DEV_MEI_ERR_FAILURE; } else { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"MODEM IS READY"MEI_CRLF)); return DSL_DEV_MEI_ERR_SUCCESS; } } /** * Get the page's data pointer * This function caculats the data address from the firmware header. * * \param pDev the device pointer * \param Page The page number. * \param data Data page or program page. * \param MaxSize The maximum size to read. * \param Buffer Pointer to data. * \param Dest Pointer to the destination address. * \return The number of bytes to read. * \ingroup Internal */ static int IFX_MEI_GetPage( DSL_DEV_Device_t *pDev, u32 Page, u32 data, u32 MaxSize, u32 *Buffer, u32 *Dest) { u32 size; u32 i; u32 *p; u32 idx, offset, nBar = 0; if (Page > DSL_DEV_PRIVATE(pDev)->img_hdr->count) { return -2; } /* Get program or data size, depending on "data" flag */ size = (data == GET_DATA) ? (DSL_DEV_PRIVATE(pDev)->img_hdr->page[Page].d_size) : (DSL_DEV_PRIVATE(pDev)->img_hdr->page[Page].p_size); /* Clear boot bit!*/ size &= BOOT_FLAG_MASK; if (size > MaxSize) { return -1; } if (size == 0) { return 0; } /* Get program or data offset, depending on "data" flag */ i = data ? (DSL_DEV_PRIVATE(pDev)->img_hdr->page[Page].d_offset) : (DSL_DEV_PRIVATE(pDev)->img_hdr->page[Page].p_offset); /* Copy data/program to buffer */ idx = i / SDRAM_SEGMENT_SIZE; offset = i % SDRAM_SEGMENT_SIZE; p = (u32 *) ((u8 *) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].address + offset); for (i = 0; i < size; i++) { if (offset + i * 4 - (nBar * SDRAM_SEGMENT_SIZE) >= SDRAM_SEGMENT_SIZE) { idx++; nBar++; p = (u32 *) ((u8 *) KSEG1ADDR ((u32)DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].address)); } Buffer[i] = *p++; } /* Pass back data/program destination address */ *Dest = data ? (DSL_DEV_PRIVATE(pDev)-> img_hdr->page[Page].d_dest) : (DSL_DEV_PRIVATE(pDev)->img_hdr->page[Page].p_dest); return size; } /** * Free the memory for ARC firmware * * \param pDev the device pointer * \param type Free all memory or free the unused memory after showtime * \ingroup Internal */ const char *free_str[4] = {"Invalid", "Free_Reload", "Free_Showtime", "Free_All", "Free_Xdata"}; static int IFX_MEI_DFEMemoryChunkAlloc( DSL_DEV_Device_t * pDev, unsigned int chunkIdx, unsigned int chunkSz) { smmu_mem_info_t *adsl_mem_info = DSL_DEV_PRIVATE(pDev)->adsl_mem_info; unsigned long mem_ptr; char *org_mem_ptr = NULL; /* Allocate memory chunk only if needed*/ if (adsl_mem_info[chunkIdx].org_address == NULL) { org_mem_ptr = kmalloc(chunkSz, GFP_KERNEL); if (org_mem_ptr == NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - chunk allocation failed: chunk=%d, size=%d"MEI_CRLF, chunkIdx, chunkSz)); return (-ENOMEM); } /* Check if the allocated chunk is not aligned*/ if (((unsigned long)org_mem_ptr) & (1023)) { /* Free current allocated chunk which is not aligned*/ kfree(org_mem_ptr); /* Allocate bigger area for further alignment*/ org_mem_ptr = kmalloc(chunkSz + 1024, GFP_KERNEL); if (org_mem_ptr == NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - chunk allocation failed: chunk=%d, size=%d"MEI_CRLF, chunkIdx, chunkSz+1024)); return (-ENOMEM); } /* Align allocated memory*/ mem_ptr = (unsigned long)(org_mem_ptr + 1023) & ~(1024 -1); } else { mem_ptr = (unsigned long)org_mem_ptr; } MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Allocated memory chunk#%d, address=0x%08X"MEI_CRLF, chunkIdx, (int)org_mem_ptr)); adsl_mem_info[chunkIdx].address = (char *) mem_ptr; adsl_mem_info[chunkIdx].org_address = org_mem_ptr; adsl_mem_info[chunkIdx].size = chunkSz; } return 0; } static int IFX_MEI_DFEMemoryFree( DSL_DEV_Device_t *pDev, int type) { int idx = 0; smmu_mem_info_t *adsl_mem_info = DSL_DEV_PRIVATE(pDev)->adsl_mem_info; for (idx = 0; idx < MAX_BAR_REGISTERS; idx++) { if (type == FREE_ALL ||adsl_mem_info[idx].type == type) { if (adsl_mem_info[idx].size > 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Freeing memory chunk#%d, address=0x%08X, type=%s"MEI_CRLF, idx, (int)adsl_mem_info[idx].org_address, free_str[adsl_mem_info[idx].type])); if (idx == XDATA_REGISTER) { xdata_alloc = 0; g_xdata_addr = NULL; } kfree (adsl_mem_info[idx].org_address); adsl_mem_info[idx].org_address = 0; adsl_mem_info[idx].address = 0; adsl_mem_info[idx].size = 0; adsl_mem_info[idx].type = 0; adsl_mem_info[idx].nCopy = 0; } } } if(mei_arc_swap_buff != NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Freeing codeswap buffer: size=%dK, location=0x%08X"MEI_CRLF, ksize(mei_arc_swap_buff)/1024, (int)mei_arc_swap_buff)); kfree(mei_arc_swap_buff); mei_arc_swap_buff = NULL; } return 0; } static int IFX_MEI_DFEMemoryAlloc( DSL_DEV_Device_t * pDev, long size) { int idx = 0; long total_size = 0; int err = 0; smmu_mem_info_t *adsl_mem_info = ((ifx_mei_device_private_t *) pDev->pPriv)->adsl_mem_info; int allocate_size = SDRAM_SEGMENT_SIZE; MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Allocating memory for image size=%d"MEI_CRLF, size)); /* Alloc Swap Pages*/ for (idx = 0; size > 0 && idx < MAX_BAR_REGISTERS; idx++) { /* skip bar15 for XDATA usage.*/ #ifndef CONFIG_IFXMIPS_MEI_FW_LOOPBACK if (idx == XDATA_REGISTER) { continue; } #endif allocate_size = (idx == (MAX_BAR_REGISTERS - 1)) ? size : SDRAM_SEGMENT_SIZE; /* Allocate memory chunk*/ if (IFX_MEI_DFEMemoryChunkAlloc( pDev, (unsigned int)idx, (unsigned int)allocate_size) != 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Chunk#%d, size=%d allocate failed"MEI_CRLF, idx, allocate_size)); err = -ENOMEM; goto allocate_error; } size -= allocate_size; total_size += allocate_size; } if (size > 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - image size is too large"MEI_CRLF)); err = -EFBIG; goto allocate_error; } /* Return number of allocated chunks*/ err = idx; /* Free unused chunks*/ for (idx = err; idx < MAX_BAR_REGISTERS; idx++) { /* Skip XDATA chunk*/ if (idx == XDATA_REGISTER) { continue; } if (adsl_mem_info[idx].org_address && adsl_mem_info[idx].size) { kfree (adsl_mem_info[idx].org_address); adsl_mem_info[idx].org_address = 0; adsl_mem_info[idx].address = 0; adsl_mem_info[idx].size = 0; adsl_mem_info[idx].type = 0; adsl_mem_info[idx].nCopy = 0; } } return err; allocate_error: IFX_MEI_DFEMemoryFree(pDev, FREE_ALL); return err; } /** * Program the BAR registers * * \param pDev the device pointer * \param nTotalBar The number of bar to program. * \ingroup Internal */ static int IFX_MEI_BarUpdate( DSL_DEV_Device_t *pDev, int nTotalBar) { int idx = 0; smmu_mem_info_t *adsl_mem_info = DSL_DEV_PRIVATE(pDev)->adsl_mem_info; for (idx = 0; idx < nTotalBar; idx++) { /* skip XDATA register*/ if (idx == XDATA_REGISTER) { continue; } IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_XMEM_BAR_BASE + idx * 4, (((uint32_t) adsl_mem_info[idx].address) & 0x0FFFFFFF)); } for (idx = nTotalBar; idx < MAX_BAR_REGISTERS; idx++) { if (idx == XDATA_REGISTER) { continue; } IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_XMEM_BAR_BASE + idx * 4, (((uint32_t)adsl_mem_info[nTotalBar - 1].address) & 0x0FFFFFFF)); /* These are for /proc/danube_mei/meminfo purpose */ adsl_mem_info[idx].address = adsl_mem_info[nTotalBar - 1].address; adsl_mem_info[idx].org_address = adsl_mem_info[nTotalBar - 1].org_address; /* Prevent it from being freed */ adsl_mem_info[idx].size = 0; } g_xdata_addr = adsl_mem_info[XDATA_REGISTER].address; IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_XMEM_BAR_BASE + XDATA_REGISTER * 4, (((uint32_t) adsl_mem_info [XDATA_REGISTER].address) & 0x0FFFFFFF)); /* update MEI_XDATA_BASE_SH*/ IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_XDATA_BASE_SH, ((unsigned long)adsl_mem_info[XDATA_REGISTER].address) & 0x0FFFFFFF); return DSL_DEV_MEI_ERR_SUCCESS; } /* This copies the firmware from secondary storage to 64k memory segment in SDRAM */ DSL_DEV_MeiError_t DSL_BSP_FWDownload( DSL_DEV_Device_t *pDev, const char *buf, unsigned long size, long *loff, long *current_offset) { ARC_IMG_HDR img_hdr_tmp; smmu_mem_info_t *adsl_mem_info = DSL_DEV_PRIVATE(pDev)->adsl_mem_info; size_t nRead = 0, nCopy = 0; char *mem_ptr; ssize_t retval = -ENOMEM; int idx = 0; if (*loff == 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Starting firmware download..."MEI_CRLF)); if (size < sizeof (img_hdr_tmp)) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Firmware size (%d) is too small"MEI_CRLF, size)); return retval; } copy_from_user((char *) &img_hdr_tmp, buf, sizeof (img_hdr_tmp)); /* header of image_size and crc are not included.*/ DSL_DEV_PRIVATE(pDev)->image_size = le32_to_cpu(img_hdr_tmp.size) + 8; if (DSL_DEV_PRIVATE(pDev)->image_size > 1024 * 1024) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Firmware size (%d) is too large"MEI_CRLF, DSL_DEV_PRIVATE(pDev)->image_size)); return retval; } /* check if arc is halt*/ IFX_MEI_ResetARC(pDev); IFX_MEI_HaltArc(pDev); /* Allocate FW chunks*/ retval = IFX_MEI_DFEMemoryAlloc(pDev, DSL_DEV_PRIVATE(pDev)->image_size); if (retval < 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - firmware binary chunks allocation failed"MEI_CRLF)); goto error; } for (idx = 0; idx < retval; idx++) { /*skip XDATA register*/ if (idx == XDATA_REGISTER) { continue; } /* Mark allocated chunks according to the FW image size*/ if (idx * SDRAM_SEGMENT_SIZE < le32_to_cpu (img_hdr_tmp.page[0].p_offset)) { adsl_mem_info[idx].type = FREE_RELOAD; } else { adsl_mem_info[idx].type = FREE_SHOWTIME; } /* Reset Chunk Copy size info*/ adsl_mem_info[idx].nCopy = 0; } DSL_DEV_PRIVATE(pDev)->nBar = retval; DSL_DEV_PRIVATE(pDev)->img_hdr = (ARC_IMG_HDR*)adsl_mem_info[0].address; /* Removed extra 1k allocation to avoid slab allocating it in 128k Allocate only if XDATA_REGISTER is not allocated previously */ if (xdata_alloc==0) { /* Allocate XDATA chunk*/ if (IFX_MEI_DFEMemoryChunkAlloc( pDev, XDATA_REGISTER, SDRAM_SEGMENT_SIZE) != 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - XDATA chunk allocation failed"MEI_CRLF)); goto error; } xdata_alloc = 1; adsl_mem_info[XDATA_REGISTER].type = FREE_XDATA; } IFX_MEI_BarUpdate(pDev, (DSL_DEV_PRIVATE(pDev)->nBar)); } else if (DSL_DEV_PRIVATE(pDev)-> image_size == 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - firmware size=0"MEI_CRLF)); goto error; } nRead = 0; while (nRead < size) { long offset = ((long) (*loff) + nRead) % SDRAM_SEGMENT_SIZE; idx = (((long) (*loff)) + nRead) / SDRAM_SEGMENT_SIZE; mem_ptr = (char *) KSEG1ADDR ((unsigned long) (adsl_mem_info[idx].address) + offset); if ((size - nRead + offset) > SDRAM_SEGMENT_SIZE) { nCopy = SDRAM_SEGMENT_SIZE - offset; } else { nCopy = size - nRead; } copy_from_user(mem_ptr, buf + nRead, nCopy); for (offset = 0; offset < (nCopy / 4); offset++) { ((unsigned long *) mem_ptr)[offset] = le32_to_cpu(((unsigned long *) mem_ptr)[offset]); } nRead += nCopy; adsl_mem_info[idx].nCopy += nCopy; } *loff += size; *current_offset = size; return DSL_DEV_MEI_ERR_SUCCESS; error: IFX_MEI_DFEMemoryFree(pDev, FREE_ALL); return DSL_DEV_MEI_ERR_FAILURE; } /* * Register a callback event. * Return: * -1 if the event already has a callback function registered. * 0 success */ int DSL_BSP_EventCBRegister( DSL_BSP_EventCallBack_t *p) { if (!p) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - invalid parameter for CB registration"MEI_CRLF)); return -EINVAL; } if (p->event > DSL_BSP_CB_LAST || p->event < DSL_BSP_CB_FIRST) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - invalid CB event %d"MEI_CRLF, p->event)); return -EINVAL; } if (dsl_bsp_event_callback[p->event].function) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - CB event %d already has a callback function registered" MEI_CRLF, p->event)); return -1; } else { dsl_bsp_event_callback[p->event].function = p->function; dsl_bsp_event_callback[p->event].event = p->event; dsl_bsp_event_callback[p->event].pData = p->pData; } return 0; } int DSL_BSP_EventCBUnregister( DSL_BSP_EventCallBack_t *p) { if (!p) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - invalid parameter for CB unregister"MEI_CRLF)); return -EINVAL; } if (p->event > DSL_BSP_CB_LAST || p->event < DSL_BSP_CB_FIRST) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - invalid CB event %d"MEI_CRLF, p->event)); return -EINVAL; } if (dsl_bsp_event_callback[p->event].function) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Unregistering event %d"MEI_CRLF, p->event)); dsl_bsp_event_callback[p->event].function = NULL; dsl_bsp_event_callback[p->event].pData = NULL; } else { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - event %d is not registered"MEI_CRLF, p->event)); return -1; } return 0; } /** * MEI Dying Gasp interrupt handler * * \param int1 * \param void0 * \param regs Pointer to the structure of danube mips registers * \ingroup Internal */ static irqreturn_t IFX_MEI_Dying_Gasp_IrqHandle( int int1, void *void0) { DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) void0; DSL_BSP_CB_Type_t event; if (pDev == NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - unable to handle interrupt, pDev is NULL"MEI_CRLF)); return IRQ_HANDLED; } #ifndef CONFIG_SMP disable_irq(pDev->nIrq[IFX_DYING_GASP]); #else disable_irq_nosync(pDev->nIrq[IFX_DYING_GASP]); #endif event = DSL_BSP_CB_DYING_GASP; if (dsl_bsp_event_callback[event].function) { (*dsl_bsp_event_callback[event].function)(pDev, event, dsl_bsp_event_callback[event].pData); } #ifdef CONFIG_USE_EMULATOR MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Dying Gasp! Shutting Down... (Work around for Amazon-S Venus emulator)"MEI_CRLF)); #else MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Dying Gasp! Shutting Down..."MEI_CRLF)); /* Ask init to reboot us */ /*kill_proc (1, SIGINT, 1);*/ #endif return IRQ_HANDLED; } extern void ifx_usb_enable_afe_oc(void); /** * MEI interrupt handler * * \param int1 * \param void0 * \param regs Pointer to the structure of danube mips registers * \ingroup Internal */ static irqreturn_t IFX_MEI_IrqHandle( int int1, void *void0) { u32 scratch; DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) void0; DSL_BSP_CB_Type_t event; #if defined(CONFIG_IFXMIPS_MEI_FW_LOOPBACK) && defined(DFE_PING_TEST) dfe_loopback_irq_handler(pDev); return IRQ_HANDLED; #endif /*CONFIG_AMAZON_S_MEI_FW_LOOPBACK*/ if (pDev == NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - unable to handle interrupt, pDev is NULL"MEI_CRLF)); return IRQ_HANDLED; } IFX_MEI_DebugRead(pDev, ARC_MEI_MAILBOXR, &scratch, 1); if (scratch & OMB_CODESWAP_MESSAGE_MSG_TYPE_MASK) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Code Swap Request interrupt received"MEI_CRLF)); return IRQ_HANDLED; } else if (scratch & OMB_CLEAREOC_INTERRUPT_CODE) { /* clear eoc message interrupt*/ MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"CEOC interrupt received"MEI_CRLF)); event = DSL_BSP_CB_CEOC_IRQ; IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_ARC2ME_STAT, ARC_TO_MEI_MSGAV); if (dsl_bsp_event_callback[event].function) { (*dsl_bsp_event_callback[event].function)(pDev, event, dsl_bsp_event_callback[event].pData); } } else if (scratch & OMB_REBOOT_INTERRUPT_CODE) { /* Reboot*/ MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"REBOOT interrupt received"MEI_CRLF)); event = DSL_BSP_CB_FIRMWARE_REBOOT; IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_ARC2ME_STAT, ARC_TO_MEI_MSGAV); if (dsl_bsp_event_callback[event].function) { (*dsl_bsp_event_callback[event].function)(pDev, event, dsl_bsp_event_callback[event].pData); } } else /* normal message*/ { IFX_MEI_MailboxRead(pDev, DSL_DEV_PRIVATE(pDev)->CMV_RxMsg, MSG_LENGTH); if (DSL_DEV_PRIVATE(pDev)-> cmv_waiting == 1) { DSL_DEV_PRIVATE(pDev)-> arcmsgav = 1; DSL_DEV_PRIVATE(pDev)-> cmv_waiting = 0; #if !defined(BSP_PORT_RTEMS) MEI_WAKEUP_EVENT (DSL_DEV_PRIVATE(pDev)->wait_queue_arcmsgav); #endif } else { DSL_DEV_PRIVATE(pDev)-> modem_ready_cnt++; memcpy((char *) DSL_DEV_PRIVATE(pDev)->Recent_indicator, (char *) DSL_DEV_PRIVATE(pDev)->CMV_RxMsg, MSG_LENGTH * 2); if (((DSL_DEV_PRIVATE(pDev)->CMV_RxMsg[0] & 0xff0) >> 4) == D2H_AUTONOMOUS_MODEM_READY_MSG) { /*check ARC ready message*/ MEI_DEBUG(MEI_DBG_MOD_CMV, MEI_DBG_MSG, (MEI_DBG_PREFIX"MODEM_READY message received"MEI_CRLF)); DSL_DEV_PRIVATE(pDev)->modem_ready = 1; MEI_WAKEUP_EVENT (DSL_DEV_PRIVATE(pDev)->wait_queue_modemready); } } } return IRQ_HANDLED; } int DSL_BSP_ATMLedCBRegister( int (*ifx_adsl_ledcallback) (void)) { g_adsl_ledcallback = ifx_adsl_ledcallback; return 0; } int DSL_BSP_ATMLedCBUnregister( int (*ifx_adsl_ledcallback) (void)) { g_adsl_ledcallback = adsl_dummy_ledcallback; return 0; } #if 0 int DSL_BSP_EventCBRegister( int (*ifx_adsl_callback)(DSL_BSP_CB_Event_t * param)) { int error = 0; if (DSL_EventCB == NULL) { DSL_EventCB = ifx_adsl_callback; } else { error = -EIO; } return error; } int DSL_BSP_EventCBUnregister( int (*ifx_adsl_callback)(DSL_BSP_CB_Event_t * param)) { int error = 0; if (DSL_EventCB == ifx_adsl_callback) { DSL_EventCB = NULL; } else { error = -EIO; } return error; } static int DSL_BSP_GetEventCB( int (**ifx_adsl_callback)(DSL_BSP_CB_Event_t * param)) { *ifx_adsl_callback = DSL_EventCB; return 0; } #endif #ifdef CONFIG_IFXMIPS_MEI_FW_LOOPBACK #define mte_reg_base (0x4800*4+0x20000) /* Iridia Registers Address Constants */ #define MTE_Reg(r) (int)(mte_reg_base + (r*4)) #define IT_AMODE MTE_Reg(0x0004) #define TIMER_DELAY (1024) #define BC0_BYTES (32) #define BC1_BYTES (30) #define NUM_MB (12) #define TIMEOUT_VALUE 2000 static void BFMWait(u32 cycle) { u32 i; for (i = 0; i < cycle; i++); } static void WriteRegLong (u32 addr, u32 data) { /* *((volatile u32 *)(addr)) = data;*/ IFX_MEI_WRITE_REGISTER_L(data, addr); } static u32 ReadRegLong (u32 addr) { /* u32 rd_val; rd_val = *((volatile u32 *)(addr)); return rd_val; */ return IFX_MEI_READ_REGISTER_L (addr); } /* This routine writes the mailbox with the data in an input array */ static void WriteMbox(u32 * mboxarray, u32 size) { IFX_MEI_DebugWrite(&dsl_devices[0], IMBOX_BASE, mboxarray, size); MEI_DEBUG(MEI_DBG_MOD_CMV, MEI_DBG_MSG, (MEI_DBG_PREFIX"write to 0x%08X"MEI_CRLF, IMBOX_BASE)); IFX_MEI_LongWordWriteOffset(&dsl_devices[0], (u32) ME_ME2ARC_INT, MEI_TO_ARC_MSGAV); } /* This routine reads the output mailbox and places the results into an array */ static void ReadMbox (u32 * mboxarray, u32 size) { IFX_MEI_DebugRead(&dsl_devices[0], OMBOX_BASE, mboxarray, size); MEI_DEBUG(MEI_DBG_MOD_CMV, MEI_DBG_MSG, (MEI_DBG_PREFIX"read from 0x%08X"MEI_CRLF, OMBOX_BASE)); } static void MEIWriteARCValue(u32 address, u32 value) { u32 i, check = 0; /* Write address register */ IFX_MEI_WRITE_REGISTER_L(address, ME_DBG_WR_AD + IFXMIPS_MEI_BASE_ADDR); /* Write data register */ IFX_MEI_WRITE_REGISTER_L(value, ME_DBG_DATA + IFXMIPS_MEI_BASE_ADDR); /* wait until complete - timeout at 40 */ for (i = 0; i < 40; i++) { check = IFX_MEI_READ_REGISTER_L(ME_ARC2ME_STAT + IFXMIPS_MEI_BASE_ADDR); if ((check & ARC_TO_MEI_DBG_DONE)) { break; } } /* clear the flag */ IFX_MEI_WRITE_REGISTER_L(ARC_TO_MEI_DBG_DONE, ME_ARC2ME_STAT + IFXMIPS_MEI_BASE_ADDR); } void arc_code_page_download(uint32_t arc_code_length, uint32_t * start_address) { int count; MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_MSG, (MEI_DBG_PREFIX"Try to download pages,size=%d"MEI_CRLF, arc_code_length)); IFX_MEI_ControlModeSet(&dsl_devices[0], MEI_MASTER_MODE); IFX_MEI_HaltArc(&dsl_devices[0]); IFX_MEI_LongWordWriteOffset(&dsl_devices[0], (u32) ME_DX_AD, 0); for (count = 0; count < arc_code_length; count++) { IFX_MEI_LongWordWriteOffset(&dsl_devices[0], (u32) ME_DX_DATA, *(start_address + count)); } IFX_MEI_ControlModeSet(&dsl_devices[0], JTAG_MASTER_MODE); } static int load_jump_table (unsigned long addr) { int i; uint32_t addr_le, addr_be; uint32_t jump_table[32]; for (i = 0; i < 16; i++) { addr_le = i * 8 + addr; addr_be = ((addr_le >> 16) & 0xffff); addr_be |= ((addr_le & 0xffff) << 16); jump_table[i * 2 + 0] = 0x0f802020; jump_table[i * 2 + 1] = addr_be; } arc_code_page_download(32, &jump_table[0]); return 0; } int got_int = 0; void dfe_loopback_irq_handler(DSL_DEV_Device_t *pDev) { uint32_t rd_mbox[10]; memset(&rd_mbox[0], 0, 10 * 4); ReadMbox(&rd_mbox[0], 6); if (rd_mbox[0] == 0x0) { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Get ARC_ACK"MEI_CRLF)); got_int = 1; } else if (rd_mbox[0] == 0x5) { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Get ARC_BUSY"MEI_CRLF)); got_int = 2; } else if (rd_mbox[0] == 0x3) { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Get ARC_EDONE"MEI_CRLF)); if (rd_mbox[1] == 0x0) { got_int = 3; MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Get E_MEMTEST"MEI_CRLF)); if (rd_mbox[2] != 0x1) { got_int = 4; MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Get Result 0x%X"MEI_CRLF, rd_mbox[2])); } } } IFX_MEI_LongWordWriteOffset(&dsl_devices[0], (u32) ME_ARC2ME_STAT, ARC_TO_MEI_DBG_DONE); MEI_MASK_AND_ACK_IRQ(pDev->nIrq[IFX_DFEIR]); disable_irq(pDev->nIrq[IFX_DFEIR]); /*got_int = 1;*/ return; } static void wait_mem_test_result(void) { uint32_t mbox[5]; mbox[0] = 0; MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Waiting Starting"MEI_CRLF)); while (mbox[0] == 0) { ReadMbox(&mbox[0], 5); } MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Try to get mem test result"MEI_CRLF)); ReadMbox(&mbox[0], 5); if (mbox[0] == 0xA) { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Success"MEI_CRLF)); } else if (mbox[0] == 0xA) { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Fail, address %X, except data %X, receive data %X"MEI_CRLF, mbox[1], mbox[2], mbox[3])); } else { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Fail"MEI_CRLF)); } } static int arc_ping_testing(DSL_DEV_Device_t *pDev) { #define MEI_PING 0x00000001 uint32_t wr_mbox[10], rd_mbox[10]; int i; for (i = 0; i < 10; i++) { wr_mbox[i] = 0; rd_mbox[i] = 0; } MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"send ping msg"MEI_CRLF)); wr_mbox[0] = MEI_PING; WriteMbox(&wr_mbox[0], 10); while (got_int == 0) { MEI_WAIT(100); } MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"send start event"MEI_CRLF)); got_int = 0; wr_mbox[0] = 0x4; wr_mbox[1] = 0; wr_mbox[2] = 0; wr_mbox[3] = (uint32_t) 0xf5acc307e; wr_mbox[4] = 5; wr_mbox[5] = 2; wr_mbox[6] = 0x1c000; wr_mbox[7] = 64; wr_mbox[8] = 0; wr_mbox[9] = 0; WriteMbox(&wr_mbox[0], 10); DSL_ENABLE_IRQ(pDev->nIrq[IFX_DFEIR]); IFX_MEI_LongWordWriteOffset(&dsl_devices[0], (u32) ME_ME2ARC_INT, MEI_TO_ARC_MSGAV); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"sleeping"MEI_CRLF)); while (1) { if (got_int > 0) { if (got_int > 3) { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"got_int >>>> 3"MEI_CRLF)); } else { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"got int = %d"MEI_CRLF, got_int)); } got_int = 0; /*schedule();*/ DSL_ENABLE_IRQ(pDev->nIrq[IFX_DFEIR]); } /*mbox_read(&rd_mbox[0],6);*/ MEI_WAIT(100); } return 0; } static DSL_DEV_MeiError_t DFE_Loopback_Test(void) { int i = 0; u32 arc_debug_data = 0, temp; DSL_DEV_Device_t *pDev = &dsl_devices[0]; uint32_t wr_mbox[10]; IFX_MEI_ResetARC(pDev); /* start the clock*/ arc_debug_data = ACL_CLK_MODE_ENABLE; IFX_MEI_DebugWrite(pDev, CRI_CCR0, &arc_debug_data, 1); #if defined( DFE_PING_TEST )|| defined( DFE_ATM_LOOPBACK) /* WriteARCreg(AUX_XMEM_LTEST,0);*/ IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); #define AUX_XMEM_LTEST 0x128 _IFX_MEI_DBGLongWordWrite(pDev, MEI_DEBUG_DEC_AUX_MASK, AUX_XMEM_LTEST, 0); IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); /* WriteARCreg(AUX_XDMA_GAP,0);*/ IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); #define AUX_XDMA_GAP 0x114 _IFX_MEI_DBGLongWordWrite(pDev, MEI_DEBUG_DEC_AUX_MASK, AUX_XDMA_GAP, 0); IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); temp = 0; _IFX_MEI_DBGLongWordWrite(pDev, MEI_DEBUG_DEC_AUX_MASK, (u32) ME_XDATA_BASE_SH + IFXMIPS_MEI_BASE_ADDR, temp); IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); i = IFX_MEI_DFEMemoryAlloc(pDev, SDRAM_SEGMENT_SIZE * 16); if (i >= 0) { int idx; for (idx = 0; idx < i; idx++) { DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].type = FREE_RELOAD; IFX_MEI_WRITE_REGISTER_L((((uint32_t) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].address) & 0x0fffffff), IFXMIPS_MEI_BASE_ADDR + ME_XMEM_BAR_BASE + idx * 4); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: bar%d(%X)=%X\n"MEI_CRLF, idx, IFXMIPS_MEI_BASE_ADDR + ME_XMEM_BAR_BASE + idx * 4, (((uint32_t) ((ifx_mei_device_private_t *) pDev->pPriv)->adsl_mem_info[idx]. address) & 0x0fffffff))); memset((u8 *) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].address, 0, SDRAM_SEGMENT_SIZE); } IFX_MEI_LongWordWriteOffset(pDev, (u32) ME_XDATA_BASE_SH, ((unsigned long) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[XDATA_REGISTER].address) & 0x0FFFFFFF); } else { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - LBT: cannot load image: no memory"MEI_CRLF)); return DSL_DEV_MEI_ERR_FAILURE; } /*WriteARCreg(AUX_IC_CTRL,2);*/ MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: Setting MEI_MASTER_MODE..."MEI_CRLF)); IFX_MEI_ControlModeSet(pDev, MEI_MASTER_MODE); #define AUX_IC_CTRL 0x11 _IFX_MEI_DBGLongWordWrite(pDev, MEI_DEBUG_DEC_AUX_MASK, AUX_IC_CTRL, 2); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: Setting JTAG_MASTER_MODE..."MEI_CRLF)); IFX_MEI_ControlModeSet(pDev, JTAG_MASTER_MODE); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: Halting ARC..."MEI_CRLF)); IFX_MEI_HaltArc(&dsl_devices[0]); #ifdef DFE_PING_TEST MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: ping test image size=%d"MEI_CRLF, sizeof (arc_ahb_access_code))); memcpy((u8 *) (DSL_DEV_PRIVATE(pDev)-> adsl_mem_info[0].address + 0x1004), &arc_ahb_access_code[0], sizeof (arc_ahb_access_code)); load_jump_table(0x80000 + 0x1004); #endif /*DFE_PING_TEST*/ MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: ARC ping test code download complete"MEI_CRLF)); #endif /*defined( DFE_PING_TEST )|| defined( DFE_ATM_LOOPBACK)*/ #ifdef DFE_MEM_TEST IFX_MEI_LongWordWriteOffset(&dsl_devices[0], (u32) ME_ARC2ME_MASK, MSGAV_EN); arc_code_page_download(1537, &code_array[0]); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: ARC mem test code download complete"MEI_CRLF)); #endif /*DFE_MEM_TEST*/ #ifdef DFE_ATM_LOOPBACK arc_debug_data = 0xf; arc_code_page_download(sizeof(code_array) / sizeof(*code_array), &code_array[0]); wr_mbox[0] = 0; /* TIMER_DELAY - org: 1024*/ wr_mbox[1] = 0; /* TXFB_START0*/ wr_mbox[2] = 0x7f; /* TXFB_END0 - org: 49*/ wr_mbox[3] = 0x80; /* TXFB_START1 - org: 80*/ wr_mbox[4] = 0xff; /* TXFB_END1 - org: 109*/ wr_mbox[5] = 0x100; /* RXFB_START0 - org: 0*/ wr_mbox[6] = 0x17f; /* RXFB_END0 - org: 49*/ wr_mbox[7] = 0x180; /* RXFB_START1 - org: 256*/ wr_mbox[8] = 0x1ff; /* RXFB_END1 - org: 315*/ WriteMbox(&wr_mbox[0], 9); /* Start Iridia IT_AMODE (in dmp access) why is it required?*/ IFX_MEI_DebugWrite(&dsl_devices[0], 0x32010, &arc_debug_data, 1); #endif /* DFE_ATM_LOOPBACK*/ IFX_MEI_IRQEnable(pDev); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"LBT: Run ARC..."MEI_CRLF)); IFX_MEI_RunArc(&dsl_devices[0]); #ifdef DFE_PING_TEST arc_ping_testing(pDev); #endif /* DFE_PING_TEST*/ #ifdef DFE_MEM_TEST wait_mem_test_result(); #endif /* DFE_MEM_TEST*/ IFX_MEI_DFEMemoryFree(pDev, FREE_ALL); return DSL_DEV_MEI_ERR_SUCCESS; } #endif /* CONFIG_AMAZON_S_MEI_FW_LOOPBACK*/ static int IFX_MEI_InitDevNode(int num) { if (num == 0) { if ((dev_major = register_chrdev(dev_major, IFX_MEI_DEVNAME, &bsp_mei_operations)) < 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - register_chrdev(%d %s) failed"MEI_CRLF, dev_major, IFX_MEI_DEVNAME)); return -ENODEV; } } return 0; } static int IFX_MEI_CleanUpDevNode (int num) { if (num == 0) { unregister_chrdev(dev_major, MEI_DIRNAME); } return 0; } static int IFX_MEI_InitDevice(int num) { DSL_DEV_Device_t *pDev; u32 temp; pDev = &dsl_devices[num]; if (pDev == NULL) { return -ENOMEM; } pDev->pPriv = &sDanube_Mei_Private[num]; memset(pDev->pPriv, 0, sizeof (ifx_mei_device_private_t)); memset(&DSL_DEV_PRIVATE(pDev)->adsl_mem_info[0], 0, sizeof (smmu_mem_info_t) * MAX_BAR_REGISTERS); if (num == 0) { pDev->nIrq[IFX_DFEIR] = IFXMIPS_MEI_INT; pDev->nIrq[IFX_DYING_GASP] = IFXMIPS_MEI_DYING_GASP_INT; pDev->base_address = IFXMIPS_MEI_BASE_ADDR; /* Power up MEI */ DSL_DFE_PMU_SETUP(IFX_PMU_ENABLE); AHBM_PMU_SETUP(IFX_PMU_ENABLE); /* To be removed The following implementation was used within older MEI driver versions for AMAZON-SE ONLY. DSL_DFE_PMU_SETUP(); AHBM_PMU_SETUP(); USB0_PHY_PMU_SETUP(); USB0_CTRL_PMU_SETUP(); */ } pDev->nInUse = 0; DSL_DEV_PRIVATE(pDev)->modem_ready = 0; DSL_DEV_PRIVATE(pDev)->arcmsgav = 0; /* for ARCMSGAV*/ MEI_INIT_WAKELIST("arcq", DSL_DEV_PRIVATE(pDev)->wait_queue_arcmsgav); /* for arc modem ready*/ MEI_INIT_WAKELIST("arcr", DSL_DEV_PRIVATE(pDev)->wait_queue_modemready); /* semaphore initialization, mutex*/ MEI_MUTEX_INIT(DSL_DEV_PRIVATE(pDev)->mei_cmv_sema, 1); #if 0 MEI_MASK_AND_ACK_IRQ(pDev->nIrq[IFX_DFEIR]); MEI_MASK_AND_ACK_IRQ(pDev->nIrq[IFX_DYING_GASP]); #endif if (request_irq(pDev->nIrq[IFX_DFEIR], IFX_MEI_IrqHandle, 0, "DFEIR", pDev) != 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - request_irq %d failed"MEI_CRLF, pDev->nIrq[IFX_DFEIR])); return -1; } if (request_irq(pDev->nIrq[IFX_DYING_GASP], IFX_MEI_Dying_Gasp_IrqHandle, 0, "DYING_GASP", pDev) != 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - request_irq %d failed"MEI_CRLF, pDev->nIrq[IFX_DYING_GASP])); return -1; } return 0; } static int IFX_MEI_ExitDevice (int num) { DSL_DEV_Device_t *pDev; pDev = &dsl_devices[num]; if (pDev == NULL) { return -EIO; } disable_irq(pDev->nIrq[IFX_DFEIR]); disable_irq(pDev->nIrq[IFX_DYING_GASP]); free_irq(pDev->nIrq[IFX_DFEIR], pDev); free_irq(pDev->nIrq[IFX_DYING_GASP], pDev); return 0; } static DSL_DEV_Device_t * IFX_BSP_HandleGet (int maj, int num) { if (num > BSP_MAX_DEVICES) { return NULL; } return &dsl_devices[num]; } DSL_DEV_Device_t * DSL_BSP_DriverHandleGet(int maj, int num) { DSL_DEV_Device_t *pDev; if (num > BSP_MAX_DEVICES) { return NULL; } pDev = &dsl_devices[num]; if (!try_module_get(pDev->owner)) { return NULL; } pDev->nInUse++; return pDev; } int DSL_BSP_DriverHandleDelete( DSL_DEV_Device_t *nHandle) { DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) nHandle; if (pDev->nInUse) { pDev->nInUse--; } module_put(pDev->owner); return 0; } static int IFX_MEI_Open( DSL_DRV_inode_t * ino, DSL_DRV_file_t * fil) { int maj = MAJOR (ino->i_rdev); int num = MINOR (ino->i_rdev); DSL_DEV_Device_t *pDev = NULL; if ((pDev = DSL_BSP_DriverHandleGet (maj, num)) == NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - open(%d:%d) fail"MEI_CRLF, maj, num)); return -EIO; } fil->private_data = pDev; return 0; } static int IFX_MEI_Release( DSL_DRV_inode_t * ino, DSL_DRV_file_t * fil) { /*int maj = MAJOR(ino->i_rdev);*/ int num = MINOR(ino->i_rdev); DSL_DEV_Device_t *pDev; pDev = &dsl_devices[num]; if (pDev == NULL) { return -EIO; } DSL_BSP_DriverHandleDelete(pDev); return 0; } /** * Callback function for linux userspace program writing */ static ssize_t IFX_MEI_Write( DSL_DRV_file_t *filp, const char *buf, size_t size, loff_t *loff) { DSL_DEV_MeiError_t mei_error = DSL_DEV_MEI_ERR_FAILURE; long offset = 0; DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) filp->private_data; if (pDev == NULL) { return -EIO; } mei_error = DSL_BSP_FWDownload(pDev, buf, size, (long *)loff, &offset); if (mei_error == DSL_DEV_MEI_ERR_FAILURE) { return -EIO; } return (ssize_t)offset; } /** * Callback function for linux userspace program ioctling */ static int IFX_MEI_IoctlCopyFrom( int from_kernel, char *dest, char *from, int size) { int ret = 0; if (!from_kernel) { ret = copy_from_user((char *) dest, (char *) from, size); } else { ret = (int)memcpy((char *) dest, (char *) from, size); } return ret; } static int IFX_MEI_IoctlCopyTo( int from_kernel, char *dest, char *from, int size) { int ret = 0; if (!from_kernel) { ret = copy_to_user((char *)dest, (char *)from, size); } else { ret = (int)memcpy((char *)dest, (char *)from, size); } return ret; } static int IFX_MEI_Ioctls( DSL_DEV_Device_t *pDev, int from_kernel, unsigned int command, unsigned long lon) { int i = 0; int meierr = DSL_DEV_MEI_ERR_SUCCESS; u32 base_address = IFXMIPS_MEI_BASE_ADDR; DSL_DEV_WinHost_Message_t winhost_msg, m; DSL_DEV_MeiDebug_t debugrdwr; DSL_DEV_MeiReg_t regrdwr; switch (command) { case DSL_FIO_BSP_CMV_WINHOST: IFX_MEI_IoctlCopyFrom(from_kernel, (char *) winhost_msg.msg.TxMessage, (char *) lon, MSG_LENGTH * 2); if ((meierr = DSL_BSP_SendCMV(pDev, winhost_msg.msg.TxMessage, YES_REPLY, winhost_msg.msg.RxMessage)) != DSL_DEV_MEI_ERR_SUCCESS) { MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - WINHOST CMV fail :TxMessage:%X %X %X %X, RxMessage:%X %X %X %X %X"MEI_CRLF, winhost_msg.msg.TxMessage[0], winhost_msg.msg.TxMessage[1], winhost_msg.msg.TxMessage[2], winhost_msg.msg.TxMessage[3], winhost_msg.msg.RxMessage[0], winhost_msg.msg.RxMessage[1], winhost_msg.msg.RxMessage[2], winhost_msg.msg.RxMessage[3], winhost_msg.msg.RxMessage[4])); meierr = DSL_DEV_MEI_ERR_FAILURE; } else { IFX_MEI_IoctlCopyTo(from_kernel, (char *)lon, (char *)winhost_msg.msg.RxMessage, MSG_LENGTH * 2); } break; case DSL_FIO_BSP_CMV_READ: IFX_MEI_IoctlCopyFrom(from_kernel, (char *)(®rdwr), (char *)lon, sizeof (DSL_DEV_MeiReg_t)); IFX_MEI_LongWordRead((u32) regrdwr.iAddress, (u32 *) & (regrdwr.iData)); IFX_MEI_IoctlCopyTo (from_kernel, (char *)lon, (char *)(®rdwr), sizeof (DSL_DEV_MeiReg_t)); break; case DSL_FIO_BSP_CMV_WRITE: IFX_MEI_IoctlCopyFrom(from_kernel, (char *)(®rdwr), (char *)lon, sizeof (DSL_DEV_MeiReg_t)); IFX_MEI_LongWordWrite ((u32) regrdwr.iAddress, regrdwr.iData); break; case DSL_FIO_BSP_GET_BASE_ADDRESS: IFX_MEI_IoctlCopyTo(from_kernel, (char *)lon, (char *)(&base_address), sizeof (base_address)); break; case DSL_FIO_BSP_IS_MODEM_READY: i = IFX_MEI_IsModemReady(pDev); IFX_MEI_IoctlCopyTo (from_kernel, (char *)lon, (char *)(&i), sizeof (int)); meierr = DSL_DEV_MEI_ERR_SUCCESS; break; case DSL_FIO_BSP_RESET: case DSL_FIO_BSP_REBOOT: /* This delay has been added during investigations within context of HDT00225573 (a-se compact board issue with ahb access) issue. */ MEI_WAIT(100); meierr = IFX_MEI_CpuModeSet(pDev, DSL_CPU_RESET); meierr = IFX_MEI_CpuModeSet(pDev, DSL_CPU_HALT); break; case DSL_FIO_BSP_HALT: meierr = IFX_MEI_CpuModeSet(pDev, DSL_CPU_HALT); break; case DSL_FIO_BSP_RUN: meierr = IFX_MEI_CpuModeSet(pDev, DSL_CPU_RUN); break; case DSL_FIO_BSP_BOOTDOWNLOAD: meierr = IFX_MEI_DownloadBootCode(pDev); break; case DSL_FIO_BSP_JTAG_ENABLE: meierr = IFX_MEI_ArcJtagEnable(pDev, 1); break; case DSL_FIO_BSP_REMOTE: IFX_MEI_IoctlCopyFrom(from_kernel, (char *)(&i), (char *)lon, sizeof (int)); meierr = IFX_MEI_AdslMailboxIRQEnable(pDev, i); break; case DSL_FIO_BSP_DSL_START: MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"DSL_FIO_BSP_DSL_START"MEI_CRLF)); if ((meierr = IFX_MEI_RunAdslModem(pDev)) != DSL_DEV_MEI_ERR_SUCCESS) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - modem run failed"MEI_CRLF)); meierr = DSL_DEV_MEI_ERR_FAILURE; } break; case DSL_FIO_BSP_DEBUG_READ: case DSL_FIO_BSP_DEBUG_WRITE: IFX_MEI_IoctlCopyFrom(from_kernel, (char *)(&debugrdwr), (char *)lon, sizeof(debugrdwr)); if (command == DSL_FIO_BSP_DEBUG_READ) { meierr = DSL_BSP_MemoryDebugAccess (pDev, DSL_BSP_MEMORY_READ, debugrdwr. iAddress, debugrdwr. buffer, debugrdwr. iCount); } else { meierr = DSL_BSP_MemoryDebugAccess (pDev, DSL_BSP_MEMORY_WRITE, debugrdwr. iAddress, debugrdwr. buffer, debugrdwr. iCount); } IFX_MEI_IoctlCopyTo(from_kernel, (char *)lon, (char *)(&debugrdwr), sizeof(debugrdwr)); break; case DSL_FIO_BSP_GET_VERSION: IFX_MEI_IoctlCopyTo(from_kernel, (char *)lon, (char *)(&bsp_mei_version), sizeof(DSL_DEV_Version_t)); break; case DSL_FIO_BSP_GET_CHIP_INFO: bsp_chip_info.major = 1; bsp_chip_info.minor = IFXMIPS_MPS_CHIPID_VERSION_GET(*IFXMIPS_MPS_CHIPID); IFX_MEI_IoctlCopyTo(from_kernel, (char *)lon, (char *)(&bsp_chip_info), sizeof (DSL_DEV_HwVersion_t)); meierr = DSL_DEV_MEI_ERR_SUCCESS; break; case DSL_FIO_BSP_FREE_RESOURCE: makeCMV(H2D_CMV_READ, DSL_CMV_GROUP_STAT, 4, 0, 1, NULL, m.msg.TxMessage); if (DSL_BSP_SendCMV(pDev, m.msg.TxMessage, YES_REPLY, m.msg.RxMessage) != DSL_DEV_MEI_ERR_SUCCESS) { meierr = DSL_DEV_MEI_ERR_FAILURE; return -EIO; } MEI_DEBUG(MEI_DBG_MOD_CMV, MEI_DBG_MSG, (MEI_DBG_PREFIX"RxMessage[4] = %#x\n"MEI_CRLF, m.msg.RxMessage[4])); if (!(m.msg.RxMessage[4] & DSL_DEV_STAT_CODESWAP_COMPLETE)) { meierr = DSL_DEV_MEI_ERR_FAILURE; return -EAGAIN; } MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_MSG, (MEI_DBG_PREFIX"Freeing all memories marked FREE_SHOWTIME"MEI_CRLF)); IFX_MEI_DFEMemoryFree(pDev, FREE_SHOWTIME); meierr = DSL_DEV_MEI_ERR_SUCCESS; break; #ifdef CONFIG_IFXMIPS_AMAZON_SE case DSL_FIO_ARC_MUX_TEST: AMAZON_SE_MEI_ARC_MUX_Test(); break; #endif default: MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Invalid IOCTL command: %d"MEI_CRLF, command)); break; } return meierr; } #ifdef CONFIG_IFXMIPS_AMAZON_SE void AMAZON_SE_MEI_ARC_MUX_Test(void) { u32 *p, i; *IFXMIPS_RCU_RST |= IFXMIPS_RCU_RST_REQ_MUX_ARC; p = (u32*)(DFE_LDST_BASE_ADDR + IRAM0_BASE); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Writing to IRAM0(%p)..."MEI_CRLF, p)); for (i = 0; i < IRAM0_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"%p: %#x"MEI_CRLF, p, *p)); } p = (u32*)(DFE_LDST_BASE_ADDR + IRAM1_BASE); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Writing to IRAM1(%p)..."MEI_CRLF, p)); for (i = 0; i < IRAM1_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"%p: %#x\n"MEI_CRLF, p, *p)); } p = (u32*)(DFE_LDST_BASE_ADDR + BRAM_BASE); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Writing to BRAM(%p)..."MEI_CRLF, p)); for (i = 0; i < BRAM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"%p: %#x\n"MEI_CRLF, p, *p)); } p = (u32*)(DFE_LDST_BASE_ADDR + XRAM_BASE); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Writing to XRAM(%p)..."MEI_CRLF, p)); for (i = 0; i < XRAM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"%p: %#x\n"MEI_CRLF, p, *p)); } p = (u32*)(DFE_LDST_BASE_ADDR + YRAM_BASE); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Writing to YRAM(%p)..."MEI_CRLF, p)); for (i = 0; i < YRAM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"%p: %#x\n"MEI_CRLF, p, *p)); } p = (u32*)(DFE_LDST_BASE_ADDR + EXT_MEM_BASE); MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Writing to EXT_MEM(%p)..."MEI_CRLF, p)); for (i = 0; i < EXT_MEM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"%p: %#x\n"MEI_CRLF, p, *p)); } *IFXMIPS_RCU_RST &= ~IFXMIPS_RCU_RST_REQ_MUX_ARC; } #endif int DSL_BSP_KernelIoctls( DSL_DEV_Device_t *pDev, unsigned int command, unsigned long lon) { int error = 0; error = IFX_MEI_Ioctls(pDev, 1, command, lon); return error; } static int IFX_MEI_UserIoctls( DSL_DRV_inode_t *ino, DSL_DRV_file_t *fil, unsigned int command, unsigned long lon) { int error = 0; int maj = MAJOR(ino->i_rdev); int num = MINOR(ino->i_rdev); DSL_DEV_Device_t *pDev; pDev = IFX_BSP_HandleGet(maj, num); if (pDev == NULL) { return -EIO; } error = IFX_MEI_Ioctls(pDev, 0, command, lon); return error; } #ifdef CONFIG_PROC_FS /* * Register a callback function for linux proc filesystem */ static int IFX_MEI_InitProcFS( int num) { struct proc_dir_entry *entry; int i ; DSL_DEV_Device_t *pDev; reg_entry_t regs_temp[] = { /* flag, name, description } */ {NULL, "arcmsgav", "arc to mei message ", 0}, {NULL, "cmv_reply", "cmv needs reply", 0}, {NULL, "cmv_waiting", "waiting for cmv reply from arc", 0}, {NULL, "modem_ready_cnt", "ARC to MEI indicator count", 0}, {NULL, "cmv_count", "MEI to ARC CMVs", 0}, {NULL, "reply_count", "ARC to MEI Reply", 0}, {NULL, "Recent_indicator", "most recent indicator", 0}, {NULL, "fw_version", "Firmware Version", 0}, {NULL, "fw_date", "Firmware Date", 0}, {NULL, "meminfo", "Memory Allocation Information", 0}, {NULL, "version", "MEI version information", 0} #ifndef MEI_DEBUG_DISABLE , {NULL, "DBG_ENABLE", "Debug level by module", 0} #endif /* #ifndef MEI_DEBUG_DISABLE*/ }; pDev = &dsl_devices[num]; if (pDev == NULL) { return -ENOMEM; } regs_temp[0].flag = &(DSL_DEV_PRIVATE(pDev)->arcmsgav); regs_temp[1].flag = &(DSL_DEV_PRIVATE(pDev)->cmv_reply); regs_temp[2].flag = &(DSL_DEV_PRIVATE(pDev)->cmv_waiting); regs_temp[3].flag = &(DSL_DEV_PRIVATE(pDev)->modem_ready_cnt); regs_temp[4].flag = &(DSL_DEV_PRIVATE(pDev)->cmv_count); regs_temp[5].flag = &(DSL_DEV_PRIVATE(pDev)->reply_count); regs_temp[6].flag = (int *) &(DSL_DEV_PRIVATE(pDev)->Recent_indicator); #ifndef MEI_DEBUG_DISABLE regs_temp[11].flag = &(DSL_DEV_PRIVATE(pDev)->dbg_level_change); #endif /* #ifndef MEI_DEBUG_DISABLE*/ memcpy((char *) regs[num], (char *) regs_temp, sizeof (regs_temp)); /* procfs*/ meidir = proc_mkdir(MEI_DIRNAME, NULL); if (meidir == NULL) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Failed to create /proc/%s"MEI_CRLF, MEI_DIRNAME)); return (-ENOMEM); } for (i = 0; i < (sizeof(regs_temp)/sizeof(reg_entry_t)); i++) { entry = create_proc_entry(regs[num][i].name, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, meidir); if (entry) { regs[num][i].low_ino = entry->low_ino; entry->proc_fops = &IFX_MEI_ProcOperations; } else { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Failed to create /proc/%s/%s"MEI_CRLF, MEI_DIRNAME, regs[num][i].name)); return (-ENOMEM); } } return 0; } #ifndef MEI_DEBUG_DISABLE static int IFX_MEI_ProcDbgLevelSet( int dbg_level_change) { MEI_DebugLevel_t dbg_level = (MEI_DebugLevel_t)dbg_level_change & 0xFF; if (dbg_level < MEI_DBG_NONE || dbg_level >= MEI_DBG_LAST) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - Debug Level Set failed, unknown level %d"MEI_CRLF, dbg_level)); return -1; } if (dbg_level_change & MEI_PROCFS_MASK_DBG_MOD_COM) { g_MEI_DebugLevel[0].dbg_lvl = dbg_level; } if (dbg_level_change & MEI_PROCFS_MASK_DBG_MOD_CMV) { g_MEI_DebugLevel[1].dbg_lvl = dbg_level; } if (dbg_level_change & MEI_PROCFS_MASK_DBG_MOD_TST) { g_MEI_DebugLevel[2].dbg_lvl = dbg_level; } return 0; } #endif /* #ifndef MEI_DEBUG_DISABLE*/ /* * Reading function for linux proc filesystem */ static int IFX_MEI_ProcRead( struct file *file, char *buf, size_t nbytes, loff_t *ppos) { int i_ino = (file->f_dentry->d_inode)->i_ino; char *p = buf; int i; int num; reg_entry_t *entry = NULL; DSL_DEV_Device_t *pDev = NULL; DSL_DEV_WinHost_Message_t m; for (num = 0; num < BSP_MAX_DEVICES; num++) { for (i = 0; i < NUM_OF_REG_ENTRY; i++) { if (regs[num][i].low_ino == (unsigned short)i_ino) { entry = ®s[num][i]; pDev = &dsl_devices[num]; break; } } } if (entry == NULL) { return -EINVAL; } else if (strcmp(entry->name, "meminfo") == 0) { if (*ppos > 0) /* Assume reading completed in previous read */ return 0; p += sprintf(p, "No Address Size\n"); for (i = 0; i < MAX_BAR_REGISTERS; i++) { p += sprintf (p, "BAR[%02d] Addr:0x%08X Size:%lu\n", i, (u32) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[i].address, DSL_DEV_PRIVATE(pDev)-> adsl_mem_info[i].size); } *ppos += (p - buf); } else if (strcmp(entry->name, "DBG_ENABLE") == 0) { if (*ppos > 0) /* Assume reading completed in previous read */ return 0; for (i = 0; i < MEI_DBG_MOD_LAST; i++) { p += sprintf(p, "%s=%d\n", g_MEI_DebugLevel[i].dbg_mod_name, g_MEI_DebugLevel[i].dbg_lvl); } *ppos += (p - buf); } else if (strcmp(entry->name, "fw_version") == 0) { if (*ppos > 0) /* Assume reading completed in previous read */ return 0; if (DSL_DEV_PRIVATE(pDev)->modem_ready_cnt < 1) return -EAGAIN; /*major:bits 0-7*/ /*minor:bits 8-15*/ makeCMV(H2D_CMV_READ, DSL_CMV_GROUP_INFO, 54, 0, 1, NULL, m.msg.TxMessage); if (DSL_BSP_SendCMV (pDev, m.msg.TxMessage, YES_REPLY, m.msg.RxMessage) != DSL_DEV_MEI_ERR_SUCCESS) return -EIO; p += sprintf(p, "FW Version: %d.%d.", m.msg.RxMessage[4] & 0xFF, (m.msg.RxMessage[4] >> 8) & 0xFF); /*sub_version:bits 4-7*/ /*int_version:bits 0-3*/ /*spl_appl:bits 8-13*/ /*rel_state:bits 14-15*/ makeCMV(H2D_CMV_READ, DSL_CMV_GROUP_INFO, 54, 1, 1, NULL, m.msg.TxMessage); if (DSL_BSP_SendCMV (pDev, m.msg.TxMessage, YES_REPLY, m.msg.RxMessage) != DSL_DEV_MEI_ERR_SUCCESS) return -EIO; p += sprintf(p, "%d.%d.%d.%d\n", (m.msg.RxMessage[4] >> 4) & 0xF, m.msg.RxMessage[4] & 0xF, (m.msg.RxMessage[4] >> 14) & 3, (m.msg.RxMessage[4] >> 8) & 0x3F); *ppos += (p - buf); } else if (strcmp(entry->name, "fw_date") == 0) { if (*ppos > 0) /* Assume reading completed in previous read */ return 0; if (DSL_DEV_PRIVATE(pDev)->modem_ready_cnt < 1) return -EAGAIN; makeCMV (H2D_CMV_READ, DSL_CMV_GROUP_INFO, 55, 0, 1, NULL, m.msg.TxMessage); if (DSL_BSP_SendCMV (pDev, m.msg.TxMessage, YES_REPLY, m.msg.RxMessage) != DSL_DEV_MEI_ERR_SUCCESS) return -EIO; /* Day/Month */ p += sprintf(p, "FW Date: %d.%d.", m.msg.RxMessage[4] & 0xFF, (m.msg.RxMessage[4] >> 8) & 0xFF); makeCMV (H2D_CMV_READ, DSL_CMV_GROUP_INFO, 55, 2, 1, NULL, m.msg.TxMessage); if (DSL_BSP_SendCMV (pDev, m.msg.TxMessage, YES_REPLY, m.msg.RxMessage) != DSL_DEV_MEI_ERR_SUCCESS) return -EIO; /* Year */ p += sprintf(p, "%d ", m.msg.RxMessage[4]); makeCMV (H2D_CMV_READ, DSL_CMV_GROUP_INFO, 55, 1, 1, NULL, m.msg.TxMessage); if (DSL_BSP_SendCMV (pDev, m.msg.TxMessage, YES_REPLY, m.msg.RxMessage) != DSL_DEV_MEI_ERR_SUCCESS) return -EIO; /* Hour:Minute */ p += sprintf(p, "%d:%d\n", (m.msg.RxMessage[4] >> 8) & 0xFF, m.msg.RxMessage[4] & 0xFF); *ppos += (p - buf); } else if (strcmp(entry->name, "version") == 0) { if (*ppos > 0) /* Assume reading completed in previous read */ return 0; p += sprintf (p, "IFX MEI V%ld.%ld.%ld\n", bsp_mei_version.major, bsp_mei_version.minor, bsp_mei_version.revision); *ppos += (p - buf); } else if (entry->flag != (int *) DSL_DEV_PRIVATE(pDev)->Recent_indicator) { if (*ppos > 0) /* Assume reading completed in previous read */ return 0; /* indicates end of file*/ p += sprintf(p, "0x%08X\n\n", *(entry->flag)); *ppos += (p - buf); if ((p - buf) > nbytes) /* Assume output can be read at one time */ return -EINVAL; } else { if ((int) (*ppos) / ((int) 7) == 16) return 0; /* indicate end of the message*/ p += sprintf (p, "0x%04X\n\n", *(((u16 *) (entry->flag)) + (int) (*ppos) / ((int) 7))); *ppos += (p - buf); } return p - buf; } /* * Writing function for linux proc filesystem */ static ssize_t IFX_MEI_ProcWrite( struct file *file, const char *buffer, size_t count, loff_t *ppos) { int i_ino = (file->f_dentry->d_inode)->i_ino; reg_entry_t *current_reg = NULL; int i = 0; int num = 0; unsigned long newRegValue = 0; char *endp = NULL; char procfs_buffer[16]={0}; DSL_DEV_Device_t *pDev = NULL; for (num = 0; num < BSP_MAX_DEVICES; num++) { for (i = 0; i < NUM_OF_REG_ENTRY; i++) { if (regs[num][i].low_ino == (unsigned short)i_ino) { current_reg = ®s[num][i]; pDev = &dsl_devices[num]; break; } } } if ((current_reg == NULL) || (current_reg->flag == (int *) DSL_DEV_PRIVATE(pDev)->Recent_indicator)) return -EINVAL; if (count > sizeof(procfs_buffer)) return -EINVAL; /* write data to the kernel buffer */ if ( copy_from_user(procfs_buffer, buffer, count) ) { return -EFAULT; } newRegValue = simple_strtoul (procfs_buffer, &endp, 0); *(current_reg->flag) = (int) newRegValue; #ifndef MEI_DEBUG_DISABLE if (strcmp(current_reg->name, "DBG_ENABLE") == 0) { IFX_MEI_ProcDbgLevelSet(*(current_reg->flag)); } #endif /* #ifndef MEI_DEBUG_DISABLE*/ return (count + endp - procfs_buffer); } #endif /*CONFIG_PROC_FS*/ static int adsl_dummy_ledcallback(void) { return 0; } int ifx_mei_atm_led_blink(void) { return g_adsl_ledcallback(); } EXPORT_SYMBOL(ifx_mei_atm_led_blink); int ifx_mei_atm_showtime_check( int *is_showtime, struct port_cell_info *port_cell, void **xdata_addr) { int i; if ( is_showtime ) { *is_showtime = g_tx_link_rate[0] == 0 && g_tx_link_rate[1] == 0 ? 0 : 1; } if ( port_cell ) { for ( i = 0; i < port_cell->port_num && i < 2; i++ ) { port_cell->tx_link_rate[i] = g_tx_link_rate[i]; } } if ( xdata_addr ) { if ( g_tx_link_rate[0] == 0 && g_tx_link_rate[1] == 0 ) { *xdata_addr = NULL; } else { *xdata_addr = g_xdata_addr; } } return 0; } EXPORT_SYMBOL(ifx_mei_atm_showtime_check); /* * Writing function for linux proc filesystem */ int __init IFX_MEI_ModuleInit(void) { int i = 0; MEI_DBG_PRINTF("Lantiq MEI driver version: %ld.%02ld.%02ld"MEI_CRLF, bsp_mei_version.major, bsp_mei_version.minor, bsp_mei_version.revision); for (i = 0; i < BSP_MAX_DEVICES; i++) { if (IFX_MEI_InitDevice(i) != 0) { MEI_DEBUG(MEI_DBG_MOD_COM, MEI_DBG_ERR, (MEI_DBG_PREFIX"ERROR - device init failed"MEI_CRLF)); return -EIO; } IFX_MEI_InitDevNode(i); #ifdef CONFIG_PROC_FS IFX_MEI_InitProcFS(i); #endif } for (i = 0; i <= DSL_BSP_CB_LAST ; i++) { dsl_bsp_event_callback[i].function = NULL; } #ifdef CONFIG_IFXMIPS_MEI_FW_LOOPBACK MEI_DEBUG(MEI_DBG_MOD_TST, MEI_DBG_PRN, (MEI_DBG_PREFIX"Start loopback test..."MEI_CRLF)); DFE_Loopback_Test(); #endif return 0; } void __exit IFX_MEI_ModuleExit(void) { int i = 0; int num; for (num = 0; num < BSP_MAX_DEVICES; num++) { IFX_MEI_CleanUpDevNode(num); #ifdef CONFIG_PROC_FS for (i = 0; i < NUM_OF_REG_ENTRY; i++) { remove_proc_entry(regs[num][i].name, meidir); } #endif } remove_proc_entry(MEI_DIRNAME, NULL); for (i = 0; i < BSP_MAX_DEVICES; i++) { for (i = 0; i < BSP_MAX_DEVICES; i++) { IFX_MEI_ExitDevice(i); } } } /* export function for DSL Driver */ /* The functions of MEI_DriverHandleGet and MEI_DriverHandleDelete are something like open/close in kernel space , where the open could be used to register a callback for autonomous messages and returns a mei driver context pointer (comparable to the file descriptor in user space) The context will be required for the multi line chips future! */ EXPORT_SYMBOL(DSL_BSP_DriverHandleGet); EXPORT_SYMBOL(DSL_BSP_DriverHandleDelete); EXPORT_SYMBOL(DSL_BSP_ATMLedCBRegister); EXPORT_SYMBOL(DSL_BSP_ATMLedCBUnregister); EXPORT_SYMBOL(DSL_BSP_KernelIoctls); EXPORT_SYMBOL(DSL_BSP_AdslLedInit); /*EXPORT_SYMBOL (DSL_BSP_AdslLedSet);*/ EXPORT_SYMBOL(DSL_BSP_FWDownload); EXPORT_SYMBOL(DSL_BSP_Showtime); EXPORT_SYMBOL(DSL_BSP_ShowtimeExit); EXPORT_SYMBOL(DSL_BSP_MemoryDebugAccess); EXPORT_SYMBOL(DSL_BSP_SendCMV); /* provide a register/unregister function for DSL driver to register a event callback function*/ EXPORT_SYMBOL(DSL_BSP_EventCBRegister); EXPORT_SYMBOL(DSL_BSP_EventCBUnregister); module_init(IFX_MEI_ModuleInit); module_exit(IFX_MEI_ModuleExit);