nt9856x/BSP/linux-kernel/drivers/mmc/host/na51055_mmchost.c
2023-03-28 15:07:53 +08:00

2374 lines
65 KiB
C
Executable File

/**
NVT mmc function
To handle mmc modules
@file na51000_mmchost.c
@ingroup
@note
Copyright Novatek Microelectronics Corp. 2016. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
*/
#include "na51055_mmchost.h"
#include "na51055_mmcreg.h"
#include <linux/io.h>
#include <linux/printk.h>
#include <mach/nvt-io.h>
#include <linux/slab.h>
#define RESET_TIMEOUT 10000
/************************* cache API ********************************/
#include <asm/cacheflush.h>
#include <linux/dma-mapping.h>
static struct mmc_nvt_host drvdump_info[3];
void dma_flushwritecache(struct device *dev, void *pbuf, u32 len)
{
dma_addr_t dma_handle;
/*void *ptr;*/
/*printk("flash write buf 0x%x, len %d\r\n", pbuf, len);*/
/*for (ptr = pbuf; ptr < (pbuf + len + PAGE_SIZE); ptr += PAGE_SIZE)
flush_dcache_page(virt_to_page(ptr));*/
dma_handle = dma_map_single(dev, pbuf, len, DMA_TO_DEVICE);
dma_sync_single_for_device(dev, dma_handle, len, DMA_TO_DEVICE);
dma_unmap_single(dev, dma_handle, len, DMA_TO_DEVICE);
}
void dma_flushreadcache(struct device *dev, void *pbuf, u32 len)
{
dma_addr_t dma_handle;
/*void *ptr;*/
/*printk("flash read buf 0x%x, len %d\r\n", pbuf, len);*/
/*for (ptr = pbuf; ptr < (pbuf + len + PAGE_SIZE); ptr += PAGE_SIZE)
flush_dcache_page(virt_to_page(ptr));*/
dma_handle = dma_map_single(dev, pbuf, len, DMA_FROM_DEVICE);
dma_sync_single_for_device(dev, dma_handle, len, DMA_FROM_DEVICE);
dma_unmap_single(dev, dma_handle, len, DMA_FROM_DEVICE);
}
void dma_flushbidircache(struct device *dev, void *pbuf, u32 len)
{
dma_addr_t dma_handle;
/*void *ptr;*/
/*printk("flash read buf 0x%x, len %d\r\n", pbuf, len);*/
/*for (ptr = pbuf; ptr < (pbuf + len + PAGE_SIZE); ptr += PAGE_SIZE)
flush_dcache_page(virt_to_page(ptr));*/
dma_handle = dma_map_single(dev, pbuf, len, DMA_BIDIRECTIONAL);
dma_sync_single_for_device(dev, dma_handle, len, DMA_BIDIRECTIONAL);
dma_unmap_single(dev, dma_handle, len, DMA_BIDIRECTIONAL);
}
/************************* cache API ********************************/
/*-------------------------------------------------------*/
/* Internal function prototypes */
/*-------------------------------------------------------*/
static REGVALUE sdiohost_getreg(struct mmc_nvt_host *host, uint32_t id,
uint32_t offset);
static void sdiohost_setreg(struct mmc_nvt_host *host, uint32_t id,
uint32_t offset, REGVALUE value);
/*-------------------------------------------------------*/
/* Private driver specific variables */
/*-------------------------------------------------------*/
static uint32_t vsdio_seg_en[SDIO_HOST_ID_COUNT] = {
FALSE,
#if (SDIO_HOST_ID_COUNT > 1)
FALSE,
#endif
#if (SDIO_HOST_ID_COUNT > 2)
FALSE
#endif
};
static uint32_t vsdio_seg_num[SDIO_HOST_ID_COUNT] = {
1,
#if (SDIO_HOST_ID_COUNT > 1)
1,
#endif
#if (SDIO_HOST_ID_COUNT > 2)
1
#endif
};
#if (SDIO_SCATTER_DMA)
#define SDIO_DES_MAX_BUF_SIZE (64*1024*1024) /*64MB*/
/*static uint32_t
vuisdio_destab[SDIO_HOST_ID_COUNT][SDIO_DES_TABLE_NUM*SDIO_DES_WORD_SIZE];*/
#endif
/*********************************************************************/
/* Public(to driver layer) SDIO host controller functions */
/*********************************************************************/
void sdiohost_setdesen(uint32_t id, uint32_t uien)
{
if (uien == 0)
vsdio_seg_en[id] = FALSE;
else
vsdio_seg_en[id] = TRUE;
}
void sdiohost_setdestab(uint32_t id, uint32_t uidesaddr, uint32_t uidesnum,
uint32_t *vuisdio_destab)
{
#if (SDIO_SCATTER_DMA)
/*union SDIO_DATA_LENGTH_REG datalenreg; */
/*union SDIO_DMA_DES_START_ADDR_REG dmadesaddrreg; */
union SDIO_DES_LINE_REG dmadeslinereg;
union SDIO_DES_LINE1_REG dmadesline1reg;
union SDIO_DES_LINE2_REG dmadesline2reg;
uint32_t uitotalsize;
struct STRG_SEG_DES *pseg_des;
uint32_t i;
if (uidesnum > SDIO_DES_TABLE_NUM) {
pr_err("Descriptor number must < SDIO_DES_TABLE_NUM\r\n");
return;
}
memset((void *)&vuisdio_destab[0], 0,
(SDIO_DES_TABLE_NUM * SDIO_DES_WORD_SIZE)<<2);
uitotalsize = 0;
pseg_des = (struct STRG_SEG_DES *)uidesaddr;
for (i = 0; i < uidesnum; i++) {
dmadeslinereg.reg = 0;
dmadesline1reg.reg = 0;
dmadesline2reg.reg = 0;
dmadeslinereg.bit.DMA_DES_VALID = 1;
if (i == (uidesnum - 1))
dmadeslinereg.bit.DMA_DES_END = 1;
else
dmadeslinereg.bit.DMA_DES_END = 0;
dmadeslinereg.bit.DMA_DES_ACT = 2;
dmadesline1reg.bit.DMA_DES_DATA_LEN = pseg_des->uisegsize;
dmadesline2reg.bit.DMA_DES_DATA_ADDR = pseg_des->uisegaddr;
vuisdio_destab[(i * SDIO_DES_WORD_SIZE) +
SDIO_DES_LINE_REG_OFS] = (uint32_t)dmadeslinereg.reg;
vuisdio_destab[(i * SDIO_DES_WORD_SIZE) +
(SDIO_DES_LINE1_REG_OFS >> 2)] = (uint32_t)dmadesline1reg.reg;
vuisdio_destab[(i * SDIO_DES_WORD_SIZE) +
(SDIO_DES_LINE2_REG_OFS >> 2)] = (uint32_t)dmadesline2reg.reg;
pseg_des++;
uitotalsize = dmadesline1reg.bit.DMA_DES_DATA_LEN;
}
vsdio_seg_num[id] = uidesnum;
#endif
}
/*
Get SDIO Busy or not
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return TRUE: ready
FALSE: busy
*/
bool sdiohost_getrdy(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_BUS_STATUS_REG stsreg;
stsreg.reg = sdiohost_getreg(host, id, SDIO_BUS_STATUS_REG_OFS);
return stsreg.bit.CARD_BUSY;
}
/*
Enable CKGEN clock for specified SDIO channel.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return void
*/
void sdiohost_enclock(struct mmc_nvt_host *host, uint32_t id)
{
clk_enable(host->clk);
}
/*
Disable CKGEN clock for specified SDIO channel.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return void
*/
void sdiohost_disclock(struct mmc_nvt_host *host, uint32_t id)
{
clk_disable(host->clk);
}
/*
Enable SD clock for specified SDIO channel.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return void
*/
void sdiohost_enclockout(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_CLOCK_CTRL_REG clk_ctrl;
clk_ctrl.reg = sdiohost_getreg(host, id, SDIO_CLOCK_CTRL_REG_OFS);
clk_ctrl.bit.CLK_DIS = 0;
sdiohost_setreg(host, id, SDIO_CLOCK_CTRL_REG_OFS, clk_ctrl.reg);
}
/*
Disable SD clock for specified SDIO channel.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return void
*/
void sdiohost_disclockout(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_CLOCK_CTRL_REG clk_ctrl;
clk_ctrl.reg = sdiohost_getreg(host, id, SDIO_CLOCK_CTRL_REG_OFS);
clk_ctrl.bit.CLK_DIS = 1;
sdiohost_setreg(host, id, SDIO_CLOCK_CTRL_REG_OFS, clk_ctrl.reg);
}
void sdiohost_setphyrst(struct mmc_nvt_host *host)
{
union SDIO_PHY_REG phyreg, phyreg_read;
u8 i;
phyreg.reg = sdiohost_getreg(host, host->id, SDIO_PHY_REG_OFS);
phyreg.bit.PHY_SW_RST = 1;
sdiohost_setreg(host, host->id, SDIO_PHY_REG_OFS, phyreg.reg);
while (1)
{
phyreg_read.reg = sdiohost_getreg(host, host->id, SDIO_PHY_REG_OFS);
if ((phyreg_read.bit.PHY_SW_RST == 0) || (i == RESET_TIMEOUT))
break;
i++;
}
if (i == RESET_TIMEOUT)
pr_err("phy reset timeout\n");
}
void sdiohost_setphysample(struct mmc_nvt_host *host, bool internal, bool before)
{
union SDIO_DLY0_REG dly0_reg;
dly0_reg.reg = sdiohost_getreg(host, host->id, SDIO_DLY0_REG_OFS);
dly0_reg.bit.SAMPLE_CLK_EDGE = host->neg_sample_edge;
dly0_reg.bit.SRC_CLK_SEL = internal;
dly0_reg.bit.PAD_CLK_SEL = before;
sdiohost_setreg(host, host->id, SDIO_DLY0_REG_OFS, dly0_reg.reg);
}
void sdiohost_setinvoutdly(struct mmc_nvt_host *host, bool data_outdly_inv, bool cmd_outdly_inv)
{
union SDIO_DLY5_REG dly5_reg;
dly5_reg.reg = sdiohost_getreg(host, host->id, SDIO_DLY5_REG_OFS);
dly5_reg.bit.DATA_OUT_DLY_INV = data_outdly_inv;
dly5_reg.bit.CMD_OUT_DLY_INV = cmd_outdly_inv;
sdiohost_setreg(host, host->id, SDIO_DLY5_REG_OFS, dly5_reg.reg);
}
void sdiohost_setphyclkoutdly(struct mmc_nvt_host *host, uint32_t outdly_sel)
{
union SDIO_CLOCK_CTRL2_REG clock_ctrl;
clock_ctrl.reg = sdiohost_getreg(host, host->id, SDIO_CLOCK_CTRL2_REG_OFS);
clock_ctrl.bit.OUTDLY_SEL = outdly_sel;
sdiohost_setreg(host, host->id, SDIO_CLOCK_CTRL2_REG_OFS, clock_ctrl.reg);
}
void sdiohost_setphyclkindly(struct mmc_nvt_host *host, uint32_t indly_sel)
{
union SDIO_CLOCK_CTRL2_REG clock_ctrl;
clock_ctrl.reg = sdiohost_getreg(host, host->id, SDIO_CLOCK_CTRL2_REG_OFS);
clock_ctrl.bit.INDLY_SEL = indly_sel;
sdiohost_setreg(host, host->id, SDIO_CLOCK_CTRL2_REG_OFS, clock_ctrl.reg);
}
static u32 driving_xfer(u32 driving)
{
u32 pad_driving;
if (driving == 40)
pad_driving = PAD_DRIVINGSINK_40MA;
else if (driving == 10)
pad_driving = PAD_DRIVINGSINK_10MA;
else if (driving == 15)
pad_driving = PAD_DRIVINGSINK_15MA;
else if (driving == 20)
pad_driving = PAD_DRIVINGSINK_20MA;
else if (driving == 25)
pad_driving = PAD_DRIVINGSINK_25MA;
else if (driving == 30)
pad_driving = PAD_DRIVINGSINK_30MA;
else if (driving == 35)
pad_driving = PAD_DRIVINGSINK_35MA;
else if (driving == 6)
pad_driving = PAD_DRIVINGSINK_6MA;
else if (driving == 16)
pad_driving = PAD_DRIVINGSINK_16MA;
else if (driving == 4)
pad_driving = PAD_DRIVINGSINK_4MA;
else if (driving == 8)
pad_driving = PAD_DRIVINGSINK_8MA;
else if (driving == 12)
pad_driving = PAD_DRIVINGSINK_12MA;
else if (driving == 3)
pad_driving = PAD_DRIVINGSINK_3MA;
else if (driving == 9)
pad_driving = PAD_DRIVINGSINK_9MA;
else if (driving == 18)
pad_driving = PAD_DRIVINGSINK_18MA;
else if (driving == 21)
pad_driving = PAD_DRIVINGSINK_21MA;
else if (driving == 24)
pad_driving = PAD_DRIVINGSINK_24MA;
else
pad_driving = PAD_DRIVINGSINK_5MA;
return pad_driving;
}
/*
Set PAD drive/sink of clock pin for specified SDIO channel.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] driving desired driving value * 10, unit: mA
valid value: 50 ~ 200
@return
- @b E_OK: sucess
- @b Else: fail
*/
int sdiohost_setpaddriving(struct mmc_nvt_host *host, SDIO_SPEED_MODE mode)
{
uint32_t data_uidriving, cmd_uidriving, clk_uidriving;
if (host->id >= SDIO_HOST_ID_COUNT)
return E_SYS;
if (mode == SDIO_MODE_DS) {
data_uidriving = driving_xfer(host->pad_driving[SDIO_DS_MODE_DATA]);
cmd_uidriving = driving_xfer(host->pad_driving[SDIO_DS_MODE_CMD]);
clk_uidriving = driving_xfer(host->pad_driving[SDIO_DS_MODE_CLK]);
} else if (mode == SDIO_MODE_HS) {
data_uidriving = driving_xfer(host->pad_driving[SDIO_HS_MODE_DATA]);
cmd_uidriving = driving_xfer(host->pad_driving[SDIO_HS_MODE_CMD]);
clk_uidriving = driving_xfer(host->pad_driving[SDIO_HS_MODE_CLK]);
} else if (mode == SDIO_MODE_SDR50) {
data_uidriving = driving_xfer(host->pad_driving[SDIO_SDR50_MODE_DATA]);
cmd_uidriving = driving_xfer(host->pad_driving[SDIO_SDR50_MODE_CMD]);
clk_uidriving = driving_xfer(host->pad_driving[SDIO_SDR50_MODE_CLK]);
} else {
data_uidriving = driving_xfer(host->pad_driving[SDIO_SDR104_MODE_DATA]);
cmd_uidriving = driving_xfer(host->pad_driving[SDIO_SDR104_MODE_CMD]);
clk_uidriving = driving_xfer(host->pad_driving[SDIO_SDR104_MODE_CLK]);
}
if (host->id == SDIO_HOST_ID_1) {
pad_set_drivingsink(PAD_DS_CGPIO12, cmd_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO13, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO14, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO15, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO16, data_uidriving);
return pad_set_drivingsink(PAD_DS_CGPIO11, clk_uidriving);
} else if (host->id == SDIO_HOST_ID_2) {
pad_set_drivingsink(PAD_DS_CGPIO18, cmd_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO19, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO20, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO21, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO22, data_uidriving);
return pad_set_drivingsink(PAD_DS_CGPIO17, clk_uidriving);
} else {
if (host->mmc) {
if (host->mmc->caps & MMC_CAP_8_BIT_DATA) {
pad_set_drivingsink(PAD_DS_CGPIO0, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO1, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO2, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO3, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO4, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO5, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO6, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO7, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO9, cmd_uidriving);
return pad_set_drivingsink(PAD_DS_CGPIO8, clk_uidriving);
} else {
pad_set_drivingsink(PAD_DS_CGPIO0, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO1, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO2, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO3, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO9, cmd_uidriving);
return pad_set_drivingsink(PAD_DS_CGPIO8, clk_uidriving);
}
} else {
pad_set_drivingsink(PAD_DS_CGPIO0, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO1, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO2, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO3, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO4, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO5, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO6, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO7, data_uidriving);
pad_set_drivingsink(PAD_DS_CGPIO9, cmd_uidriving);
return pad_set_drivingsink(PAD_DS_CGPIO8, clk_uidriving);
}
}
return E_OK;
}
/*
Reset SDIO host controller.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return void
*/
void sdiohost_reset(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_CMD_REG cmdreg;
int i = 0;
cmdreg.reg = sdiohost_getreg(host, id, SDIO_CMD_REG_OFS);
cmdreg.bit.SDC_RST = 1;
sdiohost_setreg(host, id, SDIO_CMD_REG_OFS, cmdreg.reg);
while (1) {
cmdreg.reg = sdiohost_getreg(host, id, SDIO_CMD_REG_OFS);
if ((cmdreg.bit.SDC_RST == 0) || (i == RESET_TIMEOUT))
break;
i++;
}
if (i == RESET_TIMEOUT)
pr_err("sdc reset timeout\n");
}
/*
Asynchrous reset SDIO host controller.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
- @b SDIO_HOST_ID_3: SDIO3
@return void
*/
void sdiohost_resetasync(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_DLY1_REG dlyreg1;
union SDIO_PHY_REG phyreg;
union SDIO_PHY_REG phyregread;
union SDIO_FIFO_SWITCH_REG fifoswitch;
clk_disable_unprepare(host->clk);
clk_prepare_enable(host->clk);
/* patch begin for sd write hang-up or write byte access error */
fifoswitch.reg = sdiohost_getreg(host, id, SDIO_FIFO_SWITCH_REG_OFS);
fifoswitch.bit.FIFO_SWITCH_DLY = 1;
sdiohost_setreg(host, id, SDIO_FIFO_SWITCH_REG_OFS, fifoswitch.reg);
/* patch end for sd write hang-up or write byte access error */
phyreg.reg = sdiohost_getreg(host, id, SDIO_PHY_REG_OFS);
phyreg.bit.PHY_SW_RST = 1;
sdiohost_setreg(host, id, SDIO_PHY_REG_OFS, phyreg.reg);
while (1) {
phyregread.reg = sdiohost_getreg(host, id, SDIO_PHY_REG_OFS);
if (phyregread.bit.PHY_SW_RST == 0) {
break;
}
}
dlyreg1.reg = sdiohost_getreg(host, id, SDIO_DLY1_REG_OFS);
dlyreg1.bit.DATA_READ_DLY = 2;
sdiohost_setreg(host, id, SDIO_DLY1_REG_OFS, dlyreg1.reg);
}
/*
Enable FIFO 512 Bytes (Only SDIO3).
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_3: SDIO3
@return void
*/
void sdiohost_setblkfifoen(struct mmc_nvt_host *host, bool enable)
{
union SDIO_PHY_REG phyreg;
phyreg.reg = sdiohost_getreg(host, host->id, SDIO_PHY_REG_OFS);
phyreg.bit.BLK_FIFO_EN = enable;
sdiohost_setreg(host, host->id, SDIO_PHY_REG_OFS, phyreg.reg);
}
/*
Send SD command to SD bus.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] cmd command value
@param[in] rsptype response type
- @b SDIO_HOST_RSP_NONE: no response is required
- @b SDIO_HOST_RSP_SHORT: need short (32 bits) response
- @b SDIO_HOST_RSP_LONG: need long (128 bits) response
@param[in] beniointdetect enable SDIO INT detect after command end
- @b TRUE: enable SDIO INT detection
- @b FALSE: keep SDIO INT detection
@return command result
- @b SDIO_HOST_CMD_OK: command execution success
- @b SDIO_HOST_RSP_TIMEOUT: response timeout. no response got from card.
- @b SDIO_HOST_RSP_CRCFAIL: response CRC fail.
- @b SDIO_HOST_CMD_FAIL: other fail.
*/
int sdiohost_sendcmd(struct mmc_nvt_host *host, uint32_t id, uint32_t cmd,
SDIO_HOST_RESPONSE rsptype, bool beniointdetect)
{
union SDIO_CMD_REG cmdreg;
#if (!SDIO_SCATTER_DMA)
/* Temp solution for FPGA */
sdiohost_setreg(host, id, 0x1FC, 1);
#endif
/*cmdreg.reg = 0;*/
cmdreg.reg = sdiohost_getreg(host, id, SDIO_CMD_REG_OFS);
cmdreg.bit.CMD_IDX = 0;
cmdreg.bit.NEED_RSP = 0;
cmdreg.bit.LONG_RSP = 0;
cmdreg.bit.RSP_TIMEOUT_TYPE = 0;
cmdreg.bit.ENABLE_SDIO_INT_DETECT = beniointdetect;
if (rsptype != SDIO_HOST_RSP_NONE) {
/* Need response */
cmdreg.bit.NEED_RSP = 1;
switch (rsptype) {
default:
break;
case SDIO_HOST_RSP_LONG:
cmdreg.bit.LONG_RSP = 1;
break;
case SDIO_HOST_RSP_SHORT_TYPE2:
cmdreg.bit.RSP_TIMEOUT_TYPE = 1;
break;
case SDIO_HOST_RSP_LONG_TYPE2:
cmdreg.bit.RSP_TIMEOUT_TYPE = 1;
cmdreg.bit.LONG_RSP = 1;
break;
}
}
cmdreg.bit.CMD_IDX = cmd;
sdiohost_setreg(host, id, SDIO_CMD_REG_OFS, cmdreg.reg);
if (id >= SDIO_HOST_ID_COUNT)
return SDIO_HOST_CMD_FAIL;
/* clear software status */
/*clr_flg(FLG_ID_SDIO, vsdiohosts[id].flgCommand);*/
/* Start command/data transmits */
cmdreg.bit.CMD_EN = 1;
sdiohost_setreg(host, id, SDIO_CMD_REG_OFS, cmdreg.reg);
return SDIO_HOST_CMD_OK;
}
/*
Set SDIO command argument.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] arg command argument
- possible value: 0x0000_0000 ~ 0xFFFF_FFFF
@return void
*/
void sdiohost_setarg(struct mmc_nvt_host *host, uint32_t id, uint32_t arg)
{
sdiohost_setreg(host, id, SDIO_ARGU_REG_OFS, arg);
}
/*
Get SDIO command response.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[out] prsp command response from card
@return void
*/
void sdiohost_getshortrsp(struct mmc_nvt_host *host, uint32_t id,
uint32_t *prsp)
{
union SDIO_RSP0_REG rspreg;
rspreg.reg = sdiohost_getreg(host, id, SDIO_RSP0_REG_OFS);
*prsp = (uint32_t) rspreg.reg;
}
/*
Get SDIO command long response.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[out] prsp3 command response from card (bit 127..96)
@param[out] prsp2 command response from card (bit 95..64)
@param[out] prsp1 command response from card (bit 63..32)
@param[out] prsp0 command response from card (bit 31..0)
@return void
*/
void sdiohost_getlongrsp(struct mmc_nvt_host *host, uint32_t id,
uint32_t *prsp3, uint32_t *prsp2, uint32_t *prsp1, uint32_t *prsp0)
{
union SDIO_RSP0_REG rsp0reg;
union SDIO_RSP1_REG rsp1reg;
union SDIO_RSP2_REG rsp2reg;
union SDIO_RSP3_REG rsp3reg;
rsp0reg.reg = sdiohost_getreg(host, id, SDIO_RSP0_REG_OFS);
*prsp0 = (uint32_t) rsp0reg.reg;
rsp1reg.reg = sdiohost_getreg(host, id, SDIO_RSP1_REG_OFS);
*prsp1 = (uint32_t) rsp1reg.reg;
rsp2reg.reg = sdiohost_getreg(host, id, SDIO_RSP2_REG_OFS);
*prsp2 = (uint32_t) rsp2reg.reg;
rsp3reg.reg = sdiohost_getreg(host, id, SDIO_RSP3_REG_OFS);
*prsp3 = (uint32_t) rsp3reg.reg;
}
/*
Enable SDIO interrupt.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] bits SDIO controller interrupt enable bits
@return void
*/
void sdiohost_setinten(struct mmc_nvt_host *host, uint32_t id, uint32_t bits)
{
union SDIO_INT_MASK_REG intenreg;
intenreg.reg = sdiohost_getreg(host, id, SDIO_INT_MASK_REG_OFS);
intenreg.reg |= bits;
sdiohost_setreg(host, id, SDIO_INT_MASK_REG_OFS, intenreg.reg);
}
/*
Disable SDIO interrupt.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] bits SDIO controller interrupt enable bits
@return void
*/
void sdiohost_disinten(struct mmc_nvt_host *host, uint32_t id, uint32_t bits)
{
union SDIO_INT_MASK_REG intenreg;
intenreg.reg = sdiohost_getreg(host, id, SDIO_INT_MASK_REG_OFS);
intenreg.reg &= ~bits;
sdiohost_setreg(host, id, SDIO_INT_MASK_REG_OFS, intenreg.reg);
}
/*
Set SDIO bus width.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] Width SDIO controller bus width
- @b SDIO_BUS_WIDTH1: 1 bit data bus
- @b SDIO_BUS_WIDTH4: 4 bits data bus
- @b SDIO_BUS_WIDTH8: 8 bits data bus
@return void
*/
void sdiohost_setbuswidth(struct mmc_nvt_host *host, uint32_t id,
uint32_t width)
{
union SDIO_BUS_WIDTH_REG widthreg;
widthreg.reg = 0;
widthreg.bit.BUS_WIDTH = width;
sdiohost_setreg(host, id, SDIO_BUS_WIDTH_REG_OFS, widthreg.reg);
}
/*
Get SDIO bus width.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return SDIO controller bus Width
- @b SDIO_BUS_WIDTH1
- @b SDIO_BUS_WIDTH4
- @b SDIO_BUS_WIDTH8
*/
uint32_t sdiohost_getbuswidth(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_BUS_WIDTH_REG widthreg;
widthreg.reg = sdiohost_getreg(host, id, SDIO_BUS_WIDTH_REG_OFS);
return widthreg.bit.BUS_WIDTH;
}
/*
Set SDIO bus clock.
@param[in] id SD host ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] uiclock SD bus clock in Hz
@param[out] ns ns one cycle
@return void
*/
void sdiohost_setbusclk(struct mmc_nvt_host *host, uint32_t id,
uint32_t uiclock, uint32_t *ns)
{
clk_set_rate(host->clk, uiclock);
if (ns)
*ns = (1000000) / (uiclock/1000);
}
/*
Get SDIO bus clock.
@param[in] id SD host ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return unit of Hz
*/
uint32_t sdiohost_getbusclk(struct mmc_nvt_host *host, uint32_t id)
{
return clk_get_rate(host->clk);
}
/*
Get SDIO controller block size.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return data size per block (unit: byte) (0x0001 ~ 0xFFFF)
*/
uint32_t sdiohost_getblksize(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_DATA_CTRL_REG datactrlreg;
datactrlreg.reg = sdiohost_getreg(host, id, SDIO_DATA_CTRL_REG_OFS);
return datactrlreg.bit.BLK_SIZE;
}
/*
Set SDIO controller block size.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] size data size per block (unit: byte)
- possible value: 0x0001 ~ 0xFFFF
@return void
*/
void sdiohost_setblksize(struct mmc_nvt_host *host, uint32_t id, uint32_t size)
{
union SDIO_DATA_CTRL_REG datactrlreg;
datactrlreg.reg = sdiohost_getreg(host, id, SDIO_DATA_CTRL_REG_OFS);
datactrlreg.bit.BLK_SIZE = size;
sdiohost_setreg(host, id, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
}
/*
Set SDIO controller data timeout.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] timeout time out value between data blocks (unit: SD clock)
@return void
*/
void sdiohost_setdatatimeout(struct mmc_nvt_host *host, uint32_t id,
uint32_t timeout)
{
union SDIO_DATA_TIMER_REG timerreg;
timerreg.bit.TIMEOUT = timeout;
sdiohost_setreg(host, id, SDIO_DATA_TIMER_REG_OFS, timerreg.reg);
}
/*
Reset SDIO controller data state machine.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return void
*/
void sdiohost_resetdata(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_DATA_CTRL_REG datactrlreg;
union SDIO_FIFO_CONTROL_REG fifoctrlreg;
/* //#NT#Fix SDIO data state machine abnormal when DATA CRC/Timeout
occurs before FIFO count complete */
union SDIO_STATUS_REG stsreg;
/* SDIO bug: force to clear data end status to exit
waiting data end state*/
stsreg.reg = 0;
stsreg.bit.DATA_END = 1;
sdiohost_setreg(host, id, SDIO_STATUS_REG_OFS, stsreg.reg);
fifoctrlreg.reg = 0;
sdiohost_setreg(host, id, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
while (1) {
fifoctrlreg.reg = sdiohost_getreg(host, id,
SDIO_FIFO_CONTROL_REG_OFS);
if (fifoctrlreg.bit.FIFO_EN == 0)
break;
}
datactrlreg.reg = sdiohost_getreg(host, id, SDIO_DATA_CTRL_REG_OFS);
datactrlreg.bit.DATA_EN = 0;
sdiohost_setreg(host, id, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
/* Fix SDIO data state machine abnormal when DATA
CRC/Timeout occurs before FIFO count complete */
/* Do software reset to reset SD state machine */
sdiohost_reset(host, id);
}
void sdiohost_delayd(struct mmc_nvt_host *host, uint32_t uid)
{
uint32_t i, uidummy;
for (i = uid; i; i--)
uidummy = sdiohost_getreg(host, 0, SDIO_CMD_REG_OFS);
}
void sdiohost_waitfifoempty(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_FIFO_STATUS_REG fifostsreg;
uint32_t read0, read1;
read0 = 0;
while (1) {
fifostsreg.reg = sdiohost_getreg(host, id,
SDIO_FIFO_STATUS_REG_OFS);
read1 = fifostsreg.bit.FIFO_EMPTY;
if (read0 & read1)
break;
else
read0 = read1;
}
}
void sdiohost_clrfifoen(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_FIFO_CONTROL_REG fifoctrlreg;
fifoctrlreg.reg = sdiohost_getreg(host, id, SDIO_FIFO_CONTROL_REG_OFS);
fifoctrlreg.bit.FIFO_EN = 0;
sdiohost_setreg(host, id, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
}
uint32_t sdiohost_getfifodir(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_FIFO_CONTROL_REG fifoctrlreg;
fifoctrlreg.reg = sdiohost_getreg(host, id, SDIO_FIFO_CONTROL_REG_OFS);
return fifoctrlreg.bit.FIFO_DIR;
}
/*
Setup SDIO controller data transfer in DMA mode.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] uidmaaddress buffer DRAM address
- possible value: 0x000_0000 ~ 0xFFF_FFFF
@param[in] uidatalength total transfer length
- possible value: 0x000_0001 ~ 0x3FF_FFFF
@param[in] bisread read/write mode
- @b TRUE: indicate data read transfer
- @b FALSE: indicate data write transfer
@return void
*/
void sdiohost_setupdatatransferdma(struct mmc_nvt_host *host, uint32_t id,
uint32_t uidmaaddress, uint32_t uidatalength, bool bisread, uint32_t *vuisdio_destab)
{
union SDIO_DATA_CTRL_REG datactrlreg;
union SDIO_DATA_LENGTH_REG datalenreg;
union SDIO_FIFO_CONTROL_REG fifoctrlreg;
#if (SDIO_SCATTER_DMA)
union SDIO_DMA_DES_START_ADDR_REG dmadesaddrreg;
union SDIO_DES_LINE_REG dmadeslinereg;
union SDIO_DES_LINE1_REG dmadesline1reg;
union SDIO_DES_LINE2_REG dmadesline2reg;
/*uint32_t i;*/
#else
union SDIO_DMA_START_ADDR_REG dmaaddrreg;
#endif
uint32_t uibusclk;
/* for debug */
/*fifoctrlreg.reg = sdiohost_getreg(id, SDIO_FIFO_CONTROL_REG_OFS);
if (fifoctrlreg.bit.FIFO_EN == 1) {
fifoctrlreg.reg = 0;
sdiohost_setreg(id, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
}*/
/* for debug end */
/* dummy read for patch */
sdiohost_delayd(host, 2);
uibusclk = sdiohost_getbusclk(host, id);
if (uibusclk >= 48000000)
sdiohost_delayd(host, 3);
else if ((uibusclk >= 24000000) && (uibusclk < 48000000))
sdiohost_delayd(host, 6);
else if ((uibusclk >= 12000000) && (uibusclk < 24000000))
sdiohost_delayd(host, 9);
else
sdiohost_delayd(host, 21);
/* patch for sd fifo bug end */
datactrlreg.reg = sdiohost_getreg(host, id, SDIO_DATA_CTRL_REG_OFS);
#if 0
/* multiple read => disable SDIO INT detection after transfer end */
if (bisread && (uidatalength > datactrlreg.bit.BLK_SIZE))
datactrlreg.bit.DIS_SDIO_INT_PERIOD = 1;
else
datactrlreg.bit.DIS_SDIO_INT_PERIOD = 0;
#else
/*
* The DIS_SDIO_INT_PERIOD is designed for reading infinite blocks.
* But there are some compatibility and performance issues, so it should not be used.
*/
datactrlreg.bit.DIS_SDIO_INT_PERIOD = 0;
#endif
/*move data en after fifo en*/
/*datactrlreg.bit.DATA_EN = 1;*/
sdiohost_setreg(host, id, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
#if (SDIO_SCATTER_DMA)
if (vsdio_seg_en[id] == FALSE) {
dmadeslinereg.reg = 0;
dmadesline1reg.reg = 0;
dmadesline2reg.reg = 0;
dmadeslinereg.bit.DMA_DES_VALID = 1;
dmadeslinereg.bit.DMA_DES_END = 1;
dmadeslinereg.bit.DMA_DES_ACT = 2;
dmadesline1reg.bit.DMA_DES_DATA_LEN = uidatalength;
dmadesline2reg.bit.DMA_DES_DATA_ADDR = uidmaaddress;
vuisdio_destab[SDIO_DES_LINE_REG_OFS] =
(uint32_t)dmadeslinereg.reg;
vuisdio_destab[SDIO_DES_LINE1_REG_OFS>>2] =
(uint32_t)dmadesline1reg.reg;
vuisdio_destab[SDIO_DES_LINE2_REG_OFS>>2] =
(uint32_t)dmadesline2reg.reg;
}
dmadesaddrreg.reg = 0;
dmadesaddrreg.bit.DES_ADDR = virt_to_phys((uint32_t*)&vuisdio_destab[0]);
sdiohost_setreg(host, id, SDIO_DMA_DES_START_ADDR_REG_OFS,
dmadesaddrreg.reg);
datalenreg.reg = 0;
datalenreg.bit.LENGTH = uidatalength;
sdiohost_setreg(host, id, SDIO_DATA_LENGTH_REG_OFS, datalenreg.reg);
fifoctrlreg.reg = 0;
if (vsdio_seg_en[id] == FALSE) {
/* Flush cache in data DMA*/
if (!bisread) {
dma_flushwritecache(mmc_dev(host->mmc), (void *)uidmaaddress, uidatalength);
fifoctrlreg.bit.FIFO_DIR = 1;
} else {
dma_flushreadcache(mmc_dev(host->mmc), (void *)uidmaaddress, uidatalength);
}
/* Flush cache in Des*/
dma_flushbidircache(mmc_dev(host->mmc), (void *)&vuisdio_destab[0],
SDIO_DES_WORD_SIZE<<2);
} else {
#if 0
for (i = 0; i < vsdio_seg_num[id]; i++) {
/* Flush cache in data DMA*/
if (!bisread) {
dma_flushwritecache(mmc_dev(host->mmc), (void *)(mmc_dev(host->mmc), (vuisdio_destab
[(i * SDIO_DES_WORD_SIZE) +
(SDIO_DES_LINE2_REG_OFS>>2)])),
vuisdio_destab[(i * SDIO_DES_WORD_SIZE +
SDIO_DES_LINE1_REG_OFS)>>2]);
fifoctrlreg.bit.FIFO_DIR = 1;
} else {
dma_flushreadcache(mmc_dev(host->mmc), (void *)(mmc_dev(host->mmc), (vuisdio_destab
[(i * SDIO_DES_WORD_SIZE) +
(SDIO_DES_LINE2_REG_OFS>>2)])),
vuisdio_destab[(i * SDIO_DES_WORD_SIZE +
SDIO_DES_LINE1_REG_OFS)>>2]);
}
}
#else
if (!bisread)
fifoctrlreg.bit.FIFO_DIR = 1;
else
fifoctrlreg.bit.FIFO_DIR = 0;
#endif
/* Flush cache in Des*/
dma_flushbidircache(mmc_dev(host->mmc), (void *)(&vuisdio_destab[0]),
(SDIO_DES_WORD_SIZE<<2)*SDIO_DES_TABLE_NUM);
}
#else
dmaaddrreg.reg = 0;
dmaaddrreg.bit.DRAM_ADDR = virt_to_phys((uint32_t *)uidmaaddress);
sdiohost_setreg(host, id, SDIO_DMA_START_ADDR_REG_OFS, dmaaddrreg.reg);
datalenreg.reg = 0;
datalenreg.bit.LENGTH = uidatalength;
sdiohost_setreg(host, id, SDIO_DATA_LENGTH_REG_OFS, datalenreg.reg);
fifoctrlreg.reg = 0;
/* Flush cache in DMA mode*/
if (!bisread) {
dma_flushwritecache(mmc_dev(host->mmc), (void *)uidmaaddress, uidatalength);
fifoctrlreg.bit.FIFO_DIR = 1;
} else {
dma_flushreadcache(mmc_dev(host->mmc), (void *)uidmaaddress, uidatalength);
}
#endif
fifoctrlreg.bit.FIFO_MODE = 1;
sdiohost_setreg(host, id, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
datactrlreg.reg = sdiohost_getreg(host, id, SDIO_DATA_CTRL_REG_OFS);
datactrlreg.bit.DATA_EN = 1;
sdiohost_setreg(host, id, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
fifoctrlreg.bit.FIFO_EN = 1;
sdiohost_setreg(host, id, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
}
/*
Setup SDIO controller data transfer in PIO mode.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] uidmaaddress buffer DRAM address
- possible value: 0x000_0000 ~ 0xFFF_FFFF
@param[in] uidatalength total transfer length
- possible value: 0x000_0001 ~ 0x3FF_FFFF
@param[in] bisread read/write mode
- @b TRUE: indicate data read transfer
- @b FALSE: indicate data write transfer
@return void
*/
void sdiohost_setupdatatransferpio(struct mmc_nvt_host *host, uint32_t id,
uint32_t uidmaaddress, uint32_t uidatalength, bool bisread)
{
union SDIO_DATA_CTRL_REG datactrlreg;
union SDIO_DATA_LENGTH_REG datalenreg;
union SDIO_FIFO_CONTROL_REG fifoctrlreg;
#if (!SDIO_SCATTER_DMA)
union SDIO_DMA_START_ADDR_REG dmaaddrreg;
#endif
uint32_t uibusclk;
/* dummy read for patch */
sdiohost_delayd(host, 2);
uibusclk = sdiohost_getbusclk(host, id);
if (uibusclk >= 48000000)
sdiohost_delayd(host, 3);
else if ((uibusclk >= 24000000) && (uibusclk < 48000000))
sdiohost_delayd(host, 6);
else if ((uibusclk >= 12000000) && (uibusclk < 24000000))
sdiohost_delayd(host, 9);
else
sdiohost_delayd(host, 21);
/* patch for sd fifo bug end */
datactrlreg.reg = sdiohost_getreg(host, id, SDIO_DATA_CTRL_REG_OFS);
datactrlreg.bit.DIS_SDIO_INT_PERIOD = 0;
datactrlreg.bit.DATA_EN = 1;
sdiohost_setreg(host, id, SDIO_DATA_CTRL_REG_OFS, datactrlreg.reg);
#if (!SDIO_SCATTER_DMA)
dmaaddrreg.reg = 0;
sdiohost_setreg(host, id, SDIO_DMA_START_ADDR_REG_OFS, dmaaddrreg.reg);
#endif
datalenreg.reg = 0;
datalenreg.bit.LENGTH = uidatalength;
sdiohost_setreg(host, id, SDIO_DATA_LENGTH_REG_OFS, datalenreg.reg);
fifoctrlreg.reg = 0;
if (!bisread)
fifoctrlreg.bit.FIFO_DIR = 1;
sdiohost_setreg(host, id, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
fifoctrlreg.bit.FIFO_EN = 1;
sdiohost_setreg(host, id, SDIO_FIFO_CONTROL_REG_OFS, fifoctrlreg.reg);
}
/*
Write SDIO data blocks.
@note This function should only be called in PIO mode.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] pbuf buffer DRAM address
@param[in] uiLength total length (block alignment)
@return
- @b E_OK: success
- @b E_SYS: data CRC or data timeout error
*/
int sdiohost_writeblock(struct mmc_nvt_host *host, uint32_t id, uint8_t *pbuf,
uint32_t uilength)
{
uint32_t uiwordcount, i, *pbufword;
uint32_t uifullcount, uiremaincount;
bool bwordalignment;
union SDIO_DATA_PORT_REG datareg;
union SDIO_FIFO_STATUS_REG fifostsreg;
uint32_t dstatus;
uiwordcount = (uilength + sizeof(uint32_t) - 1) / sizeof(uint32_t);
uifullcount = uiwordcount / SDIO_HOST_DATA_FIFO_DEPTH;
uiremaincount = uiwordcount % SDIO_HOST_DATA_FIFO_DEPTH;
pbufword = (uint32_t *)pbuf;
if ((uint32_t)pbuf & 0x3)
bwordalignment = FALSE;
else
bwordalignment = TRUE;
while (uifullcount) {
fifostsreg.reg = sdiohost_getreg(host, id,
SDIO_FIFO_STATUS_REG_OFS);
if (fifostsreg.bit.FIFO_EMPTY) {
if (bwordalignment == TRUE) {
/* Word alignment*/
for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
sdiohost_setreg(host, id,
SDIO_DATA_PORT_REG_OFS, *pbufword++);
}
} else {
/* Not word alignment*/
for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
datareg.reg = *pbuf++;
datareg.reg |= (*pbuf++) << 8;
datareg.reg |= (*pbuf++) << 16;
datareg.reg |= (*pbuf++) << 24;
sdiohost_setreg(host, id,
SDIO_DATA_PORT_REG_OFS, datareg.reg);
}
}
uifullcount--;
}
dstatus = sdiohost_getstatus(host, id);
if ((dstatus & SDIO_STATUS_REG_DATA_CRC_FAIL) || (dstatus & SDIO_STATUS_REG_DATA_TIMEOUT)) {
return E_SYS;
}
}
if (uiremaincount) {
while (1) {
fifostsreg.reg = sdiohost_getreg(host, id,
SDIO_FIFO_STATUS_REG_OFS);
if (fifostsreg.bit.FIFO_EMPTY)
break;
dstatus = sdiohost_getstatus(host, id);
if ((dstatus & SDIO_STATUS_REG_DATA_CRC_FAIL) || (dstatus & SDIO_STATUS_REG_DATA_TIMEOUT)) {
return E_SYS;
}
}
if (bwordalignment == TRUE) {
/* Word alignment*/
for (i = uiremaincount; i; i--) {
sdiohost_setreg(host, id,
SDIO_DATA_PORT_REG_OFS, *pbufword++);
}
} else {
/* Not word alignment*/
for (i = uiremaincount; i; i--) {
datareg.reg = *pbuf++;
datareg.reg |= (*pbuf++) << 8;
datareg.reg |= (*pbuf++) << 16;
datareg.reg |= (*pbuf++) << 24;
sdiohost_setreg(host, id,
SDIO_DATA_PORT_REG_OFS, datareg.reg);
}
}
}
return E_OK;
}
/*
Read SDIO data blocks.
@note This function should only be called in PIO mode.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[out] pbuf buffer DRAM address
@param[in] uiLength total length (block alignment)
@return
- @b E_OK: success
- @b E_SYS: data CRC or data timeout error
*/
int sdiohost_readblock(struct mmc_nvt_host *host, uint32_t id, uint8_t *pbuf,
uint32_t uilength)
{
uint32_t uiwordcount, i, *pbufword;
uint32_t uifullcount, uiremaincount;
bool bwordalignment;
union SDIO_DATA_PORT_REG datareg;
union SDIO_FIFO_STATUS_REG fifostsreg;
uint32_t dstatus;
uiwordcount = (uilength + sizeof(uint32_t) - 1) / sizeof(uint32_t);
uifullcount = uiwordcount / SDIO_HOST_DATA_FIFO_DEPTH;
uiremaincount = uiwordcount % SDIO_HOST_DATA_FIFO_DEPTH;
pbufword = (uint32_t *)pbuf;
if ((uint32_t)pbuf & 0x3)
bwordalignment = FALSE;
else
bwordalignment = TRUE;
while (uifullcount) {
fifostsreg.reg = sdiohost_getreg(host, id,
SDIO_FIFO_STATUS_REG_OFS);
if (fifostsreg.bit.FIFO_FULL) {
if (bwordalignment == TRUE) {
/* Word alignment*/
for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
*pbufword++ = sdiohost_getreg(host, id,
SDIO_DATA_PORT_REG_OFS);
}
} else {
/* Not word alignment*/
for (i = SDIO_HOST_DATA_FIFO_DEPTH; i; i--) {
datareg.reg = sdiohost_getreg(host, id,
SDIO_DATA_PORT_REG_OFS);
*pbuf++ = datareg.reg & 0xFF;
*pbuf++ = (datareg.reg>>8) & 0xFF;
*pbuf++ = (datareg.reg>>16) & 0xFF;
*pbuf++ = (datareg.reg>>24) & 0xFF;
}
}
uifullcount--;
}
dstatus = sdiohost_getstatus(host, id);
if ((dstatus & SDIO_STATUS_REG_DATA_CRC_FAIL) || (dstatus & SDIO_STATUS_REG_DATA_TIMEOUT)) {
return E_SYS;
}
}
if (uiremaincount) {
while (1) {
fifostsreg.reg = sdiohost_getreg(host, id,
SDIO_FIFO_STATUS_REG_OFS);
if (fifostsreg.bit.FIFO_CNT == uiremaincount)
break;
dstatus = sdiohost_getstatus(host, id);
if ((dstatus & SDIO_STATUS_REG_DATA_CRC_FAIL) || (dstatus & SDIO_STATUS_REG_DATA_TIMEOUT)) {
return E_SYS;
}
}
if (bwordalignment == TRUE) {
/* Word alignment*/
for (i = uiremaincount; i; i--) {
*pbufword++ = sdiohost_getreg(host, id,
SDIO_DATA_PORT_REG_OFS);
}
} else {
/* Not word alignment*/
for (i = uiremaincount; i; i--) {
datareg.reg = sdiohost_getreg(host, id,
SDIO_DATA_PORT_REG_OFS);
*pbuf++ = datareg.reg & 0xFF;
*pbuf++ = (datareg.reg>>8) & 0xFF;
*pbuf++ = (datareg.reg>>16) & 0xFF;
*pbuf++ = (datareg.reg>>24) & 0xFF;
}
}
}
return E_OK;
}
uint32_t sdiohost_setiointen(struct mmc_nvt_host *host, uint32_t id, bool ben)
{
union SDIO_INT_MASK_REG intenreg;
intenreg.reg = sdiohost_getreg(host, id, SDIO_INT_MASK_REG_OFS);
intenreg.bit.SDIO_INT_INT_EN = ben;
sdiohost_setreg(host, id, SDIO_INT_MASK_REG_OFS, intenreg.reg);
return TRUE;
}
bool sdiohost_getiointen(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_INT_MASK_REG intenreg;
intenreg.reg = sdiohost_getreg(host, id, SDIO_INT_MASK_REG_OFS);
if (intenreg.bit.SDIO_INT_INT_EN)
return TRUE;
else
return FALSE;
}
/** ********************************************************************
Private(in driver layer) SDIO host controller functions
***********************************************************************/
#if (SDIO_HOST_ID_COUNT > 1)
/*
Get SDIO controller register.
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO
- @b SDIO_HOST_ID_2: SDIO2
@param[in] offset register offset in SDIO controller (word alignment)
@return register value
*/
static REGVALUE sdiohost_getreg(struct mmc_nvt_host *host, uint32_t id,
uint32_t offset)
{
REGVALUE value;
value = nvt_readl(host->base + offset);
return value;
}
#endif
#if (SDIO_HOST_ID_COUNT > 1)
/*
Set SDIO controller register.
@param[in] id DIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@param[in] offset offset in SDIO controller (word alignment)
@param[in] value register value
@return void
*/
static void sdiohost_setreg(struct mmc_nvt_host *host, uint32_t id,
uint32_t offset, REGVALUE value)
{
nvt_writel(value, host->base + offset);
}
#endif
/*uint32_t Flag = 0;*/
#include <linux/delay.h>
void sdiohost_delay(uint32_t uius)
{
udelay(uius);
}
int sdiohost_sendsdcmd(struct mmc_nvt_host *host, uint32_t id, uint32_t cmdpart,
uint32_t param)
{
int status;
bool benintdetect = FALSE;
SDIO_HOST_RESPONSE rsptype = SDIO_HOST_RSP_NONE;
#if 0
pr_info("CMD%d arg %x %x\r\n",
cmdpart&(~(SDIO_CMD_REG_APP_CMD | SDIO_CMD_REG_VOLTAGE_SWITCH_DETECT
| SDIO_CMD_REG_ABORT | SDIO_CMD_REG_NEED_RSP | SDIO_CMD_REG_LONG_RSP
| SDIO_CMD_REG_RSP_TYPE2)),
param, cmdpart);
#endif
if ((cmdpart & SDIO_CMD_REG_LONG_RSP) == SDIO_CMD_REG_LONG_RSP) {
if (cmdpart & SDIO_CMD_REG_RSP_TYPE2)
rsptype = SDIO_HOST_RSP_LONG_TYPE2;
else
rsptype = SDIO_HOST_RSP_LONG;
} else if (cmdpart & SDIO_CMD_REG_VOLTAGE_SWITCH_DETECT) {
rsptype = SDIO_HOST_RSP_VOLT_DETECT;
} else if (cmdpart & SDIO_CMD_REG_NEED_RSP) {
if (cmdpart & SDIO_CMD_REG_RSP_TYPE2)
rsptype = SDIO_HOST_RSP_SHORT_TYPE2;
else
rsptype = SDIO_HOST_RSP_SHORT;
}
if (cmdpart & SDIO_CMD_REG_ABORT)
benintdetect = TRUE;
sdiohost_setarg(host, id, param);
/*pr_info("bEnIntDetect %d\r\n",bEnIntDetect);*/
status = sdiohost_sendcmd(host, id, cmdpart&SDIO_CMD_REG_INDEX,
rsptype, benintdetect);
return E_OK;
}
int sdiohost_open(struct mmc_nvt_host *host, uint32_t id, int voltage_switch)
{
sdiohost_setpaddriving(host, SDIO_MODE_DS);
sdiohost_resetdata(host, id);
sdiohost_resetasync(host, id);
if (nvt_get_chip_id() == CHIP_NA51055) {
sdiohost_setphysample(host, true, false);
} else {
sdiohost_setphysample(host, false, true);
}
/* Pass TG1.1-15: init freq should <=400Khz. */
/* Set to 399KHz to guarantee pass TG1.1-15 */
/*sdiohost_setbusclk(id, 399000, &ns);*/
/* Delay 1 ms (SD spec) after clock is outputted. */
/* (Delay 1024 us to reduce code size) */
sdiohost_delay(1024);
/*sdioHost_setClkGating(id, bClkGating);*/
/* restore clock gating*/
/* Interrupt Enable */
sdiohost_setinten(host, id,
SDIO_STATUS_REG_DATA_TIMEOUT |
SDIO_STATUS_REG_DATA_CRC_FAIL|
SDIO_STATUS_REG_DATA_CRC_OK |
SDIO_STATUS_REG_DATA_END |
SDIO_STATUS_REG_RSP_CRC_FAIL |
SDIO_STATUS_REG_RSP_TIMEOUT |
SDIO_STATUS_REG_RSP_CRC_OK |
SDIO_STATUS_REG_CMD_SEND);
sdiohost_setdatatimeout(host, id, 0x10000000);
sdiohost_enclockout(host, id);
return E_OK;
}
void sdiohost_setstatus(struct mmc_nvt_host *host, uint32_t id,
uint32_t status)
{
sdiohost_setreg(host, id, SDIO_STATUS_REG_OFS, status);
}
uint32_t sdiohost_getstatus(struct mmc_nvt_host *host, uint32_t id)
{
return sdiohost_getreg(host, id, SDIO_STATUS_REG_OFS);
}
void sdiohost_setpower(struct mmc_nvt_host *host, SDIO_HOST_SETPOWER_VOL vol)
{
PAD_POWER_STRUCT pad_power[1] = {0};
if (host->id == SDIO_HOST_ID_2) {
/*
pad_power->enable = 1;
pad_power->pad_power_id = PAD_POWERID_MC1;
if (vol == SDIO_HOST_SETPOWER_VOL_3P3)
pad_power->pad_power = PAD_3P3V;
else if (vol == SDIO_HOST_SETPOWER_VOL_1P8)
pad_power->pad_power = PAD_1P8V;
else
pad_power->enable = 0;
pad_set_power(pad_power);
*/
} else if (host->id == SDIO_HOST_ID_1) {
pad_power->enable = 1;
pad_power->pad_power_id = PAD_POWERID_MC0;
if (vol == SDIO_HOST_SETPOWER_VOL_3P3)
pad_power->pad_power = PAD_3P3V;
else if (vol == SDIO_HOST_SETPOWER_VOL_1P8)
pad_power->pad_power = PAD_1P8V;
else
pad_power->enable = 0;
pad_set_power(pad_power);
}
}
int sdiohost_getpower(struct mmc_nvt_host *host)
{
PAD_POWER_STRUCT pad_power[1] = {0};
if (host->id == SDIO_HOST_ID_2) {
/*
pad_power->pad_power_id = PAD_POWERID_MC1;
pad_get_power(pad_power);
return pad_power->pad_power;
*/
return 1;
} else if (host->id == SDIO_HOST_ID_1) {
pad_power->pad_power_id = PAD_POWERID_MC0;
pad_get_power(pad_power);
return pad_power->pad_power;
} else
return 1;
}
static int sdiohost_getpower_enable(struct mmc_nvt_host *host)
{
PAD_POWER_STRUCT pad_power[1] = {0};
if (host->id == SDIO_HOST_ID_2) {
/*
pad_power->pad_power_id = PAD_POWERID_MC1;
pad_get_power(pad_power);
return pad_power->enable;
*/
return 1;
} else if (host->id == SDIO_HOST_ID_1) {
pad_power->pad_power_id = PAD_POWERID_MC0;
pad_get_power(pad_power);
return pad_power->enable;
} else
return 1;
}
void sdiohost_power_switch(struct mmc_nvt_host *host, bool enable)
{
if (enable) {
if (!sdiohost_getpower_enable(host))
sdiohost_setpower(host, SDIO_HOST_SETPOWER_VOL_3P3);
} else
sdiohost_setpower(host, SDIO_HOST_SETPOWER_VOL_0);
}
void sdiohost_set_pads(struct mmc_nvt_host *host, PAD_PULL pulltype)
{
if (host->id == SDIO_HOST_ID_1) {
pad_set_pull_updown(PAD_PIN_CGPIO12, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO13, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO14, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO15, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO16, pulltype);
} else if (host->id == SDIO_HOST_ID_2) {
#if defined(CONFIG_NVT_IVOT_PLAT_NA51089)
if (host->pinmux_value & PIN_SDIO_CFG_2ND_PINMUX)
{
pad_set_pull_updown(PAD_PIN_SGPIO1, pulltype);
pad_set_pull_updown(PAD_PIN_SGPIO2, pulltype);
pad_set_pull_updown(PAD_PIN_SGPIO3, pulltype);
pad_set_pull_updown(PAD_PIN_SGPIO7, pulltype);
pad_set_pull_updown(PAD_PIN_SGPIO8, pulltype);
}
else if (host->pinmux_value & PIN_SDIO_CFG_3RD_PINMUX)
{
pad_set_pull_updown(PAD_PIN_DSIGPIO6, pulltype);
pad_set_pull_updown(PAD_PIN_DSIGPIO2, pulltype);
pad_set_pull_updown(PAD_PIN_DSIGPIO3, pulltype);
pad_set_pull_updown(PAD_PIN_DSIGPIO4, pulltype);
pad_set_pull_updown(PAD_PIN_DSIGPIO5, pulltype);
}
else
#endif
{
pad_set_pull_updown(PAD_PIN_CGPIO18, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO19, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO20, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO21, pulltype);
pad_set_pull_updown(PAD_PIN_CGPIO22, pulltype);
}
}
}
void sdiohost_set_gpios(struct mmc_nvt_host *host, bool dir_out, int value)
{
if (dir_out) {
if (host->id == SDIO_HOST_ID_1) {
gpio_direction_output(C_GPIO(11), value);
gpio_direction_output(C_GPIO(12), value);
gpio_direction_output(C_GPIO(13), value);
gpio_direction_output(C_GPIO(14), value);
gpio_direction_output(C_GPIO(15), value);
gpio_direction_output(C_GPIO(16), value);
} else if (host->id == SDIO_HOST_ID_2) {
#if defined(CONFIG_NVT_IVOT_PLAT_NA51089)
if (host->pinmux_value & PIN_SDIO_CFG_2ND_PINMUX)
{
gpio_direction_output(S_GPIO(0), value);
gpio_direction_output(S_GPIO(1), value);
gpio_direction_output(S_GPIO(2), value);
gpio_direction_output(S_GPIO(3), value);
gpio_direction_output(S_GPIO(7), value);
gpio_direction_output(S_GPIO(8), value);
}
else if (host->pinmux_value & PIN_SDIO_CFG_3RD_PINMUX)
{
gpio_direction_output(DSI_GPIO(6), value);
gpio_direction_output(DSI_GPIO(7), value);
gpio_direction_output(DSI_GPIO(2), value);
gpio_direction_output(DSI_GPIO(3), value);
gpio_direction_output(DSI_GPIO(4), value);
gpio_direction_output(DSI_GPIO(5), value);
}
else
#endif
{
gpio_direction_output(C_GPIO(17), value);
gpio_direction_output(C_GPIO(18), value);
gpio_direction_output(C_GPIO(19), value);
gpio_direction_output(C_GPIO(20), value);
gpio_direction_output(C_GPIO(21), value);
gpio_direction_output(C_GPIO(22), value);
}
}
} else {
if (host->id == SDIO_HOST_ID_1) {
gpio_direction_input(C_GPIO(11));
gpio_direction_input(C_GPIO(12));
gpio_direction_input(C_GPIO(13));
gpio_direction_input(C_GPIO(14));
gpio_direction_input(C_GPIO(15));
gpio_direction_input(C_GPIO(16));
} else if (host->id == SDIO_HOST_ID_2) {
#if defined(CONFIG_NVT_IVOT_PLAT_NA51089)
if (host->pinmux_value & PIN_SDIO_CFG_2ND_PINMUX)
{
gpio_direction_input(S_GPIO(0));
gpio_direction_input(S_GPIO(1));
gpio_direction_input(S_GPIO(2));
gpio_direction_input(S_GPIO(3));
gpio_direction_input(S_GPIO(7));
gpio_direction_input(S_GPIO(8));
}
else if (host->pinmux_value & PIN_SDIO_CFG_3RD_PINMUX)
{
gpio_direction_input(DSI_GPIO(6));
gpio_direction_input(DSI_GPIO(7));
gpio_direction_input(DSI_GPIO(2));
gpio_direction_input(DSI_GPIO(3));
gpio_direction_input(DSI_GPIO(4));
gpio_direction_input(DSI_GPIO(5));
}
else
#endif
{
gpio_direction_input(C_GPIO(17));
gpio_direction_input(C_GPIO(18));
gpio_direction_input(C_GPIO(19));
gpio_direction_input(C_GPIO(20));
gpio_direction_input(C_GPIO(21));
gpio_direction_input(C_GPIO(22));
}
}
}
}
void sdiohost_power_down(struct mmc_nvt_host *host)
{
if (host->id == SDIO_HOST_ID_1) {
int ret = 0;
PIN_GROUP_CONFIG pinmux_config[1];
pinmux_config->pin_function = PIN_FUNC_SDIO;
pinmux_config->config = 0x0;
ret = nvt_pinmux_update(pinmux_config, 1);
if (ret)
pr_err("Switch SDIO1 pinmux error\n");
sdiohost_set_pads(host, PAD_PULLDOWN);
sdiohost_set_gpios(host, true, 0);
} else if (host->id == SDIO_HOST_ID_2) {
int ret = 0;
PIN_GROUP_CONFIG pinmux_config[1];
pinmux_config->pin_function = PIN_FUNC_SDIO2;
pinmux_config->config = 0x0;
ret = nvt_pinmux_update(pinmux_config, 1);
if (ret)
pr_err("Switch SDIO2 pinmux error\n");
sdiohost_set_pads(host, PAD_PULLDOWN);
sdiohost_set_gpios(host, true, 0);
}
sdiohost_setpower(host, SDIO_HOST_SETPOWER_VOL_0);
if (host->cp_gpio)
gpio_set_value_cansleep(host->cp_gpio, !host->cp_gpio_value);
if (host->power_down_delay_ms > 0) {
msleep(host->power_down_delay_ms);
}
}
void sdiohost_power_up(struct mmc_nvt_host *host)
{
if (host->cp_gpio)
gpio_set_value_cansleep(host->cp_gpio, host->cp_gpio_value);
if (host->power_up_delay_ms > 0) {
msleep(host->power_up_delay_ms);
}
sdiohost_setpower(host, SDIO_HOST_SETPOWER_VOL_3P3);
if (host->id == SDIO_HOST_ID_1) {
int ret = 0;
PIN_GROUP_CONFIG pinmux_config[1];
sdiohost_set_gpios(host, false, 0);
pinmux_config->pin_function = PIN_FUNC_SDIO;
pinmux_config->config = host->pinmux_value;
ret = nvt_pinmux_update(pinmux_config, 1);
if (ret)
pr_err("Switch SDIO1 pinmux error\n");
sdiohost_set_pads(host, PAD_PULLUP);
} else if (host->id == SDIO_HOST_ID_2) {
int ret = 0;
PIN_GROUP_CONFIG pinmux_config[1];
sdiohost_set_gpios(host, false, 0);
pinmux_config->pin_function = PIN_FUNC_SDIO2;
pinmux_config->config = host->pinmux_value;
ret = nvt_pinmux_update(pinmux_config, 1);
if (ret)
pr_err("Switch SDIO2 pinmux error\n");
sdiohost_set_pads(host, PAD_PULLUP);
}
}
void sdiohost_power_cycle(struct mmc_nvt_host *host, uint32_t delay_ms)
{
gpio_set_value_cansleep(host->cp_gpio, !host->cp_gpio_value);
sdiohost_setpower(host, SDIO_HOST_SETPOWER_VOL_0);
sdiohost_power_down(host);
msleep(delay_ms);
sdiohost_power_up(host);
sdiohost_setpower(host, SDIO_HOST_SETPOWER_VOL_3P3);
gpio_set_value_cansleep(host->cp_gpio, host->cp_gpio_value);
}
/*
Get SDIO Data status
@param[in] id SDIO channel ID
- @b SDIO_HOST_ID_1: SDIO1
- @b SDIO_HOST_ID_2: SDIO2
@return TRUE: ready
FALSE: busy
*/
uint32_t sdiohost_getdata_status(struct mmc_nvt_host *host, uint32_t id)
{
union SDIO_BUS_STATUS_REG stsreg;
stsreg.reg = sdiohost_getreg(host, id, SDIO_BUS_STATUS_REG_OFS);
return stsreg.reg;
}
u32 sdiohost_set_voltage_switch(struct mmc_nvt_host *host)
{
union SDIO_DATA_CTRL_REG datactrl_reg;
union SDIO_VOL_SWITCH_TIMER_REG timer_reg;
union SDIO_INT_MASK_REG int_mask_reg;
host->voltage_switch_timeout = 0;
timer_reg.reg = clk_get_rate(host->clk)/1000;
sdiohost_setreg(host, host->id, SDIO_VOL_SWITCH_TIMER_REG_OFS, timer_reg.reg);
int_mask_reg.reg = sdiohost_getreg(host, host->id, SDIO_INT_MASK_REG_OFS);
int_mask_reg.bit.VOL_SWITCH_END_INT_EN = 1;
int_mask_reg.bit.VOL_SWITCH_TIMEOUT_INT_EN = 1;
sdiohost_setreg(host, host->id, SDIO_INT_MASK_REG_OFS, int_mask_reg.reg);
datactrl_reg.reg = sdiohost_getreg(host, host->id, SDIO_DATA_CTRL_REG_OFS);
datactrl_reg.bit.WAIT_VOL_SWITCH_EN = 1;
sdiohost_setreg(host, host->id, SDIO_DATA_CTRL_REG_OFS, datactrl_reg.reg);
wait_for_completion(&host->voltage_switch_complete);
int_mask_reg.reg = sdiohost_getreg(host, host->id, SDIO_INT_MASK_REG_OFS);
int_mask_reg.bit.VOL_SWITCH_END_INT_EN = 0;
int_mask_reg.bit.VOL_SWITCH_TIMEOUT_INT_EN = 0;
sdiohost_setreg(host, host->id, SDIO_INT_MASK_REG_OFS, int_mask_reg.reg);
if (host->voltage_switch_timeout) {
pr_err("voltage switch timeout\n");
if ((host->cp_gpio) && (host->id == SDIO_HOST_ID_1))
sdiohost_power_cycle(host, 500);
return -EIO;
} else
return 0;
}
void sdiohost_setphyphase_cmpen(struct mmc_nvt_host *host, u32 sel)
{
}
u32 sdiohost_getphydetout(struct mmc_nvt_host *host)
{
return 0;
}
int sdiohost_tuning_cmd(struct mmc_nvt_host *host, u32 opcode, bool print_pattern_err)
{
struct STRG_SEG_DES tuning_destable[1];
struct mmc_data *dummy_data;
u32 i, blocksize, timeout, status;
struct platform_device *pdev = to_platform_device(host->mmc->parent);
u8 *tuningbuf;
dma_addr_t tuningbuf_pa;
u8 golden_buf[64] = {
0xFF, 0x0F, 0xFF, 0x00, 0xFF, 0xCC, 0xC3, 0xCC,
0xC3, 0x3C, 0xCC, 0xFF, 0xFE, 0xFF, 0xFE, 0xEF,
0xFF, 0xDF, 0xFF, 0xDD, 0xFF, 0xFB, 0xFF, 0xFB,
0xBF, 0xFF, 0x7F, 0xFF, 0x77, 0xF7, 0xBD, 0xEF,
0xFF, 0xF0, 0xFF, 0xF0, 0x0F, 0xFC, 0xCC, 0x3C,
0xCC, 0x33, 0xCC, 0xCF, 0xFF, 0xEF, 0xFF, 0xEE,
0xFF, 0xFD, 0xFF, 0xFD, 0xDF, 0xFF, 0xBF, 0xFF,
0xBB, 0xFF, 0xF7, 0xFF, 0xF7, 0x7F, 0x7B, 0xDE
};
dummy_data = kzalloc(sizeof(struct mmc_data), GFP_KERNEL);
if (!dummy_data) {
pr_err("failed to allocate dummy_data\n");
goto read_error;
}
host->data = dummy_data;
tuningbuf = dmam_alloc_coherent(&pdev->dev, 128, &tuningbuf_pa, GFP_KERNEL);
/*Set timeout clock count and blk sz*/
blocksize = sdiohost_getblksize(host, host->id);
sdiohost_setblksize(host, host->id, 64);
timeout = (clk_get_rate(host->clk) / 1000) * 1000;
sdiohost_setdatatimeout(host, host->id, timeout);
tuning_destable[0].uisegaddr = tuningbuf_pa;
tuning_destable[0].uisegsize = 64;
sdiohost_setdestab(host->id, (uint32_t)tuning_destable, 1,
(uint32_t *)host->vuisdio_destab);
sdiohost_setupdatatransferdma(host, host->id, (u32)tuningbuf, 64,
SDIO_HOST_READ_DATA, host->vuisdio_destab);
if (sdiohost_sendsdcmd(host, host->id, opcode | SDIO_CMD_REG_NEED_RSP, 0)) {
sdiohost_resetdata(host, host->id);
pr_err("SDIO%d RCard: read tuning pattern error!!\r\n", host->id);
goto read_error;
}
if (wait_for_completion_timeout(&host->tuning_data_end, HZ*2) == 0)
goto read_error;
// Compare the data with expected tuning pattern
for (i = 0; i < 64; i++) {
if (tuningbuf[i] != golden_buf[i]) {
goto pattern_error;
}
}
status = host->status;
if ((status & SDIO_STATUS_REG_DATA_END) &&
(status & SDIO_STATUS_REG_DATA_CRC_OK))
pr_debug("Tuning pattern Data end or CRC ok\r\n");
sdiohost_setblksize(host, host->id, blocksize);
kfree(dummy_data);
dmam_free_coherent(&pdev->dev, 128, tuningbuf, tuningbuf_pa);
return E_OK;
pattern_error:
if (print_pattern_err) {
pr_err("Tuning pattern shoule be:\r\n");
for (i = 0; i < 64; i++) {
if (i != 0 && (i % 16 == 0)) {
pr_err("\n");
}
pr_err("%02x ", golden_buf[i]);
}
pr_err("nBut, pattern from card is:\n");
for (i = 0; i < 64; i++) {
if (i != 0 && (i % 16 == 0)) {
pr_err("\n");
}
pr_err("%02x ", tuningbuf[i]);
}
pr_err("\r\n");
}
read_error:
pr_err("SDIO%d Tuning error\r\n", host->id);
sdiohost_setblksize(host, host->id, blocksize);
kfree(dummy_data);
dmam_free_coherent(&pdev->dev, 128, tuningbuf, tuningbuf_pa);
return E_SYS;
}
void sdiohost_setphyclrdetval(struct mmc_nvt_host *host)
{
}
void sdiohost_setphydetch(struct mmc_nvt_host *host, u32 ch)
{
}
void sdiohost_setdlyphase_sel(struct mmc_nvt_host *host, u32 sel)
{
}
int sdiohost_getcmd(struct mmc_nvt_host *host)
{
return sdiohost_getreg(host, host->id, \
SDIO_CMD_REG_OFS) & SDIO_CMD_REG_INDEX;
}
void sdio_copy_info(struct mmc_nvt_host *info)
{
if (info->id == SDIO_HOST_ID_1)
drvdump_info[0] = *info;
else if (info->id == SDIO_HOST_ID_2)
drvdump_info[1] = *info;
else
drvdump_info[2] = *info;
}
void sdio_drvdump(void)
{
PAD_DRIVINGSINK driving;
PAD_POWER_STRUCT pad_power[1] = {0};
pr_info("SDIO1 Frequency %d Hz\n", (u32) clk_get_rate(drvdump_info[0].clk));
if (drvdump_info[0].cd_gpio)
pr_info("SDIO1 cd_gpio %d cd_detect_edge %d\n", drvdump_info[0].cd_gpio, drvdump_info[0].cd_detect_edge);
if (drvdump_info[0].cp_gpio)
pr_info("SDIO1 cp_gpio %d cp_gpio_value %d\n", drvdump_info[0].cp_gpio, drvdump_info[0].cp_gpio_value);
if (drvdump_info[0].max_voltage == SDIO_HOST_SETPOWER_VOL_1P8)
pr_info("SDIO1 max_voltage 1800 mV\n");
else
pr_info("SDIO1 max_voltage 3300 mV\n");
pad_power->pad_power_id = PAD_POWERID_MC0;
pad_get_power(pad_power);
if (pad_power->pad_power)
pr_info("SDIO1 pad_power 1800 mV\n");
else
pr_info("SDIO1 pad_power 3300 mV\n");
pr_info("SDIO1 voltage_switch %d\n", drvdump_info[0].voltage_switch);
pad_get_drivingsink(PAD_DS_CGPIO11, &driving);
if (driving & PAD_DRIVINGSINK_5MA)
pr_info("SDIO1 CLK driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_10MA)
pr_info("SDIO1 CLK driving 10 mA\n");
else if (driving & PAD_DRIVINGSINK_15MA)
pr_info("SDIO1 CLK driving 15 mA\n");
else if (driving & PAD_DRIVINGSINK_20MA)
pr_info("SDIO1 CLK driving 20 mA\n");
else if (driving & PAD_DRIVINGSINK_25MA)
pr_info("SDIO1 CLK driving 25 mA\n");
else if (driving & PAD_DRIVINGSINK_30MA)
pr_info("SDIO1 CLK driving 30 mA\n");
else if (driving & PAD_DRIVINGSINK_35MA)
pr_info("SDIO1 CLK driving 35 mA\n");
else if (driving & PAD_DRIVINGSINK_40MA)
pr_info("SDIO1 CLK driving 40 mA\n");
else
pr_info("SDIO1 CLK driving none mA\n");
pad_get_drivingsink(PAD_DS_CGPIO12, &driving);
if (driving & PAD_DRIVINGSINK_5MA)
pr_info("SDIO1 CMD driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_10MA)
pr_info("SDIO1 CMD driving 10 mA\n");
else if (driving & PAD_DRIVINGSINK_15MA)
pr_info("SDIO1 CMD driving 15 mA\n");
else if (driving & PAD_DRIVINGSINK_20MA)
pr_info("SDIO1 CMD driving 20 mA\n");
else if (driving & PAD_DRIVINGSINK_25MA)
pr_info("SDIO1 CMD driving 25 mA\n");
else if (driving & PAD_DRIVINGSINK_30MA)
pr_info("SDIO1 CMD driving 30 mA\n");
else if (driving & PAD_DRIVINGSINK_35MA)
pr_info("SDIO1 CMD driving 35 mA\n");
else if (driving & PAD_DRIVINGSINK_40MA)
pr_info("SDIO1 CMD driving 40 mA\n");
else
pr_info("SDIO1 CMD driving none mA\n");
pad_get_drivingsink(PAD_DS_CGPIO13, &driving);
if (driving & PAD_DRIVINGSINK_5MA)
pr_info("SDIO1 D0 driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_10MA)
pr_info("SDIO1 D0 driving 10 mA\n");
else if (driving & PAD_DRIVINGSINK_15MA)
pr_info("SDIO1 D0 driving 15 mA\n");
else if (driving & PAD_DRIVINGSINK_20MA)
pr_info("SDIO1 D0 driving 20 mA\n");
else if (driving & PAD_DRIVINGSINK_25MA)
pr_info("SDIO1 D0 driving 25 mA\n");
else if (driving & PAD_DRIVINGSINK_30MA)
pr_info("SDIO1 D0 driving 30 mA\n");
else if (driving & PAD_DRIVINGSINK_35MA)
pr_info("SDIO1 D0 driving 35 mA\n");
else if (driving & PAD_DRIVINGSINK_40MA)
pr_info("SDIO1 D0 driving 40 mA\n");
else
pr_info("SDIO1 D0 driving none mA\n");
pad_get_drivingsink(PAD_DS_CGPIO14, &driving);
if (driving & PAD_DRIVINGSINK_5MA)
pr_info("SDIO1 D1 driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_10MA)
pr_info("SDIO1 D1 driving 10 mA\n");
else if (driving & PAD_DRIVINGSINK_15MA)
pr_info("SDIO1 D1 driving 15 mA\n");
else if (driving & PAD_DRIVINGSINK_20MA)
pr_info("SDIO1 D1 driving 20 mA\n");
else if (driving & PAD_DRIVINGSINK_25MA)
pr_info("SDIO1 D1 driving 25 mA\n");
else if (driving & PAD_DRIVINGSINK_30MA)
pr_info("SDIO1 D1 driving 30 mA\n");
else if (driving & PAD_DRIVINGSINK_35MA)
pr_info("SDIO1 D1 driving 35 mA\n");
else if (driving & PAD_DRIVINGSINK_40MA)
pr_info("SDIO1 D1 driving 40 mA\n");
else
pr_info("SDIO1 D1 driving none mA\n");
pad_get_drivingsink(PAD_DS_CGPIO15, &driving);
if (driving & PAD_DRIVINGSINK_5MA)
pr_info("SDIO1 D2 driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_10MA)
pr_info("SDIO1 D2 driving 10 mA\n");
else if (driving & PAD_DRIVINGSINK_15MA)
pr_info("SDIO1 D2 driving 15 mA\n");
else if (driving & PAD_DRIVINGSINK_20MA)
pr_info("SDIO1 D2 driving 20 mA\n");
else if (driving & PAD_DRIVINGSINK_25MA)
pr_info("SDIO1 D2 driving 25 mA\n");
else if (driving & PAD_DRIVINGSINK_30MA)
pr_info("SDIO1 D2 driving 30 mA\n");
else if (driving & PAD_DRIVINGSINK_35MA)
pr_info("SDIO1 D2 driving 35 mA\n");
else if (driving & PAD_DRIVINGSINK_40MA)
pr_info("SDIO1 D2 driving 40 mA\n");
else
pr_info("SDIO1 D2 driving none mA\n");
pad_get_drivingsink(PAD_DS_CGPIO16, &driving);
if (driving & PAD_DRIVINGSINK_5MA)
pr_info("SDIO1 D3 driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_10MA)
pr_info("SDIO1 D3 driving 10 mA\n");
else if (driving & PAD_DRIVINGSINK_15MA)
pr_info("SDIO1 D3 driving 15 mA\n");
else if (driving & PAD_DRIVINGSINK_20MA)
pr_info("SDIO1 D3 driving 20 mA\n");
else if (driving & PAD_DRIVINGSINK_25MA)
pr_info("SDIO1 D3 driving 25 mA\n");
else if (driving & PAD_DRIVINGSINK_30MA)
pr_info("SDIO1 D3 driving 30 mA\n");
else if (driving & PAD_DRIVINGSINK_35MA)
pr_info("SDIO1 D3 driving 35 mA\n");
else if (driving & PAD_DRIVINGSINK_40MA)
pr_info("SDIO1 D3 driving 40 mA\n");
else
pr_info("SDIO1 D3 driving none mA\n");
pr_info("SDIO2 Frequency %d Hz\n", (u32) clk_get_rate(drvdump_info[1].clk));
if (drvdump_info[1].cd_gpio)
pr_info("SDIO2 cd_gpio %d cd_detect_edge %d\n", drvdump_info[1].cd_gpio, drvdump_info[1].cd_detect_edge);
if (drvdump_info[1].cp_gpio)
pr_info("SDIO2 cp_gpio %d cp_gpio_value %d\n", drvdump_info[1].cp_gpio, drvdump_info[1].cp_gpio_value);
pad_get_drivingsink(PAD_DS_CGPIO17, &driving);
if (driving & PAD_DRIVINGSINK_5MA)
pr_info("SDIO2 CLK driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_10MA)
pr_info("SDIO2 CLK driving 10 mA\n");
else if (driving & PAD_DRIVINGSINK_15MA)
pr_info("SDIO2 CLK driving 15 mA\n");
else if (driving & PAD_DRIVINGSINK_20MA)
pr_info("SDIO2 CLK driving 20 mA\n");
else if (driving & PAD_DRIVINGSINK_25MA)
pr_info("SDIO2 CLK driving 25 mA\n");
else if (driving & PAD_DRIVINGSINK_30MA)
pr_info("SDIO2 CLK driving 30 mA\n");
else if (driving & PAD_DRIVINGSINK_35MA)
pr_info("SDIO2 CLK driving 35 mA\n");
else if (driving & PAD_DRIVINGSINK_40MA)
pr_info("SDIO2 CLK driving 40 mA\n");
else
pr_info("SDIO2 CLK driving none mA\n");
pad_get_drivingsink(PAD_DS_CGPIO18, &driving);
if (nvt_get_chip_id() == CHIP_NA51055) {
if (driving & PAD_DRIVINGSINK_6MA)
pr_info("SDIO2 CMD driving 5 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 CMD driving 16 mA\n");
else
pr_info("SDIO2 CMD driving none mA\n");
} else {
if (driving & PAD_DRIVINGSINK_4MA)
pr_info("SDIO2 CMD driving 4 mA\n");
else if (driving & PAD_DRIVINGSINK_8MA)
pr_info("SDIO2 CMD driving 8 mA\n");
else if (driving & PAD_DRIVINGSINK_12MA)
pr_info("SDIO2 CMD driving 12 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 CMD driving 16 mA\n");
else
pr_info("SDIO2 CMD driving none mA\n");
}
pad_get_drivingsink(PAD_DS_CGPIO19, &driving);
if (nvt_get_chip_id() == CHIP_NA51055) {
if (driving & PAD_DRIVINGSINK_6MA)
pr_info("SDIO2 D0 driving 6 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D0 driving 16 mA\n");
else
pr_info("SDIO2 D0 driving none mA\n");
} else {
if (driving & PAD_DRIVINGSINK_4MA)
pr_info("SDIO2 D0 driving 4 mA\n");
else if (driving & PAD_DRIVINGSINK_8MA)
pr_info("SDIO2 D0 driving 8 mA\n");
else if (driving & PAD_DRIVINGSINK_12MA)
pr_info("SDIO2 D0 driving 12 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D0 driving 16 mA\n");
else
pr_info("SDIO2 D0 driving none mA\n");
}
pad_get_drivingsink(PAD_DS_CGPIO20, &driving);
if (nvt_get_chip_id() == CHIP_NA51055) {
if (driving & PAD_DRIVINGSINK_6MA)
pr_info("SDIO2 D1 driving 6 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D1 driving 16 mA\n");
else
pr_info("SDIO2 D1 driving none mA\n");
} else {
if (driving & PAD_DRIVINGSINK_4MA)
pr_info("SDIO2 D1 driving 4 mA\n");
else if (driving & PAD_DRIVINGSINK_8MA)
pr_info("SDIO2 D1 driving 8 mA\n");
else if (driving & PAD_DRIVINGSINK_12MA)
pr_info("SDIO2 D1 driving 12 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D1 driving 16 mA\n");
else
pr_info("SDIO2 D1 driving none mA\n");
}
pad_get_drivingsink(PAD_DS_CGPIO21, &driving);
if (nvt_get_chip_id() == CHIP_NA51055) {
if (driving & PAD_DRIVINGSINK_6MA)
pr_info("SDIO2 D2 driving 6 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D2 driving 16 mA\n");
else
pr_info("SDIO2 D2 driving none mA\n");
} else {
if (driving & PAD_DRIVINGSINK_4MA)
pr_info("SDIO2 D2 driving 4 mA\n");
else if (driving & PAD_DRIVINGSINK_8MA)
pr_info("SDIO2 D2 driving 8 mA\n");
else if (driving & PAD_DRIVINGSINK_12MA)
pr_info("SDIO2 D2 driving 12 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D2 driving 16 mA\n");
else
pr_info("SDIO2 D2 driving none mA\n");
}
pad_get_drivingsink(PAD_DS_CGPIO22, &driving);
if (nvt_get_chip_id() == CHIP_NA51055) {
if (driving & PAD_DRIVINGSINK_6MA)
pr_info("SDIO2 D3 driving 6 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D3 driving 16 mA\n");
else
pr_info("SDIO2 D3 driving none mA\n");
} else {
if (driving & PAD_DRIVINGSINK_4MA)
pr_info("SDIO2 D3 driving 4 mA\n");
else if (driving & PAD_DRIVINGSINK_8MA)
pr_info("SDIO2 D3 driving 8 mA\n");
else if (driving & PAD_DRIVINGSINK_12MA)
pr_info("SDIO2 D3 driving 12 mA\n");
else if (driving & PAD_DRIVINGSINK_16MA)
pr_info("SDIO2 D3 driving 16 mA\n");
else
pr_info("SDIO2 D3 driving none mA\n");
}
pr_info("SDIO3 Frequency %d Hz\n", (u32) clk_get_rate(drvdump_info[2].clk));
if (drvdump_info[2].cd_gpio)
pr_info("SDIO3 cd_gpio %d cd_detect_edge %d\n", drvdump_info[2].cd_gpio, drvdump_info[2].cd_detect_edge);
if (drvdump_info[2].cp_gpio)
pr_info("SDIO3 cp_gpio %d cp_gpio_value %d\n", drvdump_info[2].cp_gpio, drvdump_info[2].cp_gpio_value);
}
EXPORT_SYMBOL(sdio_drvdump);