/* * Sunxi SD/MMC host driver * * Copyright (C) 2015 AllWinnertech Ltd. * Author: lixiang * * 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. * * This program is distributed "as is" WITHOUT ANY WARRANTY of any * kind, whether express or implied; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __SUNXI_MMC_H__ #define __SUNXI_MMC_H__ #define DRIVER_NAME "sunxi-smhc" #define DRIVER_RIVISION "v0.6 2016-4-29 16:53" #define DRIVER_VERSION "SD/MMC/SDIO Host Controller Driver(" DRIVER_RIVISION ")" #if defined CONFIG_FPGA_V4_PLATFORM || defined CONFIG_FPGA_V7_PLATFORM #define MMC_FPGA #endif #define SMHC_DEVICE_ID (2) /*number of id in multi device*/ /*max blk count and size is limited by the SMHC_BLK_CFG register's max value*/ #define MAX_BLK_COUNT (0xFFFF) #define MAX_BLK_SIZE (0x800) /*#define MAX_DES_SIZE PAGE_SIZE*/ #define SUNXI_REQ_PAGE_SIZE (PAGE_SIZE*4) /*---------------------------------------------*/ /* registers define */ /*---------------------------------------------*/ #define SMHC_CMD_ARG2 (0x00) #define SMHC_BLK_CFG (0x04) #define SMHC_CMD_ARG1 (0x08) #define SMHC_CMD (0x0C) #define SMHC_RESP0 (0x10) #define SMHC_RESP1 (0x14) #define SMHC_RESP2 (0x18) #define SMHC_RESP3 (0x1C) #define SMHC_BUFF (0x20) #define SMHC_STA (0x24) #define SMHC_CTRL1 (0x28) #define SMHC_RST_CLK_CTRL (0x2C) #define SMHC_INT_STA (0x30) #define SMHC_INT_STA_EN (0x34) #define SMHC_INT_SIG_EN (0x38) #define SMHC_ACMD_ERR_CTRL2 (0x3C) #define SMHC_SET_ERR (0x50) #define SMHC_ADMA_ERR (0x54) #define SMHC_ADMA_ADDR (0x58) #define SMHC_CTRL3 (0x200) #define SMHC_CMD_ATTR (0x204) #define SMHC_TO_CTRL2 (0x208) #define SMHC_ATC (0x210) #define SMHC_RTC (0x214) #define SMHC_DITC0 (0x218) #define SMHC_DITC1 (0x21C) #define SMHC_TP0 (0x220) #define SMHC_TP1 (0x224) #define SMHC_CRC_STA (0x240) #define SMHC_TBC0 (0x244) #define SMHC_TBC1 (0x248) #define SMHC_BL (0x24C) #define SMHC_CEDBN (0x250) /*----------------------------------------*/ #define smhc_readl(host, reg) \ __raw_readl((host)->reg_base + reg) #define smhc_writel(host, reg, value) \ __raw_writel((value), (host)->reg_base + reg) #define smhc_readw(host, reg) \ __raw_readw((host)->reg_base + reg) #define smhc_writew(host, reg, value) \ __raw_writew((value), (host)->reg_base + reg) #define smhc_clr_bit(host, reg, bitmap) \ do { \ u32 tmp = smhc_readl(host, reg); \ tmp &= ~(bitmap); \ smhc_writel(host, reg, tmp); \ } while (0) #define smhc_set_bit(host, reg, bitmap) \ do { \ u32 tmp = smhc_readl(host, reg); \ tmp |= (bitmap); \ smhc_writel(host, reg, tmp); \ } while (0) /* control register bit field */ /*0x2c */ #define ResetAll (0x1U<<24) #define ResetCmd (0x1U<<25) #define ResetDat (0x1U<<26) #define SdclkEn (0x1U<<2) /*0x200 */ #define CPUAcessBuffEn (0x1U<<31) #define StopReadClkAtBlkGap (0x1U<<8) #define SWDebounceMode (0x1U<<5) #define DebounceEnb (0x1U<<4) #define CdDat3En (0x1U<<3) #define SdclkIdleCtrl (0x1U<<2) /* Struct for SMC Commands */ /*0x18 */ #define CMDType (0x3U<<22) #define DataExp (0x1U<<21) #define CheckRspIdx (0x1U<<20) #define CheckRspCRC (0x1U<<19) #define NoRsp (0x0U<<16) #define Rsp136 (0x1U<<16) #define Rsp48 (0x2U<<16) #define Rsp48b (0x3U<<16) #define SingleBlkTrans (0x0U<<5) #define MultiBlkTrans (0x1U<<5) #define Read (0x1U<<4) #define Write (0x0U<<4) #define AutoCmd12 (0x1U<<2) #define AutoCmd23 (0x2U<<2) #define BlkCntEn (0x1U<<1) #define DMAEn (0x1U<<0) /*0x204 */ #define SendInitSeq (0x1U<<4) #define DisableBoot (0x1U<<3) #define BootACKExp (0x1U<<2) #define AltBootMode (0x2U<<0) #define MandBootMode (0x1U<<0) /*0x03C */ #define Switch3v3To1v8 (0x1U<<19) #define DdrType (0x7<<16) #define DDR_SHIFT (16) /*0x24 */ #define CmdLineSta (0x1U<<24) #define Dat3LineSta (0x1U<<23) #define Dat2LineSta (0x1U<<22) #define Dat1LineSta (0x1U<<21) #define Dat0LineSta (0x1U<<20) #define WpPinSta (0x1U<<19) #define CdPinInvSta (0x1U<<18) #define CardStable (0x1U<<17) #define CardInsert (0x1U<<16) #define BuffRDEn (0x1U<<11) #define BuffWREn (0x1U<<10) #define RDTransActive (0x1U<<9) #define WRTransActive (0x1U<<8) #define DatLineActive (0x1U<<2) #define CmdInhibitDat (0x1U<<1) #define CmdInhibitCmd (0x1U<<0) #define BootDataStart (0x1U<<29) #define BootAckRcv (0x1U<<28) #define DSFOInt (0x1U<<30) #define DmaErrInt (0x1U<<25) #define AcmdErrInt (0x1U<<24) #define DatEndBitErrInt (0x1U<<22) #define DatCRCErrInt (0x1U<<21) #define DatTimeoutErrInt (0x1U<<20) #define CmdIdxErrInt (0x1U<<19) #define CmdEndBitErrInt (0x1U<<18) #define CmdCRCErrInt (0x1U<<17) #define CmdTimeoutErrInt (0x1U<<16) #define ErrInt (0x1U<<15) #define CardInt (0x1U<<8) #define CardRemoveInt (0x1U<<7) #define CardInsertInt (0x1U<<6) #define BuffRDRdyInt (0x1U<<5) #define BuffWRRdyInt (0x1U<<4) #define DmaInt (0x1U<<3) /*#define BlkGapEvtInt (0x1U<<2)*/ #define TransOverInt (0x1U<<1) #define CmdOverInt (0x1U<<0) #define TxDatIntBit (DmaInt | TransOverInt | DmaErrInt | ErrInt) #define RxDatIntBit (DmaInt | TransOverInt | DmaErrInt | ErrInt) #define DmaIntBit (DmaInt | DmaErrInt) #define ErrIntBit (0x437F0000) /*(0x1ff<<16)*/ #define DoneIntBit (TransOverInt|CmdOverInt) /*0x28 SMHC_CTRL1 bit field*/ #define Dma32BitSel (0x3<<3) #define DmaSel (0x3<<3) #define BusWidth (0x1<<1) #define ExtBusWidth (0x1<<5) /*0x3C Auto CMD Error Status */ #define NoAcmd12 (0x1U<<7) #define AcmdIdxErr (0x1U<<4) #define AcmdEndBitErr (0x1U<<3) #define AcmdCRCErr (0x1U<<2) #define AcmdTimeoutErr (0x1U<<1) #define NotIssueAcmd (0x0<<0) enum { ACT_NOP = 0, ACT_RSV, ACT_TRANS, ACT_LINK, }; enum { MAN_BOOT_MD = 0, ALT_BOOT_MD, }; struct sdhc_idma_des { /*=1: indicates this line of descriptor is effective. *=0: generate ADMA Error interrupt and stop ADMA to prevent runaway. */ u32 valid:1, /*=1: indicates end of descriptor. *The Transfer Complete Interrupt is generated *when the operation of the descriptor line is completed. */ end:1, /* *=1: generates DMA Interrupt *when the operation of the descriptor line is completed. */ int_en:1, : 1, /*00b: Nop, No Operation, Do not execute current line and go to next line.*/ act:2, /*01b: rsv, reserved, (Same as Nop. Do not execute current line *and go to next line.) */ /*10b: Tran, transfer data, Transfer data of one descriptor *line Transfer data of one descriptor line */ /*11b: Link, Link Descriptor, Link to another descriptor*/ : 10, length:16; u32 addr; }; struct sunxi_mmc_ctrl_regs { u32 rst_clk_ctrl; u32 int_sta_en; u32 to; u32 ctrl3; u32 int_sig_en; u32 ctrl1; u32 acmd_err_ctrl2; u32 atc; }; struct sunxi_mmc_host { struct mmc_host *mmc; struct reset_control *reset; /* IO mapping base */ void __iomem *reg_base; /* clock management */ struct clk *clk_ahb; struct clk *clk_mmc; struct clk *clk_rst; int (*sunxi_mmc_clk_set_rate)(struct sunxi_mmc_host *host, struct mmc_ios *ios); /* irq */ spinlock_t lock; int irq; u32 int_sum; u32 sdio_imask; /* dma */ u32 idma_des_size_bits; dma_addr_t sg_dma; void *sg_cpu; bool wait_dma; u32 dma_tl; u64 dma_mask; void (*sunxi_mmc_thld_ctl)(struct sunxi_mmc_host *host, struct mmc_ios *ios, struct mmc_data *data); struct mmc_request *mrq; struct mmc_request *mrq_busy; struct mmc_request *manual_stop_mrq; int ferror; u32 power_on; /* pinctrl handles */ struct pinctrl *pinctrl; struct pinctrl_state *pins_default; struct pinctrl_state *pins_sleep; /*sys node */ struct device_attribute maual_insert; struct device_attribute *dump_register; struct device_attribute dump_clk_dly; void (*sunxi_mmc_dump_dly_table)(struct sunxi_mmc_host *host); /* backup register structrue */ struct sunxi_mmc_ctrl_regs bak_regs; void (*sunxi_mmc_save_spec_reg)(struct sunxi_mmc_host *host); void (*sunxi_mmc_restore_spec_reg)(struct sunxi_mmc_host *host); void (*sunxi_mmc_set_acmda)(struct sunxi_mmc_host *host); void (*sunxi_mmc_shutdown)(struct platform_device *pdev); /*really controller id,no logic id */ int phy_index; u32 dat3_imask; /*no wait busy if wrtie end, only for customer need */ #define NO_MANUAL_WAIT_BUSY_WRITE_END 0x1 #define NO_REINIT_SHUTDOWN 0x2 #define CARD_PWR_GPIO_HIGH_ACTIVE 0x4 /*control specal function control,for customer need */ u32 ctl_spec_cap; int card_pwr_gpio; void *version_priv_dat; }; /*use to check ddr mode,not include hs400*/ #define sunxi_mmc_ddr_timing(it) \ (((it) == MMC_TIMING_UHS_DDR50) || ((it) == MMC_TIMING_MMC_DDR52)) #endif