/****************************************************************************** ** ** FILE NAME : amazon_s_mei_bsp.c ** PROJECT : Amazon-S ** MODULES : MEI ** ** DATE : 1 Jan 2006 ** AUTHOR : TC Chen ** DESCRIPTION : MEI Driver ** COPYRIGHT : Copyright (c) 2006 ** Infineon Technologies AG ** Am Campeon 1-12, 85579 Neubiberg, Germany ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** HISTORY ** $Version $Date $Author $Comment 1.00.01 TC Chen Fixed cell rate calculation issue Fixed pvovider_id of adsl mib swapping issue 1.00.02 TC Chen Added L3 Low Poewr Mode support. 1.00.03 TC Chen Fixed Clear Eoc transmit issue. 1.00.04 31/08/2006 TC Chen Add ADSL Link/Data Led Add Dual Latency Path Add AUTOBOOT_ENABLE_SET ioctl for autoboot mode enable/disable Fix fast path cell rate calculation 2.00.00 02/10/2006 TC Chen First version for the separation of DSL and MEI 2.00.01 12/10/2006 TC Chen Fix some compiling warnings 2.00.02 23/10/2006 TC Chen Fix /proc/device listing issue 2.00.03 20/12/2006 TC Chen Fix /proc/device listing issue 3.00.00 26/04/2007 KH Teh Integrated DSL CPE API Driver 2.5.x 3.01.00 04/05/2007 KH Teh Add fw_date and fw_version 3.02.00 06/07/2007 KH Teh Integrated with DSL CPE API V2.7.101 3.03.00 05/11/2007 KH Teh Integrated with DSL CPE API V3.3.8 4.00.01 22/05/2008 Huang Xiaogang Fix issue R3 firmware reboot triger via interrupt leads to system crash *******************************************************************************/ /*! \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 #define IFX_MEI_BSP #include #include #include #include #include #include #define BSP_RCU_REQ AMAZON_S_RCU_RST_REQ #define BSP_FUSE_BASE_ADDR AMAZON_S_FUSE_BASE_ADDR #define BSP_GPIO_P0_DIR AMAZON_S_GPIO_P0_DIR #define BSP_GPIO_P0_ALTSEL0 AMAZON_S_GPIO_P0_ALTSEL0 #define BSP_GPIO_P0_ALTSEL1 AMAZON_S_GPIO_P0_ALTSEL1 #define BSP_GPIO_P0_OD AMAZON_S_GPIO_P0_OD #define BSP_RCU_RST_REQ_ARC_JTAG AMAZON_S_RCU_RST_REQ_ARC_JTAG #define BSP_ICU_IM0_IER AMAZON_S_ICU_IM0_IER #define BSP_ICU_IM2_IER AMAZON_S_ICU_IM2_IER #define BSP_MEI_INT AMAZON_S_MEI_INT #define BSP_MEI_DYING_GASP_INT AMAZON_S_MEI_DYING_GASP_INT #define BSP_USB_OC_INT0 AMAZON_S_USB_OC_INT0 #define BSP_USB_OC_INT2 AMAZON_S_USB_OC_INT2 #define BSP_MPS_CHIPID_VERSION_GET AMAZON_S_MPS_CHIPID_VERSION_GET #define BSP_MPS_CHIPID AMAZON_S_MPS_CHIPID #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_AMAZON_S_MEI_FW_LOOPBACK //#define DFE_MEM_TEST //#define DFE_PING_TEST #define DFE_ATM_LOOPBACK #ifndef UINT32 #define UINT32 unsigned long #endif #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 DSL_DEV_Version_t bsp_mei_version = { major: 4, minor: 0, revision:1 }; DSL_DEV_HwVersion_t bsp_chip_info; #define IFX_MEI_DEVNAME "ifx_mei" #define BSP_MAX_DEVICES 1 #if defined(CONFIG_ATM_DANUBE) || defined(CONFIG_AMAZON_S_ATM) extern int IFX_ATM_LED_Callback_Register(int (*)(void)); extern int IFX_ATM_LED_Callback_Unregister( int (*)(void)); #endif 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_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 PROC_ITEMS 11 #define MEI_DIRNAME "amazon_s_mei" static struct proc_dir_entry *meidir; static struct file_operations IFX_MEI_ProcOperations = { read:IFX_MEI_ProcRead, write:IFX_MEI_ProcWrite, }; static reg_entry_t regs[BSP_MAX_DEVICES][PROC_ITEMS]; //total items to be monitored by /proc/mei #define NUM_OF_REG_ENTRY (sizeof(regs[0])/sizeof(reg_entry_t)) #endif void IFX_MEI_ARC_MUX_Test(void); void (*IFX_MEI_set_cell_rate)(int, u32) = NULL; int (*IFX_MEI_adsl_led_flash_cb)(void) = NULL; static u32 *mei_arc_swap_buff = NULL; // holding swap pages extern void bsp_mask_and_ack_irq(unsigned int irq_nr); #define MEI_MASK_AND_ACK_IRQ bsp_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]; 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; #ifdef BSP_DMA_DEBUG_MUTEX MEI_intstat_t flags; #endif if (destaddr & 3) return DSL_DEV_MEI_ERR_FAILURE; #ifdef BSP_DMA_DEBUG_MUTEX MEI_LOCKINT (flags); #endif // Set the write transfer address IFX_MEI_LongWordWriteOffset (pDev, MEI_XFR_ADDR_OFFSET, 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) MEI_DATA_XFR_OFFSET, temp); p++; } #ifdef BSP_DMA_DEBUG_MUTEX MEI_UNLOCKINT (flags); #endif 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; #ifdef BSP_DMA_DEBUG_MUTEX MEI_intstat_t flags; #endif if (srcaddr & 3) return DSL_DEV_MEI_ERR_FAILURE; #ifdef BSP_DMA_DEBUG_MUTEX MEI_LOCKINT (flags); #endif // Set the read transfer address IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_XFR_ADDR_OFFSET, srcaddr); // Read the data popped across DMA while (databuffsize--) { IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_DATA_XFR_OFFSET, &temp); if (databuff == (u32 *) DSL_DEV_PRIVATE(pDev)->CMV_RxMsg) // swap half word MEI_HALF_WORD_SWAP (temp); *p = temp; p++; } #ifdef BSP_DMA_DEBUG_MUTEX MEI_UNLOCKINT (flags); #endif 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) MEI_DBG_MASTER_OFFSET, &temp); switch (mode) { case JTAG_MASTER_MODE: temp &= ~(HOST_MSTR); break; case MEI_MASTER_MODE: temp |= (HOST_MSTR); break; default: IFX_MEI_EMSG ("IFX_MEI_ControlModeSet: unkonwn mode [%d]\n", mode); return; } IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DBG_MASTER_OFFSET, 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) ARC_TO_MEI_INT_MASK_OFFSET, 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) ARC_TO_MEI_INT_MASK_OFFSET, 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) ARC_TO_MEI_INT_OFFSET, &query); query &= (ARC_TO_MEI_DBG_DONE); if (query) break; i++; if (i == WHILE_DELAY) { IFX_MEI_EMSG ("PollforDbg fail!\n"); } } IFX_MEI_LongWordWriteOffset (pDev, (u32) ARC_TO_MEI_INT_OFFSET, ARC_TO_MEI_DBG_DONE); // to clear this interrupt } /** * 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) MEI_DEBUG_DEC_OFFSET, DEC_mode); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DEBUG_RAD_OFFSET, address); meiPollForDbgDone (pDev); IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_DEBUG_DATA_OFFSET, 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) MEI_DEBUG_DEC_OFFSET, DEC_mode); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DEBUG_WAD_OFFSET, address); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DEBUG_DATA_OFFSET, 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; #ifdef BSP_DMA_DEBUG_MUTEX MEI_intstat_t flags; #endif #ifdef BSP_DMA_DEBUG_MUTEX MEI_LOCKINT (flags); #endif // Open the debug port before DMP memory write IFX_MEI_ControlModeSet (pDev, MEI_MASTER_MODE); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DEBUG_DEC_OFFSET, MEI_DEBUG_DEC_DMP1_MASK); // 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, MEI_DEBUG_DEC_DMP1_MASK, address, temp); address += 4; buffer++; } // Close the debug port after DMP memory write IFX_MEI_ControlModeSet (pDev, JTAG_MASTER_MODE); #ifdef BSP_DMA_DEBUG_MUTEX MEI_UNLOCKINT (flags); #endif 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; #ifdef BSP_DMA_DEBUG_MUTEX MEI_intstat_t flags; #endif #ifdef BSP_DMA_DEBUG_MUTEX MEI_LOCKINT (flags); #endif // Open the debug port before DMP memory read IFX_MEI_ControlModeSet (pDev, MEI_MASTER_MODE); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DEBUG_DEC_OFFSET, MEI_DEBUG_DEC_DMP1_MASK); // 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, MEI_DEBUG_DEC_DMP1_MASK, address, &temp); *buffer = temp; address += 4; buffer++; } // Close the debug port after DMP memory read IFX_MEI_ControlModeSet (pDev, JTAG_MASTER_MODE); #ifdef BSP_DMA_DEBUG_MUTEX MEI_UNLOCKINT (flags); #endif 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 destaddr The address to read * \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_DebugWriteCore (DSL_DEV_Device_t * pDev, u32 destaddr, u32 * databuff, u32 databuffsize) { u32 i; u32 temp = 0x0; u32 address = 0x0; u32 *buffer = 0x0; #ifdef BSP_DMA_DEBUG_MUTEX MEI_intstat_t flags; #endif #ifdef BSP_DMA_DEBUG_MUTEX MEI_LOCKINT (flags); #endif // Open the debug port before DMP memory write IFX_MEI_ControlModeSet (pDev, MEI_MASTER_MODE); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DEBUG_DEC_OFFSET, MEI_DEBUG_DEC_DMP2_MASK); // 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, MEI_DEBUG_DEC_DMP2_MASK, address, temp); address += 4; buffer++; } // Close the debug port after DMP memory write IFX_MEI_ControlModeSet (pDev, JTAG_MASTER_MODE); #ifdef BSP_DMA_DEBUG_MUTEX MEI_UNLOCKINT (flags); #endif return DSL_DEV_MEI_ERR_SUCCESS; } #ifdef AMAZON_S_MEI_DFE_MEM_TEST /** * ARC Debug Memory Access for reading (Interleave memory). * 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_DebugReadCore (DSL_DEV_Device_t * pDev, u32 srcaddr, u32 * databuff, u32 databuffsize) { u32 i; u32 temp = 0x0; u32 address = 0x0; u32 *buffer = 0x0; #ifdef BSP_DMA_DEBUG_MUTEX MEI_intstat_t flags; #endif #ifdef BSP_DMA_DEBUG_MUTEX MEI_LOCKINT (flags); #endif // Open the debug port before DMP memory read IFX_MEI_ControlModeSet (pDev, MEI_MASTER_MODE); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_DEBUG_DEC_OFFSET, MEI_DEBUG_DEC_DMP2_MASK); // 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, MEI_DEBUG_DEC_DMP2_MASK, address, &temp); *buffer = temp; address += 4; buffer++; } // Close the debug port after DMP memory read IFX_MEI_ControlModeSet (pDev, JTAG_MASTER_MODE); #ifdef BSP_DMA_DEBUG_MUTEX MEI_UNLOCKINT (flags); #endif return DSL_DEV_MEI_ERR_SUCCESS; } #endif /** * 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) MEI_TO_ARC_INT_OFFSET, MEI_TO_ARC_MSGAV); i = 0; while (i < WHILE_DELAY) { // wait for ARC to clear the bit IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_TO_ARC_INT_OFFSET, &arc_mailbox_status); if ((arc_mailbox_status & MEI_TO_ARC_MSGAV) != MEI_TO_ARC_MSGAV) break; i++; if (i == WHILE_DELAY) { IFX_MEI_EMSG (">>> Timeout waiting for ARC to clear MEI_TO_ARC_MSGAV!!!" " MEI_TO_ARC message size = %d DWORDs <<<\n", 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) ARC_TO_MEI_INT_OFFSET, 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) { #if 1 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); #endif } /** * efuse rar program **/ static void IFX_MEI_FuseProg (DSL_DEV_Device_t * pDev) { #if 1 u32 reg_data, fuse_value; int i = 0; #ifndef CONFIG_AMAZON_S // valid for Danube/Amazon-SE chip only IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, ®_data); while ((reg_data & 0x10000000) == 0) { IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, ®_data); i++; /* 0x4000 translate to about 16 ms@111M, so should be enough */ if (i == 0x4000) return; } #endif // STEP a: Prepare memory for external accesses // Write fuse_en bit24 IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, ®_data); IFX_MEI_LongWordWrite ((u32) BSP_RCU_REQ, reg_data | (1 << 24)); IFX_MEI_FuseInit (pDev); for (i = 0; i < 4; i++) { IFX_MEI_LongWordRead ((u32) (BSP_FUSE_BASE_ADDR) + i * 4, &fuse_value); //printk("i = %d, addr = %08x, value = %08x\n", i, (u32)(BSP_FUSE_BASE_ADDR) + i * 4, fuse_value); switch (fuse_value & 0x001F0000) { case 0x00120000: reg_data = ((fuse_value & RX_DILV_ADDR_BIT_MASK) | (RX_DILV_ADDR_BIT_MASK + 0x1)); //IFX_MEI_DMAWrite (pDev, ADSL_DILV_BASE, ®_data, 1); IFX_MEI_DebugWriteCore(pDev, ADSL_DILV_BASE, ®_data, 1); break; case 0x00130000: 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); IFX_MEI_DebugWriteCore(pDev, ADSL_DILV_BASE + 4, ®_data, 1); break; case 0x000E0000: reg_data = ((fuse_value & IRAM0_ADDR_BIT_MASK) | (IRAM0_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite (pDev, IRAM0_BASE, ®_data, 1); break; case 0x000F0000: reg_data = ((fuse_value & IRAM0_ADDR_BIT_MASK) | (IRAM0_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite (pDev, IRAM0_BASE + 4, ®_data, 1); break; case 0x00100000: reg_data = ((fuse_value & IRAM1_ADDR_BIT_MASK) | (IRAM1_ADDR_BIT_MASK + 0x1)); IFX_MEI_DMAWrite (pDev, IRAM1_BASE, ®_data, 1); break; case 0x00110000: 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; default: // PPE efuse break; } } IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, ®_data); IFX_MEI_LongWordWrite ((u32) BSP_RCU_REQ, reg_data & ~(1 << 24)); IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, ®_data); #endif } static void IFX_MEI_DfeMemTest(DSL_DEV_Device_t * pDev) { #ifdef AMAZON_S_MEI_DFE_MEM_TEST unsigned int mem_info[] = {0x000000, 8, 0, 0x008000, 2, 0, 0x018000, 6, 0, 0x040000, 5, 1}; unsigned int pattern[] = {0x00000000, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA}; unsigned int addr; unsigned int data; int flag_pass; int i, j, k, l; printk("\n"); for ( i = 0; i < sizeof(mem_info) / sizeof(*mem_info) / 3; i++ ) { addr = mem_info[i * 3]; for ( j = 0; j < mem_info[i * 3 + 1]; j++ ) { flag_pass = 1; for ( k = 0; k < sizeof(pattern) / sizeof(*pattern); k++ ) { data = pattern[k]; for ( l = 0; l < 1024; l++ ) { if ( mem_info[i * 3 + 2] == 0 ) IFX_MEI_DebugWrite(pDev, addr + l * 4, &data, 1); else IFX_MEI_DebugWriteCore(pDev, addr + l * 4, &data, 1); } for ( l = 0; l < 1024; l++ ) { if ( mem_info[i * 3 + 2] == 0 ) IFX_MEI_DebugRead(pDev, addr + l * 4, &data, 1); else IFX_MEI_DebugReadCore(pDev, addr + l * 4, &data, 1); if ( data != pattern[k] ) { flag_pass = 0; printk("DFE memory test: block %08x fail, addr %08x, write %08x, read %08x\n", addr, addr + l * 4, pattern[k], data); break; } } } for ( l = 0; l < 1024; l++ ) { data = l + 1; if ( mem_info[i * 3 + 2] == 0 ) IFX_MEI_DebugWrite(pDev, addr + l * 4, &data, 1); else IFX_MEI_DebugWriteCore(pDev, addr + l * 4, &data, 1); } for ( l = 0; l < 1024; l++ ) { if ( mem_info[i * 3 + 2] == 0 ) IFX_MEI_DebugRead(pDev, addr + l * 4, &data, 1); else IFX_MEI_DebugReadCore(pDev, addr + l * 4, &data, 1); if ( data != l + 1 ) { flag_pass = 0; printk("DFE memory test: block %08x fail, addr %08x, write %08x, read %08x\n", addr, addr + l * 4, l, data); break; } } if ( flag_pass ) printk("DFE memory test: block %08x pass\n", addr); addr += 1024 * 4; } } printk("+++ ARC memory test done! +++\n"); #endif } /** * 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, MEI_DEBUG_DEC_DMP1_MASK, CRI_CCR0, &arc_debug_data); arc_debug_data |= ACL_CLK_MODE_ENABLE; _IFX_MEI_DBGLongWordWrite (pDev, MEI_DEBUG_DEC_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 ANDd 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; } #ifdef CONFIG_MIPS_AMAZON_SE #define FPI_BUG_FIX #endif /** * 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; #ifdef FPI_BUG_FIX u32 bar, i; #endif IFX_MEI_HaltArc (pDev); #ifdef FPI_BUG_FIX for (i = 0; i < 5; i++) { IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, &arc_debug_data); IFX_MEI_LongWordWrite ((u32) BSP_RCU_REQ, arc_debug_data | AMAZON_S_RCU_RST_REQ_DFE | AMAZON_S_RCU_RST_REQ_AFE); do { IFX_MEI_LongWordRead ((u32) BSP_RCU_STAT, &arc_debug_data); } while ((arc_debug_data & (AMAZON_S_RCU_RST_REQ_DFE | AMAZON_S_RCU_RST_REQ_AFE)) != (AMAZON_S_RCU_RST_REQ_DFE | AMAZON_S_RCU_RST_REQ_AFE)); IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_XMEM_BAR_BASE_OFFSET, &bar); if (bar == 0x1FFFFFE0) break; } if (i >= 5) IFX_MEI_EMSG ("IFX_MEI_ResetARC failed!\n"); #else IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, &arc_debug_data); IFX_MEI_LongWordWrite ((u32) BSP_RCU_REQ, arc_debug_data | AMAZON_S_RCU_RST_REQ_DFE | AMAZON_S_RCU_RST_REQ_AFE); #endif // reset ARC IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_RST_CONTROL_OFFSET, MEI_SOFT_RESET); IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_RST_CONTROL_OFFSET, 0); 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) { #if (defined(CONFIG_ATM_DANUBE) && defined(CONFIG_DANUBE_DSL_CPE_API)) || (defined(CONFIG_AMAZON_S) && defined(CONFIG_IFX_DSL_CPE_API)) IFX_MEI_EMSG ("Datarate US intl = %d, fast = %d\n", (int)rate_intl, (int)rate_fast); if ( IFX_MEI_set_cell_rate ) { if (rate_intl && rate_fast) { IFX_MEI_set_cell_rate (0, rate_fast / (53 * 8)); IFX_MEI_set_cell_rate (1, rate_intl / (53 * 8)); } else if (rate_fast) { IFX_MEI_set_cell_rate (0, rate_fast / (53 * 8)); } else if (rate_intl) { IFX_MEI_set_cell_rate (0, rate_intl / (53 * 8)); } else { IFX_MEI_EMSG ("Got rate fail.\n"); } } else { IFX_MEI_EMSG("no hookup from ATM driver to set cell rate\n"); } #endif 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, destaddr, (u32 *)databuff, databuffsize); break; case DSL_BSP_MEMORY_WRITE: meierr = IFX_MEI_DebugWrite (pDev, destaddr, (u32 *)databuff, 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); IFX_MEI_FuseProg (pDev); //program fuse rar IFX_MEI_DfeMemTest (pDev); // test fuse prog 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) { #if defined(__LINUX__) int meierr; #endif u32 reg_data; switch (enable) { case 1: //reserve gpio 9, 10, 11, 14, 19 for ARC JTAG bsp_port_reserve_pin (0, 9, PORT_MODULE_MEI_JTAG); bsp_port_reserve_pin (0, 10, PORT_MODULE_MEI_JTAG); bsp_port_reserve_pin (0, 11, PORT_MODULE_MEI_JTAG); bsp_port_reserve_pin (0, 14, PORT_MODULE_MEI_JTAG); bsp_port_reserve_pin (1, 3, PORT_MODULE_MEI_JTAG); bsp_port_set_dir_in(0, 11, PORT_MODULE_MEI_JTAG); bsp_port_clear_altsel0(0, 11, PORT_MODULE_MEI_JTAG); bsp_port_clear_altsel1(0, 11, PORT_MODULE_MEI_JTAG); bsp_port_set_open_drain(0, 11, PORT_MODULE_MEI_JTAG); //enable ARC JTAG IFX_MEI_LongWordRead ((u32) BSP_RCU_REQ, ®_data); IFX_MEI_LongWordWrite ((u32) BSP_RCU_REQ, reg_data | BSP_RCU_RST_REQ_ARC_JTAG); break; case 0: default: #if defined(__LINUX__) //reserve gpio 9, 10, 11, 14, 19 for ARC JTAG meierr = bsp_port_free_pin (0, 9, PORT_MODULE_MEI_JTAG); if (meierr < 0) { IFX_MEI_EMSG ("Reserve GPIO 9 Fail.\n"); goto jtag_end; } meierr = bsp_port_free_pin (0, 10, PORT_MODULE_MEI_JTAG); if (meierr < 0) { IFX_MEI_EMSG ("Reserve GPIO 10 Fail.\n"); goto jtag_end; } meierr = bsp_port_free_pin (0, 11, PORT_MODULE_MEI_JTAG); if (meierr < 0) { IFX_MEI_EMSG ("Reserve GPIO 11 Fail.\n"); goto jtag_end; } meierr = bsp_port_free_pin (0, 14, PORT_MODULE_MEI_JTAG); if (meierr < 0) { IFX_MEI_EMSG ("Reserve GPIO 14 Fail.\n"); goto jtag_end; } meierr = bsp_port_free_pin (1, 3, PORT_MODULE_MEI_JTAG); if (meierr < 0) { IFX_MEI_EMSG ("Reserve GPIO 19 Fail.\n"); goto jtag_end; } #endif break; } #if defined(__LINUX__) jtag_end: if (meierr) return DSL_DEV_MEI_ERR_FAILURE; #endif 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 __attribute__ ((unused)), DSL_DEV_LedId_t led_number __attribute__ ((unused)), DSL_DEV_LedType_t type __attribute__ ((unused)), DSL_DEV_LedHandler_t handler __attribute__ ((unused))) { #if defined(CONFIG_LEDS_AMAZON_S) 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 /*--- #if defined(CONFIG_LEDS_AMAZON_S) ---*/ return DSL_DEV_MEI_ERR_SUCCESS; }; 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; }; ////////////////makeCMV(Opcode, Group, Address, Index, Size, Data), CMV in u16 TxMessage[MSG_LENGTH]/////////////////////////// /** * 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) // write cmv to arc, if reply needed, wait for reply { DSL_DEV_MeiError_t meierror; #if defined(BSP_PORT_RTEMS) int delay_counter = 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; IFX_MEI_EMSG ("MailboxWrite Fail!\n"); IFX_MEI_EMSG ("Resetting ARC...\n"); 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 (DSL_DEV_PRIVATE(pDev)->arcmsgav == 0) MEI_WAIT_EVENT_TIMEOUT (DSL_DEV_PRIVATE(pDev)->wait_queue_arcmsgav, CMV_TIMEOUT); #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; IFX_MEI_EMSG ("\%s: DSL_DEV_MEI_ERR_MAILBOX_TIMEOUT\n", __FUNCTION__); 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; // DSL_DEV_WinHost_Message_t m; if (mei_arc_swap_buff == NULL) { mei_arc_swap_buff = (u32 *) kmalloc (MAXSWAPSIZE * 4, GFP_KERNEL); if (mei_arc_swap_buff == NULL) { IFX_MEI_EMSG (">>> malloc fail for codeswap buff!!! <<<\n"); return DSL_DEV_MEI_ERR_FAILURE; } } 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) { IFX_MEI_EMSG ("firmware header size is bigger than 64K segment size\n"); 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) { IFX_MEI_EMSG ("Firmware download is not completed. Please download firmware again!\n"); return DSL_DEV_MEI_ERR_FAILURE; } // TODO: check crc /// IFX_MEI_ResetARC (pDev); IFX_MEI_HaltArc (pDev); printk(KERN_INFO "[%s %d] -> IFX_MEI_BarUpdate()\n", __func__, __LINE__); IFX_MEI_BarUpdate (pDev, DSL_DEV_PRIVATE(pDev)->nBar); //IFX_MEI_DMSG("Starting to meiDownloadBootCode\n"); IFX_MEI_DownloadBootCode (pDev); im0_register = (*BSP_ICU_IM0_IER) & (1 << 20); im2_register = (*BSP_ICU_IM2_IER) & (1 << 20); /* Turn off irq */ #ifdef CONFIG_MIPS_AMAZON_SE disable_irq (AMAZON_SE_USB_OC_INT0); disable_irq (AMAZON_SE_USB_OC_INT2); #elif defined(CONFIG_AMAZON_S) disable_irq (BSP_USB_OC_INT0); disable_irq (BSP_USB_OC_INT2); #elif defined(CONFIG_DANUBE) disable_irq (BSP_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_MIPS_AMAZON_SE MEI_MASK_AND_ACK_IRQ (AMAZON_SE_USB_OC_INT0); MEI_MASK_AND_ACK_IRQ (AMAZON_SE_USB_OC_INT2); #elif defined(CONFIG_AMAZON_S) MEI_MASK_AND_ACK_IRQ (BSP_USB_OC_INT0); MEI_MASK_AND_ACK_IRQ (BSP_USB_OC_INT2); #elif defined(CONFIG_DANUBE) MEI_MASK_AND_ACK_IRQ (BSP_USB_OC_INT); #endif MEI_MASK_AND_ACK_IRQ (pDev->nIrq[IFX_DYING_GASP]); /* Re-enable irq */ enable_irq(pDev->nIrq[IFX_DYING_GASP]); *BSP_ICU_IM0_IER |= im0_register; *BSP_ICU_IM2_IER |= im2_register; if (DSL_DEV_PRIVATE(pDev)->modem_ready != 1) { IFX_MEI_EMSG ("Modem failed to be ready!\n"); return DSL_DEV_MEI_ERR_FAILURE; } else { IFX_MEI_DMSG("Modem is ready.\n"); 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); size &= BOOT_FLAG_MASK; // Clear boot bit! 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"}; 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) { IFX_MEI_DMSG ("Freeing memory %p (%s)\n", adsl_mem_info[idx].org_address, free_str[adsl_mem_info[idx].type]); 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 0; } static int IFX_MEI_DFEMemoryAlloc (DSL_DEV_Device_t * pDev, long size) { unsigned long mem_ptr; char *org_mem_ptr = NULL; 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; // DSL_DEV_PRIVATE(pDev)->adsl_mem_info; int allocate_size = SDRAM_SEGMENT_SIZE; printk(KERN_INFO "[%s %d]: image_size = %ld\n", __func__, __LINE__, size); // Alloc Swap Pages for (idx = 0; size > 0 && idx < MAX_BAR_REGISTERS; idx++) { // skip bar15 for XDATA usage. #ifndef CONFIG_AMAZON_S_MEI_FW_LOOPBACK if (idx == XDATA_REGISTER) continue; #endif #if 0 if (size < SDRAM_SEGMENT_SIZE) { allocate_size = size; if (allocate_size < 1024) allocate_size = 1024; } #endif if (idx == (MAX_BAR_REGISTERS - 1)) allocate_size = size; else allocate_size = SDRAM_SEGMENT_SIZE; org_mem_ptr = kmalloc (allocate_size + 1024, GFP_KERNEL); if (org_mem_ptr == NULL) { IFX_MEI_EMSG ("%d: kmalloc %d bytes memory fail!\n", idx, allocate_size); err = -ENOMEM; goto allocate_error; } mem_ptr = (unsigned long) (org_mem_ptr + 1023) & ~(1024 -1); adsl_mem_info[idx].address = (char *) mem_ptr; adsl_mem_info[idx].org_address = org_mem_ptr; adsl_mem_info[idx].size = allocate_size; size -= allocate_size; total_size += allocate_size; //printk("alloc memory idx=%d,size=%ld,addr=%X\n",idx,size,(int)adsl_mem_info[idx].address); } if (size > 0) { IFX_MEI_EMSG ("Image size is too large!\n"); err = -EFBIG; goto allocate_error; } err = idx; 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, temp; 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) MEI_XMEM_BAR_BASE_OFFSET + idx * 4, (((uint32_t) adsl_mem_info[idx].address) & 0x0FFFFFFF)); IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_XMEM_BAR_BASE_OFFSET + idx * 4, &temp); //IFX_MEI_DMSG("BAR%d: write %08X read %08X\n", // idx, (((uint32_t)adsl_mem_info[idx].address) & 0x0FFFFFFF), temp & 0x0FFFFFFF); #if 0 if ((temp & 0x0FFFFFFF) != (((uint32_t)adsl_mem_info[idx].address) & 0x0FFFFFFF)) panic ("[%s %d]: BAR%d: write %08X read %08X\n", __func__, __LINE__, idx, (((uint32_t)adsl_mem_info[idx].address) & 0x0FFFFFFF), temp & 0x0FFFFFFF); #endif } for (idx = nTotalBar; idx < MAX_BAR_REGISTERS; idx++) { if (idx == XDATA_REGISTER) continue; IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_XMEM_BAR_BASE_OFFSET + idx * 4, (((uint32_t)adsl_mem_info[nTotalBar - 1].address) & 0x0FFFFFFF)); IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_XMEM_BAR_BASE_OFFSET + idx * 4, &temp); //IFX_MEI_DMSG("BAR%d: write %08X read %08X\n", // idx, (((uint32_t)adsl_mem_info[nTotalBar - 1].address) & 0x0FFFFFFF), temp & 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; adsl_mem_info[idx].size = 0; /* Prevent it from being freed */ } IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_XMEM_BAR_BASE_OFFSET + XDATA_REGISTER * 4, (((uint32_t) adsl_mem_info [XDATA_REGISTER].address) & 0x0FFFFFFF)); IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_XMEM_BAR_BASE_OFFSET + XDATA_REGISTER * 4, &temp); //IFX_MEI_DMSG("BAR%d: write %08X read %08X\n", // XDATA_REGISTER, (((uint32_t)adsl_mem_info[XDATA_REGISTER].address) & 0x0FFFFFFF), temp & 0x0FFFFFFF); // update MEI_XDATA_BASE_SH IFX_MEI_LongWordWriteOffset (pDev, (u32) MEI_XDATA_BASE_SH_OFFSET, ((unsigned long)adsl_mem_info[XDATA_REGISTER].address) & 0x0FFFFFFF); IFX_MEI_LongWordReadOffset (pDev, (u32) MEI_XDATA_BASE_SH_OFFSET, &temp); //IFX_MEI_DMSG("MEI_XDATA_BASE_SH_OFFSET: write %08X read %08X\n", // (((uint32_t)adsl_mem_info[XDATA_REGISTER].address) & 0x0FFFFFFF), temp & 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) { if (size < sizeof (img_hdr_tmp)) { IFX_MEI_EMSG ("Firmware size is too small!\n"); 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) { IFX_MEI_EMSG ("Firmware size is too large!\n"); return retval; } // check if arc is halt IFX_MEI_ResetARC (pDev); IFX_MEI_HaltArc (pDev); IFX_MEI_DFEMemoryFree (pDev, FREE_ALL); //free all retval = IFX_MEI_DFEMemoryAlloc (pDev, DSL_DEV_PRIVATE(pDev)->image_size); if (retval < 0) { IFX_MEI_EMSG ("Error: No memory space left.\n"); goto error; } for (idx = 0; idx < retval; idx++) { //skip XDATA register if (idx == XDATA_REGISTER) continue; 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; } DSL_DEV_PRIVATE(pDev)->nBar = retval; DSL_DEV_PRIVATE(pDev)->img_hdr = (ARC_IMG_HDR *) adsl_mem_info[0].address; adsl_mem_info[XDATA_REGISTER].org_address = kmalloc (SDRAM_SEGMENT_SIZE + 1024, GFP_KERNEL); adsl_mem_info[XDATA_REGISTER].address = (char *) ((unsigned long) (adsl_mem_info[XDATA_REGISTER].org_address + 1023) & 0xFFFFFC00); adsl_mem_info[XDATA_REGISTER].size = SDRAM_SEGMENT_SIZE; if (adsl_mem_info[XDATA_REGISTER].address == NULL) { IFX_MEI_EMSG ("kmalloc memory fail!\n"); retval = -ENOMEM; goto error; } adsl_mem_info[XDATA_REGISTER].type = FREE_RELOAD; printk(KERN_INFO "[%s %d] -> IFX_MEI_BarUpdate()\n", __func__, __LINE__); IFX_MEI_BarUpdate (pDev, (DSL_DEV_PRIVATE(pDev)->nBar)); } else if (DSL_DEV_PRIVATE(pDev)-> image_size == 0) { IFX_MEI_EMSG ("Error: Firmware size=0! \n"); 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) { IFX_MEI_EMSG("Invalid parameter!\n"); return -EINVAL; } if (p->event > DSL_BSP_CB_LAST || p->event < DSL_BSP_CB_FIRST) { IFX_MEI_EMSG("Invalid Event %d\n", p->event); return -EINVAL; } if (dsl_bsp_event_callback[p->event].function) { IFX_MEI_EMSG("Event %d already has a callback function registered!\n", 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) { IFX_MEI_EMSG("Invalid parameter!\n"); return -EINVAL; } if (p->event > DSL_BSP_CB_LAST || p->event < DSL_BSP_CB_FIRST) { IFX_MEI_EMSG("Invalid Event %d\n", p->event); return -EINVAL; } if (dsl_bsp_event_callback[p->event].function) { IFX_MEI_EMSG("Unregistering Event %d...\n", p->event); dsl_bsp_event_callback[p->event].function = NULL; dsl_bsp_event_callback[p->event].pData = NULL; } else { IFX_MEI_EMSG("Event %d is not registered!\n", 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 */ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) static irqreturn_t IFX_MEI_Dying_Gasp_IrqHandle (int int1, void *void0) #else static void IFX_MEI_Dying_Gasp_IrqHandle (int int1, void *void0, struct pt_regs *regs) #endif { DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) void0; DSL_BSP_CB_Type_t event; if (pDev == NULL) IFX_MEI_EMSG("Error: Got Interrupt but pDev is NULL!!!!\n"); #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 IFX_MEI_EMSG("Dying Gasp! Shutting Down... (Work around for Amazon-S Venus emulator)\n"); #else { struct siginfo siginfo; siginfo.si_signo = SIGINT; IFX_MEI_EMSG("Dying Gasp! Shutting Down...\n"); kill_proc_info (1, &siginfo, 1); /* Ask init to reboot us */ } #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 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) IFX_MEI_IrqHandle (int int1, void *void0) #else IFX_MEI_IrqHandle (int int1, void *void0, struct pt_regs *regs) #endif //defined(BSP_PORT_RTEMS) { u32 scratch; DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) void0; #if defined(CONFIG_AMAZON_S_MEI_FW_LOOPBACK) && defined(DFE_PING_TEST) dfe_loopback_irq_handler (pDev); return IRQ_HANDLED; #endif //CONFIG_AMAZON_S_MEI_FW_LOOPBACK DSL_BSP_CB_Type_t event; if (pDev == NULL) IFX_MEI_EMSG("Error: Got Interrupt but pDev is NULL!!!!\n"); IFX_MEI_DebugRead (pDev, ARC_MEI_MAILBOXR, &scratch, 1); if (scratch & OMB_CODESWAP_MESSAGE_MSG_TYPE_MASK) { IFX_MEI_EMSG("Receive Code Swap Request interrupt!!!\n"); return IRQ_HANDLED; } else if (scratch & OMB_CLEAREOC_INTERRUPT_CODE) { // clear eoc message interrupt IFX_MEI_DMSG("OMB_CLEAREOC_INTERRUPT_CODE\n"); event = DSL_BSP_CB_CEOC_IRQ; IFX_MEI_LongWordWriteOffset (pDev, (u32) ARC_TO_MEI_INT_OFFSET, 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 IFX_MEI_DMSG("OMB_REBOOT_INTERRUPT_CODE\n"); event = DSL_BSP_CB_FIRMWARE_REBOOT; #if 1 IFX_MEI_LongWordWriteOffset (pDev, (u32) ARC_TO_MEI_INT_OFFSET, ARC_TO_MEI_MSGAV); #endif 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 IFX_MEI_DMSG ("Got MODEM_READY_MSG\n"); 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)) { #if defined(CONFIG_ATM_DANUBE) \ || defined(CONFIG_AMAZON_S_ATM) || defined(CONFIG_AMAZON_S_ATM_MODULE) \ || defined(CONFIG_AMAZON_S_PTM) || defined(CONFIG_AMAZON_S_PTM_MODULE) \ || defined(CONFIG_IFX_PPA_A5) IFX_MEI_adsl_led_flash_cb = ifx_adsl_ledcallback; return 0; #else return 0; #endif } int DSL_BSP_ATMLedCBUnregister (int (*ifx_adsl_ledcallback) (void)) { #if defined(CONFIG_ATM_DANUBE) \ || defined(CONFIG_AMAZON_S_ATM) || defined(CONFIG_AMAZON_S_ATM_MODULE) \ || defined(CONFIG_AMAZON_S_PTM) || defined(CONFIG_AMAZON_S_PTM_MODULE) \ || defined(CONFIG_IFX_PPA_A5) IFX_MEI_adsl_led_flash_cb = NULL; return 0; #else return 0; #endif } #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 //TODO, for loopback test #ifdef CONFIG_AMAZON_S_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); printk ("write to %X\n", IMBOX_BASE); IFX_MEI_LongWordWriteOffset (&dsl_devices[0], (u32) MEI_TO_ARC_INT_OFFSET, 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); printk ("read from %X\n", OMBOX_BASE); } //static void //MEIWriteARCValue (u32 address, u32 value) //{ // u32 i, check = 0; // // /* Write address register */ // IFX_MEI_WRITE_REGISTER_L (address, MEI_DEBUG_WAD_OFFSET + MEI_SPACE_ACCESS); // // /* Write data register */ // IFX_MEI_WRITE_REGISTER_L (value, MEI_DEBUG_DATA_OFFSET + MEI_SPACE_ACCESS); // // /* wait until complete - timeout at 40 */ // for (i = 0; i < 40; i++) { // check = IFX_MEI_READ_REGISTER_L (ARC_TO_MEI_INT_OFFSET + MEI_SPACE_ACCESS); // // if ((check & ARC_TO_MEI_DBG_DONE)) // break; // } // /* clear the flag */ // IFX_MEI_WRITE_REGISTER_L (ARC_TO_MEI_DBG_DONE, ARC_TO_MEI_INT_OFFSET + MEI_SPACE_ACCESS); //} void arc_code_page_download (uint32_t arc_code_length, uint32_t * start_address) { int count; printk ("try to download pages,size=%d\n", 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) MEI_XFR_ADDR_OFFSET, 0); for (count = 0; count < arc_code_length; count++) { IFX_MEI_LongWordWriteOffset (&dsl_devices[0], (u32) MEI_DATA_XFR_OFFSET, *(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; // //printk("jt %X %08X %08X\n",i,jump_table[i*2+0],jump_table[i*2+1]); // } // 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) { printk ("Get ARC_ACK\n"); got_int = 1; } else if (rd_mbox[0] == 0x5) { printk ("Get ARC_BUSY\n"); got_int = 2; } else if (rd_mbox[0] == 0x3) { printk ("Get ARC_EDONE\n"); if (rd_mbox[1] == 0x0) { got_int = 3; printk ("Get E_MEMTEST\n"); if (rd_mbox[2] != 0x1) { got_int = 4; printk ("Get Result %X\n", rd_mbox[2]); } } } IFX_MEI_LongWordWriteOffset (&dsl_devices[0], (u32) ARC_TO_MEI_INT_OFFSET, 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; // // printk ("Waiting Starting\n"); // while (mbox[0] == 0) { // ReadMbox (&mbox[0], 5); // } // printk ("Try to get mem test result.\n"); // ReadMbox (&mbox[0], 5); // if (mbox[0] == 0xA) { // printk ("Success.\n"); // } // else if (mbox[0] == 0xA) { // printk ("Fail,address %X,except data %X,receive data %X\n", // mbox[1], mbox[2], mbox[3]); // } // else { // printk ("Fail\n"); // } //} #ifdef DFE_PING_TEST 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; } printk ("send ping msg\n"); wr_mbox[0] = MEI_PING; WriteMbox (&wr_mbox[0], 10); while (got_int == 0) { MEI_WAIT (100); } printk ("send start event\n"); 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]); //printk("IFX_MEI_MailboxWrite ret=%d\n",i); IFX_MEI_LongWordWriteOffset (&dsl_devices[0], (u32) MEI_TO_ARC_INT_OFFSET, MEI_TO_ARC_MSGAV); printk ("sleeping\n"); while (1) { if (got_int > 0) { if (got_int > 3) printk ("got_int >>>> 3\n"); else printk ("got int = %d\n", got_int); got_int = 0; //schedule(); DSL_ENABLE_IRQ (pDev->nIrq[IFX_DFEIR]); } //mbox_read(&rd_mbox[0],6); MEI_WAIT (100); } return 0; } #endif 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) MEI_XDATA_BASE_SH_OFFSET + MEI_SPACE_ACCESS, 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), MEI_SPACE_ACCESS + MEI_XMEM_BAR_BASE_OFFSET + idx * 4); printk ("bar%d(%X)=%X\n", idx, MEI_SPACE_ACCESS + MEI_XMEM_BAR_BASE_OFFSET + 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) MEI_XDATA_BASE_SH_OFFSET, ((unsigned long) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[XDATA_REGISTER].address) & 0x0FFFFFFF); } else { IFX_MEI_EMSG ("cannot load image: no memory\n"); return DSL_DEV_MEI_ERR_FAILURE; } //WriteARCreg(AUX_IC_CTRL,2); printk(KERN_INFO "[%s %s %d]: Setting MEI_MASTER_MODE..\n", __FILE__, __func__, __LINE__); 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); printk(KERN_INFO "[%s %s %d]: Setting JTAG_MASTER_MODE..\n", __FILE__, __func__, __LINE__); IFX_MEI_ControlModeSet (pDev, JTAG_MASTER_MODE); printk(KERN_INFO "[%s %s %d]: Halting ARC...\n", __FILE__, __func__, __LINE__); IFX_MEI_HaltArc (&dsl_devices[0]); #ifdef DFE_PING_TEST printk ("ping test image size=%d\n", 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 printk ("ARC ping test code download complete\n"); #endif //defined( DFE_PING_TEST )|| defined( DFE_ATM_LOOPBACK) #ifdef DFE_MEM_TEST IFX_MEI_LongWordWriteOffset (&dsl_devices[0], (u32) ARC_TO_MEI_INT_MASK_OFFSET, MSGAV_EN); arc_code_page_download (1537, &code_array[0]); printk ("ARC mem test code download complete\n"); #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); printk(KERN_INFO "[%s %s %d]: run ARC...\n", __FILE__, __func__, __LINE__); 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 //end of TODO, for loopback test static int IFX_MEI_InitDevNode (int num) { if (num == 0) { if ((dev_major = register_chrdev (dev_major, IFX_MEI_DEVNAME, &bsp_mei_operations)) < 0) { IFX_MEI_EMSG ("register_chrdev(%d %s) failed!\n", 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; 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) { // u32 pmu_reg = 0; pDev->nIrq[IFX_DFEIR] = BSP_MEI_INT; pDev->nIrq[IFX_DYING_GASP] = BSP_MEI_DYING_GASP_INT; pDev->base_address = MEI_SPACE_ACCESS; /* Power up MEI */ DSL_PMU_SETUP(PMU_ENABLE); } pDev->nInUse = 0; DSL_DEV_PRIVATE(pDev)->modem_ready = 0; DSL_DEV_PRIVATE(pDev)->arcmsgav = 0; MEI_INIT_WAKELIST ("arcq", DSL_DEV_PRIVATE(pDev)->wait_queue_arcmsgav); // for ARCMSGAV MEI_INIT_WAKELIST ("arcr", DSL_DEV_PRIVATE(pDev)->wait_queue_modemready); // for arc modem ready MEI_MUTEX_INIT (DSL_DEV_PRIVATE(pDev)->mei_cmv_sema, 1); // semaphore initialization, mutex #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, IRQF_DISABLED, "DFEIR", pDev) != 0) { IFX_MEI_EMSG ("IFX_DFEIR: request_irq %d failed!\n", pDev->nIrq[IFX_DFEIR]); return -1; } //#ifndef CONFIG_USE_EMULATOR if (request_irq (pDev->nIrq[IFX_DYING_GASP], IFX_MEI_Dying_Gasp_IrqHandle, IRQF_DISABLED, "DYING_GASP", pDev) != 0) { IFX_MEI_EMSG ("IFX_DYING_GASP: request_irq %d failed!\n", pDev->nIrq[IFX_DYING_GASP]); return -1; } //#endif // IFX_MEI_DMSG("Device %d initialized. IER %#x\n", num, bsp_get_irq_ier(pDev->nIrq[IFX_DYING_GASP])); 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) { IFX_MEI_EMSG("open(%d:%d) fail!\n", 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 = MEI_SPACE_ACCESS; 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) { IFX_MEI_EMSG ("WINHOST CMV fail :TxMessage:%X %X %X %X, RxMessage:%X %X %X %X %X\n", 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: 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: if ((meierr = IFX_MEI_RunAdslModem (pDev)) != DSL_DEV_MEI_ERR_SUCCESS) { IFX_MEI_EMSG ("IFX_MEI_RunAdslModem() error..."); 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, (DSL_uint32_t *)debugrdwr.buffer, debugrdwr.iCount); else meierr = DSL_BSP_MemoryDebugAccess (pDev, DSL_BSP_MEMORY_WRITE, debugrdwr.iAddress, (DSL_uint32_t *)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 = BSP_MPS_CHIPID_VERSION_GET(*BSP_MPS_CHIPID); IFX_MEI_DMSG("DSL_FIO_BSP_GET_CHIP_INFO: version %ld\n", bsp_chip_info.major); 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; } IFX_MEI_DMSG("RxMessage[4] = %#x\n", m.msg.RxMessage[4]); if (!(m.msg.RxMessage[4] & DSL_DEV_STAT_CODESWAP_COMPLETE)) { meierr = DSL_DEV_MEI_ERR_FAILURE; return -EAGAIN; } IFX_MEI_DMSG("Freeing all memories marked FREE_SHOWTIME\n"); IFX_MEI_DFEMemoryFree (pDev, FREE_SHOWTIME); meierr = DSL_DEV_MEI_ERR_SUCCESS; break; #ifdef CONFIG_MIPS_AMAZON_SE case DSL_FIO_ARC_MUX_TEST: AMAZON_SE_MEI_ARC_MUX_Test(); break; #endif default: // IFX_MEI_EMSG("Invalid IOCTL command: %d\n"); break; } return meierr; } #ifdef CONFIG_MIPS_AMAZON_SE void AMAZON_SE_MEI_ARC_MUX_Test(void) { u32 *p, i; *AMAZON_SE_RCU_RST_REQ |= AMAZON_SE_RCU_RST_REQ_MUX_ARC; p = (u32*)(DFE_LDST_BASE_ADDR + IRAM0_BASE); IFX_MEI_EMSG("Writing to IRAM0(%p)...\n", p); for (i = 0; i < IRAM0_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) IFX_MEI_EMSG("%p: %#x\n", p, *p); } p = (u32*)(DFE_LDST_BASE_ADDR + IRAM1_BASE); IFX_MEI_EMSG("Writing to IRAM1(%p)...\n", p); for (i = 0; i < IRAM1_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) IFX_MEI_EMSG("%p: %#x\n", p, *p); } p = (u32*)(DFE_LDST_BASE_ADDR + BRAM_BASE); IFX_MEI_EMSG("Writing to BRAM(%p)...\n", p); for (i = 0; i < BRAM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) IFX_MEI_EMSG("%p: %#x\n", p, *p); } p = (u32*)(DFE_LDST_BASE_ADDR + XRAM_BASE); IFX_MEI_EMSG("Writing to XRAM(%p)...\n", p); for (i = 0; i < XRAM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) IFX_MEI_EMSG("%p: %#x\n", p, *p); } p = (u32*)(DFE_LDST_BASE_ADDR + YRAM_BASE); IFX_MEI_EMSG("Writing to YRAM(%p)...\n", p); for (i = 0; i < YRAM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) IFX_MEI_EMSG("%p: %#x\n", p, *p); } p = (u32*)(DFE_LDST_BASE_ADDR + EXT_MEM_BASE); IFX_MEI_EMSG("Writing to EXT_MEM(%p)...\n", p); for (i = 0; i < EXT_MEM_SIZE/sizeof(u32); i++, p++) { *p = 0xdeadbeef; if (*p != 0xdeadbeef) IFX_MEI_EMSG("%p: %#x\n", p, *p); } *AMAZON_SE_RCU_RST_REQ &= ~AMAZON_SE_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[PROC_ITEMS] = { /* 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}, }; 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); memcpy ((char *) regs[num], (char *) regs_temp, sizeof (regs_temp)); // procfs meidir = proc_mkdir (MEI_DIRNAME, &proc_root); if (meidir == NULL) { IFX_MEI_EMSG ("Failed to create /proc/%s\n", MEI_DIRNAME); return (-ENOMEM); } for (i = 0; i < NUM_OF_REG_ENTRY; 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 { IFX_MEI_EMSG ("Failed to create /proc/%s/%s\n", MEI_DIRNAME, regs[num][i].name); return (-ENOMEM); } } return 0; } /* * 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); //printk( "BAR[%02d] Addr:0x%08X Size:%d\n",i,adsl_mem_info[i].address,adsl_mem_info[i].size); } *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); p += sprintf (p, "Compiled on %s, %s for Linux kernel %s (jiffies: %ld)\n", __DATE__, __TIME__, UTS_RELEASE, jiffies); *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; 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 == 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; newRegValue = simple_strtoul (buffer, &endp, 0); *(current_reg->flag) = (int) newRegValue; return (count + endp - buffer); } #endif //CONFIG_PROC_FS /* * Writing function for linux proc filesystem */ int __init IFX_MEI_ModuleInit (void) { int i = 0; printk ("IFX MEI Version %ld.%02ld.%02ld", 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) { printk ("%s: Init device fail!\n", __FUNCTION__); 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_AMAZON_S_MEI_FW_LOOPBACK printk(KERN_INFO "[%s %s %d]: Start loopback test...\n", __FILE__, __func__, __LINE__); 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, &proc_root); 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 (IFX_MEI_set_cell_rate); EXPORT_SYMBOL (IFX_MEI_adsl_led_flash_cb); 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_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);