diff options
Diffstat (limited to 'drivers/mmc/host/sdhost.h')
| -rwxr-xr-x | drivers/mmc/host/sdhost.h | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhost.h b/drivers/mmc/host/sdhost.h new file mode 100755 index 00000000..a3d4fb2e --- /dev/null +++ b/drivers/mmc/host/sdhost.h @@ -0,0 +1,463 @@ +/* + * linux/drivers/mmc/host/sdhost.h - Secure Digital Host Controller Interface driver + * + * Copyright (C) 2014-2014 Jason.Wu(Jishuang.Wu), 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 as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + */ + +#ifndef __SDHOST_H_ +#define __SDHOST_H_ + +#include <linux/scatterlist.h> +#include <linux/compiler.h> +#include <linux/types.h> +#include <linux/io.h> + +#include <linux/clk.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/mmc/slot-gpio.h> + +/****************************************************************************** +* Controller flag +*------------------------------------------------------------------------------ +*/ +#define SDHOST_FLAG_ENABLE_ACMD12 0 +#define SDHOST_FLAG_ENABLE_ACMD23 0 +#define SDHOST_FLAG_USE_ADMA 1 +#define SDHOST_MAX_TIMEOUT 6 +/* + * Controller registers + */ +#if 1 +#define __local_writel(v,base,reg) writel((v),((base)+(reg))) +#define __local_writew(v,base,reg) writew((v),((base)+(reg))) +#define __local_writeb(v,base,reg) writeb((v),((base)+(reg))) +#define __local_readl(base,reg) readl(((base)+(reg))) +#define __local_readw(base,reg) readw(((base)+(reg))) +#define __local_readb(base,reg) readb(((base)+(reg))) +#else +static inline void __local_writel(uint32_t val, void __iomem * ioaddr, uint32_t reg) +{ + writel(val, (ioaddr + reg)); +} + +static inline void __local_writew(uint16_t val, void __iomem * ioaddr, uint32_t reg) +{ + uint32_t addr; + uint32_t value; + uint32_t ofst; + + ofst = (reg & 0x3) << 3; + addr = reg & (~((uint32_t) (0x3))); + value = readl((ioaddr + addr)); + value &= (~(((uint32_t) ((uint16_t) (-1))) << ofst)); + value |= (((uint32_t) val) << ofst); + writel(value, (ioaddr + addr)); +} + +static inline void __local_writeb(uint8_t val, void __iomem * ioaddr, uint32_t reg) +{ + uint32_t addr; + uint32_t value; + uint32_t ofst; + + ofst = (reg & 0x3) << 3; + addr = reg & (~((uint32_t) (0x3))); + value = readl((ioaddr + addr)); + value &= (~(((uint32_t) ((uint8_t) (-1))) << ofst)); + value |= (((uint32_t) val) << ofst); + writel(value, (ioaddr + addr)); +} + +static inline uint32_t __local_readl(void __iomem * ioaddr, uint32_t reg) +{ + return readl((ioaddr + reg)); +} + +static inline uint16_t __local_readw(void __iomem * ioaddr, uint32_t reg) +{ + uint32_t addr; + uint32_t value; + uint32_t ofst; + + ofst = (reg & 0x3) << 3; + addr = reg & (~((uint32_t) (0x3))); + value = readl((ioaddr + addr)); + return ((uint16_t) (value >> ofst)); + +} + +static inline uint8_t __local_readb(void __iomem * ioaddr, uint32_t reg) +{ + uint32_t addr; + uint32_t value; + uint32_t ofst; + + ofst = (reg & 0x3) << 3; + addr = reg & (~((uint32_t) (0x3))); + value = readl((ioaddr + addr)); + return ((uint8_t) (value >> ofst)); + +} +#endif + +#define _sdhost_writel(ioadr, val, reg) __local_writel((val), (ioadr),(reg)) +#define _sdhost_writew(ioadr, val, reg) __local_writew((val), (ioadr),(reg)) +#define _sdhost_writeb(ioadr, val, reg) __local_writeb((val), (ioadr),(reg)) +#define _sdhost_readl(ioadr, reg) __local_readl( (ioadr),(reg)) +#define _sdhost_readw(ioadr, reg) __local_readw( (ioadr),(reg)) +#define _sdhost_readb(ioadr, reg) __local_readb( (ioadr),(reg)) + +#define SDHOST_32_SYS_ADDR 0x00 +#define SDHOST_32_BLK_CNT 0x00 // used in cmd23 with ADMA in sdio 3.0 +#define SDHOST_16_BLK_CNT 0x06 +#define _sdhost_set_16_blk_cnt(ioadr,blkCnt)\ +{\ + __local_writew(((blkCnt)&0xFFFF),(ioadr),SDHOST_16_BLK_CNT);\ +} +#define _sdhost_set_32_blk_cnt(ioadr,blkCnt)\ +{\ + __local_writel(((blkCnt)&0xFFFFFFFF),(ioadr),SDHOST_32_BLK_CNT);\ +} +#define SDHOST_16_BLK_SIZE 0x04 +#define _sdhost_set_blk_size(ioadr,blkSize)\ +{\ + __local_writew(((blkSize)&0xFFF)|0x7000,(ioadr),SDHOST_16_BLK_SIZE);\ +} + +#define SDHOST_32_ARG 0x08 +#define SDHOST_16_TR_MODE 0x0C +#define __ACMD_DIS 0x00 +#define __ACMD12 0x01 +#define __ACMD23 0x02 +#define _sdhost_set_trans_mode(ioadr,ifMulti,ifRead,autoCmd,ifBlkCnt,ifDma) \ +{\ + __local_writew(\ + ((((ifMulti)?1:0)<<5)| \ + (((ifRead)?1:0)<<4)| \ + (((u16)(autoCmd))<<2)| \ + (((ifBlkCnt)?1:0)<<1)| \ + (((ifDma)?1:0)<<0)), \ + (ioadr) , SDHOST_16_TR_MODE \ + ); \ +} +#define SDHOST_16_CMD 0x0E +#define _CMD_INDEX_CHK 0x0010 +#define _CMD_CRC_CHK 0x0008 +#define _CMD_RSP_NONE 0x0000 +#define _CMD_RSP_136 0x0001 +#define _CMD_RSP_48 0x0002 +#define _CMD_RSP_48_BUSY 0x0003 +#define _RSP0 0 +#define _RSP1_5_6_7 _CMD_INDEX_CHK|_CMD_CRC_CHK|_CMD_RSP_48 +#define _RSP2 _CMD_CRC_CHK|_CMD_RSP_136 +#define _RSP3_4 _CMD_RSP_48 +#define _RSP1B_5B _CMD_INDEX_CHK|_CMD_CRC_CHK|_CMD_RSP_48_BUSY + +#define _sdhost_set_cmd(ioadr,cmd,ifHasData,rspType)\ +{\ + __local_writew(\ + ((((u16)(cmd))<<8)| \ + (((ifHasData)?1:0)<<5)| \ + ((u16)(rspType))), \ + (ioadr) , SDHOST_16_CMD \ + ); \ +} + +#define SDHOST_32_TR_MODE_AND_CMD 0x0C +#define _sdhost_set_trans_and_cmd(ioadr,ifMulti,ifRead,autoCmd,ifBlkCnt,ifDma,cmd,ifHasData,rspType) \ +{\ + __local_writel( \ + ((((ifMulti)?1:0)<<5)| \ + (((ifRead)?1:0)<<4)| \ + (((u32)(autoCmd))<<2)| \ + (((ifBlkCnt)?1:0)<<1)| \ + (((ifDma)?1:0)<<0)| \ + (((u32)(cmd))<<24)| \ + (((ifHasData)?1:0)<<21)| \ + (((u32)(rspType)) <<16)), \ + (ioadr), SDHOST_32_TR_MODE_AND_CMD\ + );\ +} + +#define SDHOST_32_RESPONSE 0x10 +#define SDHOST_32_PRES_STATE 0x24 +#define _DATA_LVL_MASK 0x00F00000 + +#define SDHOST_8_HOST_CTRL 0x28 +#define __8_BIT_MOD 0x20 +#define __4_BIT_MOD 0x02 +#define __1_BIT_MOD 0x00 +#define __SDMA_MOD 0x00 +#define __32ADMA_MOD 0x10 +#define __64ADMA_MOD 0x18 +#define __HISPD_MOD 0x04 +static inline void _sdhost_set_buswidth(void __iomem * ioadr, uint32_t buswidth) +{ + u8 ctrl = 0; + ctrl = __local_readb(ioadr, SDHOST_8_HOST_CTRL); + ctrl &= (~(__8_BIT_MOD | __4_BIT_MOD | __1_BIT_MOD)); + switch (buswidth) { + case MMC_BUS_WIDTH_1: + ctrl |= __1_BIT_MOD; + break; + case MMC_BUS_WIDTH_4: + ctrl |= __4_BIT_MOD; + break; + case MMC_BUS_WIDTH_8: + ctrl |= __8_BIT_MOD; + break; + default: + BUG_ON(1); + break; + } + __local_writeb(ctrl, ioadr, SDHOST_8_HOST_CTRL); +} + +static inline void _sdhost_set_DMA(void __iomem * ioadr, u8 dmaMod) +{ + u8 ctrl = 0; + ctrl = __local_readb(ioadr, SDHOST_8_HOST_CTRL); + ctrl &= (~(__SDMA_MOD | __32ADMA_MOD | __64ADMA_MOD)); + ctrl |= dmaMod; + __local_writeb(ctrl, ioadr, SDHOST_8_HOST_CTRL); +} + +static inline void _sdhost_enable_HISPD(void __iomem * ioadr) +{ + u8 ctrl = 0; + ctrl = __local_readb(ioadr, SDHOST_8_HOST_CTRL); + ctrl |= __HISPD_MOD; + __local_writeb(ctrl, ioadr, SDHOST_8_HOST_CTRL); +} + +//#define SDHOST_8_PWR_CTRL 0x29 // not used +#define SDHOST_8_BLK_GAP 0x2A // not used +#define SDHOST_8_WACKUP_CTRL 0x2B // not used + +#define SDHOST_16_CLK_CTRL 0x2C +#define __CLK_IN_EN 0x0001 +#define __CLK_IN_STABLE 0x0002 +#define __CLK_SD 0x0004 +#define __CLK_MAX_DIV 2046 +static inline void _sdhost_AllClk_off(void __iomem * ioadr) +{ + __local_writew(0, ioadr, SDHOST_16_CLK_CTRL); +} + +static inline void _sdhost_SDClk_off(void __iomem * ioadr) +{ + u16 ctrl = 0; + ctrl = __local_readw(ioadr, SDHOST_16_CLK_CTRL); + ctrl &= (~__CLK_SD); + __local_writew(ctrl, ioadr, SDHOST_16_CLK_CTRL); +} + +static inline void _sdhost_SDClk_on(void __iomem * ioadr) +{ + u16 ctrl = 0; + ctrl = __local_readw(ioadr, SDHOST_16_CLK_CTRL); + ctrl |= __CLK_SD; + __local_writew(ctrl, ioadr, SDHOST_16_CLK_CTRL); +} + +static inline uint32_t _sdhost_calcDiv(uint32_t baseClk, uint32_t clk) +{ + uint32_t N; + + if (baseClk <= clk) { + return 0; + } + + N = (uint32_t) (baseClk / clk); + N = (N >> 1); + if (N) + N--; + if ((baseClk / ((N + 1) << 1)) > clk) { + N++; + } + if (__CLK_MAX_DIV < N) { + N = __CLK_MAX_DIV; + } + return N; +} + +static inline void _sdhost_Clk_set_and_on(void __iomem * ioadr, uint32_t div) +{ + u16 ctrl = 0; + __local_writew(0, ioadr, SDHOST_16_CLK_CTRL); + ctrl |= (uint16_t) (((div & 0x300) >> 2) | ((div & 0xFF) << 8)); + ctrl |= __CLK_IN_EN; + __local_writew(ctrl, ioadr, SDHOST_16_CLK_CTRL); + while (!(__CLK_IN_STABLE & __local_readw(ioadr, SDHOST_16_CLK_CTRL))) ; +} + +#define SDHOST_8_TIMEOUT 0x2E +#define __DATA_TIMEOUT_MAX_VAL 0xe +static inline uint8_t _sdhost_calcTimeout(unsigned int clock, uint8_t TimeOutValue) +{ + unsigned target_timeout, current_timeout; + uint8_t count = 0; + target_timeout = TimeOutValue * clock; + current_timeout = 1 << 16; + while (target_timeout > current_timeout) { + count++; + current_timeout <<= 1; + } + count--; + if (count >= 0xF) + count = 0xE; + return count; +} + +#define SDHOST_8_RST 0x2F +#define _RST_ALL 0x01 +#define _RST_CMD 0x02 +#define _RST_DATA 0x04 +#define _RST_EMMC 0x08 // spredtrum define it byself +#define _sdhost_reset(ioadr,mask) \ +{\ + __local_writeb((_RST_EMMC|(mask)), (ioadr) , SDHOST_8_RST); \ + while (__local_readb((ioadr), SDHOST_8_RST) & (mask)); \ +} +/* spredtrum define it byself */ +#define _sdhost_reset_emmc(ioadr) \ +{\ + __local_writeb(0, (ioadr) , SDHOST_8_RST);\ + mdelay(2);\ + __local_writeb(_RST_EMMC, (ioadr) , SDHOST_8_RST);\ +} + +#define SDHOST_32_INT_ST 0x30 +#define SDHOST_32_INT_ST_EN 0x34 +#define SDHOST_32_INT_SIG_EN 0x38 +#define _INT_CMD_END 0x00000001 +#define _INT_TRAN_END 0x00000002 +#define _INT_DMA_END 0x00000008 +#define _INT_WR_RDY 0x00000010 // not used +#define _INT_RD_RDY 0x00000020 // not used +#define _INT_ERR 0x00008000 +#define _INT_ERR_CMD_TIMEOUT 0x00010000 +#define _INT_ERR_CMD_CRC 0x00020000 +#define _INT_ERR_CMD_END 0x00040000 +#define _INT_ERR_CMD_INDEX 0x00080000 +#define _INT_ERR_DATA_TIMEOUT 0x00100000 +#define _INT_ERR_DATA_CRC 0x00200000 +#define _INT_ERR_DATA_END 0x00400000 +#define _INT_ERR_CUR_LIMIT 0x00800000 +#define _INT_ERR_ACMD 0x01000000 +#define _INT_ERR_ADMA 0x02000000 + +// used in irq +#define _INT_FILTER_ERR_CMD (_INT_ERR_CMD_TIMEOUT|_INT_ERR_CMD_CRC|_INT_ERR_CMD_END|_INT_ERR_CMD_INDEX) +#define _INT_FILTER_ERR_DATA (_INT_ERR_DATA_TIMEOUT|_INT_ERR_DATA_CRC|_INT_ERR_DATA_END) +#define _INT_FILTER_ERR (_INT_ERR|_INT_FILTER_ERR_CMD|_INT_FILTER_ERR_DATA|_INT_ERR_ACMD|_INT_ERR_ADMA) +#define _INT_FILTER_NORMAL (_INT_CMD_END|_INT_TRAN_END) + +// used for setting +#define _DATA_FILTER_RD_SIGLE _INT_TRAN_END|_INT_DMA_END|_INT_ERR|_INT_ERR_DATA_TIMEOUT|_INT_ERR_DATA_CRC|_INT_ERR_DATA_END +#define _DATA_FILTER_RD_MULTI _INT_TRAN_END|_INT_DMA_END|_INT_ERR|_INT_ERR_DATA_TIMEOUT|_INT_ERR_DATA_CRC|_INT_ERR_DATA_END +#define _DATA_FILTER_WR_SIGLE _INT_TRAN_END|_INT_DMA_END|_INT_ERR|_INT_ERR_DATA_TIMEOUT|_INT_ERR_DATA_CRC +#define _DATA_FILTER_WR_MULT _INT_TRAN_END|_INT_DMA_END|_INT_ERR|_INT_ERR_DATA_TIMEOUT|_INT_ERR_DATA_CRC +#define _CMD_FILTER_R0 _INT_CMD_END +#define _CMD_FILTER_R2 _INT_CMD_END|_INT_ERR|_INT_ERR_CMD_TIMEOUT|_INT_ERR_CMD_CRC|_INT_ERR_CMD_END +#define _CMD_FILTER_R3 _INT_CMD_END|_INT_ERR|_INT_ERR_CMD_TIMEOUT|_INT_ERR_CMD_END +#define _CMD_FILTER_R1_R4_R5_R6_R7 _INT_CMD_END|_INT_ERR|_INT_ERR_CMD_TIMEOUT|_INT_ERR_CMD_CRC|_INT_ERR_CMD_END|_INT_ERR_CMD_INDEX +#define _CMD_FILTER_R1B _INT_CMD_END|_INT_ERR|_INT_ERR_CMD_TIMEOUT|_INT_ERR_CMD_CRC|_INT_ERR_CMD_END|_INT_ERR_CMD_INDEX|_INT_TRAN_END|_INT_ERR_DATA_TIMEOUT + +#define _sdhost_disableall_int(ioadr) \ +{\ + __local_writel(0x0, (ioadr) , SDHOST_32_INT_SIG_EN); \ + __local_writel(0x0, (ioadr) , SDHOST_32_INT_ST_EN); \ + __local_writel(0xFFFFFFFF, (ioadr) , SDHOST_32_INT_ST); \ +} +#define _sdhost_enable_int(ioadr,mask) \ +{\ + __local_writel((mask), (ioadr) , SDHOST_32_INT_ST_EN); \ + __local_writel((mask), (ioadr) , SDHOST_32_INT_SIG_EN); \ +} + +#define _sdhost_clear_int(ioadr,mask) \ +{\ + __local_writel((mask), (ioadr) , SDHOST_32_INT_ST); \ +} + +#define SDHOST_16_ACMD_ERR 0x3C + +#define SDHOST_16_HOST_CTRL_2 0x3E +#define __TIMING_MODE_SDR12 0x0000 +#define __TIMING_MODE_SDR25 0x0001 +#define __TIMING_MODE_SDR50 0x0002 +#define __TIMING_MODE_SDR104 0x0003 +#define __TIMING_MODE_DDR50 0x0004 +#define __TIMING_MODE_SDR200 0x0005 +#define _sdhost_set_UHS_mode(ioadr,mode) \ +{\ + __local_writew((mode),(ioadr),SDHOST_16_HOST_CTRL_2);\ +} + +#define SDHOST_MAX_CUR 1020 + +// following register is defined by spreadtrum self.It is not standard register of SDIO. +#define _sdhost_set_delay(ioadr,writeDelay,readPosDelay,readNegDelay) \ +{\ + __local_writel((writeDelay),(ioadr),0x80);\ + __local_writel((readPosDelay),(ioadr),0x84);\ + __local_writel((readNegDelay),(ioadr),0x88);\ +} + +/****************************************************************************** +* Controller block structure +*------------------------------------------------------------------------------ +*/ + +struct sdhost_host { +//--globe resource--- + spinlock_t lock; + struct mmc_host *mmc; +//--basic resource--- + void __iomem *ioaddr; + int irq; + const char *deviceName; + int detect_gpio; + const char *SD_Pwr_Name; + const char *_1_8V_signal_Name; + uint32_t ocr_avail; + char *clkName; + char *clkParentName; + uint32_t base_clk; + uint32_t caps; + uint32_t caps2; + uint32_t pm_caps; + uint32_t writeDelay; + uint32_t readPosDelay; + uint32_t readNegDelay; +//--extern resource getted by base resource--- + uint64_t dma_mask; + uint8_t dataTimeOutVal; + struct regulator *SD_pwr; + struct regulator *_1_8V_signal; + uint32_t signal_default_Voltage; + bool _1_8V_signal_enabled; + struct clk *clk; + struct clk *clk_parent; + struct tasklet_struct finish_tasklet; + struct timer_list timer; +//--runtime param--- + uint32_t int_filter; + struct mmc_ios ios; + struct mmc_request *mrq; /* Current request */ + struct mmc_command *cmd; /* Current command */ + uint16_t autoCmdMode; +//--debugfs--- + struct dentry *debugfs_root; +}; + +#endif /* __SDHOST_H_ */ |
