363 lines
9.9 KiB
C
363 lines
9.9 KiB
C
/*
|
|
* Sunxi SD/MMC host driver
|
|
*
|
|
* Copyright (C) 2015 AllWinnertech Ltd.
|
|
* Author: lixiang <lixiang@allwinnertech>
|
|
*
|
|
* 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 <linux/clk.h>
|
|
#include <linux/clk/sunxi.h>
|
|
|
|
#include <linux/gpio.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/scatterlist.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/reset.h>
|
|
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/of_platform.h>
|
|
|
|
#include <linux/mmc/host.h>
|
|
#include <linux/mmc/sd.h>
|
|
#include <linux/mmc/sdio.h>
|
|
#include <linux/mmc/mmc.h>
|
|
#include <linux/mmc/core.h>
|
|
#include <linux/mmc/card.h>
|
|
#include <linux/mmc/slot-gpio.h>
|
|
|
|
#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
|