| /** |
| * |
| * Name: stdhost.c |
| * Project: Wireless LAN, Bus driver for SDIO interface |
| * Version: $Revision: 1.1 $ |
| * Date: $Date: 2007/01/18 09:21:35 $ |
| * Purpose: This module handles the SDIO Standard Host Interface. |
| * |
| * Copyright (C) 2003-2009, Marvell International Ltd. |
| * |
| * This software file (the "File") is distributed by Marvell International |
| * Ltd. under the terms of the GNU General Public License Version 2, June 1991 |
| * (the "License"). You may use, redistribute and/or modify this File in |
| * accordance with the terms and conditions of the License, a copy of which |
| * is available by writing to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the |
| * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. |
| * |
| * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE |
| * ARE EXPRESSLY DISCLAIMED. The License provides additional details about |
| * this warranty disclaimer. |
| * |
| */ |
| |
| /****************************************************************************** |
| * |
| * History: |
| * |
| * $Log: stdhost.c,v $ |
| * Revision 1.1 2007/01/18 09:21:35 pweber |
| * Put under CVS control |
| * |
| * Revision 1.4 2005/12/08 12:00:27 ebauer |
| * Driver ckecks AND update voltage registry value if not correct |
| * |
| * Revision 1.3 2005/12/07 13:40:19 ebauer |
| * Modify check of registry voltage value |
| * |
| * Revision 1.2 2005/10/31 10:34:59 jschmalz |
| * Bugfixes Chariot (Interface hang) |
| * |
| * Revision 1.1 2005/10/07 08:43:47 jschmalz |
| * Put SDIO with FPGA under CVS control |
| * |
| * |
| ******************************************************************************/ |
| |
| #include "h/skdrv1st.h" |
| #include "h/skdrv2nd.h" |
| |
| //define the SD Block Size |
| //for SD8381-B0 chip, it could be 32,64,128,256,512 |
| //for all other chips including SD8381-A0, it must be 32 |
| #define POLLING_TIMES 2000 |
| |
| #define USE_FPGA_POWER_RAMP |
| // #define DMA_SUPPORT_RD |
| // #define DMA_SUPPORT_WR |
| // #define FIFO_CMD52_DEBUG |
| |
| SK_U8 ena_func[8] = { 0, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0x7E, 0xFE }; |
| |
| SK_BOOL SDHost_DumpCIS(PSD_DEVICE_DATA pDev, SK_U8 function_number, |
| SK_U32 length); |
| |
| extern int block_size, dma_support; |
| |
| /****************************************************************************** |
| * |
| * SDHost_InitializeCard - Initialize the plugged in SDIO card |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * TRUE on success |
| */ |
| SK_BOOL |
| SDHost_InitializeCard(PSD_DEVICE_DATA pDev) |
| { |
| SK_U8 OCR[3]; |
| SK_U8 RCA[2]; |
| SK_U8 Cis[DEVICE_NAME_LENGTH]; |
| SK_U16 usVal, ucPowerCurr[FPGA_POWER_STEPS] = FPGA_POWER_VAL_ENUM; |
| SK_U8 ucValue; |
| SK_U8 ucConfigId; |
| SK_U8 ucPowerValue = 0; |
| SK_U8 R; |
| SK_U32 ulArg; |
| SK_U32 j, i, ulValue, ulResponse, cnt; |
| SK_U32 cislength; |
| SK_U32 RegVal; |
| SK_U32 u32Val; |
| |
| SDHost_DisableInterrupt(pDev, STDHOST_NORMAL_IRQ_ALL_SIG_ENA); |
| |
| _SLEEP_MS(pDev, 100); |
| |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "SDHost_InitializeCard()\n")); |
| /*--- mmoser 3/7/2006 ---*/ |
| cnt = 0; |
| |
| pDev->crc_len = 0; |
| |
| ZERO_MEMORY(OCR, 3); |
| ZERO_MEMORY(RCA, 2); |
| ZERO_MEMORY(Cis, DEVICE_NAME_LENGTH); |
| |
| // Setup the SD clock |
| if (pDev->baseClockFreq == 0) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "Base clock frequency not available!\n")); |
| return SK_FALSE; |
| } |
| if (pDev->ClockSpeed != 0) { |
| usVal = MK_CLOCK((SK_U16) pDev->ClockSpeed) | STDHOST_INTERNAL_CLK_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| } else { |
| SK_U32 ClockSpeed = 1; // set the clock initially to 25MHz |
| usVal = MK_CLOCK((SK_U16) ClockSpeed) | STDHOST_INTERNAL_CLK_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| } |
| /* Set the Rx Clock to Rising Edge */ |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, FPGA_CORE_CTRL_REG, &u32Val); |
| u32Val |= FPGA_RAISING_EDGE; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, FPGA_CORE_CTRL_REG, u32Val); |
| |
| for (j = 0; j < MAX_WAIT_CLOCK_STABLE; j++) { |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal); |
| if ((usVal & STDHOST_INTERNAL_CLK_STABLE) == |
| STDHOST_INTERNAL_CLK_STABLE) { |
| break; |
| } |
| } |
| if (j >= MAX_WAIT_CLOCK_STABLE) { |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "SD clock remains unstable!\n")); |
| return SK_FALSE; |
| } |
| // Enable clock to card |
| usVal |= STDHOST_CLOCK_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| |
| // enable DMA support depending on ChipRev |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_CHIP_REVISION, &ucValue); |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "ChipRevision: 0x%x\n", ucValue)); |
| { |
| SK_U8 hi, lo; |
| lo = ucValue & 0x0F; |
| hi = (ucValue >> 4) & 0x0F; |
| printk("\n****************************************************\n"); |
| printk("********* FPGA-ChipRevision: %x.%x (0x%2.02X) *********\n", |
| hi, lo, ucValue); |
| printk("****************************************************\n"); |
| } |
| |
| pDev->dma_support = 0; |
| if ((ucValue >= FPGA_CHIP_REV_2_0) && dma_support) { |
| if ((pDev->debug_flags & DEBUG_USE_RD_DMA) == DEBUG_USE_RD_DMA) |
| pDev->dma_support |= DMA_RD_SUPPORT; |
| |
| if ((pDev->debug_flags & DEBUG_USE_WR_DMA) == DEBUG_USE_WR_DMA) |
| pDev->dma_support |= DMA_WR_SUPPORT; |
| |
| // pDev->dma_support = DMA_WR_SUPPORT | DMA_RD_SUPPORT; |
| // pDev->dma_support = DMA_RD_SUPPORT; |
| // pDev->dma_support = 0; |
| } else { |
| pDev->dma_support = 0; |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "***************************************************\n")); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "* CardBus-to-SDIO Adapter FPGA Rev: V0x%x *\n", |
| ucValue)); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "* This FPGA revision does NOT support DMA mode, *\n")); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "* please update your adapter to Rev 20 or higher *\n")); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "***************************************************\n")); |
| } |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "DMA_SUPPORT: 0x%x\n", pDev->dma_support)); |
| printk |
| ("**************++ DMA_SUPPORT: 0x%x debug_flags=0x%8.08X ++************************\n", |
| pDev->dma_support, pDev->debug_flags); |
| // pweber / tschrobenhauser 03.08.2005 |
| // check the power regulator output voltage is stable |
| // WAIT UNTIL ADDR 0x20E, Bit 0 == 1 |
| |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_CARD_REVISION, &ucValue); |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "CardRevision: 0x%x\n", ucValue)); |
| if (ucValue == FPGA_CARD_REV_1_1) { |
| // SK_U8 ucConfigId; |
| // SK_U8 ucPowerValue=0; |
| // LINUX: get voltage value from module parameter 'sdio_voltage' |
| RegVal = pDev->sdio_voltage; |
| |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_CONFIG_ID, &ucConfigId); |
| if (ucConfigId & FPGA_CONFIG_3_3_V) { |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "Configuration ID : 3.3V\n")); |
| // Check if registry value is ok |
| if ((RegVal >= FPGA_POWER_REG_3_3_V_MIN) && |
| (RegVal <= FPGA_POWER_REG_3_3_V_MAX)) { |
| ucPowerValue = (SK_U8) RegVal; |
| } else { |
| ucPowerValue = FPGA_POWER_REG_3_3_V; |
| } |
| } else if (ucConfigId & FPGA_CONFIG_2_5_V) { |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "Configuration ID : 2.5V\n")); |
| // Check if registry value is ok |
| if ((RegVal >= FPGA_POWER_REG_2_5_V_MIN) && |
| (RegVal <= FPGA_POWER_REG_2_5_V_MAX)) { |
| ucPowerValue = (SK_U8) RegVal; |
| } else { |
| ucPowerValue = FPGA_POWER_REG_2_5_V; |
| } |
| } else if (ucConfigId & FPGA_CONFIG_1_8_V) { |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "Configuration ID : 1.8V\n")); |
| // Check if registry value is ok |
| if ((RegVal >= FPGA_POWER_REG_1_8_V_MIN) && |
| (RegVal <= FPGA_POWER_REG_1_8_V_MAX)) { |
| ucPowerValue = (SK_U8) RegVal; |
| } else { |
| ucPowerValue = FPGA_POWER_REG_1_8_V; |
| } |
| } |
| } |
| #ifndef USE_FPGA_POWER_RAMP // [fhm] ramp-up SDIO port voltage |
| |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_DATA, ucPowerValue); |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_CMD, |
| FPGA_POWER_REG_CMD_START); |
| |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "wait for stable voltage\n")); |
| cnt = 0; |
| do { |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_STATUS, &ucValue); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "PowerRegulatorControl: 0x%x\n", ucValue)); |
| } while (++cnt < 10000 && (ucValue & FPGA_POWER_REG_STABLE) == 0); |
| DBGPRINT(DBG_ERROR, ("wait for stable voltage: cnt=%d\n", cnt)); |
| |
| // Turn on highest supplied voltage |
| ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage); |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue); |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "MaxSupplyVoltage: %d\n", pDev->maxSupplyVoltage)); |
| |
| ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage) | STDHOST_POWER_ON; |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue); |
| |
| #else |
| _SLEEP_MS(pDev, 100); // [mb] for de-bounce |
| for (i = 0; i < FPGA_POWER_STEPS; i++) { |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_DATA, |
| (SK_U8) ucPowerCurr[i]); |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_CMD, |
| FPGA_POWER_REG_CMD_START); |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "wait for stable voltage (0x%x)\n", |
| ucPowerCurr[i])); |
| cnt = 0; |
| do { |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, FPGA_POWER_REG_STATUS, &ucValue); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "PowerRegulatorControl: 0x%x\n", ucValue)); |
| } while (++cnt < 10000 && (ucValue & FPGA_POWER_REG_STABLE) == 0); |
| DBGPRINT(DBG_ERROR, ("wait for stable voltage: cnt=%d\n", cnt)); |
| if (cnt == 10000) |
| return SK_FALSE; |
| |
| // switch on SDIO port voltage if lowest voltage is stable |
| if (ucPowerCurr[i] == FPGA_POWER_REG_0_7_V) { |
| ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage); |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue); |
| ucValue = MK_VOLTAGE(pDev->maxSupplyVoltage) | STDHOST_POWER_ON; |
| //[mb] |
| _SLEEP_MS(pDev, 50); // wait until voltage has reached the |
| // set level |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_POWER_CTRL, ucValue); |
| } |
| // leave for loop, if desired power level has been set |
| if (ucPowerCurr[i] == (SK_U16) ucPowerValue) |
| break; |
| //[mb] |
| if ((ucPowerCurr[i] < FPGA_POWER_REG_1_2_V) && |
| (ucPowerCurr[i] > FPGA_POWER_REG_1_0_V)) |
| udelay(FPGA_POWER_RAMP_DELAY * 6); |
| else |
| udelay(FPGA_POWER_RAMP_DELAY); |
| if (i < FPGA_POWER_STEPS - 1) { |
| if (ucPowerCurr[i + 1] > (SK_U16) ucPowerValue) |
| ucPowerCurr[i + 1] = (SK_U16) ucPowerValue; |
| } |
| } |
| |
| #endif // [fhm] |
| |
| _SLEEP_MS(pDev, 100); // pweber 03.08.2005 |
| |
| if (pDev->bus_type == SDIO_SPI_TYPE) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "--------------> SPI-Mode : Send CMD0\n")); |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x200, &ulValue); |
| ulValue |= 0x00000001; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, 0x200, ulValue); |
| |
| SDHost_SendCmd(pDev, 0, 0, 0, &ulResponse); // CMD0 for transit to |
| // SPI mode |
| SDHost_SendCmd(pDev, 59, 0, 0, &ulResponse); // CMD59 turn off CRC |
| } |
| // _SLEEP_MS( pDev, 100); pweber 03.08.2005 |
| |
| if (!SDHost_ReadOCR(pDev, OCR)) { |
| DBGPRINT(DBG_W528D | DBG_ERROR, (KERN_DEBUG "ReadOCR failed!\n")); |
| return SK_FALSE; |
| } |
| // check if our supply voltage is supported |
| |
| if ((OCR[0] & 0xE0) == 0) // Support for 3.3 - 3.6 V |
| { |
| DBGPRINT(DBG_W528D | DBG_ERROR, |
| (KERN_DEBUG "Card does not support our supply voltage!\n")); |
| return SK_FALSE; |
| } |
| |
| if (!SDHost_WriteOCR(pDev, OCR)) { |
| DBGPRINT(DBG_W528D | DBG_ERROR, (KERN_DEBUG "WriteOCR failed!\n")); |
| return SK_FALSE; |
| } |
| |
| if (pDev->bus_type == SDIO_BUS_TYPE) { |
| // Send CMD3 ident -> standby |
| if (!SDHost_ReadRCA(pDev, RCA)) { |
| return SK_FALSE; |
| } |
| |
| if (RCA[0] == 0 && RCA[1] == 0) { |
| // Try to get new RCA |
| if (!SDHost_ReadRCA(pDev, RCA)) { |
| return SK_FALSE; |
| } |
| if (RCA[0] == 0 && RCA[1] == 0) { |
| // Failed to get a valid RCA |
| return SK_FALSE; |
| } |
| } |
| ulArg = RCA[0] << 24 | RCA[1] << 16; |
| // CMD7 to select card and go to transfer state. |
| if (!SDHost_SendCmd(pDev, 7, ulArg, 0, &ulResponse)) { |
| if (++pDev->bus_errors > MAX_BUS_ERRORS) { |
| SDHost_SetCardOutEvent(pDev); |
| } |
| return SK_FALSE; |
| } |
| } |
| |
| j = 0; |
| while (j++ < 5) { |
| // IO Enable all supported functions |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "IO Enable all supported functions: 0x%2.02X\n", |
| ena_func[pDev->number_of_functions])); |
| SDHost_CMD52_Write(pDev, IO_ENABLE_REG, 0, |
| ena_func[pDev->number_of_functions]); |
| if (SDHost_CMD52_Read(pDev, IO_ENABLE_REG, 0, &R)) { |
| break; |
| } |
| } |
| |
| if (j >= 5) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "FN0 : I/O Enable FAILED!!!!!!!!!!!!\n")); |
| return SK_FALSE; |
| } |
| |
| /*--- mmoser 3/22/2006 ---*/ |
| j = 0; |
| while (j++ < 5) { |
| // INT Enable function 0 |
| if (SDHost_CMD52_Write |
| (pDev, INT_ENABLE_REG, 0, |
| ena_func[pDev->number_of_functions] | IENM)) { |
| SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &R); |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "FN0 : INT Enable 0x%2.02X\n", R)); |
| break; |
| } |
| } |
| |
| if (j >= 5) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "FN0 : INT Enable FAILED!!!!!!!!!!!!\n")); |
| return SK_FALSE; |
| } |
| |
| // IO Ready function 1 |
| if (SDHost_CMD52_Read(pDev, IO_READY_REG, 0, &R)) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "I/O Ready(R/O) 0x%2.02X\n", R)); |
| } |
| // Read Card Capability |
| if (SDHost_CMD52_Read(pDev, CARD_CAPABILITY_REG, 0, &R)) { |
| #ifdef DBG |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "Card Capability\n")); |
| if (R & 0x01) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " SDC:CMD52 supported\n")); |
| } else { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG " SDC:CMD52 not supported\n")); |
| } |
| if (R & 0x02) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " SMB:CMD53 supported\n")); |
| } else { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG " SMB:CMD53 not supported\n")); |
| } |
| if (R & 0x04) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG " SRW:Read Wait supported\n")); |
| } else { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG " SRW:Read Wait not supported\n")); |
| } |
| if (R & 0x08) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " SBS supported\n")); |
| } else { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " SBD not supported\n")); |
| } |
| if (R & 0x10) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " S4MI supported\n")); |
| } else { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " S4MI not supported\n")); |
| } |
| if (R & 0x20) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " E4MI supported(R/W)\n")); |
| } else { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG " E4MI not supported(R/W)\n")); |
| } |
| if (R & 0x40) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " LSC supported\n")); |
| } else { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " LSC not supported\n")); |
| } |
| if (R & 0x80) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " 4BLS supported\n")); |
| } else { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG " 4BLS not supported\n")); |
| } |
| #endif |
| } |
| if (SDHost_CMD52_Read(pDev, FUNCTION_SELECT_REG, 0, &R)) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "Card Function Selected for Suspend/Resume(R/W) 0x%2.02X!\n", |
| R)); |
| } |
| // Exec Flags |
| if (SDHost_CMD52_Read(pDev, EXEC_FLAGS_REG, 0, &R)) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "Exec Flags(R/O)0x%2.02X\n", R)); |
| } |
| // Ready Flags |
| if (SDHost_CMD52_Read(pDev, READY_FLAGS_REG, 0, &R)) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "Ready Flags(R/O)0x%2.02X\n", R)); |
| } |
| |
| if (pDev->bus_width == SDIO_4_BIT) { |
| SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x82); // 0x80:CD |
| // disable,1 |
| // bit;0x82:CD |
| // disable,4 |
| // bit |
| } else { |
| SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x80); // 0x80:CD |
| // disable,1 |
| // bit;0x82:CD |
| // disable,4 |
| // bit |
| } |
| |
| SDHost_CMD52_Read(pDev, BUS_INTERFACE_CONTROL_REG, 0, &R); |
| |
| switch (R & 0x0F) { |
| case 0x02: |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "4 bit mode,")); |
| break; |
| case 0x00: |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "1 bit mode,")); |
| break; |
| default: |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "1 or 4 bit mode error,")); |
| } |
| if ((R & 0xF0) == 0x80) { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "CD Disable!\n")); |
| } else { |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "CD Enable!\n")); |
| } |
| |
| SDHost_Enable_HighSpeedMode(pDev); |
| |
| // set function 0-7 block size |
| for (i = 0; i <= pDev->number_of_functions; i++) { |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(i), 0, |
| (SK_U8) (block_size & 0x00ff)); |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(i), 0, |
| (SK_U8) (block_size >> 8)); |
| pDev->sd_ids[i].blocksize = block_size; |
| } |
| |
| /* |
| for (i=0;i<8;i++) |
| { |
| SDHost_DumpCIS(pDev, i, 512 ); |
| } |
| */ |
| |
| for (i = 0; i <= pDev->number_of_functions; i++) { |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_0_REG(i), 0, &R)) { |
| break; |
| } |
| pDev->cisptr[i] = R; |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_1_REG(i), 0, &R)) { |
| pDev->cisptr[i] = 0; |
| } |
| pDev->cisptr[i] |= (R << 8); |
| } |
| |
| cislength = DEVICE_NAME_LENGTH; |
| if (!SDHost_ReadCIS(pDev, 0, CISTPL_VERS_1, Cis, &cislength)) { |
| return SK_FALSE; |
| } |
| if (cislength > 0) { |
| memcpy(pDev->DeviceName, "SDIOBus\\", 8); |
| for (i = 0, j = 8; i < cislength; i++) { |
| pDev->DeviceName[j++] = (Cis[i] == ' ' ? '_' : Cis[i]); |
| } |
| pDev->DeviceName[j++] = 0; |
| pDev->DeviceNameLength = j; |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG " DeviceName (len=%d): %s\n", |
| pDev->DeviceNameLength, pDev->DeviceName)); |
| } |
| |
| cislength = 4; |
| if (!SDHost_ReadCIS(pDev, 0, CISTPL_MANFID, Cis, &cislength)) { |
| return SK_FALSE; |
| } |
| if (cislength > 0) { |
| unsigned short vendor, device; |
| vendor = *((short *) Cis); |
| device = *((short *) &Cis[2]); |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "%s: vendor=0x%4.04X device=0x%4.04X\n", |
| __FUNCTION__, vendor, device)); |
| for (i = 0; i <= pDev->number_of_functions; i++) { |
| pDev->sd_ids[i].vendor = vendor; |
| pDev->sd_ids[i].device = device; |
| pDev->sd_ids[i].fn = i; |
| if (i > 0) { |
| if (SDHost_ReadCIS(pDev, i, CISTPL_MANFID, Cis, &cislength)) { |
| if (cislength > 0) { |
| pDev->sd_ids[i].vendor = *((short *) Cis); |
| pDev->sd_ids[i].device = *((short *) &Cis[2]); |
| } |
| } |
| SDHost_CMD52_Read(pDev, FN_CSA_REG(i), 0, &R); |
| pDev->sd_ids[i].class = R; |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG |
| "fn%d: class=0x%4.04X vendor=0x%4.04X,device=0x%4.04X\n", |
| i, pDev->sd_ids[i].class, pDev->sd_ids[i].vendor, |
| pDev->sd_ids[i].device)); |
| } else { |
| pDev->sd_ids[i].class = 0; |
| } |
| } |
| } |
| // Clear irq status bits |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, 0xFFFF); |
| |
| /*--- mmoser 08.09.2005 ---*/ |
| pDev->initialized = SK_TRUE; |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_Init - Initialize the FPGA SDIO/CardBus interface |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| void |
| SDHost_Init(PSD_DEVICE_DATA pDev) |
| { |
| SK_U32 ulVal; |
| SK_U8 ucHostCtrl = 0; |
| SK_U16 usVal; |
| |
| ENTER(); |
| |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "SDHost_Init(pDev=0x%p, IOBase=0x%p)\n", pDev, |
| pDev->IOBase[0])); |
| |
| /*--- mmoser 4/4/2006 ---*/ |
| pDev->SurpriseRemoved = 0; |
| |
| // issue software reset |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, STDHOST_SW_RESET_ALL); |
| |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "SDHost_Init() line=%d\n", __LINE__)); |
| |
| // Read the Host Controller Version |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_HOST_CONTROLLER_VERSION, &usVal); |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG |
| "SD Host Spec Version 0x%2.02X - Vendor Version 0x%2.02x\n", |
| GET_SPEC_VERSION_NR(usVal), GET_VENDOR_VERSION_NR(usVal))); |
| |
| if (pDev->bus_type == SDIO_BUS_TYPE && pDev->bus_width == SDIO_4_BIT) { |
| ucHostCtrl |= STDHOST_4_BIT_ENA; |
| } |
| // Read capabilities |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_CAPABILITIES, &ulVal); |
| |
| if ((ulVal & STDHOST_CAP_VOLTAGE_1_8) == STDHOST_CAP_VOLTAGE_1_8) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "1.8V supported\n")); |
| pDev->maxSupplyVoltage = STDHOST_VOLTAGE_1_8_V; |
| } |
| if ((ulVal & STDHOST_CAP_VOLTAGE_3_0) == STDHOST_CAP_VOLTAGE_3_0) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "3.0V supported\n")); |
| pDev->maxSupplyVoltage = STDHOST_VOLTAGE_3_0_V; |
| } |
| if ((ulVal & STDHOST_CAP_VOLTAGE_3_3) == STDHOST_CAP_VOLTAGE_3_3) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "3.3V supported\n")); |
| pDev->maxSupplyVoltage = STDHOST_VOLTAGE_3_3_V; |
| } |
| if ((ulVal & STDHOST_CAP_SUSPENSE_RESUME) == STDHOST_CAP_SUSPENSE_RESUME) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "Suspense/resume supported\n")); |
| } |
| if ((ulVal & STDHOST_CAP_DMA) == STDHOST_CAP_DMA) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "DMA supported\n")); |
| } |
| if ((ulVal & STDHOST_CAP_HIGH_SPEED) == STDHOST_CAP_HIGH_SPEED) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "High speed supported\n")); |
| ucHostCtrl |= STDHOST_HIGH_SPEED_ENA; |
| } |
| pDev->max_block_size = SD_BLOCK_SIZE; |
| if ((ulVal & STDHOST_CAP_MAX_BLOCK_512) == STDHOST_CAP_MAX_BLOCK_512) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "Max Block Length : 512\n")); |
| pDev->max_block_size = 512; |
| } else if ((ulVal & STDHOST_CAP_MAX_BLOCK_1024) == |
| STDHOST_CAP_MAX_BLOCK_1024) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "Max Block Length : 1024\n")); |
| pDev->max_block_size = 1024; |
| } else if ((ulVal & STDHOST_CAP_MAX_BLOCK_2048) == |
| STDHOST_CAP_MAX_BLOCK_2048) { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "Max Block Length : 2048\n")); |
| pDev->max_block_size = 2048; |
| } |
| if (block_size > pDev->max_block_size) |
| block_size = pDev->max_block_size; |
| |
| pDev->baseClockFreq = GET_CAP_BASE_CLOCK_FREQ(ulVal); |
| |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "Base clock : %d MHz\n", pDev->baseClockFreq)); |
| |
| if ((ulVal & STDHOST_CAP_TIMEOUT_CLOCK_UNIT_MHZ) == |
| STDHOST_CAP_TIMEOUT_CLOCK_UNIT_MHZ) { |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "Timeout clock : %d MHz\n", |
| (ulVal & STDHOST_CAP_TIMEOUT_CLOCK_FREQ))); |
| } else { |
| DBGPRINT(DBG_LOAD, (KERN_DEBUG "Timeout clock : %d kHz\n", |
| (ulVal & STDHOST_CAP_TIMEOUT_CLOCK_FREQ))); |
| } |
| |
| // Read the max current capabilities |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_MAX_CURRENT_CAP, &ulVal); |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "Max. current @1.8V=%dmA @3.0V=%dmA @3.3V=%dmA\n", |
| CALC_MAX_CURRENT_IN_MA(GET_MAX_CURRENT_CAP_1_8_V(ulVal)), |
| CALC_MAX_CURRENT_IN_MA(GET_MAX_CURRENT_CAP_3_0_V(ulVal)), |
| CALC_MAX_CURRENT_IN_MA(GET_MAX_CURRENT_CAP_3_3_V(ulVal)))); |
| |
| // Setup host control register |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl); |
| |
| /*--- mmoser 14.09.2005 ---*/ |
| // Reset all pending irq bits |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, 0xFFFF); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0xFFFF); |
| |
| // Enable error irq status |
| usVal = 0xFFFF; |
| // usVal = STDHOST_ERROR_IRQ_VENDOR_SIG_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS_ENABLE, usVal); |
| |
| /*--- mmoser 1/2/2007 ---*/ |
| // Enable GPI interrupts |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| STDHOST_ERROR_IRQ_VENDOR_SIG_ENA); |
| |
| // Enable card detect |
| usVal = 0xFFFF; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, usVal); |
| usVal = STDHOST_NORMAL_IRQ_CARD_ALL_ENA; |
| usVal &= ~STDHOST_NORMAL_IRQ_CARD_SIG_ENA; // Don't enable card interrupt |
| // at this point! |
| pDev->lastIRQSignalMask = 0; |
| pDev->currentIRQSignalMask = usVal; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, usVal); |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal); |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "SDHost_Init() : present state=0x%8.08X\n", ulVal)); |
| |
| /*--- mmoser 12.09.2005 ---*/ |
| pDev->initialized = SK_TRUE; |
| |
| LEAVE(); |
| |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_isCardPresent - checks whether a SDIO card is in the SDIO socket |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE card is in socket |
| * SK_FALSE no card in socket |
| * |
| */ |
| SK_BOOL |
| SDHost_isCardPresent(PSD_DEVICE_DATA pDev) |
| { |
| SK_U32 ulVal; |
| SK_U16 usVal; |
| |
| // mmoser 2005-11-21 |
| /*--- mmoser 13.09.2005 ---*/ |
| if (pDev->SurpriseRemoved) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_isCardPresent: Surprise Removal of Card!\n")); |
| return SK_FALSE; |
| } |
| |
| if (pDev->initialized == SK_FALSE) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_isCardPresent(): SD Host Adapter is NOT initialized. (%d)\n", |
| pDev->initialized)); |
| return SK_FALSE; |
| } |
| // Read the Host Controller Version to check if SD Host adapter is |
| // available |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_HOST_CONTROLLER_VERSION, &usVal); |
| if (usVal == 0xFFFF) { |
| // There is probably no SD Host Adapter available |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_isCardPresent(): SD Host Adapter is NOT present. (%4.04X)\n", |
| usVal)); |
| return SK_FALSE; |
| } |
| // Read present state register to check whether a SD card is present |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal); |
| if ((ulVal & STDHOST_STATE_CARD_INSERTED) == 0) { |
| // There is probably no card in the socket |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_isCardPresent(): Card is NOT present. (%8.08X)\n", |
| ulVal)); |
| return SK_FALSE; |
| } |
| |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SendCmd - Send a SDIO command to the card |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| */ |
| SK_BOOL |
| SDHost_SendCmd(PSD_DEVICE_DATA pDev, SK_U8 cmd, SK_U32 arg, SK_U16 transferMode, |
| SK_U32 * pulResp) |
| { |
| SK_U32 retry, max_retry; |
| SK_U32 ulVal; |
| SK_U16 usCmd; |
| SK_U32 ulIrq; |
| SK_U16 usSigEna; |
| |
| // max_retry depends on actual bus clock speed |
| max_retry = |
| MAX_WAIT_COMMAND_INHIBIT * (pDev->ClockSpeed == |
| 0 ? 1 : pDev->ClockSpeed); |
| |
| // Read present state register to check whether Command Inhibit (CMD) = 0 |
| for (retry = 0; retry < max_retry; retry++) { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal); |
| if (cmd == 53) { |
| if ((ulVal & STDHOST_STATE_CMD_INHIB_DAT) == 0) { |
| break; |
| } |
| } else { |
| if ((ulVal & STDHOST_STATE_CMD_INHIB_CMD) == 0) { |
| break; |
| } |
| } |
| /*--- mmoser 3/7/2006 ---*/ |
| if (retry & 0xFFFFFFFE) |
| UDELAY(1); |
| } |
| if (retry >= max_retry) { |
| if (cmd == 53) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_SendCmd() : Command Inhibit DAT remains busy! (max_retry=%d)\n", |
| max_retry)); |
| // reset the data line and FIFO |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| UDELAY(10); // wait until reset is complete |
| |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, 0); |
| } else { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_SendCmd() : Command Inhibit CMD remains busy! (max_retry=%d)\n", |
| max_retry)); |
| // reset the cmd line |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_CMD_LINE); |
| UDELAY(10); // wait until reset is complete |
| |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, 0); |
| } |
| return SK_FALSE; |
| } |
| // clear irq bit |
| |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, 0xFFFF0000 | // ERROR_IRQ_STATUS |
| STDHOST_NORMAL_IRQ_ERROR | |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE | |
| STDHOST_NORMAL_IRQ_CMD_COMPLETE); |
| |
| usCmd = MK_CMD(cmd) | MK_CMD_TYPE(STDHOST_CMD_TYPE_NORMAL); |
| |
| switch (cmd) { |
| case 0: |
| { |
| usCmd |= STDHOST_RESP_TYPE_NONE; |
| break; |
| } |
| case 3: |
| { |
| usCmd |= STDHOST_CMD_INDEX_CHK_ENA | |
| STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R6; |
| break; |
| } |
| case 5: |
| { |
| usCmd |= STDHOST_RESP_TYPE_R4; |
| break; |
| } |
| case 7: |
| { |
| usCmd |= STDHOST_CMD_INDEX_CHK_ENA | |
| STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R1b; |
| break; |
| } |
| case 52: |
| case 53: |
| { |
| usCmd |= STDHOST_CMD_INDEX_CHK_ENA | |
| STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R5; |
| break; |
| } |
| case 59: |
| { |
| usCmd |= STDHOST_RESP_TYPE_NONE; |
| break; |
| } |
| default: |
| { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_SendCmd() : Command 0x%2.02X not supported!\n", |
| cmd)); |
| return SK_FALSE; |
| } |
| } |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal); |
| |
| clear_bit(0, &pDev->cmd_complete_evt.event); |
| |
| // mmoser 2007-06-08 : Ensure that CMD_COMPLETE signal is enabled |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| &usSigEna); |
| usSigEna |= STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| usSigEna); |
| |
| pDev->errorOccured = 0; |
| |
| // initiate the cmd |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_CMD_ARGUMENT, arg); |
| ulVal = (usCmd << 16) | transferMode; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, ulVal); |
| |
| #ifdef DBG |
| if ((pDev->debug_flags & DEBUG_SHOW_REG_10_14) == DEBUG_SHOW_REG_10_14) { |
| if (cmd == 53) { |
| for (retry = 0; retry < 10; retry++) { |
| SK_U32 ulR1, ulR2; |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, &ulR1); |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_63_32, &ulR2); |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "retry=%d 63-32 : 0x%8.08X 31-0 : 0x%8.08X\n", retry, |
| ulR2, ulR1)); |
| } |
| } |
| } |
| #endif |
| |
| /**/ if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_CMD_COMPLETE) { |
| //printk("%s @ %d: Wait CMD complete\n",__FUNCTION__,__LINE__); |
| if (SDHost_wait_event(pDev, &pDev->cmd_complete_evt, 100)) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "%s @ %d: Wait CMD complete ---> FAILED !\n", |
| __FUNCTION__, __LINE__)); |
| return SK_FALSE; |
| } |
| clear_bit(0, &pDev->cmd_complete_evt.event); |
| } else |
| /**/ { |
| max_retry = |
| MAX_WAIT_COMMAND_COMPLETE * 10 * (pDev->ClockSpeed == |
| 0 ? 1 : pDev->ClockSpeed); |
| // Wait for end of command |
| for (retry = 0; retry < max_retry; retry++) { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulIrq); |
| if ((ulIrq & STDHOST_NORMAL_IRQ_CMD_COMPLETE) == |
| STDHOST_NORMAL_IRQ_CMD_COMPLETE) { |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| STDHOST_NORMAL_IRQ_CMD_COMPLETE); |
| |
| break; |
| } |
| /*--- mmoser 3/7/2006 ---*/ |
| if (retry & 0xFFFFFFFE) |
| UDELAY(1); |
| } |
| if (retry >= max_retry) { |
| |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| &usCmd); |
| // printk("status_enable=0x%4.04X\n",usCmd); |
| if ((usCmd & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0) { |
| usCmd |= STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, |
| STDHOST_NORMAL_IRQ_STATUS_ENABLE, usCmd); |
| MEM_READ_USHORT(pDev, SK_SLOT_0, |
| STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usCmd); |
| // printk("RESTORED:status_enable=0x%4.04X\n",usCmd); |
| } |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_SendCmd() : Command not completed! (max_retry=%d)\n", |
| max_retry)); |
| // printk("#"); |
| return SK_FALSE; |
| } |
| |
| } |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, pulResp); |
| |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SendAbort - Aborts an SDIO CMD53 block transfer |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| */ |
| SK_BOOL |
| SDHost_SendAbort(PSD_DEVICE_DATA pDev) |
| { |
| |
| // return SDHost_CMD52_Write(pDev, IO_ABORT_REG, 0, 0x03); |
| |
| //#ifdef __XXX__ |
| SK_U32 retry, max_retry; |
| SK_U32 ulVal; |
| SK_U32 ulArg; |
| SK_U16 usCmd; |
| // SK_U32 ulIrq; |
| |
| ulArg = MAKE_SDIO_OFFSET(IO_ABORT_REG) | MAKE_SDIO_FUNCTION(0x00) | 0x07; |
| |
| // max_retry depends on actual bus clock speed |
| max_retry = |
| MAX_WAIT_COMMAND_INHIBIT * (pDev->ClockSpeed == |
| 0 ? 1 : pDev->ClockSpeed); |
| |
| // clear irq bit |
| |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE | |
| STDHOST_NORMAL_IRQ_CMD_COMPLETE); |
| |
| /*--- mmoser 3/7/2006 ---*/ |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal); |
| |
| usCmd = MK_CMD(52) | |
| MK_CMD_TYPE(STDHOST_CMD_TYPE_ABORT) | |
| STDHOST_CMD_INDEX_CHK_ENA | |
| STDHOST_CMD_CRC_CHK_ENA | STDHOST_RESP_TYPE_R5; |
| |
| // initiate the cmd |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_CMD_ARGUMENT, ulArg); |
| |
| ulVal = (usCmd << 16) | STDHOST_READ_DIR_SELECT; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, ulVal); |
| |
| // Read present state register to check whether Command Inhibit (CMD) = 0 |
| for (retry = 0; retry < max_retry; retry++) { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal); |
| if (((ulVal & STDHOST_STATE_CMD_INHIB_DAT) == 0) && |
| ((ulVal & STDHOST_STATE_CMD_INHIB_CMD) == 0)) { |
| break; |
| } |
| UDELAY(1); |
| } |
| if (retry >= max_retry) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_SendAbort() : Command Inhibit (CMD/DAT) remains busy! (max_retry=%d)\n", |
| max_retry)); |
| return SK_FALSE; |
| } |
| |
| return SK_TRUE; |
| //#endif |
| } |
| |
| /****************************************************************************** |
| * |
| * isCmdFailed - checks whether the FPGA reports an error condition |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| isCmdFailed(PSD_DEVICE_DATA pDev) |
| { |
| SK_U16 errStatus; |
| |
| // Read error status register |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, &errStatus); |
| |
| if ((errStatus & 0x00FF) != 0) { |
| printk("%s: 0x%4.04X: ", __FUNCTION__, errStatus); |
| if (errStatus & STDHOST_ERROR_IRQ_CURRENT_LIMIT) { |
| printk("CURRENT_LIMIT "); |
| } |
| if (errStatus & STDHOST_ERROR_IRQ_DATA_END_BIT) { |
| printk("DATA_END_BIT "); |
| } |
| if (errStatus & STDHOST_ERROR_IRQ_DATA_CRC) { |
| printk("DATA_CRC "); |
| } |
| if (errStatus & STDHOST_ERROR_IRQ_DATA_TIMEOUT) { |
| printk("DATA_TIMEOUT "); |
| } |
| if (errStatus & STDHOST_ERROR_IRQ_CMD_INDEX) { |
| printk("CMD_INDEX "); |
| } |
| if (errStatus & STDHOST_ERROR_IRQ_CMD_END_BIT) { |
| printk("CMD_END_BIT "); |
| } |
| if (errStatus & STDHOST_ERROR_IRQ_CMD_CRC) { |
| printk("CMD_CRC "); |
| } else if (errStatus & STDHOST_ERROR_IRQ_CMD_TIMEOUT) { |
| printk("CMD_TIMEOUT "); |
| } |
| printk("\n"); |
| |
| // Reset the error status irq register |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0x00FF); |
| return SK_TRUE; |
| } else { |
| return SK_FALSE; |
| } |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD52_Read - Read one byte from the SDIO card |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD52_Read(PSD_DEVICE_DATA pDev, SK_U32 Offset, SK_U8 function_number, |
| SK_U8 * pReturnData) |
| { |
| SK_U8 Resp; |
| SK_U32 ulResponse; |
| SK_U8 D8, D16; |
| SK_U32 retry, Arg; |
| |
| /*--- mmoser 8/8/2007 ---*/ |
| SK_U16 lastIRQMask; |
| SK_U16 lastErrorIRQMask; |
| |
| /*--- mmoser 3/31/2006 ---*/ |
| if (pDev->SurpriseRemoved == SK_TRUE) { |
| printk |
| ("CMD52 READ FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n", |
| function_number, Offset, pDev->bus_errors); |
| return SK_FALSE; |
| } |
| |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| &lastIRQMask); |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| &lastErrorIRQMask); |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD))); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA))); |
| |
| #ifdef FIFO_CMD52_DEBUG |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0204, &ulResponse); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "(3)RD Fifo Stat : 0x%x \n", ulResponse)); |
| |
| if (ulResponse != 0x40010000) { |
| SK_U32 tmp; |
| SK_U16 i; |
| printk("(3)RD Fifo Stat : 0x%x \n", ulResponse); |
| for (i = 0; i < (ulResponse & 0x3ff); i++) |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x20, &tmp); |
| } |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0208, &ulResponse); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "(3)WR Fifo Stat : 0x%x \n", ulResponse)); |
| if (ulResponse != 0x40000000) |
| printk("(3)WR Fifo Stat : 0x%x \n", ulResponse); |
| #endif |
| |
| Arg = MAKE_SDIO_OFFSET(Offset) | MAKE_SDIO_FUNCTION(function_number); |
| |
| retry = 0; |
| while (1) { |
| if (SDHost_SendCmd(pDev, 52, Arg, STDHOST_READ_DIR_SELECT, &ulResponse)) { |
| break; |
| } |
| if (retry++ > 5) { |
| /* |
| if (++pDev->bus_errors > MAX_BUS_ERRORS ) |
| { |
| SDHost_SetCardOutEvent(pDev); |
| } |
| */ |
| if (!SDHost_isCardPresent(pDev)) { |
| pDev->SurpriseRemoved = SK_TRUE; |
| SDHost_SetCardOutEvent(pDev); |
| } |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD52 READ FAILED : fn=%2.02X reg=%8.08X (bus_errors=%d)\n", |
| function_number, Offset, pDev->bus_errors)); |
| return SK_FALSE; |
| } |
| // mmoser 2006-02-22 |
| if (retry > 1) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD52 READ FAILED : fn=%2.02X reg=%8.08X (bus_errors=%d) retry=%d\n", |
| function_number, Offset, pDev->bus_errors, retry)); |
| } |
| |
| UDELAY(200); |
| } |
| |
| D16 = GET_BITS_23_16(ulResponse); |
| |
| Resp = D16; |
| |
| if (pDev->bus_type == SDIO_BUS_TYPE) { |
| // SDIO bus |
| |
| // mask 11001011 |
| if (Resp & 0xCB) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD52 READ fn=%2.02X reg=%8.08X RESP Error:0x%2.02X (0x%8.08X)\n", |
| function_number, Offset, Resp, ulResponse)); |
| UDELAY(100); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } else if ((Resp & 0x30) == 0) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD52 READ fn=%2.02X reg=%8.08X RESP Error,card not selected!:0x%2.02X (0x%8.08X)\n", |
| function_number, Offset, Resp, ulResponse)); |
| UDELAY(100); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } |
| } else { |
| // SPI bus |
| |
| if (Resp & 0x5C) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG "CMD52 READ RESP Error:0x%.2X\n", Resp)); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } |
| } |
| if (isCmdFailed(pDev)) { |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } |
| |
| D8 = GET_BITS_15_08(ulResponse); |
| *pReturnData = D8; |
| |
| if (pDev->bus_errors > 0) { |
| pDev->bus_errors--; |
| } |
| |
| DBGPRINT(DBG_W528D_CMD52, |
| (KERN_DEBUG |
| "CMD52 READ : fn=%2.02X reg=%8.08X data=%2.02X (%2.02X %2.02X/%8.08X)\n", |
| function_number, Offset, *pReturnData, D16, D8, ulResponse)); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD52_Write - Write one byte from the SDIO card |
| * - |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD52_Write(PSD_DEVICE_DATA pDev, SK_U32 Offset, SK_U8 function_number, |
| SK_U8 Data) |
| { |
| SK_U8 Resp; |
| SK_U32 ulResponse; |
| SK_U32 Arg, retry; |
| /*--- mmoser 8/8/2007 ---*/ |
| SK_U16 lastIRQMask; |
| SK_U16 lastErrorIRQMask; |
| |
| /*--- mmoser 3/31/2006 ---*/ |
| if (pDev->SurpriseRemoved == SK_TRUE) { |
| printk |
| ("CMD52 WRITE : Surprise Removed !!!! fn=%2.02X reg=%8.08X data=%2.02X (bus_errors=%d)\n", |
| function_number, Offset, Data, pDev->bus_errors); |
| return SK_FALSE; |
| } |
| |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| &lastIRQMask); |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| &lastErrorIRQMask); |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD))); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA))); |
| |
| DBGPRINT(DBG_W528D_CMD52, |
| (KERN_DEBUG |
| "CMD52 WRITE : fn=%2.02X reg=%8.08X data=%2.02X (bus_errors=%d)\n", |
| function_number, Offset, Data, pDev->bus_errors)); |
| |
| #ifdef FIFO_CMD52_DEBUG |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0204, &ulResponse); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "(4)RD Fifo Stat : 0x%x \n", ulResponse)); |
| |
| if (ulResponse != 0x40010000) { |
| SK_U32 tmp; |
| SK_U16 i; |
| printk("(4)RD Fifo Stat : 0x%x \n", ulResponse); |
| for (i = 0; i < (ulResponse & 0x3ff); i++) |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x20, &tmp); |
| } |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x0208, &ulResponse); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "(4)WR Fifo Stat : 0x%x \n", ulResponse)); |
| |
| if (ulResponse != 0x40000000) |
| printk("(4)WR Fifo Stat : 0x%x \n", ulResponse); |
| #endif |
| |
| Arg = MAKE_SDIO_OFFSET(Offset) | |
| MAKE_SDIO_FUNCTION(function_number) | MAKE_SDIO_DIR(1) | (SK_U8) Data; |
| retry = 0; |
| while (1) { |
| |
| if (SDHost_SendCmd(pDev, 52, Arg, STDHOST_READ_DIR_SELECT, &ulResponse)) { |
| break; |
| } |
| if (retry++ > 5) { |
| if (!SDHost_isCardPresent(pDev)) { |
| pDev->SurpriseRemoved = SK_TRUE; |
| SDHost_SetCardOutEvent(pDev); |
| } |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD52 WRITE FAILED : fn=%2.02X reg=%8.08X data=%2.02X\n", |
| function_number, Offset, Data)); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } |
| UDELAY(200); |
| } |
| |
| Resp = GET_BITS_23_16(ulResponse); |
| |
| if (pDev->bus_type == SDIO_BUS_TYPE) { |
| // SDIO bus |
| |
| // mask 11001011 |
| if (Resp & 0xCB) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD52 READ fn=%2.02X reg=%8.08X RESP Error:0x%2.02X (0x%8.08X)\n", |
| function_number, Offset, Resp, ulResponse)); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } else if ((Resp & 0x30) == 0) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD52 READ fn=%2.02X reg=%8.08X RESP Error,card not selected!:0x%2.02X (0x%8.08X)\n", |
| function_number, Offset, Resp, ulResponse)); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } |
| } else { |
| // SPI bus |
| |
| if (Resp & 0x5C) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG "CMD52 READ RESP Error:0x%.2X\n", Resp)); |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } |
| } |
| |
| if (isCmdFailed(pDev)) { |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_FALSE; |
| } |
| if (pDev->bus_errors > 0) { |
| pDev->bus_errors--; |
| } |
| |
| /*--- mmoser 8/8/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_ReadRCA - Read the RCA from SDIO card |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_ReadRCA(PSD_DEVICE_DATA pDev, SK_U8 * pRca) |
| { |
| SK_U8 ucStatus1, ucStatus2; |
| SK_U32 ulResponse; |
| |
| // CMD3 to read card RCA. |
| if (!SDHost_SendCmd(pDev, 3, 0, 0, &ulResponse)) { |
| if (++pDev->bus_errors > MAX_BUS_ERRORS) { |
| SDHost_SetCardOutEvent(pDev); |
| } |
| return SK_FALSE; |
| } |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, &ulResponse); |
| |
| pRca[0] = GET_BITS_39_32(ulResponse); |
| pRca[1] = GET_BITS_31_24(ulResponse); |
| |
| ucStatus1 = GET_BITS_23_16(ulResponse); |
| ucStatus2 = GET_BITS_15_08(ulResponse); |
| |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ReadRCA: %2.02X%2.02X - CardStatus=%2.02X%2.02X\n", |
| pRca[0], pRca[1], ucStatus1 &= 0xE0, ucStatus2)); |
| return SK_TRUE; |
| } |
| |
| SK_BOOL |
| is_ValidCISTuple(SK_U8 cistpl) |
| { |
| switch (cistpl) { |
| case CISTPL_VERS_1: |
| case CISTPL_MANFID: |
| case CISTPL_FUNCID: |
| case CISTPL_FUNCE: |
| case CISTPL_END: |
| { |
| return SK_TRUE; |
| } |
| default: |
| { |
| return SK_FALSE; |
| } |
| } |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_ReadCIS - Read element 'cistpl' from the card's CIS |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_ReadCIS(PSD_DEVICE_DATA pDev, SK_U8 function_number, SK_U8 cistpl, |
| SK_U8 * pBuf, SK_U32 * length) |
| { |
| SK_U8 R; |
| SK_U8 tuple; |
| SK_U8 tuple_len; |
| SK_U8 tuple_end = 0; |
| SK_U32 _cis = 0; |
| |
| if (pBuf == NULL || length == NULL || *length == 0) { |
| DBGPRINT(DBG_W528D | DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_ReadCIS : Illegal Parameters pBuf=%p length=%d\n", |
| pBuf, *length)); |
| return SK_FALSE; |
| } |
| |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_0_REG(function_number), 0, &R)) { |
| return SK_FALSE; |
| } |
| _cis = R; |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_1_REG(function_number), 0, &R)) { |
| return SK_FALSE; |
| } |
| _cis |= (R << 8); |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_2_REG(function_number), 0, &R)) { |
| return SK_FALSE; |
| } |
| _cis |= (R << 16); |
| |
| // Search for CISTPL |
| if (_cis != 0) { |
| SK_U32 i = 0; |
| SK_U32 j = 0; |
| |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "SDHost_ReadCIS : CIS=%8.08X\n", _cis)); |
| |
| R = 0; |
| tuple_len = 0; |
| while (R != CISTPL_END) { |
| // Read Tuple |
| SDHost_CMD52_Read(pDev, _cis + j, function_number, &tuple); |
| j++; |
| |
| R = tuple; |
| if (!is_ValidCISTuple(R)) { |
| continue; |
| } |
| // Read Tuple Length |
| SDHost_CMD52_Read(pDev, _cis + j, function_number, &tuple_len); |
| j++; |
| R = tuple; |
| |
| // printk("cistpl=0x%2.02X tuple=0x%2.02X tuple_length=%d j=%d\n",cistpl,tuple,tuple_len,j); |
| if (R != CISTPL_NULL && R != CISTPL_END) { |
| tuple_end = j + tuple_len; |
| } |
| |
| if (tuple == cistpl) { |
| switch (cistpl) { |
| case CISTPL_VERS_1: |
| { |
| j += 2; |
| i = 0; |
| |
| while (j < tuple_end && i < *length - 1) { |
| SDHost_CMD52_Read(pDev, _cis + j, function_number, |
| &R); |
| j++; |
| // printk("%2.02X ",R); |
| pBuf[i++] = (R == 0 ? ' ' : R); |
| } |
| i -= 3; |
| pBuf[i] = 0; |
| *length = i; |
| |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ReadCIS : fn=%d cistpl=%2.02X |%s| len=%d\n", |
| function_number, cistpl, pBuf, *length)); |
| // printk("\nCISTPL_VERS_1 found!\n"); |
| return SK_TRUE; |
| break; |
| } |
| case CISTPL_MANFID: |
| case CISTPL_FUNCID: |
| case CISTPL_FUNCE: |
| { |
| i = 0; |
| DBGPRINT(DBG_W528D, |
| ("SDHost_ReadCIS : fn=%d cistpl=%2.02X |", |
| function_number, cistpl)); |
| while (j <= tuple_end && i < *length) { |
| SDHost_CMD52_Read(pDev, _cis + j, function_number, |
| &R); |
| j++; |
| pBuf[i++] = R; |
| // printk("%2.02X ",R); |
| |
| DBGPRINT(DBG_W528D, ("%2.02x ", R)); |
| } |
| *length = i; |
| |
| DBGPRINT(DBG_W528D, ("| len=%d\n", *length)); |
| |
| // printk("\ncistpl=0x%2.02X found!\n",cistpl); |
| |
| return SK_TRUE; |
| |
| break; |
| } |
| } |
| } else { |
| j = tuple_end; |
| } |
| } |
| } |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "SDHost_ReadCIS : fn=%d cistpl=%2.02X |%s| len=%d\n", |
| function_number, cistpl, pBuf, *length)); |
| |
| *length = 0; |
| return SK_FALSE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_ReadOCR - Read the OCR (supported voltages) from the SDIO card |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_ReadOCR(PSD_DEVICE_DATA pDev, SK_U8 * pOcr) |
| { |
| SK_U32 i, j; |
| SK_U32 ulResponse; |
| SK_U8 ucValue = 0; |
| // SK_U8 R1,R2,R3,R4,R5,R6; |
| SK_U8 R2, R3, R4, R5; |
| |
| R2 = R3 = R4 = R5 = 0; |
| j = 0; |
| while (j++ < 5) { |
| // Wait until power cycle is complete |
| for (i = 0; i < 100; i++) { |
| if (!SDHost_SendCmd(pDev, 5, 0, 0, &ulResponse)) { |
| if (++pDev->bus_errors > MAX_BUS_ERRORS) { |
| SDHost_SetCardOutEvent(pDev); |
| return SK_FALSE; |
| } |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "SDHost_ReadOCR() retry=%d\n", j)); |
| |
| continue; |
| } |
| |
| R2 = GET_BITS_15_08(ulResponse); |
| R3 = GET_BITS_23_16(ulResponse); |
| R4 = GET_BITS_31_24(ulResponse); |
| R5 = GET_BITS_39_32(ulResponse); |
| |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ReadOCR(31-0) retry=%d : 0x%2.02X %2.02X %2.02X %2.02X\n", |
| j, R5, R4, R3, R2)); |
| |
| pDev->number_of_functions = (R5 >> 4) & 0x07; |
| ucValue = GET_BITS_39_32(ulResponse); |
| |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "SDHost_ReadOCR(%d) : 0x%2.02X\n", |
| pDev->bus_type, ucValue)); |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "SDHost_ReadOCR() : 0x%8.08X\n", ulResponse)); |
| |
| if (ucValue & 0x80) { |
| // power cycle is complete |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ReadOCR() : power cycle is complete\n")); |
| break; |
| } |
| } |
| if (i == 100) { |
| DBGPRINT(DBG_W528D | DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_ReadOCR() FAILED : Power cycle not complete after %d retries (0x%2.02X)!\n", |
| i, ucValue)); |
| return SK_FALSE; |
| } |
| |
| pOcr[0] = R4; |
| pOcr[1] = R3; |
| pOcr[2] = R2; |
| |
| if (R4 != 0 || R3 != 0) { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ReadOCR() : PwrCycle:%X,IO_n:%X,Mem_p:%X,OCR:[0x%2.02X%2.02X%2.02X]\n", |
| ucValue & 0x80, ucValue & 0x70, ucValue & 0x40, pOcr[0], |
| pOcr[1], pOcr[2])); |
| |
| return SK_TRUE; |
| } |
| } |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "SDHost_ReadOCR() FAILED : Cannot read OCR!\n")); |
| return SK_FALSE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_WriteOCR - Write the OCR (supported voltages) to the SDIO card |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_WriteOCR(PSD_DEVICE_DATA pDev, SK_U8 * pOcr) |
| { |
| SK_U32 ulArg; |
| SK_U32 ulResponse; |
| SK_U8 ucValue; |
| SK_U32 i; |
| |
| ulArg = pOcr[0] << 16 | pOcr[1] << 8 | pOcr[2]; |
| // Wait until power cycle is complete |
| for (i = 0; i < 100; i++) { |
| if (!SDHost_SendCmd(pDev, 5, ulArg, 0, &ulResponse)) { |
| if (++pDev->bus_errors > MAX_BUS_ERRORS) { |
| SDHost_SetCardOutEvent(pDev); |
| } |
| return SK_FALSE; |
| } |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_RESP_BITS_31_0, &ulResponse); |
| |
| ucValue = GET_BITS_39_32(ulResponse); |
| |
| if (ucValue & 0x80) { |
| // power cycle is complete |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "I/O Power up status is ready and set new voltage ok!\n")); |
| break; |
| } |
| } |
| if (i == 100) { |
| DBGPRINT(DBG_W528D | DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_WriteOCR() FAILED : Power cycle not complete after %d retries!\n", |
| i)); |
| return SK_FALSE; |
| } |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "SDHost_WriteOCR() : PwrCycle:%X,IO_n:%X,Mem_p:%X\n", |
| ucValue & 0x80, ucValue & 0x70, ucValue & 0x40)); |
| |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD53_Read - Read a block of data from the SDIO card |
| * - |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD53_Read(PSD_DEVICE_DATA pDev, |
| SK_U32 Offset, |
| SK_U8 function_number, |
| SK_U8 mode, |
| SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz) |
| { |
| SK_U16 uwTransferMode; |
| SK_U32 size; |
| SK_U32 i, blkCnt, Arg; |
| SK_U32 ulResponse, retry, max_retry; |
| SK_U32 *pSrc32; |
| SK_U32 *pDest32; |
| SK_U8 RESP; |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "CMD53 READ fn=%2.02X reg=%8.08X data=0x%2.0X\n", |
| function_number, Offset, *(pData))); |
| /*--- mmoser 3/31/2006 ---*/ |
| if (pDev->SurpriseRemoved == SK_TRUE) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 READ FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n", |
| function_number, Offset, pDev->bus_errors)); |
| return SK_FALSE; |
| } |
| |
| if (Count > 0x1FF) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n", |
| (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count)); |
| return SK_FALSE; |
| } |
| DBGPRINT(DBG_W528D_CMD53, |
| (KERN_DEBUG "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d\n", |
| (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count)); |
| |
| if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block |
| // mode |
| { |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0, |
| (SK_U8) (blksz & 0x00ff)); |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0, |
| (SK_U8) (blksz >> 8)); |
| pDev->sd_ids[function_number].blocksize = blksz; |
| } |
| |
| uwTransferMode = STDHOST_READ_DIR_SELECT; |
| |
| if (mode == BYTE_MODE) { |
| size = Count; |
| |
| blkCnt = 1 << 16 | Count; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt); |
| } else { |
| size = blksz * Count; |
| |
| /* 20050630 mmoser HW-Workaround */ |
| if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_RD) == |
| DEBUG_DISABLE_HW_WORKAROUND_RD) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } else { |
| if (Count > 1) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } |
| } |
| uwTransferMode |= STDHOST_BLOCK_COUNT_ENA; |
| |
| blkCnt = Count << 16 | blksz | DMA_16K_BOUNDARY; |
| |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt); |
| } |
| |
| Arg = MAKE_SDIO_OFFSET(Offset) | |
| MAKE_SDIO_OP_CODE(opcode) | |
| MAKE_SDIO_BLOCK_MODE(mode) | |
| MAKE_SDIO_FUNCTION(function_number) | (Count & 0x01FF); |
| |
| retry = 0; |
| while (1) { |
| if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) { |
| break; |
| } |
| if (retry++ > 5) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "CMD53 READ FAILED : fn=%2.02X reg=%8.08X\n", |
| function_number, Offset)); |
| return SK_FALSE; |
| } |
| UDELAY(5); |
| } |
| |
| RESP = GET_BITS_23_16(ulResponse); |
| if (pDev->bus_type == SDIO_BUS_TYPE) { |
| if (RESP & 0xCB) { |
| DBGPRINT(DBG_W528D_CMD53, |
| (KERN_DEBUG "CMD53 Read RESP Error:0x%.2X\n", RESP)); |
| return SK_FALSE; |
| } else if ((RESP & 0x30) == 0) { |
| DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 Read RESP Error,card not selected!:0x%.2X\n", |
| RESP)); |
| return SK_FALSE; |
| } |
| } else { |
| if (RESP & 0x5C) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG "CMD53 READ RESP Error:0x%.2X\n", RESP)); |
| return SK_FALSE; |
| } |
| } |
| |
| pSrc32 = |
| (SK_U32 *) (((SK_U32) (SK_BAR((pDev), (SK_SLOT_0)))) + |
| (STDHOST_DATA_PORT)); |
| pDest32 = (SK_U32 *) pData; |
| |
| retry = 0; |
| max_retry = |
| MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed == |
| 0 ? 1 : pDev->ClockSpeed); |
| |
| i = 0; |
| while (i < size) { |
| if (i % blksz == 0) { |
| retry = 0; |
| |
| do { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, |
| &ulResponse); |
| if ((ulResponse & STDHOST_STATE_BUFFER_RD_ENABLE) == |
| STDHOST_STATE_BUFFER_RD_ENABLE) { |
| break; |
| } |
| |
| /*--- mmoser 3/13/2006 ---*/ |
| UDELAY(1); |
| } while (++retry < max_retry); |
| /*--- mmoser 3/3/2006 ---*/ |
| if (retry >= max_retry) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 READ FAILED : STDHOST_STATE_BUFFER_RD_ENABLE remains 0\nfn=%2.02X reg=%8.08X\n", |
| function_number, Offset)); |
| if (mode) { |
| SDHost_SendAbort(pDev); |
| } |
| return SK_FALSE; |
| } |
| } |
| *pDest32 = *pSrc32; |
| pDest32++; |
| i += 4; |
| } |
| |
| /* |
| { |
| SK_U16 i; |
| |
| printk( KERN_DEBUG "\n%s\n", __FUNCTION__ ); |
| for( i=0; i<size; i++ ) { |
| if( i % 16 ==0 ) |
| printk( "\n"); |
| |
| printk( "%2.02X ", pData[i] ); |
| |
| } |
| } |
| */ |
| |
| if (mode) { |
| SDHost_SendAbort(pDev); |
| } |
| /*--- mmoser 1/5/2007 ---*/ |
| // STDHOST_NORMAL_IRQ_ERROR is used for GPI interrupts !!!! |
| // |
| /* |
| MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal); |
| if (ulVal&STDHOST_NORMAL_IRQ_ERROR) |
| { |
| SDHost_ErrorRecovery(pDev); |
| DBGPRINT(DBG_ERROR,( KERN_DEBUG "SDHost_CMD53_Read() : Command Error 0x%8.08X\n",ulVal)); |
| return SK_FALSE; |
| } |
| */ |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD53_Read_DMA - Read a block of data from the SDIO card |
| * - |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD53_Read_DMA(PSD_DEVICE_DATA pDev, |
| SK_U32 Offset, |
| SK_U8 function_number, |
| SK_U8 mode, |
| SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz) |
| { |
| SK_U16 uwTransferMode; |
| SK_U32 size; |
| SK_U32 blkCnt, Arg; |
| SK_U32 ulResponse, retry, max_retry; |
| SK_U8 RESP; |
| SK_U64 PhysAddr; |
| SK_U32 ulResp; |
| |
| /*--- mmoser 1/10/2007 ---*/ |
| SK_U16 lastIRQMask; |
| SK_U16 lastErrorIRQMask; |
| |
| /*--- mmoser 3/31/2006 ---*/ |
| if (pDev->SurpriseRemoved == SK_TRUE) { |
| printk |
| ("CMD53 READ FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n", |
| function_number, Offset, pDev->bus_errors); |
| return SK_FALSE; |
| } |
| |
| if (Count > 0x1FF) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n", |
| (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count)); |
| return SK_FALSE; |
| } |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| &lastIRQMask); |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| &lastErrorIRQMask); |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD))); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA))); |
| |
| DBGPRINT(DBG_W528D_CMD53, |
| (KERN_DEBUG "CMD53 %s READ : fn=%2.02X reg=%8.08X len=%d\n", |
| (mode ? "BLOCK" : "BYTE"), function_number, Offset, Count)); |
| |
| if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block |
| // mode |
| { |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0, |
| (SK_U8) (blksz & 0x00ff)); |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0, |
| (SK_U8) (blksz >> 8)); |
| pDev->sd_ids[function_number].blocksize = blksz; |
| } |
| |
| uwTransferMode = STDHOST_READ_DIR_SELECT; |
| |
| if (mode == BYTE_MODE) { |
| size = Count; |
| blkCnt = 1 << 16 | Count; |
| uwTransferMode |= STDHOST_DMA_ENA; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt); |
| } else { |
| size = blksz * Count; |
| |
| /* 20050630 mmoser HW-Workaround */ |
| if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_RD) == |
| DEBUG_DISABLE_HW_WORKAROUND_RD) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } else { |
| if (Count > 1) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } |
| } |
| |
| uwTransferMode |= STDHOST_BLOCK_COUNT_ENA | STDHOST_DMA_ENA; |
| |
| blkCnt = Count << 16 | blksz | DMA_16K_BOUNDARY; |
| |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "blkCnt: 0x%x \n", blkCnt)); |
| |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blkCnt); |
| } |
| |
| Arg = MAKE_SDIO_OFFSET(Offset) | |
| MAKE_SDIO_OP_CODE(opcode) | |
| MAKE_SDIO_BLOCK_MODE(mode) | |
| MAKE_SDIO_FUNCTION(function_number) | (Count & 0x01FF); |
| |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| // set the DMA address |
| PhysAddr = (SK_U64) pci_map_page(pDev->dev, |
| virt_to_page(pDev->dma_rbuff), |
| ((unsigned long) (pDev-> |
| dma_rbuff) & ~PAGE_MASK), |
| 8192, PCI_DMA_FROMDEVICE); |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS, |
| (SK_U32) (PhysAddr + pDev->dma_start_malign + |
| pDev->dma_rx_malign)); |
| // MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS,&ulResp); |
| // printk("dma_abuf:0x%p phys:0x%x rx_malign:%d (read-back=0x%x)\n", pDev->dma_rbuff, (SK_U32)PhysAddr, pDev->dma_rx_malign, ulResp ); |
| #else // SYSKT_DMA_MALIGN_TEST |
| |
| // set the DMA address |
| PhysAddr = (SK_U64) pci_map_page(pDev->dev, virt_to_page(pData), |
| ((unsigned long) pData & ~PAGE_MASK), |
| size, PCI_DMA_FROMDEVICE); |
| |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS, (SK_U32) PhysAddr); |
| // printk("\n\nCMD53 READ PhysAddr: 0x%x (virt:0x%x)\n",(SK_U32) PhysAddr, |
| // (SK_U32) pData ); |
| #endif // SYSKT_DMA_MALIGN_TEST |
| |
| /* |
| DBGPRINT(DBG_ERROR,( KERN_DEBUG "\n\nCMD53 READ PhysAddr: 0x%x (virt:0x%x)\n",(SK_U32) PhysAddr, (SK_U32) pData ) ); |
| MEM_READ_ULONG (pDev, SK_SLOT_0, 0x0204, &ulResp); |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "(1)RD Fifo Stat : 0x%x \n", ulResp )); |
| MEM_READ_ULONG (pDev, SK_SLOT_0, 0x0208, &ulResp); |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "(1)WR Fifo Stat : 0x%x \n", ulResp )); |
| */ |
| pDev->CmdInProgress = 1; |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| |
| retry = 0; |
| while (1) { |
| |
| if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) { |
| break; |
| } |
| if (retry++ > 5) { |
| if (!SDHost_isCardPresent(pDev)) { |
| pDev->SurpriseRemoved = SK_TRUE; |
| SDHost_SetCardOutEvent(pDev); |
| } |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "CMD53 READ FAILED : fn=%2.02X reg=%8.08X\n", |
| function_number, Offset)); |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| UDELAY(5); |
| } |
| |
| RESP = GET_BITS_23_16(ulResponse); |
| if (pDev->bus_type == SDIO_BUS_TYPE) { |
| if (RESP & 0xCB) { |
| DBGPRINT(DBG_W528D_CMD53, |
| (KERN_DEBUG "CMD53 Read RESP Error:0x%.2X\n", RESP)); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } else if ((RESP & 0x30) == 0) { |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| |
| DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 Read RESP Error,card not selected!:0x%.2X\n", |
| RESP)); |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| } else { |
| if (RESP & 0x5C) { |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG "CMD53 READ RESP Error:0x%.2X\n", RESP)); |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| } |
| if (isCmdFailed(pDev)) { |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| |
| retry = 0; |
| max_retry = |
| MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed == |
| 0 ? 1 : pDev->ClockSpeed); |
| |
| // wait for DMA to complete |
| if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) { |
| if (SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1000)) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "%s -> SDHost_wait_event trans_complete failed\n", |
| __FUNCTION__)); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| } else { |
| retry = 0; |
| if (test_bit(0, &pDev->trans_complete_evt.event) == 0) { |
| // if ( SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1 ) ) { |
| do { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| &ulResp); |
| if ((ulResp & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) == |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE) { |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE); |
| break; |
| } |
| /*--- mmoser 3/14/2006 ---*/ |
| UDELAY(1); |
| } while (++retry < max_retry); |
| } else { |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| } |
| if (retry >= max_retry) { |
| DBGPRINT(DBG_WARNING | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 Read : STDHOST_NORMAL_IRQ_TRANS_COMPLETE not set!(count=%d max_retry=%d)\n", |
| Count, max_retry)); |
| // reset the data line and FIFO |
| } |
| } |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, 0); |
| |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| { |
| memcpy(pData, |
| (void *) (pDev->dma_rbuff + pDev->dma_start_malign + |
| pDev->dma_rx_malign), size); |
| // pDev->dma_rx_malign++; |
| pDev->dma_rx_malign %= 64; |
| } |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, size, PCI_DMA_FROMDEVICE); |
| #endif |
| |
| #ifdef WAR_SEND_ABORT |
| // Needed for FPGA workaround |
| if (mode) { |
| SDHost_SendAbort(pDev); |
| } |
| #endif // WAR_SEND_ABORT |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| /* |
| { |
| int j; |
| for (j=0; j < 64 && j < size; j++) |
| { |
| printk("%2.02X ",pData[j]); |
| if ((j+1)%16 == 0) |
| { |
| printk("\n"); |
| } |
| } |
| printk("\n"); |
| } |
| */ |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD53_Write - Write a block of data to the SDIO card |
| * - |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD53_Write(PSD_DEVICE_DATA pDev, |
| SK_U32 Offset, |
| SK_U8 function_number, |
| SK_U8 mode, |
| SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz) |
| { |
| SK_U16 uwTransferMode; |
| SK_U32 Arg; |
| SK_U32 ulResponse; |
| SK_U32 blk_cnt, cnt; |
| SK_U32 *pSrc32, *pEnd32; |
| SK_U32 *pDest32; |
| SK_U8 RESP; |
| SK_U32 retry, max_retry; |
| SK_U32 i; |
| |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "CMD53 WRITE fn=%2.02X reg=%8.08X data=0x%2.0X\n", |
| function_number, Offset, *(pData))); |
| |
| /*--- mmoser 3/31/2006 ---*/ |
| if (pDev->SurpriseRemoved == SK_TRUE) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 WRITE FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n", |
| function_number, Offset, pDev->bus_errors)); |
| return SK_FALSE; |
| } |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| |
| if (Count >= 512) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 WRITE : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n", |
| function_number, Offset, Count)); |
| return SK_FALSE; |
| } |
| |
| DBGPRINT(DBG_W528D_CMD53, |
| (KERN_DEBUG |
| "CMD53 WRITE %s MODE : fn=%2.02X reg=%8.08X %s=%d block_size=%d\n", |
| (mode ? "BLOCK" : "BYTE"), function_number, Offset, |
| (mode ? "blocks" : "length"), Count, blksz)); |
| |
| if ((*(pData + 4) == 0x03) && (Count == 2)) { |
| SK_U32 x; |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "\n**** TRIGGER *****\n")); |
| MEM_READ_ULONG(pDev, SK_SLOT_0, 0x200, &x); |
| x |= ((1 << 24) | (1 << 16)); |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, 0x200, x); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "**** pData 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n", |
| *(pData + 0), *(pData + 1), *(pData + 2), *(pData + 3), |
| *(pData + 4), *(pData + 5))); |
| } |
| |
| if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block |
| // mode |
| { |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0, |
| (SK_U8) (blksz & 0x00ff)); |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0, |
| (SK_U8) (blksz >> 8)); |
| pDev->sd_ids[function_number].blocksize = blksz; |
| } |
| uwTransferMode = 0; |
| |
| if (mode == BYTE_MODE) { |
| cnt = Count; |
| |
| blk_cnt = 1 << 16 | Count; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt); |
| } else { |
| cnt = Count * blksz; |
| |
| /* 20050630 mmoser HW-Workaround */ |
| if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_WR) == |
| DEBUG_DISABLE_HW_WORKAROUND_WR) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } else { |
| if (Count > 1) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } |
| } |
| |
| uwTransferMode |= STDHOST_BLOCK_COUNT_ENA; |
| |
| blk_cnt = Count << 16 | blksz | DMA_16K_BOUNDARY; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt); |
| } |
| |
| pSrc32 = (SK_U32 *) pData; |
| pDest32 = |
| (SK_U32 *) (((SK_U32) (SK_BAR((pDev), (SK_SLOT_0)))) + |
| (STDHOST_DATA_PORT)); |
| |
| Arg = MAKE_SDIO_OFFSET(Offset) | |
| MAKE_SDIO_OP_CODE(opcode) | |
| MAKE_SDIO_BLOCK_MODE(mode) | |
| MAKE_SDIO_FUNCTION(function_number) | |
| MAKE_SDIO_DIR(1) | (Count & 0x01FF); |
| |
| max_retry = |
| MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed == |
| 0 ? 1 : pDev->ClockSpeed); |
| |
| pEnd32 = (SK_U32 *) ((SK_U32) pSrc32 + cnt); |
| |
| // #define PREFILL_FIFO |
| |
| /*** mmoser 2006-03-03 **/ |
| #ifdef PREFILL_FIFO |
| // --> The whole message is always written to the FIFO! each FIFO has 2K |
| // Fill the FIFO before issuing the command |
| i = 0; |
| while (i < 2000 && pSrc32 < pEnd32) { |
| if (i % blksz == 0) { |
| retry = 0; |
| |
| do { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, |
| &ulResponse); |
| if ((ulResponse & STDHOST_STATE_BUFFER_WR_ENABLE) == |
| STDHOST_STATE_BUFFER_WR_ENABLE) { |
| break; |
| } |
| |
| /*--- mmoser 3/13/2006 ---*/ |
| UDELAY(1); |
| } while (++retry < max_retry); |
| |
| /*--- mmoser 3/3/2006 ---*/ |
| if (retry >= max_retry) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 WRITE FAILED : STDHOST_STATE_BUFFER_WR_ENABLE remains 0\nfn=%2.02X reg=%8.08X\n", |
| function_number, Offset)); |
| return SK_FALSE; |
| } |
| } |
| |
| *pDest32 = *pSrc32; |
| pSrc32++; |
| i += 4; |
| } |
| #endif // PREFILL_FIFO |
| |
| /*--- mmoser 8/29/2006 ---*/ |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| |
| retry = 0; |
| while (1) { |
| |
| if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) { |
| break; |
| } |
| if (retry++ > 5) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "CMD53 WRITE FAILED : fn=%2.02X reg=%8.08X\n", |
| function_number, Offset)); |
| return SK_FALSE; |
| } |
| UDELAY(5); |
| } |
| |
| RESP = GET_BITS_23_16(ulResponse); |
| |
| if (pDev->bus_type == SDIO_BUS_TYPE) { |
| if (RESP & 0xCB) { |
| DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR, |
| (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP)); |
| // reset the data line and FIFO |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| return SK_FALSE; |
| } else if ((RESP & 0x30) == 0) { |
| DBGPRINT(DBG_W528D | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 WRITE RESP Error,card not selected!:0x%.2X\n", |
| RESP)); |
| // reset the data line and FIFO |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| return SK_FALSE; |
| } |
| |
| } else { |
| if (RESP & 0x5C) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP)); |
| // reset the data line and FIFO |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| return SK_FALSE; |
| } |
| } |
| |
| #ifndef PREFILL_FIFO |
| i = 0; |
| #endif |
| |
| // Fill FIFO with remaining data, if any ... |
| while (pSrc32 < pEnd32) { |
| if (i % blksz == 0) { |
| retry = 0; |
| |
| do { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, |
| &ulResponse); |
| if ((ulResponse & STDHOST_STATE_BUFFER_WR_ENABLE) == |
| STDHOST_STATE_BUFFER_WR_ENABLE) { |
| break; |
| } |
| |
| /*--- mmoser 3/13/2006 ---*/ |
| UDELAY(1); |
| } while (++retry < max_retry); |
| /*--- mmoser 3/3/2006 ---*/ |
| if (retry >= max_retry) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 WRITE FAILED : STDHOST_STATE_BUFFER_WR_ENABLE remains 0\nfn=%2.02X reg=%8.08X\n", |
| function_number, Offset)); |
| if (mode) { |
| SDHost_SendAbort(pDev); |
| } |
| return SK_FALSE; |
| } |
| } |
| |
| *pDest32 = *pSrc32; |
| pSrc32++; |
| i += 4; |
| } |
| |
| if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) { |
| if (SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1000)) { |
| return SK_FALSE; |
| } |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| } else { |
| retry = 0; |
| do { |
| SK_U32 ulResp; |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulResp); |
| if ((ulResp & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) == |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE) { |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE); |
| break; |
| } |
| |
| /*--- mmoser 3/14/2006 ---*/ |
| UDELAY(1); |
| } while (++retry < max_retry); |
| if (retry >= max_retry) { |
| DBGPRINT(DBG_WARNING, |
| (KERN_DEBUG |
| "CMD53 Write : STDHOST_NORMAL_IRQ_TRANS_COMPLETE not set!(count=%d max_retry=%d)\n", |
| Count, max_retry)); |
| // reset the data line and FIFO |
| } |
| } |
| |
| if (mode) { |
| SDHost_SendAbort(pDev); |
| } |
| |
| /*--- mmoser 1/5/2007 ---*/ |
| // STDHOST_NORMAL_IRQ_ERROR is used for GPI interrupts !!!! |
| /* |
| MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, &ulVal); |
| if (ulVal&STDHOST_NORMAL_IRQ_ERROR) |
| { |
| SDHost_ErrorRecovery(pDev); |
| DBGPRINT(DBG_ERROR,( KERN_DEBUG "SDHost_CMD53_Write() : Command Error 0x%8.08X\n",ulVal)); |
| return SK_FALSE; |
| } |
| */ |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD53_Write_DMA - Write a block of data to the SDIO card |
| * - |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD53_Write_DMA(PSD_DEVICE_DATA pDev, |
| SK_U32 Offset, |
| SK_U8 function_number, |
| SK_U8 mode, |
| SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz) |
| { |
| SK_U16 uwTransferMode; |
| SK_U32 Arg; |
| SK_U32 ulResponse; |
| SK_U32 blk_cnt, cnt; |
| SK_U32 *pSrc32; |
| SK_U32 *pDest32; |
| SK_U8 RESP; |
| SK_U32 retry, max_retry; |
| SK_U32 ulResp; |
| SK_U64 PhysAddr; |
| /*--- mmoser 1/10/2007 ---*/ |
| SK_U16 lastIRQMask; |
| SK_U16 lastErrorIRQMask; |
| |
| /*--- mmoser 3/31/2006 ---*/ |
| if (pDev->SurpriseRemoved == SK_TRUE) { |
| /*--- mmoser 1/10/2007 ---*/ |
| printk |
| ("CMD53 WRITE FAILED : Surprise Removed !!! fn=%2.02X reg=%8.08X (bus_errors=%d)\n", |
| function_number, Offset, pDev->bus_errors); |
| return SK_FALSE; |
| } |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| |
| if (Count >= 512) { |
| /*--- mmoser 1/10/2007 ---*/ |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 WRITE : fn=%2.02X reg=%8.08X len=%d > 512 ERROR!!!!!!\n", |
| function_number, Offset, Count)); |
| return SK_FALSE; |
| } |
| |
| /* |
| if(( *(pData) == 0x3C) && (Count == 2) ) { |
| SK_U32 x; |
| DBGPRINT(DBG_ERROR,( KERN_DEBUG "\n**** TRIGGER *****\n")); |
| MEM_READ_ULONG (pDev, SK_SLOT_0, 0x200, &x); |
| x |= ((1 << 24) | (1 << 16)); |
| MEM_WRITE_ULONG (pDev, SK_SLOT_0, 0x200, x); |
| DBGPRINT(DBG_ERROR,( KERN_DEBUG "**** pData 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n", |
| *(pData+0),*(pData+1),*(pData+2),*(pData+3), *(pData+4), *(pData+5))); |
| } |
| */ |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| &lastIRQMask); |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| &lastErrorIRQMask); |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| (lastIRQMask & (~STDHOST_NORMAL_IRQ_CARD))); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| (lastErrorIRQMask & (~STDHOST_ERROR_IRQ_VENDOR_ENA))); |
| |
| DBGPRINT(DBG_W528D_CMD53, |
| (KERN_DEBUG |
| "CMD53 WRITE %s MODE : fn=%2.02X reg=%8.08X %s=%d block_size=%d\n", |
| (mode ? "BLOCK" : "BYTE"), function_number, Offset, |
| (mode ? "blocks" : "length"), Count, blksz)); |
| |
| if (mode && (blksz != pDev->sd_ids[function_number].blocksize)) // block |
| // mode |
| { |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_0_REG(function_number), 0, |
| (SK_U8) (blksz & 0x00ff)); |
| SDHost_CMD52_Write(pDev, FN_BLOCK_SIZE_1_REG(function_number), 0, |
| (SK_U8) (blksz >> 8)); |
| pDev->sd_ids[function_number].blocksize = blksz; |
| } |
| uwTransferMode = 0; |
| |
| if (mode == BYTE_MODE) { |
| cnt = Count; |
| |
| blk_cnt = 1 << 16 | Count; |
| uwTransferMode |= STDHOST_DMA_ENA; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt); |
| } else { |
| cnt = Count * blksz; |
| |
| /* 20050630 mmoser HW-Workaround */ |
| if ((pDev->debug_flags & DEBUG_DISABLE_HW_WORKAROUND_WR) == |
| DEBUG_DISABLE_HW_WORKAROUND_WR) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } else { |
| if (Count > 1) { |
| uwTransferMode |= STDHOST_MULTI_BLOCK_SELECT; |
| } |
| } |
| |
| /* |
| { |
| int j; |
| for (j=0; j < 64 && j < cnt; j++) |
| { |
| printk("%2.02X ",pData[j]); |
| if ((j+1)%16 == 0) |
| { |
| printk("\n"); |
| } |
| } |
| printk("\n"); |
| } |
| */ |
| // enable DMA transfer |
| uwTransferMode |= (STDHOST_BLOCK_COUNT_ENA | STDHOST_DMA_ENA); |
| |
| blk_cnt = Count << 16 | blksz | DMA_16K_BOUNDARY; |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_BLOCK_SIZE, blk_cnt); |
| } |
| |
| pSrc32 = (SK_U32 *) pData; |
| pDest32 = |
| (SK_U32 *) (((SK_U32) (SK_BAR((pDev), (SK_SLOT_0)))) + |
| (STDHOST_DATA_PORT)); |
| |
| Arg = MAKE_SDIO_OFFSET(Offset) | |
| MAKE_SDIO_OP_CODE(opcode) | |
| MAKE_SDIO_BLOCK_MODE(mode) | |
| MAKE_SDIO_FUNCTION(function_number) | |
| MAKE_SDIO_DIR(1) | (Count & 0x01FF); |
| |
| max_retry = |
| MAX_WAIT_COMMAND_COMPLETE * (pDev->ClockSpeed == |
| 0 ? 1 : pDev->ClockSpeed); |
| |
| // max_retry = MAX_WAIT_COMMAND_COMPLETE * 100 * (pDev->ClockSpeed == 0 ? 1 |
| // : pDev->ClockSpeed); |
| /*--- mmoser 8/29/2006 ---*/ |
| |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| // set the DMA address |
| PhysAddr = (SK_U64) pci_map_page(pDev->dev, |
| virt_to_page(pDev->dma_tbuff), |
| ((unsigned long) (pDev-> |
| dma_tbuff) & ~PAGE_MASK), |
| 8192, PCI_DMA_FROMDEVICE); |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS, |
| (SK_U32) (PhysAddr + pDev->dma_start_malign + |
| pDev->dma_tx_malign)); |
| |
| // MEM_READ_ULONG (pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS,&ulResp); |
| // printk("dma_abuf:0x%p phys:0x%x tx_malign:%d (read-back=0x%x)\n", pDev->dma_tbuff, (SK_U32)PhysAddr, pDev->dma_tx_malign, ulResp ); |
| memcpy((void *) (pDev->dma_tbuff + pDev->dma_start_malign + |
| pDev->dma_tx_malign), pData, cnt); |
| //printk("TX org: %2.02X %2.02X %2.02X %2.02X ...\n",pData[0],pData[1],pData[2],pData[3]); |
| //pTmp = (SK_U8 *)(pDev->dma_tbuff+pDev->dma_start_malign+pDev->dma_tx_malign); |
| //printk("TX cp : %2.02X %2.02X %2.02X %2.02X ...\n",pTmp[0],pTmp[1],pTmp[2],pTmp[3]); |
| pDev->dma_tx_malign++; |
| pDev->dma_tx_malign %= 64; |
| |
| #else // SYSKT_DMA_MALIGN_TEST |
| // set the DMA address |
| PhysAddr = (SK_U64) pci_map_page(pDev->dev, virt_to_page(pData), |
| ((unsigned long) pData & ~PAGE_MASK), |
| cnt, PCI_DMA_TODEVICE); |
| |
| MEM_WRITE_ULONG(pDev, SK_SLOT_0, STDHOST_SYSTEM_ADDRESS, (SK_U32) PhysAddr); |
| #endif |
| |
| pDev->CmdInProgress = 1; |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| |
| retry = 0; |
| while (1) { |
| |
| if (SDHost_SendCmd(pDev, 53, Arg, uwTransferMode, &ulResponse)) { |
| break; |
| } |
| if (retry++ > 5) { |
| if (!SDHost_isCardPresent(pDev)) { |
| pDev->SurpriseRemoved = SK_TRUE; |
| SDHost_SetCardOutEvent(pDev); |
| } |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "CMD53 WRITE FAILED : fn=%2.02X reg=%8.08X\n", |
| function_number, Offset)); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| UDELAY(5); |
| } |
| RESP = GET_BITS_23_16(ulResponse); |
| |
| if (pDev->bus_type == SDIO_BUS_TYPE) { |
| if (RESP & 0xCB) { |
| DBGPRINT(DBG_W528D_CMD53 | DBG_ERROR, |
| (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP)); |
| // reset the data line and FIFO |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } else if ((RESP & 0x30) == 0) { |
| DBGPRINT(DBG_W528D | DBG_ERROR, |
| (KERN_DEBUG |
| "CMD53 WRITE RESP Error,card not selected!:0x%.2X\n", |
| RESP)); |
| // reset the data line and FIFO |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| |
| } else { |
| if (RESP & 0x5C) { |
| DBGPRINT(DBG_W528D_CMD52 | DBG_ERROR, |
| (KERN_DEBUG "CMD53 WRITE RESP Error:0x%.2X\n", RESP)); |
| // reset the data line and FIFO |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| } |
| if (isCmdFailed(pDev)) { |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| // wait for DMA to complete |
| if (pDev->currentIRQSignalMask & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) { |
| if (SDHost_wait_event(pDev, &pDev->trans_complete_evt, 1000)) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "%s -> SDHost_wait_event trans_complete failed\n", |
| __FUNCTION__)); |
| /*--- mmoser 1/10/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, |
| PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, |
| PCI_DMA_FROMDEVICE); |
| #endif |
| return SK_FALSE; |
| } |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| } else { |
| retry = 0; |
| ulResp = 0; |
| if (test_bit(0, &pDev->trans_complete_evt.event) == 0) { |
| do { |
| |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| &ulResp); |
| if ((ulResp & STDHOST_NORMAL_IRQ_TRANS_COMPLETE) == |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE) { |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| STDHOST_NORMAL_IRQ_TRANS_COMPLETE); |
| break; |
| } |
| /*--- mmoser 3/14/2006 ---*/ |
| UDELAY(1); |
| } while (++retry < max_retry); |
| |
| } // check event |
| else { |
| clear_bit(0, &pDev->trans_complete_evt.event); |
| printk("%s xxx event instead of polling\n", __FUNCTION__); |
| } |
| if (retry >= max_retry) { |
| DBGPRINT(DBG_WARNING, |
| (KERN_DEBUG |
| "CMD53 Write : STDHOST_NORMAL_IRQ_TRANS_COMPLETE not set!(count=%d max_retry=%d)0x%x\n", |
| Count, max_retry, ulResp)); |
| // reset the data line and FIFO |
| } |
| } |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_TRANSFER_MODE, 0); |
| |
| #ifdef SYSKT_DMA_MALIGN_TEST |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, 8192, PCI_DMA_FROMDEVICE); |
| #else |
| pci_unmap_page(pDev->dev, (dma_addr_t) PhysAddr, cnt, PCI_DMA_FROMDEVICE); |
| #endif |
| |
| #ifdef WAR_SEND_ABORT |
| // Needed for FPGA workaround |
| if (mode) { |
| SDHost_SendAbort(pDev); |
| } |
| #endif // WAR_SEND_ABORT |
| |
| /*--- mmoser 1/5/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, |
| lastIRQMask); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| lastErrorIRQMask); |
| pDev->CmdInProgress = 0; |
| |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD53_Read - Read a block of data from the SDIO card |
| * - |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD53_ReadEx(PSD_DEVICE_DATA pDev, |
| SK_U32 Offset, |
| SK_U8 function_number, |
| SK_U8 mode, |
| SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz) |
| { |
| SK_BOOL rc; |
| |
| if (pDev->dma_support & DMA_RD_SUPPORT) { |
| // printk("SDHost_CMD53_ReadEx (DMA): Count=%d |
| // blksz=%d\n",Count,blksz); |
| rc = SDHost_CMD53_Read_DMA(pDev, Offset, function_number, mode, opcode, |
| pData, Count, blksz); |
| } else { |
| // printk("SDHost_CMD53_ReadEx: Count=%d blksz=%d\n",Count,blksz); |
| rc = SDHost_CMD53_Read(pDev, Offset, function_number, mode, opcode, |
| pData, Count, blksz); |
| } |
| |
| return rc; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_CMD53_Write - Write a block of data to the SDIO card |
| * - |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * SK_TRUE on success |
| * |
| */ |
| SK_BOOL |
| SDHost_CMD53_WriteEx(PSD_DEVICE_DATA pDev, |
| SK_U32 Offset, |
| SK_U8 function_number, |
| SK_U8 mode, |
| SK_U8 opcode, SK_U8 * pData, SK_U32 Count, SK_U32 blksz) |
| { |
| |
| if (pDev->dma_support & DMA_WR_SUPPORT) { |
| // printk("SDHost_CMD53_WriteEx (DMA): Count=%d |
| // blksz=%d\n",Count,blksz); |
| return SDHost_CMD53_Write_DMA(pDev, Offset, function_number, mode, |
| opcode, pData, Count, blksz); |
| } else { |
| // printk("SDHost_CMD53_WriteEx: Count=%d blksz=%d\n",Count,blksz); |
| return SDHost_CMD53_Write(pDev, Offset, function_number, mode, opcode, |
| pData, Count, blksz); |
| } |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_EnableInterrupt - Enable the interrupts on the FPGA |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_EnableInterrupt(PSD_DEVICE_DATA pDev, SK_U16 mask) |
| { |
| // SK_U16 usSigEna; |
| pDev->currentIRQSignalMask |= mask; |
| |
| /* |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna); |
| if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 ) |
| { |
| printk("@%d ####################################################################################################\n",__LINE__); |
| } |
| */ |
| |
| DBGPRINT(DBG_IRQ, (KERN_DEBUG "Enable PCI Interrupt (0x%4.04X)\n", |
| pDev->currentIRQSignalMask)); |
| |
| /*--- mmoser 1/2/2007 ---*/ |
| if (pDev->CmdInProgress == 0) { |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, |
| STDHOST_ERROR_IRQ_VENDOR_SIG_ENA); |
| /* |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna); |
| if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 ) |
| { |
| printk("@%d ####################################################################################################\n",__LINE__); |
| } |
| */ |
| } |
| // save last irq mask |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, |
| &pDev->lastIRQSignalMask); |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, |
| pDev->currentIRQSignalMask); |
| /* |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna); |
| |
| if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 ) |
| { |
| printk("@%d #################################################################################################### (mask=0x%4.04X)\n",__LINE__,pDev->currentIRQSignalMask); |
| } |
| */ |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_DisableInterrupt - Disable the interrupts on the FPGA |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_DisableInterrupt(PSD_DEVICE_DATA pDev, SK_U16 mask) |
| { |
| |
| /* |
| { |
| SK_U16 usSigEna; |
| |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna); |
| if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 ) |
| { |
| printk("@%d ####################################################################################################\n",__LINE__); |
| } |
| |
| } |
| */ |
| |
| // save current irq mask |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, |
| &pDev->currentIRQSignalMask); |
| |
| pDev->lastIRQSignalMask = pDev->currentIRQSignalMask; |
| |
| DBGPRINT(DBG_IRQ, (KERN_DEBUG "Disable PCI Interrupt (0x%4.04X)\n", |
| pDev->currentIRQSignalMask & ~mask)); |
| |
| /*--- mmoser 1/2/2007 ---*/ |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_SIGNAL_ENABLE, 0); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, |
| pDev->currentIRQSignalMask & ~mask); |
| /* |
| { |
| SK_U16 usSigEna; |
| |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS_ENABLE, &usSigEna); |
| if ( (usSigEna & STDHOST_NORMAL_IRQ_CMD_COMPLETE_ENA) == 0 ) |
| { |
| printk("@%d #################################################################################################### (mask=0x%4.04X)\n",__LINE__,pDev->currentIRQSignalMask & ~mask); |
| } |
| } |
| */ |
| pDev->currentIRQSignalMask &= ~mask; |
| |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_if_EnableInterrupt - Exported interface function |
| * |
| * Description: |
| * Exported interface function : Enable only card related interrupts |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_if_EnableInterrupt(PSD_DEVICE_DATA pDev) |
| { |
| SDHost_EnableInterrupt(pDev, STDHOST_NORMAL_IRQ_CARD_ALL_ENA); |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_if_DisableInterrupt - Exported interface function |
| * |
| * Description: |
| * Exported interface function : Disable only card related interrupts |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_if_DisableInterrupt(PSD_DEVICE_DATA pDev) |
| { |
| SDHost_DisableInterrupt(pDev, STDHOST_NORMAL_IRQ_CARD_ALL_ENA); |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SetCardOutEvent - Set the card out event |
| * |
| * Description: |
| * |
| * Notes: WINDOWS only |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_SetCardOutEvent(PSD_DEVICE_DATA pDev) |
| { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "SDHost_SetCardOutEvent() ---> CARD REMOVED\n")); |
| if (!pDev->isRemoving) { |
| queue_work(pDev->workqueue, &pDev->card_out_work); |
| } |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_lockInterface - Lock the SDIO interface |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| SK_BOOL |
| SDHost_lockInterface(PSD_DEVICE_DATA pDev) |
| { |
| #ifdef SK_SDIO_LOCK_INTERFACE |
| if (INTERLOCKED_INC(&pDev->if_lock) > 1) { |
| INTERLOCKED_DEC(&pDev->if_lock); |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "SDHost_lockInterface() FAILED !!! if_lock=%d\n", |
| pDev->if_lock)); |
| return SK_FALSE; |
| } |
| #endif |
| |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_unlockInterface - unlock the SDIO interface |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_unlockInterface(PSD_DEVICE_DATA pDev) |
| { |
| #ifdef SK_SDIO_LOCK_INTERFACE |
| if (INTERLOCKED_DEC(&pDev->if_lock) < 0) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_unlockInterface() was already zero !!!! --> ignore.\n", |
| pDev->if_lock)); |
| INTERLOCKED_INC(&pDev->if_lock); |
| } |
| #endif |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SetLed - Set the LED on the FPGA interface |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_SetLed(PSD_DEVICE_DATA pDev, SK_U8 led, SK_U8 on) |
| { |
| if (on) { |
| LED_ON(led); |
| } else { |
| LED_OFF(led); |
| } |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SetClockSpeed - Set the SDIO bus clock speed |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_SetClockSpeed(PSD_DEVICE_DATA pDev, SK_U32 bus_freq) |
| { |
| SK_U32 freq = 0; |
| |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "%s: set clock to %d\n", __FUNCTION__, |
| bus_freq == 0 ? 25 : bus_freq)); |
| |
| if (bus_freq == 50) { |
| freq = 0; /* 50 MHz */ |
| } else if (bus_freq == 0 || bus_freq == 25) { |
| freq = 1; /* default: 25 MHz */ |
| } else if (bus_freq == 12) { |
| freq = 2; /* 12 MHz */ |
| } else if (bus_freq == 6) { |
| freq = 4; /* 6 MHz */ |
| } else if (bus_freq == 3) { |
| freq = 8; /* 3 MHz */ |
| } else if (bus_freq == 2) { |
| freq = 16; /* 1,5 MHz */ |
| } else if (bus_freq == 800) { |
| freq = 32; /* 800 kHz */ |
| } else if (bus_freq == 300) { |
| freq = 64; /* 300 kHz */ |
| } else if (bus_freq == 200) { |
| freq = 128; /* 200 kHz */ |
| } else { |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "%s: illegal clock %d\n", __FUNCTION__, bus_freq)); |
| return; |
| } |
| pDev->ClockSpeed = freq; |
| |
| if (!pDev->ClockSpeed) { |
| SDHost_Enable_HighSpeedMode(pDev); |
| } else { |
| |
| SDHost_Disable_HighSpeedMode(pDev); |
| } |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SetClock - Set the SDIO bus clock on/off |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_SetClock(PSD_DEVICE_DATA pDev, SK_U8 on) |
| { |
| SK_U16 usVal; |
| int j; |
| |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal); |
| |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "%s: turn clock %s\n", __FUNCTION__, |
| (on == 1 ? "ON" : "OFF"))); |
| |
| if (on) { |
| if (usVal & STDHOST_INTERNAL_CLK_ENA) { |
| if (usVal & STDHOST_INTERNAL_CLK_STABLE) { |
| if (usVal & STDHOST_CLOCK_ENA) { |
| // clock is already stable and running |
| return; |
| } else { |
| // Enable clock to card |
| usVal |= STDHOST_CLOCK_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, |
| usVal); |
| return; |
| } |
| } |
| // there is something fishy with the clock. |
| // -> disable internal clock first |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "%s: SD internal clock is unstable!\n", |
| __FUNCTION__)); |
| usVal &= ~STDHOST_INTERNAL_CLK_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| } |
| |
| usVal |= STDHOST_INTERNAL_CLK_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| for (j = 0; j < MAX_WAIT_CLOCK_STABLE; j++) { |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal); |
| if ((usVal & STDHOST_INTERNAL_CLK_STABLE) == |
| STDHOST_INTERNAL_CLK_STABLE) { |
| break; |
| } |
| } |
| if (j >= MAX_WAIT_CLOCK_STABLE) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "%s: SD clock remains unstable!\n", |
| __FUNCTION__)); |
| return; |
| } |
| // Enable clock to card |
| usVal |= STDHOST_CLOCK_ENA; |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| } else { |
| // Disable clock to card |
| usVal &= ~(STDHOST_CLOCK_ENA | STDHOST_INTERNAL_CLK_ENA); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| } |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SetBusWidth - Set the SDIO bus width |
| * |
| * Description: |
| * |
| * Notes: see Part_A2_Host_Controller.pdf p.61 |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| SK_BOOL |
| SDHost_SetBusWidth(PSD_DEVICE_DATA pDev, SK_U8 width) |
| { |
| SK_U16 usValue, usOrgValue; |
| SK_U8 ucHostCtrl = 0; |
| SK_U8 orgIntEnable; |
| |
| if (pDev->bus_type != SDIO_BUS_TYPE) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG "%s: not possible in current bus mode (%d)\n", |
| __FUNCTION__, pDev->bus_type)); |
| return SK_FALSE; |
| } |
| |
| DBGPRINT(DBG_LOAD, |
| (KERN_DEBUG "%s: bus width = %d\n", __FUNCTION__, width)); |
| // save current irq mask |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, |
| &usOrgValue); |
| |
| // disable card interrupt |
| usValue = usOrgValue; |
| usValue &= ~STDHOST_NORMAL_IRQ_CARD_SIG_ENA; |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, |
| usValue); |
| |
| // Disable Host Interrupt on card |
| if (!SDHost_CMD52_Read(pDev, INT_ENABLE_REG, 0, &orgIntEnable)) { |
| return SK_FALSE; |
| } |
| if (!SDHost_CMD52_Write(pDev, INT_ENABLE_REG, 0, 0)) { |
| return SK_FALSE; |
| } |
| // Read current host control register |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, &ucHostCtrl); |
| |
| if (width == SDIO_4_BIT) { |
| pDev->bus_width = SDIO_4_BIT; |
| if (!SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x82)) // 0x80:CD |
| // disable,1 |
| // bit;0x82:CD |
| // disable,4 |
| // bit |
| { |
| return SK_FALSE; |
| } |
| ucHostCtrl |= STDHOST_4_BIT_ENA; |
| } else { |
| pDev->bus_width = SDIO_1_BIT; |
| if (!SDHost_CMD52_Write(pDev, BUS_INTERFACE_CONTROL_REG, 0, 0x80)) // 0x80:CD |
| // disable,1 |
| // bit;0x80:CD |
| // disable,1 |
| // bit |
| { |
| return SK_FALSE; |
| } |
| ucHostCtrl &= ~STDHOST_4_BIT_ENA; |
| } |
| |
| // Setup host control register |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl); |
| |
| // Re-enable Host Interrupt on card |
| if (!SDHost_CMD52_Write(pDev, INT_ENABLE_REG, 0, orgIntEnable)) { |
| return SK_FALSE; |
| } |
| // Re-enable card interrupt |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_SIGNAL_ENABLE, |
| usOrgValue); |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_SetGPO - Set the GPO on/off |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| SK_BOOL |
| SDHost_SetGPO(PSD_DEVICE_DATA pDev, SK_U8 on) |
| { |
| if (!pDev->CardIn) { |
| return SK_FALSE; |
| } |
| |
| if (on) { |
| |
| GPO_ON(); |
| } else { |
| |
| GPO_OFF(); |
| } |
| return SK_TRUE; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_PsState - Set the power state of the upper layer driver |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_PsState(PSD_DEVICE_DATA pDev, SK_U8 State) |
| { |
| pDev->PsState = State; |
| } |
| |
| /****************************************************************************** |
| * |
| * SDHost_ErrorRecovery - SDIO Standard Host Spec conform error recovery |
| * |
| * Description: |
| * |
| * Notes: |
| * |
| * Context: |
| * |
| * Returns: |
| * |
| */ |
| VOID |
| SDHost_ErrorRecovery(PSD_DEVICE_DATA pDev) |
| { |
| SK_U8 ucValue; |
| SK_U16 usValue; |
| SK_U32 j, ulVal, ulDataLineMask; |
| |
| // We have to do spec conform error recovery |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, &usValue); |
| DBGPRINT(DBG_ERROR, (KERN_DEBUG "~#~#~#~#\n")); |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "SDHost_ErrorRecovery : ERROR_IRQ_STATUS=0x%4.04X\n", |
| usValue)); |
| // 1.) check whether any of bits3-0 are set. |
| if (usValue & 0x000F) { |
| // reset the command line |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_CMD_LINE); |
| |
| // wait until CMD line reset is 0 |
| j = 0; |
| do { |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, &ucValue); |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ErrorRecovery : CMD-LINE SW_RESET=0x%2.02X\n", |
| ucValue)); |
| UDELAY(2); |
| } while ((ucValue & STDHOST_SW_RESET_CMD_LINE) && j++ < 10000); |
| } |
| // 2.) check whether any of bits6-4 are set. |
| if (usValue & 0x0070) { |
| |
| // reset the data line |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, |
| STDHOST_SW_RESET, STDHOST_SW_RESET_DAT_LINE); |
| |
| // wait until data line reset is 0 |
| j = 0; |
| do { |
| |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_SW_RESET, &ucValue); |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ErrorRecovery : DAT-LINE SW_RESET=0x%2.02X\n", |
| ucValue)); |
| UDELAY(2); |
| } while ((ucValue & STDHOST_SW_RESET_DAT_LINE) && j++ < 10000); |
| |
| } |
| // clear error irq bits |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0xFFFF); |
| |
| // wait for more than 40 us |
| UDELAY(100); |
| |
| if (pDev->bus_type == SDIO_SPI_TYPE) { |
| ulDataLineMask = STDHOST_STATE_DAT0_LINE_LVL; |
| } else { |
| if (pDev->bus_width == SDIO_1_BIT) { |
| ulDataLineMask = STDHOST_STATE_DAT0_LINE_LVL; |
| } else { |
| ulDataLineMask = |
| (STDHOST_STATE_DAT0_LINE_LVL | STDHOST_STATE_DAT1_LINE_LVL | |
| STDHOST_STATE_DAT2_LINE_LVL | STDHOST_STATE_DAT3_LINE_LVL); |
| } |
| } |
| for (j = 0; j < 50; j++) { |
| MEM_READ_ULONG(pDev, SK_SLOT_0, STDHOST_PRESENT_STATE, &ulVal); |
| UDELAY(5); |
| if ((ulVal & ulDataLineMask) == ulDataLineMask) { |
| break; |
| } |
| } |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG |
| "SDHost_ErrorRecovery : DAT-LINE=%d %d %d %d CMD-Line=%d\n", |
| ulVal & STDHOST_STATE_DAT3_LINE_LVL ? 1 : 0, |
| ulVal & STDHOST_STATE_DAT2_LINE_LVL ? 1 : 0, |
| ulVal & STDHOST_STATE_DAT1_LINE_LVL ? 1 : 0, |
| ulVal & STDHOST_STATE_DAT0_LINE_LVL ? 1 : 0, |
| ulVal & STDHOST_STATE_CMD_LINE_LVL ? 1 : 0)); |
| if (j >= 50) { |
| DBGPRINT(DBG_ERROR, |
| (KERN_DEBUG |
| "SDHost_ErrorRecovery : Present state=8x%8.08X : Non-recoverable error (bad datalines 0x%8.08X)!!!!!!!!!!!!!!!!!!!!\n", |
| ulVal, ulVal & ulDataLineMask)); |
| } |
| // clear error irq bits |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_ERROR_IRQ_STATUS, 0xFFFF); |
| // clear normal irq bits |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_NORMAL_IRQ_STATUS, |
| ~(pDev->currentIRQSignalMask)); |
| |
| UDELAY(100); |
| } |
| |
| SK_U32 |
| SDHost_wait_event(PSD_DEVICE_DATA pDev, SDHOST_EVENT * pEvt, SK_U32 to) |
| { |
| SK_U32 timeOut = 0; |
| SK_U32 rc = 0; |
| |
| DECLARE_WAITQUEUE(sdwait, current); |
| |
| if (to == 0) { |
| timeOut = LONG_MAX; |
| } else { |
| timeOut = to; |
| } |
| |
| // DBGPRINT(DBG_ALL, (">>> %s: timeout=%d event=%ld\n",__FUNCTION__,timeOut,pEvt->event)); |
| |
| add_wait_queue(&pEvt->wq, &sdwait); |
| set_current_state(TASK_INTERRUPTIBLE); |
| |
| while ((test_bit(0, &pEvt->event) == 0) && timeOut) { |
| timeOut = schedule_timeout(timeOut); |
| if (signal_pending(current)) { |
| rc = 1; |
| DBGPRINT(DBG_ALL, ("%s: Signal pending!\n", __FUNCTION__)); |
| break; |
| } |
| } |
| |
| if (timeOut <= 0 || (test_bit(0, &pEvt->event) == 0)) { |
| rc = 2; |
| DBGPRINT(DBG_ALL, |
| ("%s: timeout=%d event=%ld\n", __FUNCTION__, timeOut, |
| pEvt->event)); |
| } |
| set_current_state(TASK_RUNNING); |
| remove_wait_queue(&pEvt->wq, &sdwait); |
| |
| // DBGPRINT(DBG_ALL, ("<<< %s: timeout=%d |
| // event=%ld\n",__FUNCTION__,timeOut,pEvt->event)); |
| |
| return (rc); |
| } |
| |
| SK_BOOL |
| SDHost_DumpCIS(PSD_DEVICE_DATA pDev, SK_U8 function_number, SK_U32 length) |
| { |
| SK_U8 R; |
| SK_U32 _cis = 0; |
| SK_U32 j; |
| SK_U32 i = 0; |
| SK_U32 len = 0; |
| SK_U32 state = 0; |
| |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_0_REG(function_number), 0, &R)) { |
| return SK_FALSE; |
| } |
| _cis = R; |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_1_REG(function_number), 0, &R)) { |
| return SK_FALSE; |
| } |
| _cis |= (R << 8); |
| if (!SDHost_CMD52_Read(pDev, FN_CIS_POINTER_2_REG(function_number), 0, &R)) { |
| return SK_FALSE; |
| } |
| _cis |= (R << 16); |
| |
| // Search for CISTPL |
| printk("SDHost_DumpCIS : FN=%d CIS=%8.08X\n", function_number, _cis); |
| R = 0; |
| |
| if (_cis == 0) { |
| return SK_FALSE; |
| } |
| |
| j = 0; |
| while (j < length) { |
| SDHost_CMD52_Read(pDev, _cis + j, function_number, &R); |
| j++; |
| switch (state) { |
| case 0: |
| { |
| printk("%2.02X:", R); |
| state++; |
| if (R == 0xFF) { |
| printk("END\n"); |
| return SK_TRUE; |
| } |
| break; |
| } |
| case 1: |
| { |
| printk("len=%2.02X:", R); |
| len = R; |
| i = 0; |
| state++; |
| break; |
| } |
| case 2: |
| { |
| printk("%2.02X ", R); |
| i++; |
| if (i >= len) { |
| printk("\n"); |
| state = 0; |
| } |
| break; |
| } |
| } |
| } |
| printk("\n"); |
| |
| return SK_TRUE; |
| } |
| |
| SK_BOOL |
| SDHost_Disable_HighSpeedMode(PSD_DEVICE_DATA pDev) |
| { |
| SK_U8 R; |
| SK_U16 usVal; |
| SK_U8 ucHostCtrl = 0; |
| |
| // Turn Off Bus Clock |
| SDHost_SetClock(pDev, 0); |
| |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal); |
| |
| usVal &= 0x00FF; |
| usVal |= MK_CLOCK((SK_U16) pDev->ClockSpeed); |
| |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| // Turn On Bus Clock |
| SDHost_SetClock(pDev, 1); |
| |
| if (SDHost_CMD52_Read(pDev, HIGH_SPEED_REG, 0, &R) && pDev->ClockSpeed != 0) { |
| if (R & EHS) { |
| // Disable high speed mode if requested bus clock is not 50MHz |
| R &= ~EHS; |
| SDHost_CMD52_Write(pDev, HIGH_SPEED_REG, 0, R); |
| } |
| } |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, &ucHostCtrl); |
| |
| if (ucHostCtrl & STDHOST_HIGH_SPEED_ENA) { |
| ucHostCtrl &= ~STDHOST_HIGH_SPEED_ENA; |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl); |
| } |
| return SK_TRUE; |
| } |
| |
| SK_BOOL |
| SDHost_Enable_HighSpeedMode(PSD_DEVICE_DATA pDev) |
| { |
| SK_U8 R; |
| SK_U16 usVal; |
| SK_U8 ucHostCtrl = 0; |
| |
| // Read High Speed register of CCCR |
| if (SDHost_CMD52_Read(pDev, HIGH_SPEED_REG, 0, &R) && |
| (pDev->ClockSpeed == 0)) { |
| if (R & SHS) { |
| /* Make the clock edge to rising */ |
| MEM_READ_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, &ucHostCtrl); |
| ucHostCtrl |= STDHOST_HIGH_SPEED_ENA; |
| MEM_WRITE_UCHAR(pDev, SK_SLOT_0, STDHOST_HOST_CTRL, ucHostCtrl); |
| |
| DBGPRINT(DBG_W528D, (KERN_DEBUG "High speed mode is supported.\n")); |
| |
| // Enable high speed mode if requested bus clock is 50MHz |
| // and card supports high speed mode |
| R |= EHS; |
| SDHost_CMD52_Write(pDev, HIGH_SPEED_REG, 0, R); |
| |
| /* Change the Host controller clock to 50MHZ */ |
| // Turn Off Bus Clock |
| SDHost_SetClock(pDev, 0); |
| MEM_READ_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, &usVal); |
| usVal &= 0x00FF; |
| usVal |= MK_CLOCK((SK_U16) pDev->ClockSpeed); |
| MEM_WRITE_USHORT(pDev, SK_SLOT_0, STDHOST_CLOCK_CTRL, usVal); |
| // Turn On Bus Clock |
| SDHost_SetClock(pDev, 1); |
| } else { |
| DBGPRINT(DBG_W528D, |
| (KERN_DEBUG "High speed mode is not supported.\n")); |
| } |
| } |
| return SK_TRUE; |
| } |