120848903SChaotian Jing /* 220848903SChaotian Jing * Copyright (c) 2014-2015 MediaTek Inc. 320848903SChaotian Jing * Author: Chaotian.Jing <chaotian.jing@mediatek.com> 420848903SChaotian Jing * 520848903SChaotian Jing * This program is free software; you can redistribute it and/or modify 620848903SChaotian Jing * it under the terms of the GNU General Public License version 2 as 720848903SChaotian Jing * published by the Free Software Foundation. 820848903SChaotian Jing * 920848903SChaotian Jing * This program is distributed in the hope that it will be useful, 1020848903SChaotian Jing * but WITHOUT ANY WARRANTY; without even the implied warranty of 1120848903SChaotian Jing * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1220848903SChaotian Jing * GNU General Public License for more details. 1320848903SChaotian Jing */ 1420848903SChaotian Jing 1520848903SChaotian Jing #include <linux/module.h> 1620848903SChaotian Jing #include <linux/clk.h> 1720848903SChaotian Jing #include <linux/delay.h> 1820848903SChaotian Jing #include <linux/dma-mapping.h> 1920848903SChaotian Jing #include <linux/ioport.h> 2020848903SChaotian Jing #include <linux/irq.h> 2120848903SChaotian Jing #include <linux/of_address.h> 2220848903SChaotian Jing #include <linux/of_irq.h> 2320848903SChaotian Jing #include <linux/of_gpio.h> 2420848903SChaotian Jing #include <linux/pinctrl/consumer.h> 2520848903SChaotian Jing #include <linux/platform_device.h> 2620848903SChaotian Jing #include <linux/regulator/consumer.h> 2720848903SChaotian Jing #include <linux/spinlock.h> 2820848903SChaotian Jing 2920848903SChaotian Jing #include <linux/mmc/card.h> 3020848903SChaotian Jing #include <linux/mmc/core.h> 3120848903SChaotian Jing #include <linux/mmc/host.h> 3220848903SChaotian Jing #include <linux/mmc/mmc.h> 3320848903SChaotian Jing #include <linux/mmc/sd.h> 3420848903SChaotian Jing #include <linux/mmc/sdio.h> 3520848903SChaotian Jing 3620848903SChaotian Jing #define MAX_BD_NUM 1024 3720848903SChaotian Jing 3820848903SChaotian Jing /*--------------------------------------------------------------------------*/ 3920848903SChaotian Jing /* Common Definition */ 4020848903SChaotian Jing /*--------------------------------------------------------------------------*/ 4120848903SChaotian Jing #define MSDC_BUS_1BITS 0x0 4220848903SChaotian Jing #define MSDC_BUS_4BITS 0x1 4320848903SChaotian Jing #define MSDC_BUS_8BITS 0x2 4420848903SChaotian Jing 4520848903SChaotian Jing #define MSDC_BURST_64B 0x6 4620848903SChaotian Jing 4720848903SChaotian Jing /*--------------------------------------------------------------------------*/ 4820848903SChaotian Jing /* Register Offset */ 4920848903SChaotian Jing /*--------------------------------------------------------------------------*/ 5020848903SChaotian Jing #define MSDC_CFG 0x0 5120848903SChaotian Jing #define MSDC_IOCON 0x04 5220848903SChaotian Jing #define MSDC_PS 0x08 5320848903SChaotian Jing #define MSDC_INT 0x0c 5420848903SChaotian Jing #define MSDC_INTEN 0x10 5520848903SChaotian Jing #define MSDC_FIFOCS 0x14 5620848903SChaotian Jing #define SDC_CFG 0x30 5720848903SChaotian Jing #define SDC_CMD 0x34 5820848903SChaotian Jing #define SDC_ARG 0x38 5920848903SChaotian Jing #define SDC_STS 0x3c 6020848903SChaotian Jing #define SDC_RESP0 0x40 6120848903SChaotian Jing #define SDC_RESP1 0x44 6220848903SChaotian Jing #define SDC_RESP2 0x48 6320848903SChaotian Jing #define SDC_RESP3 0x4c 6420848903SChaotian Jing #define SDC_BLK_NUM 0x50 6520848903SChaotian Jing #define SDC_ACMD_RESP 0x80 6620848903SChaotian Jing #define MSDC_DMA_SA 0x90 6720848903SChaotian Jing #define MSDC_DMA_CTRL 0x98 6820848903SChaotian Jing #define MSDC_DMA_CFG 0x9c 6920848903SChaotian Jing #define MSDC_PATCH_BIT 0xb0 7020848903SChaotian Jing #define MSDC_PATCH_BIT1 0xb4 7120848903SChaotian Jing #define MSDC_PAD_TUNE 0xec 7220848903SChaotian Jing 7320848903SChaotian Jing /*--------------------------------------------------------------------------*/ 7420848903SChaotian Jing /* Register Mask */ 7520848903SChaotian Jing /*--------------------------------------------------------------------------*/ 7620848903SChaotian Jing 7720848903SChaotian Jing /* MSDC_CFG mask */ 7820848903SChaotian Jing #define MSDC_CFG_MODE (0x1 << 0) /* RW */ 7920848903SChaotian Jing #define MSDC_CFG_CKPDN (0x1 << 1) /* RW */ 8020848903SChaotian Jing #define MSDC_CFG_RST (0x1 << 2) /* RW */ 8120848903SChaotian Jing #define MSDC_CFG_PIO (0x1 << 3) /* RW */ 8220848903SChaotian Jing #define MSDC_CFG_CKDRVEN (0x1 << 4) /* RW */ 8320848903SChaotian Jing #define MSDC_CFG_BV18SDT (0x1 << 5) /* RW */ 8420848903SChaotian Jing #define MSDC_CFG_BV18PSS (0x1 << 6) /* R */ 8520848903SChaotian Jing #define MSDC_CFG_CKSTB (0x1 << 7) /* R */ 8620848903SChaotian Jing #define MSDC_CFG_CKDIV (0xff << 8) /* RW */ 8720848903SChaotian Jing #define MSDC_CFG_CKMOD (0x3 << 16) /* RW */ 8820848903SChaotian Jing 8920848903SChaotian Jing /* MSDC_IOCON mask */ 9020848903SChaotian Jing #define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */ 9120848903SChaotian Jing #define MSDC_IOCON_RSPL (0x1 << 1) /* RW */ 9220848903SChaotian Jing #define MSDC_IOCON_DSPL (0x1 << 2) /* RW */ 9320848903SChaotian Jing #define MSDC_IOCON_DDLSEL (0x1 << 3) /* RW */ 9420848903SChaotian Jing #define MSDC_IOCON_DDR50CKD (0x1 << 4) /* RW */ 9520848903SChaotian Jing #define MSDC_IOCON_DSPLSEL (0x1 << 5) /* RW */ 9620848903SChaotian Jing #define MSDC_IOCON_W_DSPL (0x1 << 8) /* RW */ 9720848903SChaotian Jing #define MSDC_IOCON_D0SPL (0x1 << 16) /* RW */ 9820848903SChaotian Jing #define MSDC_IOCON_D1SPL (0x1 << 17) /* RW */ 9920848903SChaotian Jing #define MSDC_IOCON_D2SPL (0x1 << 18) /* RW */ 10020848903SChaotian Jing #define MSDC_IOCON_D3SPL (0x1 << 19) /* RW */ 10120848903SChaotian Jing #define MSDC_IOCON_D4SPL (0x1 << 20) /* RW */ 10220848903SChaotian Jing #define MSDC_IOCON_D5SPL (0x1 << 21) /* RW */ 10320848903SChaotian Jing #define MSDC_IOCON_D6SPL (0x1 << 22) /* RW */ 10420848903SChaotian Jing #define MSDC_IOCON_D7SPL (0x1 << 23) /* RW */ 10520848903SChaotian Jing #define MSDC_IOCON_RISCSZ (0x3 << 24) /* RW */ 10620848903SChaotian Jing 10720848903SChaotian Jing /* MSDC_PS mask */ 10820848903SChaotian Jing #define MSDC_PS_CDEN (0x1 << 0) /* RW */ 10920848903SChaotian Jing #define MSDC_PS_CDSTS (0x1 << 1) /* R */ 11020848903SChaotian Jing #define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */ 11120848903SChaotian Jing #define MSDC_PS_DAT (0xff << 16) /* R */ 11220848903SChaotian Jing #define MSDC_PS_CMD (0x1 << 24) /* R */ 11320848903SChaotian Jing #define MSDC_PS_WP (0x1 << 31) /* R */ 11420848903SChaotian Jing 11520848903SChaotian Jing /* MSDC_INT mask */ 11620848903SChaotian Jing #define MSDC_INT_MMCIRQ (0x1 << 0) /* W1C */ 11720848903SChaotian Jing #define MSDC_INT_CDSC (0x1 << 1) /* W1C */ 11820848903SChaotian Jing #define MSDC_INT_ACMDRDY (0x1 << 3) /* W1C */ 11920848903SChaotian Jing #define MSDC_INT_ACMDTMO (0x1 << 4) /* W1C */ 12020848903SChaotian Jing #define MSDC_INT_ACMDCRCERR (0x1 << 5) /* W1C */ 12120848903SChaotian Jing #define MSDC_INT_DMAQ_EMPTY (0x1 << 6) /* W1C */ 12220848903SChaotian Jing #define MSDC_INT_SDIOIRQ (0x1 << 7) /* W1C */ 12320848903SChaotian Jing #define MSDC_INT_CMDRDY (0x1 << 8) /* W1C */ 12420848903SChaotian Jing #define MSDC_INT_CMDTMO (0x1 << 9) /* W1C */ 12520848903SChaotian Jing #define MSDC_INT_RSPCRCERR (0x1 << 10) /* W1C */ 12620848903SChaotian Jing #define MSDC_INT_CSTA (0x1 << 11) /* R */ 12720848903SChaotian Jing #define MSDC_INT_XFER_COMPL (0x1 << 12) /* W1C */ 12820848903SChaotian Jing #define MSDC_INT_DXFER_DONE (0x1 << 13) /* W1C */ 12920848903SChaotian Jing #define MSDC_INT_DATTMO (0x1 << 14) /* W1C */ 13020848903SChaotian Jing #define MSDC_INT_DATCRCERR (0x1 << 15) /* W1C */ 13120848903SChaotian Jing #define MSDC_INT_ACMD19_DONE (0x1 << 16) /* W1C */ 13220848903SChaotian Jing #define MSDC_INT_DMA_BDCSERR (0x1 << 17) /* W1C */ 13320848903SChaotian Jing #define MSDC_INT_DMA_GPDCSERR (0x1 << 18) /* W1C */ 13420848903SChaotian Jing #define MSDC_INT_DMA_PROTECT (0x1 << 19) /* W1C */ 13520848903SChaotian Jing 13620848903SChaotian Jing /* MSDC_INTEN mask */ 13720848903SChaotian Jing #define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */ 13820848903SChaotian Jing #define MSDC_INTEN_CDSC (0x1 << 1) /* RW */ 13920848903SChaotian Jing #define MSDC_INTEN_ACMDRDY (0x1 << 3) /* RW */ 14020848903SChaotian Jing #define MSDC_INTEN_ACMDTMO (0x1 << 4) /* RW */ 14120848903SChaotian Jing #define MSDC_INTEN_ACMDCRCERR (0x1 << 5) /* RW */ 14220848903SChaotian Jing #define MSDC_INTEN_DMAQ_EMPTY (0x1 << 6) /* RW */ 14320848903SChaotian Jing #define MSDC_INTEN_SDIOIRQ (0x1 << 7) /* RW */ 14420848903SChaotian Jing #define MSDC_INTEN_CMDRDY (0x1 << 8) /* RW */ 14520848903SChaotian Jing #define MSDC_INTEN_CMDTMO (0x1 << 9) /* RW */ 14620848903SChaotian Jing #define MSDC_INTEN_RSPCRCERR (0x1 << 10) /* RW */ 14720848903SChaotian Jing #define MSDC_INTEN_CSTA (0x1 << 11) /* RW */ 14820848903SChaotian Jing #define MSDC_INTEN_XFER_COMPL (0x1 << 12) /* RW */ 14920848903SChaotian Jing #define MSDC_INTEN_DXFER_DONE (0x1 << 13) /* RW */ 15020848903SChaotian Jing #define MSDC_INTEN_DATTMO (0x1 << 14) /* RW */ 15120848903SChaotian Jing #define MSDC_INTEN_DATCRCERR (0x1 << 15) /* RW */ 15220848903SChaotian Jing #define MSDC_INTEN_ACMD19_DONE (0x1 << 16) /* RW */ 15320848903SChaotian Jing #define MSDC_INTEN_DMA_BDCSERR (0x1 << 17) /* RW */ 15420848903SChaotian Jing #define MSDC_INTEN_DMA_GPDCSERR (0x1 << 18) /* RW */ 15520848903SChaotian Jing #define MSDC_INTEN_DMA_PROTECT (0x1 << 19) /* RW */ 15620848903SChaotian Jing 15720848903SChaotian Jing /* MSDC_FIFOCS mask */ 15820848903SChaotian Jing #define MSDC_FIFOCS_RXCNT (0xff << 0) /* R */ 15920848903SChaotian Jing #define MSDC_FIFOCS_TXCNT (0xff << 16) /* R */ 16020848903SChaotian Jing #define MSDC_FIFOCS_CLR (0x1 << 31) /* RW */ 16120848903SChaotian Jing 16220848903SChaotian Jing /* SDC_CFG mask */ 16320848903SChaotian Jing #define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */ 16420848903SChaotian Jing #define SDC_CFG_INSWKUP (0x1 << 1) /* RW */ 16520848903SChaotian Jing #define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */ 16620848903SChaotian Jing #define SDC_CFG_SDIO (0x1 << 19) /* RW */ 16720848903SChaotian Jing #define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */ 16820848903SChaotian Jing #define SDC_CFG_INTATGAP (0x1 << 21) /* RW */ 16920848903SChaotian Jing #define SDC_CFG_DTOC (0xff << 24) /* RW */ 17020848903SChaotian Jing 17120848903SChaotian Jing /* SDC_STS mask */ 17220848903SChaotian Jing #define SDC_STS_SDCBUSY (0x1 << 0) /* RW */ 17320848903SChaotian Jing #define SDC_STS_CMDBUSY (0x1 << 1) /* RW */ 17420848903SChaotian Jing #define SDC_STS_SWR_COMPL (0x1 << 31) /* RW */ 17520848903SChaotian Jing 17620848903SChaotian Jing /* MSDC_DMA_CTRL mask */ 17720848903SChaotian Jing #define MSDC_DMA_CTRL_START (0x1 << 0) /* W */ 17820848903SChaotian Jing #define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */ 17920848903SChaotian Jing #define MSDC_DMA_CTRL_RESUME (0x1 << 2) /* W */ 18020848903SChaotian Jing #define MSDC_DMA_CTRL_MODE (0x1 << 8) /* RW */ 18120848903SChaotian Jing #define MSDC_DMA_CTRL_LASTBUF (0x1 << 10) /* RW */ 18220848903SChaotian Jing #define MSDC_DMA_CTRL_BRUSTSZ (0x7 << 12) /* RW */ 18320848903SChaotian Jing 18420848903SChaotian Jing /* MSDC_DMA_CFG mask */ 18520848903SChaotian Jing #define MSDC_DMA_CFG_STS (0x1 << 0) /* R */ 18620848903SChaotian Jing #define MSDC_DMA_CFG_DECSEN (0x1 << 1) /* RW */ 18720848903SChaotian Jing #define MSDC_DMA_CFG_AHBHPROT2 (0x2 << 8) /* RW */ 18820848903SChaotian Jing #define MSDC_DMA_CFG_ACTIVEEN (0x2 << 12) /* RW */ 18920848903SChaotian Jing #define MSDC_DMA_CFG_CS12B16B (0x1 << 16) /* RW */ 19020848903SChaotian Jing 19120848903SChaotian Jing /* MSDC_PATCH_BIT mask */ 19220848903SChaotian Jing #define MSDC_PATCH_BIT_ODDSUPP (0x1 << 1) /* RW */ 19320848903SChaotian Jing #define MSDC_INT_DAT_LATCH_CK_SEL (0x7 << 7) 19420848903SChaotian Jing #define MSDC_CKGEN_MSDC_DLY_SEL (0x1f << 10) 19520848903SChaotian Jing #define MSDC_PATCH_BIT_IODSSEL (0x1 << 16) /* RW */ 19620848903SChaotian Jing #define MSDC_PATCH_BIT_IOINTSEL (0x1 << 17) /* RW */ 19720848903SChaotian Jing #define MSDC_PATCH_BIT_BUSYDLY (0xf << 18) /* RW */ 19820848903SChaotian Jing #define MSDC_PATCH_BIT_WDOD (0xf << 22) /* RW */ 19920848903SChaotian Jing #define MSDC_PATCH_BIT_IDRTSEL (0x1 << 26) /* RW */ 20020848903SChaotian Jing #define MSDC_PATCH_BIT_CMDFSEL (0x1 << 27) /* RW */ 20120848903SChaotian Jing #define MSDC_PATCH_BIT_INTDLSEL (0x1 << 28) /* RW */ 20220848903SChaotian Jing #define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */ 20320848903SChaotian Jing #define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */ 20420848903SChaotian Jing 20520848903SChaotian Jing #define REQ_CMD_EIO (0x1 << 0) 20620848903SChaotian Jing #define REQ_CMD_TMO (0x1 << 1) 20720848903SChaotian Jing #define REQ_DAT_ERR (0x1 << 2) 20820848903SChaotian Jing #define REQ_STOP_EIO (0x1 << 3) 20920848903SChaotian Jing #define REQ_STOP_TMO (0x1 << 4) 21020848903SChaotian Jing #define REQ_CMD_BUSY (0x1 << 5) 21120848903SChaotian Jing 21220848903SChaotian Jing #define MSDC_PREPARE_FLAG (0x1 << 0) 21320848903SChaotian Jing #define MSDC_ASYNC_FLAG (0x1 << 1) 21420848903SChaotian Jing #define MSDC_MMAP_FLAG (0x1 << 2) 21520848903SChaotian Jing 21620848903SChaotian Jing #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ 21720848903SChaotian Jing #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ 21820848903SChaotian Jing 21920848903SChaotian Jing /*--------------------------------------------------------------------------*/ 22020848903SChaotian Jing /* Descriptor Structure */ 22120848903SChaotian Jing /*--------------------------------------------------------------------------*/ 22220848903SChaotian Jing struct mt_gpdma_desc { 22320848903SChaotian Jing u32 gpd_info; 22420848903SChaotian Jing #define GPDMA_DESC_HWO (0x1 << 0) 22520848903SChaotian Jing #define GPDMA_DESC_BDP (0x1 << 1) 22620848903SChaotian Jing #define GPDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ 22720848903SChaotian Jing #define GPDMA_DESC_INT (0x1 << 16) 22820848903SChaotian Jing u32 next; 22920848903SChaotian Jing u32 ptr; 23020848903SChaotian Jing u32 gpd_data_len; 23120848903SChaotian Jing #define GPDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ 23220848903SChaotian Jing #define GPDMA_DESC_EXTLEN (0xff << 16) /* bit16 ~ bit23 */ 23320848903SChaotian Jing u32 arg; 23420848903SChaotian Jing u32 blknum; 23520848903SChaotian Jing u32 cmd; 23620848903SChaotian Jing }; 23720848903SChaotian Jing 23820848903SChaotian Jing struct mt_bdma_desc { 23920848903SChaotian Jing u32 bd_info; 24020848903SChaotian Jing #define BDMA_DESC_EOL (0x1 << 0) 24120848903SChaotian Jing #define BDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ 24220848903SChaotian Jing #define BDMA_DESC_BLKPAD (0x1 << 17) 24320848903SChaotian Jing #define BDMA_DESC_DWPAD (0x1 << 18) 24420848903SChaotian Jing u32 next; 24520848903SChaotian Jing u32 ptr; 24620848903SChaotian Jing u32 bd_data_len; 24720848903SChaotian Jing #define BDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ 24820848903SChaotian Jing }; 24920848903SChaotian Jing 25020848903SChaotian Jing struct msdc_dma { 25120848903SChaotian Jing struct scatterlist *sg; /* I/O scatter list */ 25220848903SChaotian Jing struct mt_gpdma_desc *gpd; /* pointer to gpd array */ 25320848903SChaotian Jing struct mt_bdma_desc *bd; /* pointer to bd array */ 25420848903SChaotian Jing dma_addr_t gpd_addr; /* the physical address of gpd array */ 25520848903SChaotian Jing dma_addr_t bd_addr; /* the physical address of bd array */ 25620848903SChaotian Jing }; 25720848903SChaotian Jing 25820848903SChaotian Jing struct msdc_host { 25920848903SChaotian Jing struct device *dev; 26020848903SChaotian Jing struct mmc_host *mmc; /* mmc structure */ 26120848903SChaotian Jing int cmd_rsp; 26220848903SChaotian Jing 26320848903SChaotian Jing spinlock_t lock; 26420848903SChaotian Jing struct mmc_request *mrq; 26520848903SChaotian Jing struct mmc_command *cmd; 26620848903SChaotian Jing struct mmc_data *data; 26720848903SChaotian Jing int error; 26820848903SChaotian Jing 26920848903SChaotian Jing void __iomem *base; /* host base address */ 27020848903SChaotian Jing 27120848903SChaotian Jing struct msdc_dma dma; /* dma channel */ 27220848903SChaotian Jing u64 dma_mask; 27320848903SChaotian Jing 27420848903SChaotian Jing u32 timeout_ns; /* data timeout ns */ 27520848903SChaotian Jing u32 timeout_clks; /* data timeout clks */ 27620848903SChaotian Jing 27720848903SChaotian Jing struct pinctrl *pinctrl; 27820848903SChaotian Jing struct pinctrl_state *pins_default; 27920848903SChaotian Jing struct pinctrl_state *pins_uhs; 28020848903SChaotian Jing struct delayed_work req_timeout; 28120848903SChaotian Jing int irq; /* host interrupt */ 28220848903SChaotian Jing 28320848903SChaotian Jing struct clk *src_clk; /* msdc source clock */ 28420848903SChaotian Jing struct clk *h_clk; /* msdc h_clk */ 28520848903SChaotian Jing u32 mclk; /* mmc subsystem clock frequency */ 28620848903SChaotian Jing u32 src_clk_freq; /* source clock frequency */ 28720848903SChaotian Jing u32 sclk; /* SD/MS bus clock frequency */ 28820848903SChaotian Jing bool ddr; 28920848903SChaotian Jing bool vqmmc_enabled; 29020848903SChaotian Jing }; 29120848903SChaotian Jing 29220848903SChaotian Jing static void sdr_set_bits(void __iomem *reg, u32 bs) 29320848903SChaotian Jing { 29420848903SChaotian Jing u32 val = readl(reg); 29520848903SChaotian Jing 29620848903SChaotian Jing val |= bs; 29720848903SChaotian Jing writel(val, reg); 29820848903SChaotian Jing } 29920848903SChaotian Jing 30020848903SChaotian Jing static void sdr_clr_bits(void __iomem *reg, u32 bs) 30120848903SChaotian Jing { 30220848903SChaotian Jing u32 val = readl(reg); 30320848903SChaotian Jing 30420848903SChaotian Jing val &= ~bs; 30520848903SChaotian Jing writel(val, reg); 30620848903SChaotian Jing } 30720848903SChaotian Jing 30820848903SChaotian Jing static void sdr_set_field(void __iomem *reg, u32 field, u32 val) 30920848903SChaotian Jing { 31020848903SChaotian Jing unsigned int tv = readl(reg); 31120848903SChaotian Jing 31220848903SChaotian Jing tv &= ~field; 31320848903SChaotian Jing tv |= ((val) << (ffs((unsigned int)field) - 1)); 31420848903SChaotian Jing writel(tv, reg); 31520848903SChaotian Jing } 31620848903SChaotian Jing 31720848903SChaotian Jing static void sdr_get_field(void __iomem *reg, u32 field, u32 *val) 31820848903SChaotian Jing { 31920848903SChaotian Jing unsigned int tv = readl(reg); 32020848903SChaotian Jing 32120848903SChaotian Jing *val = ((tv & field) >> (ffs((unsigned int)field) - 1)); 32220848903SChaotian Jing } 32320848903SChaotian Jing 32420848903SChaotian Jing static void msdc_reset_hw(struct msdc_host *host) 32520848903SChaotian Jing { 32620848903SChaotian Jing u32 val; 32720848903SChaotian Jing 32820848903SChaotian Jing sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_RST); 32920848903SChaotian Jing while (readl(host->base + MSDC_CFG) & MSDC_CFG_RST) 33020848903SChaotian Jing cpu_relax(); 33120848903SChaotian Jing 33220848903SChaotian Jing sdr_set_bits(host->base + MSDC_FIFOCS, MSDC_FIFOCS_CLR); 33320848903SChaotian Jing while (readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_CLR) 33420848903SChaotian Jing cpu_relax(); 33520848903SChaotian Jing 33620848903SChaotian Jing val = readl(host->base + MSDC_INT); 33720848903SChaotian Jing writel(val, host->base + MSDC_INT); 33820848903SChaotian Jing } 33920848903SChaotian Jing 34020848903SChaotian Jing static void msdc_cmd_next(struct msdc_host *host, 34120848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd); 34220848903SChaotian Jing 34320848903SChaotian Jing static u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | 34420848903SChaotian Jing MSDC_INTEN_DATCRCERR | MSDC_INTEN_DMA_BDCSERR | 34520848903SChaotian Jing MSDC_INTEN_DMA_GPDCSERR | MSDC_INTEN_DMA_PROTECT; 34620848903SChaotian Jing 34720848903SChaotian Jing static u8 msdc_dma_calcs(u8 *buf, u32 len) 34820848903SChaotian Jing { 34920848903SChaotian Jing u32 i, sum = 0; 35020848903SChaotian Jing 35120848903SChaotian Jing for (i = 0; i < len; i++) 35220848903SChaotian Jing sum += buf[i]; 35320848903SChaotian Jing return 0xff - (u8) sum; 35420848903SChaotian Jing } 35520848903SChaotian Jing 35620848903SChaotian Jing static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, 35720848903SChaotian Jing struct mmc_data *data) 35820848903SChaotian Jing { 35920848903SChaotian Jing unsigned int j, dma_len; 36020848903SChaotian Jing dma_addr_t dma_address; 36120848903SChaotian Jing u32 dma_ctrl; 36220848903SChaotian Jing struct scatterlist *sg; 36320848903SChaotian Jing struct mt_gpdma_desc *gpd; 36420848903SChaotian Jing struct mt_bdma_desc *bd; 36520848903SChaotian Jing 36620848903SChaotian Jing sg = data->sg; 36720848903SChaotian Jing 36820848903SChaotian Jing gpd = dma->gpd; 36920848903SChaotian Jing bd = dma->bd; 37020848903SChaotian Jing 37120848903SChaotian Jing /* modify gpd */ 37220848903SChaotian Jing gpd->gpd_info |= GPDMA_DESC_HWO; 37320848903SChaotian Jing gpd->gpd_info |= GPDMA_DESC_BDP; 37420848903SChaotian Jing /* need to clear first. use these bits to calc checksum */ 37520848903SChaotian Jing gpd->gpd_info &= ~GPDMA_DESC_CHECKSUM; 37620848903SChaotian Jing gpd->gpd_info |= msdc_dma_calcs((u8 *) gpd, 16) << 8; 37720848903SChaotian Jing 37820848903SChaotian Jing /* modify bd */ 37920848903SChaotian Jing for_each_sg(data->sg, sg, data->sg_count, j) { 38020848903SChaotian Jing dma_address = sg_dma_address(sg); 38120848903SChaotian Jing dma_len = sg_dma_len(sg); 38220848903SChaotian Jing 38320848903SChaotian Jing /* init bd */ 38420848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_BLKPAD; 38520848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_DWPAD; 38620848903SChaotian Jing bd[j].ptr = (u32)dma_address; 38720848903SChaotian Jing bd[j].bd_data_len &= ~BDMA_DESC_BUFLEN; 38820848903SChaotian Jing bd[j].bd_data_len |= (dma_len & BDMA_DESC_BUFLEN); 38920848903SChaotian Jing 39020848903SChaotian Jing if (j == data->sg_count - 1) /* the last bd */ 39120848903SChaotian Jing bd[j].bd_info |= BDMA_DESC_EOL; 39220848903SChaotian Jing else 39320848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_EOL; 39420848903SChaotian Jing 39520848903SChaotian Jing /* checksume need to clear first */ 39620848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_CHECKSUM; 39720848903SChaotian Jing bd[j].bd_info |= msdc_dma_calcs((u8 *)(&bd[j]), 16) << 8; 39820848903SChaotian Jing } 39920848903SChaotian Jing 40020848903SChaotian Jing sdr_set_field(host->base + MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, 1); 40120848903SChaotian Jing dma_ctrl = readl_relaxed(host->base + MSDC_DMA_CTRL); 40220848903SChaotian Jing dma_ctrl &= ~(MSDC_DMA_CTRL_BRUSTSZ | MSDC_DMA_CTRL_MODE); 40320848903SChaotian Jing dma_ctrl |= (MSDC_BURST_64B << 12 | 1 << 8); 40420848903SChaotian Jing writel_relaxed(dma_ctrl, host->base + MSDC_DMA_CTRL); 40520848903SChaotian Jing writel((u32)dma->gpd_addr, host->base + MSDC_DMA_SA); 40620848903SChaotian Jing } 40720848903SChaotian Jing 40820848903SChaotian Jing static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq) 40920848903SChaotian Jing { 41020848903SChaotian Jing struct mmc_data *data = mrq->data; 41120848903SChaotian Jing 41220848903SChaotian Jing if (!(data->host_cookie & MSDC_PREPARE_FLAG)) { 41320848903SChaotian Jing bool read = (data->flags & MMC_DATA_READ) != 0; 41420848903SChaotian Jing 41520848903SChaotian Jing data->host_cookie |= MSDC_PREPARE_FLAG; 41620848903SChaotian Jing data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len, 41720848903SChaotian Jing read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); 41820848903SChaotian Jing } 41920848903SChaotian Jing } 42020848903SChaotian Jing 42120848903SChaotian Jing static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq) 42220848903SChaotian Jing { 42320848903SChaotian Jing struct mmc_data *data = mrq->data; 42420848903SChaotian Jing 42520848903SChaotian Jing if (data->host_cookie & MSDC_ASYNC_FLAG) 42620848903SChaotian Jing return; 42720848903SChaotian Jing 42820848903SChaotian Jing if (data->host_cookie & MSDC_PREPARE_FLAG) { 42920848903SChaotian Jing bool read = (data->flags & MMC_DATA_READ) != 0; 43020848903SChaotian Jing 43120848903SChaotian Jing dma_unmap_sg(host->dev, data->sg, data->sg_len, 43220848903SChaotian Jing read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); 43320848903SChaotian Jing data->host_cookie &= ~MSDC_PREPARE_FLAG; 43420848903SChaotian Jing } 43520848903SChaotian Jing } 43620848903SChaotian Jing 43720848903SChaotian Jing /* clock control primitives */ 43820848903SChaotian Jing static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) 43920848903SChaotian Jing { 44020848903SChaotian Jing u32 timeout, clk_ns; 44120848903SChaotian Jing u32 mode = 0; 44220848903SChaotian Jing 44320848903SChaotian Jing host->timeout_ns = ns; 44420848903SChaotian Jing host->timeout_clks = clks; 44520848903SChaotian Jing if (host->sclk == 0) { 44620848903SChaotian Jing timeout = 0; 44720848903SChaotian Jing } else { 44820848903SChaotian Jing clk_ns = 1000000000UL / host->sclk; 44920848903SChaotian Jing timeout = (ns + clk_ns - 1) / clk_ns + clks; 45020848903SChaotian Jing /* in 1048576 sclk cycle unit */ 45120848903SChaotian Jing timeout = (timeout + (0x1 << 20) - 1) >> 20; 45220848903SChaotian Jing sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &mode); 45320848903SChaotian Jing /*DDR mode will double the clk cycles for data timeout */ 45420848903SChaotian Jing timeout = mode >= 2 ? timeout * 2 : timeout; 45520848903SChaotian Jing timeout = timeout > 1 ? timeout - 1 : 0; 45620848903SChaotian Jing timeout = timeout > 255 ? 255 : timeout; 45720848903SChaotian Jing } 45820848903SChaotian Jing sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, timeout); 45920848903SChaotian Jing } 46020848903SChaotian Jing 46120848903SChaotian Jing static void msdc_gate_clock(struct msdc_host *host) 46220848903SChaotian Jing { 46320848903SChaotian Jing clk_disable_unprepare(host->src_clk); 46420848903SChaotian Jing clk_disable_unprepare(host->h_clk); 46520848903SChaotian Jing } 46620848903SChaotian Jing 46720848903SChaotian Jing static void msdc_ungate_clock(struct msdc_host *host) 46820848903SChaotian Jing { 46920848903SChaotian Jing clk_prepare_enable(host->h_clk); 47020848903SChaotian Jing clk_prepare_enable(host->src_clk); 47120848903SChaotian Jing while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) 47220848903SChaotian Jing cpu_relax(); 47320848903SChaotian Jing } 47420848903SChaotian Jing 47520848903SChaotian Jing static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz) 47620848903SChaotian Jing { 47720848903SChaotian Jing u32 mode; 47820848903SChaotian Jing u32 flags; 47920848903SChaotian Jing u32 div; 48020848903SChaotian Jing u32 sclk; 48120848903SChaotian Jing 48220848903SChaotian Jing if (!hz) { 48320848903SChaotian Jing dev_dbg(host->dev, "set mclk to 0\n"); 48420848903SChaotian Jing host->mclk = 0; 48520848903SChaotian Jing sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); 48620848903SChaotian Jing return; 48720848903SChaotian Jing } 48820848903SChaotian Jing 48920848903SChaotian Jing flags = readl(host->base + MSDC_INTEN); 49020848903SChaotian Jing sdr_clr_bits(host->base + MSDC_INTEN, flags); 49120848903SChaotian Jing if (ddr) { /* may need to modify later */ 49220848903SChaotian Jing mode = 0x2; /* ddr mode and use divisor */ 49320848903SChaotian Jing if (hz >= (host->src_clk_freq >> 2)) { 49420848903SChaotian Jing div = 0; /* mean div = 1/4 */ 49520848903SChaotian Jing sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */ 49620848903SChaotian Jing } else { 49720848903SChaotian Jing div = (host->src_clk_freq + ((hz << 2) - 1)) / (hz << 2); 49820848903SChaotian Jing sclk = (host->src_clk_freq >> 2) / div; 49920848903SChaotian Jing div = (div >> 1); 50020848903SChaotian Jing } 50120848903SChaotian Jing } else if (hz >= host->src_clk_freq) { 50220848903SChaotian Jing mode = 0x1; /* no divisor */ 50320848903SChaotian Jing div = 0; 50420848903SChaotian Jing sclk = host->src_clk_freq; 50520848903SChaotian Jing } else { 50620848903SChaotian Jing mode = 0x0; /* use divisor */ 50720848903SChaotian Jing if (hz >= (host->src_clk_freq >> 1)) { 50820848903SChaotian Jing div = 0; /* mean div = 1/2 */ 50920848903SChaotian Jing sclk = host->src_clk_freq >> 1; /* sclk = clk / 2 */ 51020848903SChaotian Jing } else { 51120848903SChaotian Jing div = (host->src_clk_freq + ((hz << 2) - 1)) / (hz << 2); 51220848903SChaotian Jing sclk = (host->src_clk_freq >> 2) / div; 51320848903SChaotian Jing } 51420848903SChaotian Jing } 51520848903SChaotian Jing sdr_set_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD | MSDC_CFG_CKDIV, 51620848903SChaotian Jing (mode << 8) | (div % 0xff)); 51720848903SChaotian Jing sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); 51820848903SChaotian Jing while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) 51920848903SChaotian Jing cpu_relax(); 52020848903SChaotian Jing host->sclk = sclk; 52120848903SChaotian Jing host->mclk = hz; 52220848903SChaotian Jing host->ddr = ddr; 52320848903SChaotian Jing /* need because clk changed. */ 52420848903SChaotian Jing msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); 52520848903SChaotian Jing sdr_set_bits(host->base + MSDC_INTEN, flags); 52620848903SChaotian Jing 52720848903SChaotian Jing dev_dbg(host->dev, "sclk: %d, ddr: %d\n", host->sclk, ddr); 52820848903SChaotian Jing } 52920848903SChaotian Jing 53020848903SChaotian Jing static inline u32 msdc_cmd_find_resp(struct msdc_host *host, 53120848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 53220848903SChaotian Jing { 53320848903SChaotian Jing u32 resp; 53420848903SChaotian Jing 53520848903SChaotian Jing switch (mmc_resp_type(cmd)) { 53620848903SChaotian Jing /* Actually, R1, R5, R6, R7 are the same */ 53720848903SChaotian Jing case MMC_RSP_R1: 53820848903SChaotian Jing resp = 0x1; 53920848903SChaotian Jing break; 54020848903SChaotian Jing case MMC_RSP_R1B: 54120848903SChaotian Jing resp = 0x7; 54220848903SChaotian Jing break; 54320848903SChaotian Jing case MMC_RSP_R2: 54420848903SChaotian Jing resp = 0x2; 54520848903SChaotian Jing break; 54620848903SChaotian Jing case MMC_RSP_R3: 54720848903SChaotian Jing resp = 0x3; 54820848903SChaotian Jing break; 54920848903SChaotian Jing case MMC_RSP_NONE: 55020848903SChaotian Jing default: 55120848903SChaotian Jing resp = 0x0; 55220848903SChaotian Jing break; 55320848903SChaotian Jing } 55420848903SChaotian Jing 55520848903SChaotian Jing return resp; 55620848903SChaotian Jing } 55720848903SChaotian Jing 55820848903SChaotian Jing static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, 55920848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 56020848903SChaotian Jing { 56120848903SChaotian Jing /* rawcmd : 56220848903SChaotian Jing * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 | 56320848903SChaotian Jing * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode 56420848903SChaotian Jing */ 56520848903SChaotian Jing u32 opcode = cmd->opcode; 56620848903SChaotian Jing u32 resp = msdc_cmd_find_resp(host, mrq, cmd); 56720848903SChaotian Jing u32 rawcmd = (opcode & 0x3f) | ((resp & 0x7) << 7); 56820848903SChaotian Jing 56920848903SChaotian Jing host->cmd_rsp = resp; 57020848903SChaotian Jing 57120848903SChaotian Jing if ((opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int) -1) || 57220848903SChaotian Jing opcode == MMC_STOP_TRANSMISSION) 57320848903SChaotian Jing rawcmd |= (0x1 << 14); 57420848903SChaotian Jing else if (opcode == SD_SWITCH_VOLTAGE) 57520848903SChaotian Jing rawcmd |= (0x1 << 30); 57620848903SChaotian Jing else if (opcode == SD_APP_SEND_SCR || 57720848903SChaotian Jing opcode == SD_APP_SEND_NUM_WR_BLKS || 57820848903SChaotian Jing (opcode == SD_SWITCH && mmc_cmd_type(cmd) == MMC_CMD_ADTC) || 57920848903SChaotian Jing (opcode == SD_APP_SD_STATUS && mmc_cmd_type(cmd) == MMC_CMD_ADTC) || 58020848903SChaotian Jing (opcode == MMC_SEND_EXT_CSD && mmc_cmd_type(cmd) == MMC_CMD_ADTC)) 58120848903SChaotian Jing rawcmd |= (0x1 << 11); 58220848903SChaotian Jing 58320848903SChaotian Jing if (cmd->data) { 58420848903SChaotian Jing struct mmc_data *data = cmd->data; 58520848903SChaotian Jing 58620848903SChaotian Jing if (mmc_op_multi(opcode)) { 58720848903SChaotian Jing if (mmc_card_mmc(host->mmc->card) && mrq->sbc && 58820848903SChaotian Jing !(mrq->sbc->arg & 0xFFFF0000)) 58920848903SChaotian Jing rawcmd |= 0x2 << 28; /* AutoCMD23 */ 59020848903SChaotian Jing } 59120848903SChaotian Jing 59220848903SChaotian Jing rawcmd |= ((data->blksz & 0xFFF) << 16); 59320848903SChaotian Jing if (data->flags & MMC_DATA_WRITE) 59420848903SChaotian Jing rawcmd |= (0x1 << 13); 59520848903SChaotian Jing if (data->blocks > 1) 59620848903SChaotian Jing rawcmd |= (0x2 << 11); 59720848903SChaotian Jing else 59820848903SChaotian Jing rawcmd |= (0x1 << 11); 59920848903SChaotian Jing /* Always use dma mode */ 60020848903SChaotian Jing sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_PIO); 60120848903SChaotian Jing 60220848903SChaotian Jing if (host->timeout_ns != data->timeout_ns || 60320848903SChaotian Jing host->timeout_clks != data->timeout_clks) 60420848903SChaotian Jing msdc_set_timeout(host, data->timeout_ns, 60520848903SChaotian Jing data->timeout_clks); 60620848903SChaotian Jing 60720848903SChaotian Jing writel(data->blocks, host->base + SDC_BLK_NUM); 60820848903SChaotian Jing } 60920848903SChaotian Jing return rawcmd; 61020848903SChaotian Jing } 61120848903SChaotian Jing 61220848903SChaotian Jing static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq, 61320848903SChaotian Jing struct mmc_command *cmd, struct mmc_data *data) 61420848903SChaotian Jing { 61520848903SChaotian Jing bool read; 61620848903SChaotian Jing 61720848903SChaotian Jing WARN_ON(host->data); 61820848903SChaotian Jing host->data = data; 61920848903SChaotian Jing read = data->flags & MMC_DATA_READ; 62020848903SChaotian Jing 62120848903SChaotian Jing mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); 62220848903SChaotian Jing msdc_dma_setup(host, &host->dma, data); 62320848903SChaotian Jing sdr_set_bits(host->base + MSDC_INTEN, data_ints_mask); 62420848903SChaotian Jing sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1); 62520848903SChaotian Jing dev_dbg(host->dev, "DMA start\n"); 62620848903SChaotian Jing dev_dbg(host->dev, "%s: cmd=%d DMA data: %d blocks; read=%d\n", 62720848903SChaotian Jing __func__, cmd->opcode, data->blocks, read); 62820848903SChaotian Jing } 62920848903SChaotian Jing 63020848903SChaotian Jing static int msdc_auto_cmd_done(struct msdc_host *host, int events, 63120848903SChaotian Jing struct mmc_command *cmd) 63220848903SChaotian Jing { 63320848903SChaotian Jing u32 *rsp = cmd->resp; 63420848903SChaotian Jing 63520848903SChaotian Jing rsp[0] = readl(host->base + SDC_ACMD_RESP); 63620848903SChaotian Jing 63720848903SChaotian Jing if (events & MSDC_INT_ACMDRDY) { 63820848903SChaotian Jing cmd->error = 0; 63920848903SChaotian Jing } else { 64020848903SChaotian Jing msdc_reset_hw(host); 64120848903SChaotian Jing if (events & MSDC_INT_ACMDCRCERR) { 64220848903SChaotian Jing cmd->error = -EILSEQ; 64320848903SChaotian Jing host->error |= REQ_STOP_EIO; 64420848903SChaotian Jing } else if (events & MSDC_INT_ACMDTMO) { 64520848903SChaotian Jing cmd->error = -ETIMEDOUT; 64620848903SChaotian Jing host->error |= REQ_STOP_TMO; 64720848903SChaotian Jing } 64820848903SChaotian Jing dev_err(host->dev, 64920848903SChaotian Jing "%s: AUTO_CMD%d arg=%08X; rsp %08X; cmd_error=%d\n", 65020848903SChaotian Jing __func__, cmd->opcode, cmd->arg, rsp[0], cmd->error); 65120848903SChaotian Jing } 65220848903SChaotian Jing return cmd->error; 65320848903SChaotian Jing } 65420848903SChaotian Jing 65520848903SChaotian Jing static void msdc_track_cmd_data(struct msdc_host *host, 65620848903SChaotian Jing struct mmc_command *cmd, struct mmc_data *data) 65720848903SChaotian Jing { 65820848903SChaotian Jing if (host->error) 65920848903SChaotian Jing dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", 66020848903SChaotian Jing __func__, cmd->opcode, cmd->arg, host->error); 66120848903SChaotian Jing } 66220848903SChaotian Jing 66320848903SChaotian Jing static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) 66420848903SChaotian Jing { 66520848903SChaotian Jing unsigned long flags; 66620848903SChaotian Jing bool ret; 66720848903SChaotian Jing 66820848903SChaotian Jing ret = cancel_delayed_work(&host->req_timeout); 66920848903SChaotian Jing if (!ret) { 67020848903SChaotian Jing /* delay work already running */ 67120848903SChaotian Jing return; 67220848903SChaotian Jing } 67320848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 67420848903SChaotian Jing host->mrq = NULL; 67520848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 67620848903SChaotian Jing 67720848903SChaotian Jing msdc_track_cmd_data(host, mrq->cmd, mrq->data); 67820848903SChaotian Jing if (mrq->data) 67920848903SChaotian Jing msdc_unprepare_data(host, mrq); 68020848903SChaotian Jing mmc_request_done(host->mmc, mrq); 68120848903SChaotian Jing } 68220848903SChaotian Jing 68320848903SChaotian Jing /* returns true if command is fully handled; returns false otherwise */ 68420848903SChaotian Jing static bool msdc_cmd_done(struct msdc_host *host, int events, 68520848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 68620848903SChaotian Jing { 68720848903SChaotian Jing bool done = false; 68820848903SChaotian Jing bool sbc_error; 68920848903SChaotian Jing unsigned long flags; 69020848903SChaotian Jing u32 *rsp = cmd->resp; 69120848903SChaotian Jing 69220848903SChaotian Jing if (mrq->sbc && cmd == mrq->cmd && 69320848903SChaotian Jing (events & (MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR 69420848903SChaotian Jing | MSDC_INT_ACMDTMO))) 69520848903SChaotian Jing msdc_auto_cmd_done(host, events, mrq->sbc); 69620848903SChaotian Jing 69720848903SChaotian Jing sbc_error = mrq->sbc && mrq->sbc->error; 69820848903SChaotian Jing 69920848903SChaotian Jing if (!sbc_error && !(events & (MSDC_INT_CMDRDY 70020848903SChaotian Jing | MSDC_INT_RSPCRCERR 70120848903SChaotian Jing | MSDC_INT_CMDTMO))) 70220848903SChaotian Jing return done; 70320848903SChaotian Jing 70420848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 70520848903SChaotian Jing done = !host->cmd; 70620848903SChaotian Jing host->cmd = NULL; 70720848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 70820848903SChaotian Jing 70920848903SChaotian Jing if (done) 71020848903SChaotian Jing return true; 71120848903SChaotian Jing 71220848903SChaotian Jing sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY | 71320848903SChaotian Jing MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO | 71420848903SChaotian Jing MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR | 71520848903SChaotian Jing MSDC_INTEN_ACMDTMO); 71620848903SChaotian Jing writel(cmd->arg, host->base + SDC_ARG); 71720848903SChaotian Jing 71820848903SChaotian Jing if (cmd->flags & MMC_RSP_PRESENT) { 71920848903SChaotian Jing if (cmd->flags & MMC_RSP_136) { 72020848903SChaotian Jing rsp[0] = readl(host->base + SDC_RESP3); 72120848903SChaotian Jing rsp[1] = readl(host->base + SDC_RESP2); 72220848903SChaotian Jing rsp[2] = readl(host->base + SDC_RESP1); 72320848903SChaotian Jing rsp[3] = readl(host->base + SDC_RESP0); 72420848903SChaotian Jing } else { 72520848903SChaotian Jing rsp[0] = readl(host->base + SDC_RESP0); 72620848903SChaotian Jing } 72720848903SChaotian Jing } 72820848903SChaotian Jing 72920848903SChaotian Jing if (!sbc_error && !(events & MSDC_INT_CMDRDY)) { 73020848903SChaotian Jing msdc_reset_hw(host); 73120848903SChaotian Jing if (events & MSDC_INT_RSPCRCERR) { 73220848903SChaotian Jing cmd->error = -EILSEQ; 73320848903SChaotian Jing host->error |= REQ_CMD_EIO; 73420848903SChaotian Jing } else if (events & MSDC_INT_CMDTMO) { 73520848903SChaotian Jing cmd->error = -ETIMEDOUT; 73620848903SChaotian Jing host->error |= REQ_CMD_TMO; 73720848903SChaotian Jing } 73820848903SChaotian Jing } 73920848903SChaotian Jing if (cmd->error) 74020848903SChaotian Jing dev_dbg(host->dev, 74120848903SChaotian Jing "%s: cmd=%d arg=%08X; rsp %08X; cmd_error=%d\n", 74220848903SChaotian Jing __func__, cmd->opcode, cmd->arg, rsp[0], 74320848903SChaotian Jing cmd->error); 74420848903SChaotian Jing 74520848903SChaotian Jing msdc_cmd_next(host, mrq, cmd); 74620848903SChaotian Jing return true; 74720848903SChaotian Jing } 74820848903SChaotian Jing 74920848903SChaotian Jing /* It is the core layer's responsibility to ensure card status 75020848903SChaotian Jing * is correct before issue a request. but host design do below 75120848903SChaotian Jing * checks recommended. 75220848903SChaotian Jing */ 75320848903SChaotian Jing static inline bool msdc_cmd_is_ready(struct msdc_host *host, 75420848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 75520848903SChaotian Jing { 75620848903SChaotian Jing /* The max busy time we can endure is 20ms */ 75720848903SChaotian Jing unsigned long tmo = jiffies + msecs_to_jiffies(20); 75820848903SChaotian Jing 75920848903SChaotian Jing while ((readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) && 76020848903SChaotian Jing time_before(jiffies, tmo)) 76120848903SChaotian Jing cpu_relax(); 76220848903SChaotian Jing if (readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) { 76320848903SChaotian Jing dev_err(host->dev, "CMD bus busy detected\n"); 76420848903SChaotian Jing host->error |= REQ_CMD_BUSY; 76520848903SChaotian Jing msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd); 76620848903SChaotian Jing return false; 76720848903SChaotian Jing } 76820848903SChaotian Jing 76920848903SChaotian Jing if (mmc_resp_type(cmd) == MMC_RSP_R1B || cmd->data) { 77020848903SChaotian Jing tmo = jiffies + msecs_to_jiffies(20); 77120848903SChaotian Jing /* R1B or with data, should check SDCBUSY */ 77220848903SChaotian Jing while ((readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) && 77320848903SChaotian Jing time_before(jiffies, tmo)) 77420848903SChaotian Jing cpu_relax(); 77520848903SChaotian Jing if (readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) { 77620848903SChaotian Jing dev_err(host->dev, "Controller busy detected\n"); 77720848903SChaotian Jing host->error |= REQ_CMD_BUSY; 77820848903SChaotian Jing msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd); 77920848903SChaotian Jing return false; 78020848903SChaotian Jing } 78120848903SChaotian Jing } 78220848903SChaotian Jing return true; 78320848903SChaotian Jing } 78420848903SChaotian Jing 78520848903SChaotian Jing static void msdc_start_command(struct msdc_host *host, 78620848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 78720848903SChaotian Jing { 78820848903SChaotian Jing u32 rawcmd; 78920848903SChaotian Jing 79020848903SChaotian Jing WARN_ON(host->cmd); 79120848903SChaotian Jing host->cmd = cmd; 79220848903SChaotian Jing 79320848903SChaotian Jing if (!msdc_cmd_is_ready(host, mrq, cmd)) 79420848903SChaotian Jing return; 79520848903SChaotian Jing 79620848903SChaotian Jing if ((readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16 || 79720848903SChaotian Jing readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) { 79820848903SChaotian Jing dev_err(host->dev, "TX/RX FIFO non-empty before start of IO. Reset\n"); 79920848903SChaotian Jing msdc_reset_hw(host); 80020848903SChaotian Jing } 80120848903SChaotian Jing 80220848903SChaotian Jing cmd->error = 0; 80320848903SChaotian Jing rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd); 80420848903SChaotian Jing mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); 80520848903SChaotian Jing 80620848903SChaotian Jing sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY | 80720848903SChaotian Jing MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO | 80820848903SChaotian Jing MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR | 80920848903SChaotian Jing MSDC_INTEN_ACMDTMO); 81020848903SChaotian Jing writel(cmd->arg, host->base + SDC_ARG); 81120848903SChaotian Jing writel(rawcmd, host->base + SDC_CMD); 81220848903SChaotian Jing } 81320848903SChaotian Jing 81420848903SChaotian Jing static void msdc_cmd_next(struct msdc_host *host, 81520848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 81620848903SChaotian Jing { 81720848903SChaotian Jing if (cmd->error || (mrq->sbc && mrq->sbc->error)) 81820848903SChaotian Jing msdc_request_done(host, mrq); 81920848903SChaotian Jing else if (cmd == mrq->sbc) 82020848903SChaotian Jing msdc_start_command(host, mrq, mrq->cmd); 82120848903SChaotian Jing else if (!cmd->data) 82220848903SChaotian Jing msdc_request_done(host, mrq); 82320848903SChaotian Jing else 82420848903SChaotian Jing msdc_start_data(host, mrq, cmd, cmd->data); 82520848903SChaotian Jing } 82620848903SChaotian Jing 82720848903SChaotian Jing static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) 82820848903SChaotian Jing { 82920848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 83020848903SChaotian Jing 83120848903SChaotian Jing host->error = 0; 83220848903SChaotian Jing WARN_ON(host->mrq); 83320848903SChaotian Jing host->mrq = mrq; 83420848903SChaotian Jing 83520848903SChaotian Jing if (mrq->data) 83620848903SChaotian Jing msdc_prepare_data(host, mrq); 83720848903SChaotian Jing 83820848903SChaotian Jing /* if SBC is required, we have HW option and SW option. 83920848903SChaotian Jing * if HW option is enabled, and SBC does not have "special" flags, 84020848903SChaotian Jing * use HW option, otherwise use SW option 84120848903SChaotian Jing */ 84220848903SChaotian Jing if (mrq->sbc && (!mmc_card_mmc(mmc->card) || 84320848903SChaotian Jing (mrq->sbc->arg & 0xFFFF0000))) 84420848903SChaotian Jing msdc_start_command(host, mrq, mrq->sbc); 84520848903SChaotian Jing else 84620848903SChaotian Jing msdc_start_command(host, mrq, mrq->cmd); 84720848903SChaotian Jing } 84820848903SChaotian Jing 84920848903SChaotian Jing static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, 85020848903SChaotian Jing bool is_first_req) 85120848903SChaotian Jing { 85220848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 85320848903SChaotian Jing struct mmc_data *data = mrq->data; 85420848903SChaotian Jing 85520848903SChaotian Jing if (!data) 85620848903SChaotian Jing return; 85720848903SChaotian Jing 85820848903SChaotian Jing msdc_prepare_data(host, mrq); 85920848903SChaotian Jing data->host_cookie |= MSDC_ASYNC_FLAG; 86020848903SChaotian Jing } 86120848903SChaotian Jing 86220848903SChaotian Jing static void msdc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, 86320848903SChaotian Jing int err) 86420848903SChaotian Jing { 86520848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 86620848903SChaotian Jing struct mmc_data *data; 86720848903SChaotian Jing 86820848903SChaotian Jing data = mrq->data; 86920848903SChaotian Jing if (!data) 87020848903SChaotian Jing return; 87120848903SChaotian Jing if (data->host_cookie) { 87220848903SChaotian Jing data->host_cookie &= ~MSDC_ASYNC_FLAG; 87320848903SChaotian Jing msdc_unprepare_data(host, mrq); 87420848903SChaotian Jing } 87520848903SChaotian Jing } 87620848903SChaotian Jing 87720848903SChaotian Jing static void msdc_data_xfer_next(struct msdc_host *host, 87820848903SChaotian Jing struct mmc_request *mrq, struct mmc_data *data) 87920848903SChaotian Jing { 88020848903SChaotian Jing if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && !mrq->stop->error && 88120848903SChaotian Jing (!data->bytes_xfered || !mrq->sbc)) 88220848903SChaotian Jing msdc_start_command(host, mrq, mrq->stop); 88320848903SChaotian Jing else 88420848903SChaotian Jing msdc_request_done(host, mrq); 88520848903SChaotian Jing } 88620848903SChaotian Jing 88720848903SChaotian Jing static bool msdc_data_xfer_done(struct msdc_host *host, u32 events, 88820848903SChaotian Jing struct mmc_request *mrq, struct mmc_data *data) 88920848903SChaotian Jing { 89020848903SChaotian Jing struct mmc_command *stop = data->stop; 89120848903SChaotian Jing unsigned long flags; 89220848903SChaotian Jing bool done; 89320848903SChaotian Jing unsigned int check_data = events & 89420848903SChaotian Jing (MSDC_INT_XFER_COMPL | MSDC_INT_DATCRCERR | MSDC_INT_DATTMO 89520848903SChaotian Jing | MSDC_INT_DMA_BDCSERR | MSDC_INT_DMA_GPDCSERR 89620848903SChaotian Jing | MSDC_INT_DMA_PROTECT); 89720848903SChaotian Jing 89820848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 89920848903SChaotian Jing done = !host->data; 90020848903SChaotian Jing if (check_data) 90120848903SChaotian Jing host->data = NULL; 90220848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 90320848903SChaotian Jing 90420848903SChaotian Jing if (done) 90520848903SChaotian Jing return true; 90620848903SChaotian Jing 90720848903SChaotian Jing if (check_data || (stop && stop->error)) { 90820848903SChaotian Jing dev_dbg(host->dev, "DMA status: 0x%8X\n", 90920848903SChaotian Jing readl(host->base + MSDC_DMA_CFG)); 91020848903SChaotian Jing sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 91120848903SChaotian Jing 1); 91220848903SChaotian Jing while (readl(host->base + MSDC_DMA_CFG) & MSDC_DMA_CFG_STS) 91320848903SChaotian Jing cpu_relax(); 91420848903SChaotian Jing sdr_clr_bits(host->base + MSDC_INTEN, data_ints_mask); 91520848903SChaotian Jing dev_dbg(host->dev, "DMA stop\n"); 91620848903SChaotian Jing 91720848903SChaotian Jing if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) { 91820848903SChaotian Jing data->bytes_xfered = data->blocks * data->blksz; 91920848903SChaotian Jing } else { 92020848903SChaotian Jing dev_err(host->dev, "interrupt events: %x\n", events); 92120848903SChaotian Jing msdc_reset_hw(host); 92220848903SChaotian Jing host->error |= REQ_DAT_ERR; 92320848903SChaotian Jing data->bytes_xfered = 0; 92420848903SChaotian Jing 92520848903SChaotian Jing if (events & MSDC_INT_DATTMO) 92620848903SChaotian Jing data->error = -ETIMEDOUT; 92720848903SChaotian Jing 92820848903SChaotian Jing dev_err(host->dev, "%s: cmd=%d; blocks=%d", 92920848903SChaotian Jing __func__, mrq->cmd->opcode, data->blocks); 93020848903SChaotian Jing dev_err(host->dev, "data_error=%d xfer_size=%d\n", 93120848903SChaotian Jing (int)data->error, data->bytes_xfered); 93220848903SChaotian Jing } 93320848903SChaotian Jing 93420848903SChaotian Jing msdc_data_xfer_next(host, mrq, data); 93520848903SChaotian Jing done = true; 93620848903SChaotian Jing } 93720848903SChaotian Jing return done; 93820848903SChaotian Jing } 93920848903SChaotian Jing 94020848903SChaotian Jing static void msdc_set_buswidth(struct msdc_host *host, u32 width) 94120848903SChaotian Jing { 94220848903SChaotian Jing u32 val = readl(host->base + SDC_CFG); 94320848903SChaotian Jing 94420848903SChaotian Jing val &= ~SDC_CFG_BUSWIDTH; 94520848903SChaotian Jing 94620848903SChaotian Jing switch (width) { 94720848903SChaotian Jing default: 94820848903SChaotian Jing case MMC_BUS_WIDTH_1: 94920848903SChaotian Jing val |= (MSDC_BUS_1BITS << 16); 95020848903SChaotian Jing break; 95120848903SChaotian Jing case MMC_BUS_WIDTH_4: 95220848903SChaotian Jing val |= (MSDC_BUS_4BITS << 16); 95320848903SChaotian Jing break; 95420848903SChaotian Jing case MMC_BUS_WIDTH_8: 95520848903SChaotian Jing val |= (MSDC_BUS_8BITS << 16); 95620848903SChaotian Jing break; 95720848903SChaotian Jing } 95820848903SChaotian Jing 95920848903SChaotian Jing writel(val, host->base + SDC_CFG); 96020848903SChaotian Jing dev_dbg(host->dev, "Bus Width = %d", width); 96120848903SChaotian Jing } 96220848903SChaotian Jing 96320848903SChaotian Jing static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) 96420848903SChaotian Jing { 96520848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 96620848903SChaotian Jing int min_uv, max_uv; 96720848903SChaotian Jing int ret = 0; 96820848903SChaotian Jing 96920848903SChaotian Jing if (!IS_ERR(mmc->supply.vqmmc)) { 97020848903SChaotian Jing if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 97120848903SChaotian Jing min_uv = 3300000; 97220848903SChaotian Jing max_uv = 3300000; 97320848903SChaotian Jing } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { 97420848903SChaotian Jing min_uv = 1800000; 97520848903SChaotian Jing max_uv = 1800000; 97620848903SChaotian Jing } else { 97720848903SChaotian Jing dev_err(host->dev, "Unsupported signal voltage!\n"); 97820848903SChaotian Jing return -EINVAL; 97920848903SChaotian Jing } 98020848903SChaotian Jing 98120848903SChaotian Jing ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); 98220848903SChaotian Jing if (ret) { 98320848903SChaotian Jing dev_err(host->dev, 98420848903SChaotian Jing "Regulator set error %d: %d - %d\n", 98520848903SChaotian Jing ret, min_uv, max_uv); 98620848903SChaotian Jing } else { 98720848903SChaotian Jing /* Apply different pinctrl settings for different signal voltage */ 98820848903SChaotian Jing if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) 98920848903SChaotian Jing pinctrl_select_state(host->pinctrl, host->pins_uhs); 99020848903SChaotian Jing else 99120848903SChaotian Jing pinctrl_select_state(host->pinctrl, host->pins_default); 99220848903SChaotian Jing } 99320848903SChaotian Jing } 99420848903SChaotian Jing return ret; 99520848903SChaotian Jing } 99620848903SChaotian Jing 99720848903SChaotian Jing static int msdc_card_busy(struct mmc_host *mmc) 99820848903SChaotian Jing { 99920848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 100020848903SChaotian Jing u32 status = readl(host->base + MSDC_PS); 100120848903SChaotian Jing 100220848903SChaotian Jing /* check if any pin between dat[0:3] is low */ 100320848903SChaotian Jing if (((status >> 16) & 0xf) != 0xf) 100420848903SChaotian Jing return 1; 100520848903SChaotian Jing 100620848903SChaotian Jing return 0; 100720848903SChaotian Jing } 100820848903SChaotian Jing 100920848903SChaotian Jing static void msdc_request_timeout(struct work_struct *work) 101020848903SChaotian Jing { 101120848903SChaotian Jing struct msdc_host *host = container_of(work, struct msdc_host, 101220848903SChaotian Jing req_timeout.work); 101320848903SChaotian Jing 101420848903SChaotian Jing /* simulate HW timeout status */ 101520848903SChaotian Jing dev_err(host->dev, "%s: aborting cmd/data/mrq\n", __func__); 101620848903SChaotian Jing if (host->mrq) { 101720848903SChaotian Jing dev_err(host->dev, "%s: aborting mrq=%p cmd=%d\n", __func__, 101820848903SChaotian Jing host->mrq, host->mrq->cmd->opcode); 101920848903SChaotian Jing if (host->cmd) { 102020848903SChaotian Jing dev_err(host->dev, "%s: aborting cmd=%d\n", 102120848903SChaotian Jing __func__, host->cmd->opcode); 102220848903SChaotian Jing msdc_cmd_done(host, MSDC_INT_CMDTMO, host->mrq, 102320848903SChaotian Jing host->cmd); 102420848903SChaotian Jing } else if (host->data) { 102520848903SChaotian Jing dev_err(host->dev, "%s: abort data: cmd%d; %d blocks\n", 102620848903SChaotian Jing __func__, host->mrq->cmd->opcode, 102720848903SChaotian Jing host->data->blocks); 102820848903SChaotian Jing msdc_data_xfer_done(host, MSDC_INT_DATTMO, host->mrq, 102920848903SChaotian Jing host->data); 103020848903SChaotian Jing } 103120848903SChaotian Jing } 103220848903SChaotian Jing } 103320848903SChaotian Jing 103420848903SChaotian Jing static irqreturn_t msdc_irq(int irq, void *dev_id) 103520848903SChaotian Jing { 103620848903SChaotian Jing struct msdc_host *host = (struct msdc_host *) dev_id; 103720848903SChaotian Jing 103820848903SChaotian Jing while (true) { 103920848903SChaotian Jing unsigned long flags; 104020848903SChaotian Jing struct mmc_request *mrq; 104120848903SChaotian Jing struct mmc_command *cmd; 104220848903SChaotian Jing struct mmc_data *data; 104320848903SChaotian Jing u32 events, event_mask; 104420848903SChaotian Jing 104520848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 104620848903SChaotian Jing events = readl(host->base + MSDC_INT); 104720848903SChaotian Jing event_mask = readl(host->base + MSDC_INTEN); 104820848903SChaotian Jing /* clear interrupts */ 104920848903SChaotian Jing writel(events & event_mask, host->base + MSDC_INT); 105020848903SChaotian Jing 105120848903SChaotian Jing mrq = host->mrq; 105220848903SChaotian Jing cmd = host->cmd; 105320848903SChaotian Jing data = host->data; 105420848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 105520848903SChaotian Jing 105620848903SChaotian Jing if (!(events & event_mask)) 105720848903SChaotian Jing break; 105820848903SChaotian Jing 105920848903SChaotian Jing if (!mrq) { 106020848903SChaotian Jing dev_err(host->dev, 106120848903SChaotian Jing "%s: MRQ=NULL; events=%08X; event_mask=%08X\n", 106220848903SChaotian Jing __func__, events, event_mask); 106320848903SChaotian Jing WARN_ON(1); 106420848903SChaotian Jing break; 106520848903SChaotian Jing } 106620848903SChaotian Jing 106720848903SChaotian Jing dev_dbg(host->dev, "%s: events=%08X\n", __func__, events); 106820848903SChaotian Jing 106920848903SChaotian Jing if (cmd) 107020848903SChaotian Jing msdc_cmd_done(host, events, mrq, cmd); 107120848903SChaotian Jing else if (data) 107220848903SChaotian Jing msdc_data_xfer_done(host, events, mrq, data); 107320848903SChaotian Jing } 107420848903SChaotian Jing 107520848903SChaotian Jing return IRQ_HANDLED; 107620848903SChaotian Jing } 107720848903SChaotian Jing 107820848903SChaotian Jing static void msdc_init_hw(struct msdc_host *host) 107920848903SChaotian Jing { 108020848903SChaotian Jing u32 val; 108120848903SChaotian Jing 108220848903SChaotian Jing /* Configure to MMC/SD mode, clock free running */ 108320848903SChaotian Jing sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN); 108420848903SChaotian Jing 108520848903SChaotian Jing /* Reset */ 108620848903SChaotian Jing msdc_reset_hw(host); 108720848903SChaotian Jing 108820848903SChaotian Jing /* Disable card detection */ 108920848903SChaotian Jing sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); 109020848903SChaotian Jing 109120848903SChaotian Jing /* Disable and clear all interrupts */ 109220848903SChaotian Jing writel(0, host->base + MSDC_INTEN); 109320848903SChaotian Jing val = readl(host->base + MSDC_INT); 109420848903SChaotian Jing writel(val, host->base + MSDC_INT); 109520848903SChaotian Jing 109620848903SChaotian Jing writel(0, host->base + MSDC_PAD_TUNE); 109720848903SChaotian Jing writel(0, host->base + MSDC_IOCON); 109820848903SChaotian Jing sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); 109920848903SChaotian Jing writel(0x403c004f, host->base + MSDC_PATCH_BIT); 110020848903SChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1); 110120848903SChaotian Jing writel(0xffff0089, host->base + MSDC_PATCH_BIT1); 110220848903SChaotian Jing /* Configure to enable SDIO mode. 110320848903SChaotian Jing * it's must otherwise sdio cmd5 failed 110420848903SChaotian Jing */ 110520848903SChaotian Jing sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); 110620848903SChaotian Jing 110720848903SChaotian Jing /* disable detect SDIO device interrupt function */ 110820848903SChaotian Jing sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); 110920848903SChaotian Jing 111020848903SChaotian Jing /* Configure to default data timeout */ 111120848903SChaotian Jing sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); 111220848903SChaotian Jing 111320848903SChaotian Jing dev_dbg(host->dev, "init hardware done!"); 111420848903SChaotian Jing } 111520848903SChaotian Jing 111620848903SChaotian Jing static void msdc_deinit_hw(struct msdc_host *host) 111720848903SChaotian Jing { 111820848903SChaotian Jing u32 val; 111920848903SChaotian Jing /* Disable and clear all interrupts */ 112020848903SChaotian Jing writel(0, host->base + MSDC_INTEN); 112120848903SChaotian Jing 112220848903SChaotian Jing val = readl(host->base + MSDC_INT); 112320848903SChaotian Jing writel(val, host->base + MSDC_INT); 112420848903SChaotian Jing } 112520848903SChaotian Jing 112620848903SChaotian Jing /* init gpd and bd list in msdc_drv_probe */ 112720848903SChaotian Jing static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma) 112820848903SChaotian Jing { 112920848903SChaotian Jing struct mt_gpdma_desc *gpd = dma->gpd; 113020848903SChaotian Jing struct mt_bdma_desc *bd = dma->bd; 113120848903SChaotian Jing int i; 113220848903SChaotian Jing 113320848903SChaotian Jing memset(gpd, 0, sizeof(struct mt_gpdma_desc)); 113420848903SChaotian Jing 113520848903SChaotian Jing gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */ 113620848903SChaotian Jing gpd->ptr = (u32)dma->bd_addr; /* physical address */ 113720848903SChaotian Jing 113820848903SChaotian Jing memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM); 113920848903SChaotian Jing for (i = 0; i < (MAX_BD_NUM - 1); i++) 114020848903SChaotian Jing bd[i].next = (u32)dma->bd_addr + sizeof(*bd) * (i + 1); 114120848903SChaotian Jing } 114220848903SChaotian Jing 114320848903SChaotian Jing static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 114420848903SChaotian Jing { 114520848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 114620848903SChaotian Jing int ret; 114720848903SChaotian Jing u32 ddr = 0; 114820848903SChaotian Jing 114920848903SChaotian Jing if (ios->timing == MMC_TIMING_UHS_DDR50 || 115020848903SChaotian Jing ios->timing == MMC_TIMING_MMC_DDR52) 115120848903SChaotian Jing ddr = 1; 115220848903SChaotian Jing 115320848903SChaotian Jing msdc_set_buswidth(host, ios->bus_width); 115420848903SChaotian Jing 115520848903SChaotian Jing /* Suspend/Resume will do power off/on */ 115620848903SChaotian Jing switch (ios->power_mode) { 115720848903SChaotian Jing case MMC_POWER_UP: 115820848903SChaotian Jing if (!IS_ERR(mmc->supply.vmmc)) { 115920848903SChaotian Jing ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 116020848903SChaotian Jing ios->vdd); 116120848903SChaotian Jing if (ret) { 116220848903SChaotian Jing dev_err(host->dev, "Failed to set vmmc power!\n"); 116320848903SChaotian Jing return; 116420848903SChaotian Jing } 116520848903SChaotian Jing } 116620848903SChaotian Jing break; 116720848903SChaotian Jing case MMC_POWER_ON: 116820848903SChaotian Jing if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { 116920848903SChaotian Jing ret = regulator_enable(mmc->supply.vqmmc); 117020848903SChaotian Jing if (ret) 117120848903SChaotian Jing dev_err(host->dev, "Failed to set vqmmc power!\n"); 117220848903SChaotian Jing else 117320848903SChaotian Jing host->vqmmc_enabled = true; 117420848903SChaotian Jing } 117520848903SChaotian Jing break; 117620848903SChaotian Jing case MMC_POWER_OFF: 117720848903SChaotian Jing if (!IS_ERR(mmc->supply.vmmc)) 117820848903SChaotian Jing mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 117920848903SChaotian Jing 118020848903SChaotian Jing if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) { 118120848903SChaotian Jing regulator_disable(mmc->supply.vqmmc); 118220848903SChaotian Jing host->vqmmc_enabled = false; 118320848903SChaotian Jing } 118420848903SChaotian Jing break; 118520848903SChaotian Jing default: 118620848903SChaotian Jing break; 118720848903SChaotian Jing } 118820848903SChaotian Jing 118920848903SChaotian Jing if (host->mclk != ios->clock || host->ddr != ddr) 119020848903SChaotian Jing msdc_set_mclk(host, ddr, ios->clock); 119120848903SChaotian Jing } 119220848903SChaotian Jing 119320848903SChaotian Jing static struct mmc_host_ops mt_msdc_ops = { 119420848903SChaotian Jing .post_req = msdc_post_req, 119520848903SChaotian Jing .pre_req = msdc_pre_req, 119620848903SChaotian Jing .request = msdc_ops_request, 119720848903SChaotian Jing .set_ios = msdc_ops_set_ios, 119820848903SChaotian Jing .start_signal_voltage_switch = msdc_ops_switch_volt, 119920848903SChaotian Jing .card_busy = msdc_card_busy, 120020848903SChaotian Jing }; 120120848903SChaotian Jing 120220848903SChaotian Jing static int msdc_drv_probe(struct platform_device *pdev) 120320848903SChaotian Jing { 120420848903SChaotian Jing struct mmc_host *mmc; 120520848903SChaotian Jing struct msdc_host *host; 120620848903SChaotian Jing struct resource *res; 120720848903SChaotian Jing int ret; 120820848903SChaotian Jing 120920848903SChaotian Jing if (!pdev->dev.of_node) { 121020848903SChaotian Jing dev_err(&pdev->dev, "No DT found\n"); 121120848903SChaotian Jing return -EINVAL; 121220848903SChaotian Jing } 121320848903SChaotian Jing /* Allocate MMC host for this device */ 121420848903SChaotian Jing mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); 121520848903SChaotian Jing if (!mmc) 121620848903SChaotian Jing return -ENOMEM; 121720848903SChaotian Jing 121820848903SChaotian Jing host = mmc_priv(mmc); 121920848903SChaotian Jing ret = mmc_of_parse(mmc); 122020848903SChaotian Jing if (ret) 122120848903SChaotian Jing goto host_free; 122220848903SChaotian Jing 122320848903SChaotian Jing res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 122420848903SChaotian Jing host->base = devm_ioremap_resource(&pdev->dev, res); 122520848903SChaotian Jing if (IS_ERR(host->base)) { 122620848903SChaotian Jing ret = PTR_ERR(host->base); 122720848903SChaotian Jing goto host_free; 122820848903SChaotian Jing } 122920848903SChaotian Jing 123020848903SChaotian Jing ret = mmc_regulator_get_supply(mmc); 123120848903SChaotian Jing if (ret == -EPROBE_DEFER) 123220848903SChaotian Jing goto host_free; 123320848903SChaotian Jing 123420848903SChaotian Jing host->src_clk = devm_clk_get(&pdev->dev, "source"); 123520848903SChaotian Jing if (IS_ERR(host->src_clk)) { 123620848903SChaotian Jing ret = PTR_ERR(host->src_clk); 123720848903SChaotian Jing goto host_free; 123820848903SChaotian Jing } 123920848903SChaotian Jing 124020848903SChaotian Jing host->h_clk = devm_clk_get(&pdev->dev, "hclk"); 124120848903SChaotian Jing if (IS_ERR(host->h_clk)) { 124220848903SChaotian Jing ret = PTR_ERR(host->h_clk); 124320848903SChaotian Jing goto host_free; 124420848903SChaotian Jing } 124520848903SChaotian Jing 124620848903SChaotian Jing host->irq = platform_get_irq(pdev, 0); 124720848903SChaotian Jing if (host->irq < 0) { 124820848903SChaotian Jing ret = -EINVAL; 124920848903SChaotian Jing goto host_free; 125020848903SChaotian Jing } 125120848903SChaotian Jing 125220848903SChaotian Jing host->pinctrl = devm_pinctrl_get(&pdev->dev); 125320848903SChaotian Jing if (IS_ERR(host->pinctrl)) { 125420848903SChaotian Jing ret = PTR_ERR(host->pinctrl); 125520848903SChaotian Jing dev_err(&pdev->dev, "Cannot find pinctrl!\n"); 125620848903SChaotian Jing goto host_free; 125720848903SChaotian Jing } 125820848903SChaotian Jing 125920848903SChaotian Jing host->pins_default = pinctrl_lookup_state(host->pinctrl, "default"); 126020848903SChaotian Jing if (IS_ERR(host->pins_default)) { 126120848903SChaotian Jing ret = PTR_ERR(host->pins_default); 126220848903SChaotian Jing dev_err(&pdev->dev, "Cannot find pinctrl default!\n"); 126320848903SChaotian Jing goto host_free; 126420848903SChaotian Jing } 126520848903SChaotian Jing 126620848903SChaotian Jing host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); 126720848903SChaotian Jing if (IS_ERR(host->pins_uhs)) { 126820848903SChaotian Jing ret = PTR_ERR(host->pins_uhs); 126920848903SChaotian Jing dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n"); 127020848903SChaotian Jing goto host_free; 127120848903SChaotian Jing } 127220848903SChaotian Jing 127320848903SChaotian Jing host->dev = &pdev->dev; 127420848903SChaotian Jing host->mmc = mmc; 127520848903SChaotian Jing host->src_clk_freq = clk_get_rate(host->src_clk); 127620848903SChaotian Jing /* Set host parameters to mmc */ 127720848903SChaotian Jing mmc->ops = &mt_msdc_ops; 127820848903SChaotian Jing mmc->f_min = host->src_clk_freq / (4 * 255); 127920848903SChaotian Jing 128020848903SChaotian Jing mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23; 128120848903SChaotian Jing /* MMC core transfer sizes tunable parameters */ 128220848903SChaotian Jing mmc->max_segs = MAX_BD_NUM; 128320848903SChaotian Jing mmc->max_seg_size = BDMA_DESC_BUFLEN; 128420848903SChaotian Jing mmc->max_blk_size = 2048; 128520848903SChaotian Jing mmc->max_req_size = 512 * 1024; 128620848903SChaotian Jing mmc->max_blk_count = mmc->max_req_size / 512; 128720848903SChaotian Jing host->dma_mask = DMA_BIT_MASK(32); 128820848903SChaotian Jing mmc_dev(mmc)->dma_mask = &host->dma_mask; 128920848903SChaotian Jing 129020848903SChaotian Jing host->timeout_clks = 3 * 1048576; 129120848903SChaotian Jing host->dma.gpd = dma_alloc_coherent(&pdev->dev, 129220848903SChaotian Jing sizeof(struct mt_gpdma_desc), 129320848903SChaotian Jing &host->dma.gpd_addr, GFP_KERNEL); 129420848903SChaotian Jing host->dma.bd = dma_alloc_coherent(&pdev->dev, 129520848903SChaotian Jing MAX_BD_NUM * sizeof(struct mt_bdma_desc), 129620848903SChaotian Jing &host->dma.bd_addr, GFP_KERNEL); 129720848903SChaotian Jing if (!host->dma.gpd || !host->dma.bd) { 129820848903SChaotian Jing ret = -ENOMEM; 129920848903SChaotian Jing goto release_mem; 130020848903SChaotian Jing } 130120848903SChaotian Jing msdc_init_gpd_bd(host, &host->dma); 130220848903SChaotian Jing INIT_DELAYED_WORK(&host->req_timeout, msdc_request_timeout); 130320848903SChaotian Jing spin_lock_init(&host->lock); 130420848903SChaotian Jing 130520848903SChaotian Jing platform_set_drvdata(pdev, mmc); 130620848903SChaotian Jing msdc_ungate_clock(host); 130720848903SChaotian Jing msdc_init_hw(host); 130820848903SChaotian Jing 130920848903SChaotian Jing ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq, 131020848903SChaotian Jing IRQF_TRIGGER_LOW | IRQF_ONESHOT, pdev->name, host); 131120848903SChaotian Jing if (ret) 131220848903SChaotian Jing goto release; 131320848903SChaotian Jing 131420848903SChaotian Jing ret = mmc_add_host(mmc); 131520848903SChaotian Jing if (ret) 131620848903SChaotian Jing goto release; 131720848903SChaotian Jing 131820848903SChaotian Jing return 0; 131920848903SChaotian Jing 132020848903SChaotian Jing release: 132120848903SChaotian Jing platform_set_drvdata(pdev, NULL); 132220848903SChaotian Jing msdc_deinit_hw(host); 132320848903SChaotian Jing msdc_gate_clock(host); 132420848903SChaotian Jing release_mem: 132520848903SChaotian Jing if (host->dma.gpd) 132620848903SChaotian Jing dma_free_coherent(&pdev->dev, 132720848903SChaotian Jing sizeof(struct mt_gpdma_desc), 132820848903SChaotian Jing host->dma.gpd, host->dma.gpd_addr); 132920848903SChaotian Jing if (host->dma.bd) 133020848903SChaotian Jing dma_free_coherent(&pdev->dev, 133120848903SChaotian Jing MAX_BD_NUM * sizeof(struct mt_bdma_desc), 133220848903SChaotian Jing host->dma.bd, host->dma.bd_addr); 133320848903SChaotian Jing host_free: 133420848903SChaotian Jing mmc_free_host(mmc); 133520848903SChaotian Jing 133620848903SChaotian Jing return ret; 133720848903SChaotian Jing } 133820848903SChaotian Jing 133920848903SChaotian Jing static int msdc_drv_remove(struct platform_device *pdev) 134020848903SChaotian Jing { 134120848903SChaotian Jing struct mmc_host *mmc; 134220848903SChaotian Jing struct msdc_host *host; 134320848903SChaotian Jing 134420848903SChaotian Jing mmc = platform_get_drvdata(pdev); 134520848903SChaotian Jing host = mmc_priv(mmc); 134620848903SChaotian Jing 134720848903SChaotian Jing platform_set_drvdata(pdev, NULL); 134820848903SChaotian Jing mmc_remove_host(host->mmc); 134920848903SChaotian Jing msdc_deinit_hw(host); 135020848903SChaotian Jing msdc_gate_clock(host); 135120848903SChaotian Jing 135220848903SChaotian Jing dma_free_coherent(&pdev->dev, 135320848903SChaotian Jing sizeof(struct mt_gpdma_desc), 135420848903SChaotian Jing host->dma.gpd, host->dma.gpd_addr); 135520848903SChaotian Jing dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), 135620848903SChaotian Jing host->dma.bd, host->dma.bd_addr); 135720848903SChaotian Jing 135820848903SChaotian Jing mmc_free_host(host->mmc); 135920848903SChaotian Jing 136020848903SChaotian Jing return 0; 136120848903SChaotian Jing } 136220848903SChaotian Jing 136320848903SChaotian Jing static const struct of_device_id msdc_of_ids[] = { 136420848903SChaotian Jing { .compatible = "mediatek,mt8135-mmc", }, 136520848903SChaotian Jing {} 136620848903SChaotian Jing }; 136720848903SChaotian Jing 136820848903SChaotian Jing static struct platform_driver mt_msdc_driver = { 136920848903SChaotian Jing .probe = msdc_drv_probe, 137020848903SChaotian Jing .remove = msdc_drv_remove, 137120848903SChaotian Jing .driver = { 137220848903SChaotian Jing .name = "mtk-msdc", 137320848903SChaotian Jing .of_match_table = msdc_of_ids, 137420848903SChaotian Jing }, 137520848903SChaotian Jing }; 137620848903SChaotian Jing 137720848903SChaotian Jing module_platform_driver(mt_msdc_driver); 137820848903SChaotian Jing MODULE_LICENSE("GPL v2"); 137920848903SChaotian Jing MODULE_DESCRIPTION("MediaTek SD/MMC Card Driver"); 1380