11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 220848903SChaotian Jing /* 320848903SChaotian Jing * Copyright (c) 2014-2015 MediaTek Inc. 420848903SChaotian Jing * Author: Chaotian.Jing <chaotian.jing@mediatek.com> 520848903SChaotian Jing */ 620848903SChaotian Jing 720848903SChaotian Jing #include <linux/module.h> 820848903SChaotian Jing #include <linux/clk.h> 920848903SChaotian Jing #include <linux/delay.h> 1020848903SChaotian Jing #include <linux/dma-mapping.h> 1120848903SChaotian Jing #include <linux/ioport.h> 1220848903SChaotian Jing #include <linux/irq.h> 1320848903SChaotian Jing #include <linux/of_address.h> 14909b3456SRyder Lee #include <linux/of_device.h> 1520848903SChaotian Jing #include <linux/of_irq.h> 1620848903SChaotian Jing #include <linux/of_gpio.h> 1720848903SChaotian Jing #include <linux/pinctrl/consumer.h> 1820848903SChaotian Jing #include <linux/platform_device.h> 194b8a43e9SChaotian Jing #include <linux/pm.h> 204b8a43e9SChaotian Jing #include <linux/pm_runtime.h> 2120848903SChaotian Jing #include <linux/regulator/consumer.h> 226397b7f5SChaotian Jing #include <linux/slab.h> 2320848903SChaotian Jing #include <linux/spinlock.h> 24b8789ec4SUlf Hansson #include <linux/interrupt.h> 2520848903SChaotian Jing 2620848903SChaotian Jing #include <linux/mmc/card.h> 2720848903SChaotian Jing #include <linux/mmc/core.h> 2820848903SChaotian Jing #include <linux/mmc/host.h> 2920848903SChaotian Jing #include <linux/mmc/mmc.h> 3020848903SChaotian Jing #include <linux/mmc/sd.h> 3120848903SChaotian Jing #include <linux/mmc/sdio.h> 328d53e412SChaotian Jing #include <linux/mmc/slot-gpio.h> 3320848903SChaotian Jing 3420848903SChaotian Jing #define MAX_BD_NUM 1024 3520848903SChaotian Jing 3620848903SChaotian Jing /*--------------------------------------------------------------------------*/ 3720848903SChaotian Jing /* Common Definition */ 3820848903SChaotian Jing /*--------------------------------------------------------------------------*/ 3920848903SChaotian Jing #define MSDC_BUS_1BITS 0x0 4020848903SChaotian Jing #define MSDC_BUS_4BITS 0x1 4120848903SChaotian Jing #define MSDC_BUS_8BITS 0x2 4220848903SChaotian Jing 4320848903SChaotian Jing #define MSDC_BURST_64B 0x6 4420848903SChaotian Jing 4520848903SChaotian Jing /*--------------------------------------------------------------------------*/ 4620848903SChaotian Jing /* Register Offset */ 4720848903SChaotian Jing /*--------------------------------------------------------------------------*/ 4820848903SChaotian Jing #define MSDC_CFG 0x0 4920848903SChaotian Jing #define MSDC_IOCON 0x04 5020848903SChaotian Jing #define MSDC_PS 0x08 5120848903SChaotian Jing #define MSDC_INT 0x0c 5220848903SChaotian Jing #define MSDC_INTEN 0x10 5320848903SChaotian Jing #define MSDC_FIFOCS 0x14 5420848903SChaotian Jing #define SDC_CFG 0x30 5520848903SChaotian Jing #define SDC_CMD 0x34 5620848903SChaotian Jing #define SDC_ARG 0x38 5720848903SChaotian Jing #define SDC_STS 0x3c 5820848903SChaotian Jing #define SDC_RESP0 0x40 5920848903SChaotian Jing #define SDC_RESP1 0x44 6020848903SChaotian Jing #define SDC_RESP2 0x48 6120848903SChaotian Jing #define SDC_RESP3 0x4c 6220848903SChaotian Jing #define SDC_BLK_NUM 0x50 63d9dcbfc8SChaotian Jing #define SDC_ADV_CFG0 0x64 64c9b5061eSChaotian Jing #define EMMC_IOCON 0x7c 6520848903SChaotian Jing #define SDC_ACMD_RESP 0x80 662a9bde19SChaotian Jing #define DMA_SA_H4BIT 0x8c 6720848903SChaotian Jing #define MSDC_DMA_SA 0x90 6820848903SChaotian Jing #define MSDC_DMA_CTRL 0x98 6920848903SChaotian Jing #define MSDC_DMA_CFG 0x9c 7020848903SChaotian Jing #define MSDC_PATCH_BIT 0xb0 7120848903SChaotian Jing #define MSDC_PATCH_BIT1 0xb4 722fea5819SChaotian Jing #define MSDC_PATCH_BIT2 0xb8 7320848903SChaotian Jing #define MSDC_PAD_TUNE 0xec 7439add252SChaotian Jing #define MSDC_PAD_TUNE0 0xf0 756397b7f5SChaotian Jing #define PAD_DS_TUNE 0x188 761ede5cb8Syong mao #define PAD_CMD_TUNE 0x18c 776397b7f5SChaotian Jing #define EMMC50_CFG0 0x208 78c8609b22SChaotian Jing #define EMMC50_CFG3 0x220 79d9dcbfc8SChaotian Jing #define SDC_FIFO_CFG 0x228 8020848903SChaotian Jing 8120848903SChaotian Jing /*--------------------------------------------------------------------------*/ 82a2e6d1f6SChaotian Jing /* Top Pad Register Offset */ 83a2e6d1f6SChaotian Jing /*--------------------------------------------------------------------------*/ 84a2e6d1f6SChaotian Jing #define EMMC_TOP_CONTROL 0x00 85a2e6d1f6SChaotian Jing #define EMMC_TOP_CMD 0x04 86a2e6d1f6SChaotian Jing #define EMMC50_PAD_DS_TUNE 0x0c 87a2e6d1f6SChaotian Jing 88a2e6d1f6SChaotian Jing /*--------------------------------------------------------------------------*/ 8920848903SChaotian Jing /* Register Mask */ 9020848903SChaotian Jing /*--------------------------------------------------------------------------*/ 9120848903SChaotian Jing 9220848903SChaotian Jing /* MSDC_CFG mask */ 9320848903SChaotian Jing #define MSDC_CFG_MODE (0x1 << 0) /* RW */ 9420848903SChaotian Jing #define MSDC_CFG_CKPDN (0x1 << 1) /* RW */ 9520848903SChaotian Jing #define MSDC_CFG_RST (0x1 << 2) /* RW */ 9620848903SChaotian Jing #define MSDC_CFG_PIO (0x1 << 3) /* RW */ 9720848903SChaotian Jing #define MSDC_CFG_CKDRVEN (0x1 << 4) /* RW */ 9820848903SChaotian Jing #define MSDC_CFG_BV18SDT (0x1 << 5) /* RW */ 9920848903SChaotian Jing #define MSDC_CFG_BV18PSS (0x1 << 6) /* R */ 10020848903SChaotian Jing #define MSDC_CFG_CKSTB (0x1 << 7) /* R */ 10120848903SChaotian Jing #define MSDC_CFG_CKDIV (0xff << 8) /* RW */ 10220848903SChaotian Jing #define MSDC_CFG_CKMOD (0x3 << 16) /* RW */ 1036397b7f5SChaotian Jing #define MSDC_CFG_HS400_CK_MODE (0x1 << 18) /* RW */ 104762d491aSChaotian Jing #define MSDC_CFG_HS400_CK_MODE_EXTRA (0x1 << 22) /* RW */ 105762d491aSChaotian Jing #define MSDC_CFG_CKDIV_EXTRA (0xfff << 8) /* RW */ 106762d491aSChaotian Jing #define MSDC_CFG_CKMOD_EXTRA (0x3 << 20) /* RW */ 10720848903SChaotian Jing 10820848903SChaotian Jing /* MSDC_IOCON mask */ 10920848903SChaotian Jing #define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */ 11020848903SChaotian Jing #define MSDC_IOCON_RSPL (0x1 << 1) /* RW */ 11120848903SChaotian Jing #define MSDC_IOCON_DSPL (0x1 << 2) /* RW */ 11220848903SChaotian Jing #define MSDC_IOCON_DDLSEL (0x1 << 3) /* RW */ 11320848903SChaotian Jing #define MSDC_IOCON_DDR50CKD (0x1 << 4) /* RW */ 11420848903SChaotian Jing #define MSDC_IOCON_DSPLSEL (0x1 << 5) /* RW */ 11520848903SChaotian Jing #define MSDC_IOCON_W_DSPL (0x1 << 8) /* RW */ 11620848903SChaotian Jing #define MSDC_IOCON_D0SPL (0x1 << 16) /* RW */ 11720848903SChaotian Jing #define MSDC_IOCON_D1SPL (0x1 << 17) /* RW */ 11820848903SChaotian Jing #define MSDC_IOCON_D2SPL (0x1 << 18) /* RW */ 11920848903SChaotian Jing #define MSDC_IOCON_D3SPL (0x1 << 19) /* RW */ 12020848903SChaotian Jing #define MSDC_IOCON_D4SPL (0x1 << 20) /* RW */ 12120848903SChaotian Jing #define MSDC_IOCON_D5SPL (0x1 << 21) /* RW */ 12220848903SChaotian Jing #define MSDC_IOCON_D6SPL (0x1 << 22) /* RW */ 12320848903SChaotian Jing #define MSDC_IOCON_D7SPL (0x1 << 23) /* RW */ 12420848903SChaotian Jing #define MSDC_IOCON_RISCSZ (0x3 << 24) /* RW */ 12520848903SChaotian Jing 12620848903SChaotian Jing /* MSDC_PS mask */ 12720848903SChaotian Jing #define MSDC_PS_CDEN (0x1 << 0) /* RW */ 12820848903SChaotian Jing #define MSDC_PS_CDSTS (0x1 << 1) /* R */ 12920848903SChaotian Jing #define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */ 13020848903SChaotian Jing #define MSDC_PS_DAT (0xff << 16) /* R */ 1319e2582e5Syong mao #define MSDC_PS_DATA1 (0x1 << 17) /* R */ 13220848903SChaotian Jing #define MSDC_PS_CMD (0x1 << 24) /* R */ 13320848903SChaotian Jing #define MSDC_PS_WP (0x1 << 31) /* R */ 13420848903SChaotian Jing 13520848903SChaotian Jing /* MSDC_INT mask */ 13620848903SChaotian Jing #define MSDC_INT_MMCIRQ (0x1 << 0) /* W1C */ 13720848903SChaotian Jing #define MSDC_INT_CDSC (0x1 << 1) /* W1C */ 13820848903SChaotian Jing #define MSDC_INT_ACMDRDY (0x1 << 3) /* W1C */ 13920848903SChaotian Jing #define MSDC_INT_ACMDTMO (0x1 << 4) /* W1C */ 14020848903SChaotian Jing #define MSDC_INT_ACMDCRCERR (0x1 << 5) /* W1C */ 14120848903SChaotian Jing #define MSDC_INT_DMAQ_EMPTY (0x1 << 6) /* W1C */ 14220848903SChaotian Jing #define MSDC_INT_SDIOIRQ (0x1 << 7) /* W1C */ 14320848903SChaotian Jing #define MSDC_INT_CMDRDY (0x1 << 8) /* W1C */ 14420848903SChaotian Jing #define MSDC_INT_CMDTMO (0x1 << 9) /* W1C */ 14520848903SChaotian Jing #define MSDC_INT_RSPCRCERR (0x1 << 10) /* W1C */ 14620848903SChaotian Jing #define MSDC_INT_CSTA (0x1 << 11) /* R */ 14720848903SChaotian Jing #define MSDC_INT_XFER_COMPL (0x1 << 12) /* W1C */ 14820848903SChaotian Jing #define MSDC_INT_DXFER_DONE (0x1 << 13) /* W1C */ 14920848903SChaotian Jing #define MSDC_INT_DATTMO (0x1 << 14) /* W1C */ 15020848903SChaotian Jing #define MSDC_INT_DATCRCERR (0x1 << 15) /* W1C */ 15120848903SChaotian Jing #define MSDC_INT_ACMD19_DONE (0x1 << 16) /* W1C */ 15220848903SChaotian Jing #define MSDC_INT_DMA_BDCSERR (0x1 << 17) /* W1C */ 15320848903SChaotian Jing #define MSDC_INT_DMA_GPDCSERR (0x1 << 18) /* W1C */ 15420848903SChaotian Jing #define MSDC_INT_DMA_PROTECT (0x1 << 19) /* W1C */ 15520848903SChaotian Jing 15620848903SChaotian Jing /* MSDC_INTEN mask */ 15720848903SChaotian Jing #define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */ 15820848903SChaotian Jing #define MSDC_INTEN_CDSC (0x1 << 1) /* RW */ 15920848903SChaotian Jing #define MSDC_INTEN_ACMDRDY (0x1 << 3) /* RW */ 16020848903SChaotian Jing #define MSDC_INTEN_ACMDTMO (0x1 << 4) /* RW */ 16120848903SChaotian Jing #define MSDC_INTEN_ACMDCRCERR (0x1 << 5) /* RW */ 16220848903SChaotian Jing #define MSDC_INTEN_DMAQ_EMPTY (0x1 << 6) /* RW */ 16320848903SChaotian Jing #define MSDC_INTEN_SDIOIRQ (0x1 << 7) /* RW */ 16420848903SChaotian Jing #define MSDC_INTEN_CMDRDY (0x1 << 8) /* RW */ 16520848903SChaotian Jing #define MSDC_INTEN_CMDTMO (0x1 << 9) /* RW */ 16620848903SChaotian Jing #define MSDC_INTEN_RSPCRCERR (0x1 << 10) /* RW */ 16720848903SChaotian Jing #define MSDC_INTEN_CSTA (0x1 << 11) /* RW */ 16820848903SChaotian Jing #define MSDC_INTEN_XFER_COMPL (0x1 << 12) /* RW */ 16920848903SChaotian Jing #define MSDC_INTEN_DXFER_DONE (0x1 << 13) /* RW */ 17020848903SChaotian Jing #define MSDC_INTEN_DATTMO (0x1 << 14) /* RW */ 17120848903SChaotian Jing #define MSDC_INTEN_DATCRCERR (0x1 << 15) /* RW */ 17220848903SChaotian Jing #define MSDC_INTEN_ACMD19_DONE (0x1 << 16) /* RW */ 17320848903SChaotian Jing #define MSDC_INTEN_DMA_BDCSERR (0x1 << 17) /* RW */ 17420848903SChaotian Jing #define MSDC_INTEN_DMA_GPDCSERR (0x1 << 18) /* RW */ 17520848903SChaotian Jing #define MSDC_INTEN_DMA_PROTECT (0x1 << 19) /* RW */ 17620848903SChaotian Jing 17720848903SChaotian Jing /* MSDC_FIFOCS mask */ 17820848903SChaotian Jing #define MSDC_FIFOCS_RXCNT (0xff << 0) /* R */ 17920848903SChaotian Jing #define MSDC_FIFOCS_TXCNT (0xff << 16) /* R */ 18020848903SChaotian Jing #define MSDC_FIFOCS_CLR (0x1 << 31) /* RW */ 18120848903SChaotian Jing 18220848903SChaotian Jing /* SDC_CFG mask */ 18320848903SChaotian Jing #define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */ 18420848903SChaotian Jing #define SDC_CFG_INSWKUP (0x1 << 1) /* RW */ 18520848903SChaotian Jing #define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */ 18620848903SChaotian Jing #define SDC_CFG_SDIO (0x1 << 19) /* RW */ 18720848903SChaotian Jing #define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */ 18820848903SChaotian Jing #define SDC_CFG_INTATGAP (0x1 << 21) /* RW */ 18920848903SChaotian Jing #define SDC_CFG_DTOC (0xff << 24) /* RW */ 19020848903SChaotian Jing 19120848903SChaotian Jing /* SDC_STS mask */ 19220848903SChaotian Jing #define SDC_STS_SDCBUSY (0x1 << 0) /* RW */ 19320848903SChaotian Jing #define SDC_STS_CMDBUSY (0x1 << 1) /* RW */ 19420848903SChaotian Jing #define SDC_STS_SWR_COMPL (0x1 << 31) /* RW */ 19520848903SChaotian Jing 19626c71a13Syong mao #define SDC_DAT1_IRQ_TRIGGER (0x1 << 19) /* RW */ 197d9dcbfc8SChaotian Jing /* SDC_ADV_CFG0 mask */ 198d9dcbfc8SChaotian Jing #define SDC_RX_ENHANCE_EN (0x1 << 20) /* RW */ 199d9dcbfc8SChaotian Jing 2002a9bde19SChaotian Jing /* DMA_SA_H4BIT mask */ 2012a9bde19SChaotian Jing #define DMA_ADDR_HIGH_4BIT (0xf << 0) /* RW */ 2022a9bde19SChaotian Jing 20320848903SChaotian Jing /* MSDC_DMA_CTRL mask */ 20420848903SChaotian Jing #define MSDC_DMA_CTRL_START (0x1 << 0) /* W */ 20520848903SChaotian Jing #define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */ 20620848903SChaotian Jing #define MSDC_DMA_CTRL_RESUME (0x1 << 2) /* W */ 20720848903SChaotian Jing #define MSDC_DMA_CTRL_MODE (0x1 << 8) /* RW */ 20820848903SChaotian Jing #define MSDC_DMA_CTRL_LASTBUF (0x1 << 10) /* RW */ 20920848903SChaotian Jing #define MSDC_DMA_CTRL_BRUSTSZ (0x7 << 12) /* RW */ 21020848903SChaotian Jing 21120848903SChaotian Jing /* MSDC_DMA_CFG mask */ 21220848903SChaotian Jing #define MSDC_DMA_CFG_STS (0x1 << 0) /* R */ 21320848903SChaotian Jing #define MSDC_DMA_CFG_DECSEN (0x1 << 1) /* RW */ 21420848903SChaotian Jing #define MSDC_DMA_CFG_AHBHPROT2 (0x2 << 8) /* RW */ 21520848903SChaotian Jing #define MSDC_DMA_CFG_ACTIVEEN (0x2 << 12) /* RW */ 21620848903SChaotian Jing #define MSDC_DMA_CFG_CS12B16B (0x1 << 16) /* RW */ 21720848903SChaotian Jing 21820848903SChaotian Jing /* MSDC_PATCH_BIT mask */ 21920848903SChaotian Jing #define MSDC_PATCH_BIT_ODDSUPP (0x1 << 1) /* RW */ 22020848903SChaotian Jing #define MSDC_INT_DAT_LATCH_CK_SEL (0x7 << 7) 22120848903SChaotian Jing #define MSDC_CKGEN_MSDC_DLY_SEL (0x1f << 10) 22220848903SChaotian Jing #define MSDC_PATCH_BIT_IODSSEL (0x1 << 16) /* RW */ 22320848903SChaotian Jing #define MSDC_PATCH_BIT_IOINTSEL (0x1 << 17) /* RW */ 22420848903SChaotian Jing #define MSDC_PATCH_BIT_BUSYDLY (0xf << 18) /* RW */ 22520848903SChaotian Jing #define MSDC_PATCH_BIT_WDOD (0xf << 22) /* RW */ 22620848903SChaotian Jing #define MSDC_PATCH_BIT_IDRTSEL (0x1 << 26) /* RW */ 22720848903SChaotian Jing #define MSDC_PATCH_BIT_CMDFSEL (0x1 << 27) /* RW */ 22820848903SChaotian Jing #define MSDC_PATCH_BIT_INTDLSEL (0x1 << 28) /* RW */ 22920848903SChaotian Jing #define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */ 23020848903SChaotian Jing #define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */ 23120848903SChaotian Jing 2328f34e5bdSChaotian Jing #define MSDC_PATCH_BIT1_CMDTA (0x7 << 3) /* RW */ 233d9dcbfc8SChaotian Jing #define MSDC_PATCH_BIT1_STOP_DLY (0xf << 8) /* RW */ 234d9dcbfc8SChaotian Jing 2352fea5819SChaotian Jing #define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */ 2362fea5819SChaotian Jing #define MSDC_PATCH_BIT2_CFGCRCSTS (0x1 << 28) /* RW */ 2372a9bde19SChaotian Jing #define MSDC_PB2_SUPPORT_64G (0x1 << 1) /* RW */ 2382fea5819SChaotian Jing #define MSDC_PB2_RESPWAIT (0x3 << 2) /* RW */ 2392fea5819SChaotian Jing #define MSDC_PB2_RESPSTSENSEL (0x7 << 16) /* RW */ 2402fea5819SChaotian Jing #define MSDC_PB2_CRCSTSENSEL (0x7 << 29) /* RW */ 2412fea5819SChaotian Jing 2421ede5cb8Syong mao #define MSDC_PAD_TUNE_DATWRDLY (0x1f << 0) /* RW */ 2436397b7f5SChaotian Jing #define MSDC_PAD_TUNE_DATRRDLY (0x1f << 8) /* RW */ 2446397b7f5SChaotian Jing #define MSDC_PAD_TUNE_CMDRDLY (0x1f << 16) /* RW */ 2451ede5cb8Syong mao #define MSDC_PAD_TUNE_CMDRRDLY (0x1f << 22) /* RW */ 2461ede5cb8Syong mao #define MSDC_PAD_TUNE_CLKTDLY (0x1f << 27) /* RW */ 2472fea5819SChaotian Jing #define MSDC_PAD_TUNE_RXDLYSEL (0x1 << 15) /* RW */ 2482fea5819SChaotian Jing #define MSDC_PAD_TUNE_RD_SEL (0x1 << 13) /* RW */ 2492fea5819SChaotian Jing #define MSDC_PAD_TUNE_CMD_SEL (0x1 << 21) /* RW */ 2506397b7f5SChaotian Jing 2516397b7f5SChaotian Jing #define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */ 2526397b7f5SChaotian Jing #define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */ 2536397b7f5SChaotian Jing #define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */ 2546397b7f5SChaotian Jing 2551ede5cb8Syong mao #define PAD_CMD_TUNE_RX_DLY3 (0x1f << 1) /* RW */ 2561ede5cb8Syong mao 2576397b7f5SChaotian Jing #define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */ 2586397b7f5SChaotian Jing #define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */ 2596397b7f5SChaotian Jing #define EMMC50_CFG_CFCSTS_SEL (0x1 << 4) /* RW */ 2606397b7f5SChaotian Jing 261c8609b22SChaotian Jing #define EMMC50_CFG3_OUTS_WR (0x1f << 0) /* RW */ 262c8609b22SChaotian Jing 263d9dcbfc8SChaotian Jing #define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */ 264d9dcbfc8SChaotian Jing #define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */ 265d9dcbfc8SChaotian Jing 266a2e6d1f6SChaotian Jing /* EMMC_TOP_CONTROL mask */ 267a2e6d1f6SChaotian Jing #define PAD_RXDLY_SEL (0x1 << 0) /* RW */ 268a2e6d1f6SChaotian Jing #define DELAY_EN (0x1 << 1) /* RW */ 269a2e6d1f6SChaotian Jing #define PAD_DAT_RD_RXDLY2 (0x1f << 2) /* RW */ 270a2e6d1f6SChaotian Jing #define PAD_DAT_RD_RXDLY (0x1f << 7) /* RW */ 271a2e6d1f6SChaotian Jing #define PAD_DAT_RD_RXDLY2_SEL (0x1 << 12) /* RW */ 272a2e6d1f6SChaotian Jing #define PAD_DAT_RD_RXDLY_SEL (0x1 << 13) /* RW */ 273a2e6d1f6SChaotian Jing #define DATA_K_VALUE_SEL (0x1 << 14) /* RW */ 274a2e6d1f6SChaotian Jing #define SDC_RX_ENH_EN (0x1 << 15) /* TW */ 275a2e6d1f6SChaotian Jing 276a2e6d1f6SChaotian Jing /* EMMC_TOP_CMD mask */ 277a2e6d1f6SChaotian Jing #define PAD_CMD_RXDLY2 (0x1f << 0) /* RW */ 278a2e6d1f6SChaotian Jing #define PAD_CMD_RXDLY (0x1f << 5) /* RW */ 279a2e6d1f6SChaotian Jing #define PAD_CMD_RD_RXDLY2_SEL (0x1 << 10) /* RW */ 280a2e6d1f6SChaotian Jing #define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */ 281a2e6d1f6SChaotian Jing #define PAD_CMD_TX_DLY (0x1f << 12) /* RW */ 282a2e6d1f6SChaotian Jing 28320848903SChaotian Jing #define REQ_CMD_EIO (0x1 << 0) 28420848903SChaotian Jing #define REQ_CMD_TMO (0x1 << 1) 28520848903SChaotian Jing #define REQ_DAT_ERR (0x1 << 2) 28620848903SChaotian Jing #define REQ_STOP_EIO (0x1 << 3) 28720848903SChaotian Jing #define REQ_STOP_TMO (0x1 << 4) 28820848903SChaotian Jing #define REQ_CMD_BUSY (0x1 << 5) 28920848903SChaotian Jing 29020848903SChaotian Jing #define MSDC_PREPARE_FLAG (0x1 << 0) 29120848903SChaotian Jing #define MSDC_ASYNC_FLAG (0x1 << 1) 29220848903SChaotian Jing #define MSDC_MMAP_FLAG (0x1 << 2) 29320848903SChaotian Jing 2944b8a43e9SChaotian Jing #define MTK_MMC_AUTOSUSPEND_DELAY 50 29520848903SChaotian Jing #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ 29620848903SChaotian Jing #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ 29720848903SChaotian Jing 298d087bde5SNeilBrown #define DEFAULT_DEBOUNCE (8) /* 8 cycles CD debounce */ 299d087bde5SNeilBrown 3006397b7f5SChaotian Jing #define PAD_DELAY_MAX 32 /* PAD delay cells */ 30120848903SChaotian Jing /*--------------------------------------------------------------------------*/ 30220848903SChaotian Jing /* Descriptor Structure */ 30320848903SChaotian Jing /*--------------------------------------------------------------------------*/ 30420848903SChaotian Jing struct mt_gpdma_desc { 30520848903SChaotian Jing u32 gpd_info; 30620848903SChaotian Jing #define GPDMA_DESC_HWO (0x1 << 0) 30720848903SChaotian Jing #define GPDMA_DESC_BDP (0x1 << 1) 30820848903SChaotian Jing #define GPDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ 30920848903SChaotian Jing #define GPDMA_DESC_INT (0x1 << 16) 3102a9bde19SChaotian Jing #define GPDMA_DESC_NEXT_H4 (0xf << 24) 3112a9bde19SChaotian Jing #define GPDMA_DESC_PTR_H4 (0xf << 28) 31220848903SChaotian Jing u32 next; 31320848903SChaotian Jing u32 ptr; 31420848903SChaotian Jing u32 gpd_data_len; 31520848903SChaotian Jing #define GPDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ 31620848903SChaotian Jing #define GPDMA_DESC_EXTLEN (0xff << 16) /* bit16 ~ bit23 */ 31720848903SChaotian Jing u32 arg; 31820848903SChaotian Jing u32 blknum; 31920848903SChaotian Jing u32 cmd; 32020848903SChaotian Jing }; 32120848903SChaotian Jing 32220848903SChaotian Jing struct mt_bdma_desc { 32320848903SChaotian Jing u32 bd_info; 32420848903SChaotian Jing #define BDMA_DESC_EOL (0x1 << 0) 32520848903SChaotian Jing #define BDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ 32620848903SChaotian Jing #define BDMA_DESC_BLKPAD (0x1 << 17) 32720848903SChaotian Jing #define BDMA_DESC_DWPAD (0x1 << 18) 3282a9bde19SChaotian Jing #define BDMA_DESC_NEXT_H4 (0xf << 24) 3292a9bde19SChaotian Jing #define BDMA_DESC_PTR_H4 (0xf << 28) 33020848903SChaotian Jing u32 next; 33120848903SChaotian Jing u32 ptr; 33220848903SChaotian Jing u32 bd_data_len; 33320848903SChaotian Jing #define BDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ 3346ef042bdSChaotian Jing #define BDMA_DESC_BUFLEN_EXT (0xffffff) /* bit0 ~ bit23 */ 33520848903SChaotian Jing }; 33620848903SChaotian Jing 33720848903SChaotian Jing struct msdc_dma { 33820848903SChaotian Jing struct scatterlist *sg; /* I/O scatter list */ 33920848903SChaotian Jing struct mt_gpdma_desc *gpd; /* pointer to gpd array */ 34020848903SChaotian Jing struct mt_bdma_desc *bd; /* pointer to bd array */ 34120848903SChaotian Jing dma_addr_t gpd_addr; /* the physical address of gpd array */ 34220848903SChaotian Jing dma_addr_t bd_addr; /* the physical address of bd array */ 34320848903SChaotian Jing }; 34420848903SChaotian Jing 3454b8a43e9SChaotian Jing struct msdc_save_para { 3464b8a43e9SChaotian Jing u32 msdc_cfg; 3474b8a43e9SChaotian Jing u32 iocon; 3484b8a43e9SChaotian Jing u32 sdc_cfg; 3494b8a43e9SChaotian Jing u32 pad_tune; 3504b8a43e9SChaotian Jing u32 patch_bit0; 3514b8a43e9SChaotian Jing u32 patch_bit1; 3522fea5819SChaotian Jing u32 patch_bit2; 3536397b7f5SChaotian Jing u32 pad_ds_tune; 3541ede5cb8Syong mao u32 pad_cmd_tune; 3556397b7f5SChaotian Jing u32 emmc50_cfg0; 356c8609b22SChaotian Jing u32 emmc50_cfg3; 357d9dcbfc8SChaotian Jing u32 sdc_fifo_cfg; 358a2e6d1f6SChaotian Jing u32 emmc_top_control; 359a2e6d1f6SChaotian Jing u32 emmc_top_cmd; 360a2e6d1f6SChaotian Jing u32 emmc50_pad_ds_tune; 3616397b7f5SChaotian Jing }; 3626397b7f5SChaotian Jing 363762d491aSChaotian Jing struct mtk_mmc_compatible { 364762d491aSChaotian Jing u8 clk_div_bits; 3659e2582e5Syong mao bool recheck_sdio_irq; 3667f3d5852SChaotian Jing bool hs400_tune; /* only used for MT8173 */ 36739add252SChaotian Jing u32 pad_tune_reg; 3682fea5819SChaotian Jing bool async_fifo; 3692fea5819SChaotian Jing bool data_tune; 370acde28c4SChaotian Jing bool busy_check; 371d9dcbfc8SChaotian Jing bool stop_clk_fix; 372d9dcbfc8SChaotian Jing bool enhance_rx; 3732a9bde19SChaotian Jing bool support_64g; 374d087bde5SNeilBrown bool use_internal_cd; 375762d491aSChaotian Jing }; 376762d491aSChaotian Jing 37786beac37SChaotian Jing struct msdc_tune_para { 37886beac37SChaotian Jing u32 iocon; 37986beac37SChaotian Jing u32 pad_tune; 3801ede5cb8Syong mao u32 pad_cmd_tune; 381a2e6d1f6SChaotian Jing u32 emmc_top_control; 382a2e6d1f6SChaotian Jing u32 emmc_top_cmd; 38386beac37SChaotian Jing }; 38486beac37SChaotian Jing 3856397b7f5SChaotian Jing struct msdc_delay_phase { 3866397b7f5SChaotian Jing u8 maxlen; 3876397b7f5SChaotian Jing u8 start; 3886397b7f5SChaotian Jing u8 final_phase; 3894b8a43e9SChaotian Jing }; 3904b8a43e9SChaotian Jing 39120848903SChaotian Jing struct msdc_host { 39220848903SChaotian Jing struct device *dev; 393762d491aSChaotian Jing const struct mtk_mmc_compatible *dev_comp; 39420848903SChaotian Jing struct mmc_host *mmc; /* mmc structure */ 39520848903SChaotian Jing int cmd_rsp; 39620848903SChaotian Jing 39720848903SChaotian Jing spinlock_t lock; 39820848903SChaotian Jing struct mmc_request *mrq; 39920848903SChaotian Jing struct mmc_command *cmd; 40020848903SChaotian Jing struct mmc_data *data; 40120848903SChaotian Jing int error; 40220848903SChaotian Jing 40320848903SChaotian Jing void __iomem *base; /* host base address */ 404a2e6d1f6SChaotian Jing void __iomem *top_base; /* host top register base address */ 40520848903SChaotian Jing 40620848903SChaotian Jing struct msdc_dma dma; /* dma channel */ 40720848903SChaotian Jing u64 dma_mask; 40820848903SChaotian Jing 40920848903SChaotian Jing u32 timeout_ns; /* data timeout ns */ 41020848903SChaotian Jing u32 timeout_clks; /* data timeout clks */ 41120848903SChaotian Jing 41220848903SChaotian Jing struct pinctrl *pinctrl; 41320848903SChaotian Jing struct pinctrl_state *pins_default; 41420848903SChaotian Jing struct pinctrl_state *pins_uhs; 41520848903SChaotian Jing struct delayed_work req_timeout; 41620848903SChaotian Jing int irq; /* host interrupt */ 41720848903SChaotian Jing 41820848903SChaotian Jing struct clk *src_clk; /* msdc source clock */ 41920848903SChaotian Jing struct clk *h_clk; /* msdc h_clk */ 420258bac4aSChaotian Jing struct clk *bus_clk; /* bus clock which used to access register */ 4213c1a8844SChaotian Jing struct clk *src_clk_cg; /* msdc source clock control gate */ 42220848903SChaotian Jing u32 mclk; /* mmc subsystem clock frequency */ 42320848903SChaotian Jing u32 src_clk_freq; /* source clock frequency */ 4246e622947SChaotian Jing unsigned char timing; 42520848903SChaotian Jing bool vqmmc_enabled; 426d17bb71cSChaotian Jing u32 latch_ck; 4276397b7f5SChaotian Jing u32 hs400_ds_delay; 4281ede5cb8Syong mao u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */ 4291ede5cb8Syong mao u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */ 4301ede5cb8Syong mao bool hs400_cmd_resp_sel_rising; 4311ede5cb8Syong mao /* cmd response sample selection for HS400 */ 4325462ff39SChaotian Jing bool hs400_mode; /* current eMMC will run at hs400 mode */ 433d087bde5SNeilBrown bool internal_cd; /* Use internal card-detect logic */ 4344b8a43e9SChaotian Jing struct msdc_save_para save_para; /* used when gate HCLK */ 43586beac37SChaotian Jing struct msdc_tune_para def_tune_para; /* default tune setting */ 43686beac37SChaotian Jing struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ 43720848903SChaotian Jing }; 43820848903SChaotian Jing 439762d491aSChaotian Jing static const struct mtk_mmc_compatible mt8135_compat = { 440762d491aSChaotian Jing .clk_div_bits = 8, 4419e2582e5Syong mao .recheck_sdio_irq = false, 4427f3d5852SChaotian Jing .hs400_tune = false, 44339add252SChaotian Jing .pad_tune_reg = MSDC_PAD_TUNE, 4442fea5819SChaotian Jing .async_fifo = false, 4452fea5819SChaotian Jing .data_tune = false, 446acde28c4SChaotian Jing .busy_check = false, 447d9dcbfc8SChaotian Jing .stop_clk_fix = false, 448d9dcbfc8SChaotian Jing .enhance_rx = false, 4492a9bde19SChaotian Jing .support_64g = false, 450762d491aSChaotian Jing }; 451762d491aSChaotian Jing 452762d491aSChaotian Jing static const struct mtk_mmc_compatible mt8173_compat = { 453762d491aSChaotian Jing .clk_div_bits = 8, 4549e2582e5Syong mao .recheck_sdio_irq = true, 4557f3d5852SChaotian Jing .hs400_tune = true, 45639add252SChaotian Jing .pad_tune_reg = MSDC_PAD_TUNE, 4572fea5819SChaotian Jing .async_fifo = false, 4582fea5819SChaotian Jing .data_tune = false, 459acde28c4SChaotian Jing .busy_check = false, 460d9dcbfc8SChaotian Jing .stop_clk_fix = false, 461d9dcbfc8SChaotian Jing .enhance_rx = false, 4622a9bde19SChaotian Jing .support_64g = false, 463762d491aSChaotian Jing }; 464762d491aSChaotian Jing 465a2e6d1f6SChaotian Jing static const struct mtk_mmc_compatible mt8183_compat = { 466a2e6d1f6SChaotian Jing .clk_div_bits = 12, 4679e2582e5Syong mao .recheck_sdio_irq = false, 468a2e6d1f6SChaotian Jing .hs400_tune = false, 469a2e6d1f6SChaotian Jing .pad_tune_reg = MSDC_PAD_TUNE0, 470a2e6d1f6SChaotian Jing .async_fifo = true, 471a2e6d1f6SChaotian Jing .data_tune = true, 472a2e6d1f6SChaotian Jing .busy_check = true, 473a2e6d1f6SChaotian Jing .stop_clk_fix = true, 474a2e6d1f6SChaotian Jing .enhance_rx = true, 475a2e6d1f6SChaotian Jing .support_64g = true, 476a2e6d1f6SChaotian Jing }; 477a2e6d1f6SChaotian Jing 478762d491aSChaotian Jing static const struct mtk_mmc_compatible mt2701_compat = { 479762d491aSChaotian Jing .clk_div_bits = 12, 4809e2582e5Syong mao .recheck_sdio_irq = false, 4817f3d5852SChaotian Jing .hs400_tune = false, 48239add252SChaotian Jing .pad_tune_reg = MSDC_PAD_TUNE0, 4832fea5819SChaotian Jing .async_fifo = true, 4842fea5819SChaotian Jing .data_tune = true, 485acde28c4SChaotian Jing .busy_check = false, 486d9dcbfc8SChaotian Jing .stop_clk_fix = false, 487d9dcbfc8SChaotian Jing .enhance_rx = false, 4882a9bde19SChaotian Jing .support_64g = false, 489762d491aSChaotian Jing }; 490762d491aSChaotian Jing 491762d491aSChaotian Jing static const struct mtk_mmc_compatible mt2712_compat = { 492762d491aSChaotian Jing .clk_div_bits = 12, 4939e2582e5Syong mao .recheck_sdio_irq = false, 4947f3d5852SChaotian Jing .hs400_tune = false, 49539add252SChaotian Jing .pad_tune_reg = MSDC_PAD_TUNE0, 4962fea5819SChaotian Jing .async_fifo = true, 4972fea5819SChaotian Jing .data_tune = true, 498acde28c4SChaotian Jing .busy_check = true, 499d9dcbfc8SChaotian Jing .stop_clk_fix = true, 500d9dcbfc8SChaotian Jing .enhance_rx = true, 5012a9bde19SChaotian Jing .support_64g = true, 502762d491aSChaotian Jing }; 503762d491aSChaotian Jing 504966580adSSean Wang static const struct mtk_mmc_compatible mt7622_compat = { 505966580adSSean Wang .clk_div_bits = 12, 5069e2582e5Syong mao .recheck_sdio_irq = false, 507966580adSSean Wang .hs400_tune = false, 508966580adSSean Wang .pad_tune_reg = MSDC_PAD_TUNE0, 509966580adSSean Wang .async_fifo = true, 510966580adSSean Wang .data_tune = true, 511966580adSSean Wang .busy_check = true, 512966580adSSean Wang .stop_clk_fix = true, 513966580adSSean Wang .enhance_rx = true, 5142a9bde19SChaotian Jing .support_64g = false, 515966580adSSean Wang }; 516966580adSSean Wang 51789822b73SFabien Parent static const struct mtk_mmc_compatible mt8516_compat = { 51889822b73SFabien Parent .clk_div_bits = 12, 5199e2582e5Syong mao .recheck_sdio_irq = false, 52089822b73SFabien Parent .hs400_tune = false, 52189822b73SFabien Parent .pad_tune_reg = MSDC_PAD_TUNE0, 52289822b73SFabien Parent .async_fifo = true, 52389822b73SFabien Parent .data_tune = true, 52489822b73SFabien Parent .busy_check = true, 52589822b73SFabien Parent .stop_clk_fix = true, 52689822b73SFabien Parent }; 52789822b73SFabien Parent 528afb7c791SNeilBrown static const struct mtk_mmc_compatible mt7620_compat = { 529afb7c791SNeilBrown .clk_div_bits = 8, 5309e2582e5Syong mao .recheck_sdio_irq = false, 531afb7c791SNeilBrown .hs400_tune = false, 532afb7c791SNeilBrown .pad_tune_reg = MSDC_PAD_TUNE, 533afb7c791SNeilBrown .async_fifo = false, 534afb7c791SNeilBrown .data_tune = false, 535afb7c791SNeilBrown .busy_check = false, 536afb7c791SNeilBrown .stop_clk_fix = false, 537afb7c791SNeilBrown .enhance_rx = false, 538d087bde5SNeilBrown .use_internal_cd = true, 539afb7c791SNeilBrown }; 540afb7c791SNeilBrown 541762d491aSChaotian Jing static const struct of_device_id msdc_of_ids[] = { 542762d491aSChaotian Jing { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, 543762d491aSChaotian Jing { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, 544a2e6d1f6SChaotian Jing { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, 545762d491aSChaotian Jing { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, 546762d491aSChaotian Jing { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, 547966580adSSean Wang { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, 54889822b73SFabien Parent { .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat}, 549afb7c791SNeilBrown { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, 550762d491aSChaotian Jing {} 551762d491aSChaotian Jing }; 552762d491aSChaotian Jing MODULE_DEVICE_TABLE(of, msdc_of_ids); 553762d491aSChaotian Jing 55420848903SChaotian Jing static void sdr_set_bits(void __iomem *reg, u32 bs) 55520848903SChaotian Jing { 55620848903SChaotian Jing u32 val = readl(reg); 55720848903SChaotian Jing 55820848903SChaotian Jing val |= bs; 55920848903SChaotian Jing writel(val, reg); 56020848903SChaotian Jing } 56120848903SChaotian Jing 56220848903SChaotian Jing static void sdr_clr_bits(void __iomem *reg, u32 bs) 56320848903SChaotian Jing { 56420848903SChaotian Jing u32 val = readl(reg); 56520848903SChaotian Jing 56620848903SChaotian Jing val &= ~bs; 56720848903SChaotian Jing writel(val, reg); 56820848903SChaotian Jing } 56920848903SChaotian Jing 57020848903SChaotian Jing static void sdr_set_field(void __iomem *reg, u32 field, u32 val) 57120848903SChaotian Jing { 57220848903SChaotian Jing unsigned int tv = readl(reg); 57320848903SChaotian Jing 57420848903SChaotian Jing tv &= ~field; 57520848903SChaotian Jing tv |= ((val) << (ffs((unsigned int)field) - 1)); 57620848903SChaotian Jing writel(tv, reg); 57720848903SChaotian Jing } 57820848903SChaotian Jing 57920848903SChaotian Jing static void sdr_get_field(void __iomem *reg, u32 field, u32 *val) 58020848903SChaotian Jing { 58120848903SChaotian Jing unsigned int tv = readl(reg); 58220848903SChaotian Jing 58320848903SChaotian Jing *val = ((tv & field) >> (ffs((unsigned int)field) - 1)); 58420848903SChaotian Jing } 58520848903SChaotian Jing 58620848903SChaotian Jing static void msdc_reset_hw(struct msdc_host *host) 58720848903SChaotian Jing { 58820848903SChaotian Jing u32 val; 58920848903SChaotian Jing 59020848903SChaotian Jing sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_RST); 59120848903SChaotian Jing while (readl(host->base + MSDC_CFG) & MSDC_CFG_RST) 59220848903SChaotian Jing cpu_relax(); 59320848903SChaotian Jing 59420848903SChaotian Jing sdr_set_bits(host->base + MSDC_FIFOCS, MSDC_FIFOCS_CLR); 59520848903SChaotian Jing while (readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_CLR) 59620848903SChaotian Jing cpu_relax(); 59720848903SChaotian Jing 59820848903SChaotian Jing val = readl(host->base + MSDC_INT); 59920848903SChaotian Jing writel(val, host->base + MSDC_INT); 60020848903SChaotian Jing } 60120848903SChaotian Jing 60220848903SChaotian Jing static void msdc_cmd_next(struct msdc_host *host, 60320848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd); 6049e2582e5Syong mao static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb); 60520848903SChaotian Jing 606726a9aacSChaotian Jing static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR | 607726a9aacSChaotian Jing MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY | 608726a9aacSChaotian Jing MSDC_INTEN_ACMDCRCERR | MSDC_INTEN_ACMDTMO; 609726a9aacSChaotian Jing static const u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | 61020848903SChaotian Jing MSDC_INTEN_DATCRCERR | MSDC_INTEN_DMA_BDCSERR | 61120848903SChaotian Jing MSDC_INTEN_DMA_GPDCSERR | MSDC_INTEN_DMA_PROTECT; 61220848903SChaotian Jing 61320848903SChaotian Jing static u8 msdc_dma_calcs(u8 *buf, u32 len) 61420848903SChaotian Jing { 61520848903SChaotian Jing u32 i, sum = 0; 61620848903SChaotian Jing 61720848903SChaotian Jing for (i = 0; i < len; i++) 61820848903SChaotian Jing sum += buf[i]; 61920848903SChaotian Jing return 0xff - (u8) sum; 62020848903SChaotian Jing } 62120848903SChaotian Jing 62220848903SChaotian Jing static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, 62320848903SChaotian Jing struct mmc_data *data) 62420848903SChaotian Jing { 62520848903SChaotian Jing unsigned int j, dma_len; 62620848903SChaotian Jing dma_addr_t dma_address; 62720848903SChaotian Jing u32 dma_ctrl; 62820848903SChaotian Jing struct scatterlist *sg; 62920848903SChaotian Jing struct mt_gpdma_desc *gpd; 63020848903SChaotian Jing struct mt_bdma_desc *bd; 63120848903SChaotian Jing 63220848903SChaotian Jing sg = data->sg; 63320848903SChaotian Jing 63420848903SChaotian Jing gpd = dma->gpd; 63520848903SChaotian Jing bd = dma->bd; 63620848903SChaotian Jing 63720848903SChaotian Jing /* modify gpd */ 63820848903SChaotian Jing gpd->gpd_info |= GPDMA_DESC_HWO; 63920848903SChaotian Jing gpd->gpd_info |= GPDMA_DESC_BDP; 64020848903SChaotian Jing /* need to clear first. use these bits to calc checksum */ 64120848903SChaotian Jing gpd->gpd_info &= ~GPDMA_DESC_CHECKSUM; 64220848903SChaotian Jing gpd->gpd_info |= msdc_dma_calcs((u8 *) gpd, 16) << 8; 64320848903SChaotian Jing 64420848903SChaotian Jing /* modify bd */ 64520848903SChaotian Jing for_each_sg(data->sg, sg, data->sg_count, j) { 64620848903SChaotian Jing dma_address = sg_dma_address(sg); 64720848903SChaotian Jing dma_len = sg_dma_len(sg); 64820848903SChaotian Jing 64920848903SChaotian Jing /* init bd */ 65020848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_BLKPAD; 65120848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_DWPAD; 6522a9bde19SChaotian Jing bd[j].ptr = lower_32_bits(dma_address); 6532a9bde19SChaotian Jing if (host->dev_comp->support_64g) { 6542a9bde19SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_PTR_H4; 6552a9bde19SChaotian Jing bd[j].bd_info |= (upper_32_bits(dma_address) & 0xf) 6562a9bde19SChaotian Jing << 28; 6572a9bde19SChaotian Jing } 6586ef042bdSChaotian Jing 6596ef042bdSChaotian Jing if (host->dev_comp->support_64g) { 6606ef042bdSChaotian Jing bd[j].bd_data_len &= ~BDMA_DESC_BUFLEN_EXT; 6616ef042bdSChaotian Jing bd[j].bd_data_len |= (dma_len & BDMA_DESC_BUFLEN_EXT); 6626ef042bdSChaotian Jing } else { 66320848903SChaotian Jing bd[j].bd_data_len &= ~BDMA_DESC_BUFLEN; 66420848903SChaotian Jing bd[j].bd_data_len |= (dma_len & BDMA_DESC_BUFLEN); 6656ef042bdSChaotian Jing } 66620848903SChaotian Jing 66720848903SChaotian Jing if (j == data->sg_count - 1) /* the last bd */ 66820848903SChaotian Jing bd[j].bd_info |= BDMA_DESC_EOL; 66920848903SChaotian Jing else 67020848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_EOL; 67120848903SChaotian Jing 67220848903SChaotian Jing /* checksume need to clear first */ 67320848903SChaotian Jing bd[j].bd_info &= ~BDMA_DESC_CHECKSUM; 67420848903SChaotian Jing bd[j].bd_info |= msdc_dma_calcs((u8 *)(&bd[j]), 16) << 8; 67520848903SChaotian Jing } 67620848903SChaotian Jing 67720848903SChaotian Jing sdr_set_field(host->base + MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, 1); 67820848903SChaotian Jing dma_ctrl = readl_relaxed(host->base + MSDC_DMA_CTRL); 67920848903SChaotian Jing dma_ctrl &= ~(MSDC_DMA_CTRL_BRUSTSZ | MSDC_DMA_CTRL_MODE); 68020848903SChaotian Jing dma_ctrl |= (MSDC_BURST_64B << 12 | 1 << 8); 68120848903SChaotian Jing writel_relaxed(dma_ctrl, host->base + MSDC_DMA_CTRL); 6822a9bde19SChaotian Jing if (host->dev_comp->support_64g) 6832a9bde19SChaotian Jing sdr_set_field(host->base + DMA_SA_H4BIT, DMA_ADDR_HIGH_4BIT, 6842a9bde19SChaotian Jing upper_32_bits(dma->gpd_addr) & 0xf); 6852a9bde19SChaotian Jing writel(lower_32_bits(dma->gpd_addr), host->base + MSDC_DMA_SA); 68620848903SChaotian Jing } 68720848903SChaotian Jing 68820848903SChaotian Jing static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq) 68920848903SChaotian Jing { 69020848903SChaotian Jing struct mmc_data *data = mrq->data; 69120848903SChaotian Jing 69220848903SChaotian Jing if (!(data->host_cookie & MSDC_PREPARE_FLAG)) { 69320848903SChaotian Jing data->host_cookie |= MSDC_PREPARE_FLAG; 69420848903SChaotian Jing data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len, 695feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 69620848903SChaotian Jing } 69720848903SChaotian Jing } 69820848903SChaotian Jing 69920848903SChaotian Jing static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq) 70020848903SChaotian Jing { 70120848903SChaotian Jing struct mmc_data *data = mrq->data; 70220848903SChaotian Jing 70320848903SChaotian Jing if (data->host_cookie & MSDC_ASYNC_FLAG) 70420848903SChaotian Jing return; 70520848903SChaotian Jing 70620848903SChaotian Jing if (data->host_cookie & MSDC_PREPARE_FLAG) { 70720848903SChaotian Jing dma_unmap_sg(host->dev, data->sg, data->sg_len, 708feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 70920848903SChaotian Jing data->host_cookie &= ~MSDC_PREPARE_FLAG; 71020848903SChaotian Jing } 71120848903SChaotian Jing } 71220848903SChaotian Jing 71320848903SChaotian Jing /* clock control primitives */ 71420848903SChaotian Jing static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) 71520848903SChaotian Jing { 71620848903SChaotian Jing u32 timeout, clk_ns; 71720848903SChaotian Jing u32 mode = 0; 71820848903SChaotian Jing 71920848903SChaotian Jing host->timeout_ns = ns; 72020848903SChaotian Jing host->timeout_clks = clks; 72156f6cbbeSChaotian Jing if (host->mmc->actual_clock == 0) { 72220848903SChaotian Jing timeout = 0; 72320848903SChaotian Jing } else { 72456f6cbbeSChaotian Jing clk_ns = 1000000000UL / host->mmc->actual_clock; 72520848903SChaotian Jing timeout = (ns + clk_ns - 1) / clk_ns + clks; 72620848903SChaotian Jing /* in 1048576 sclk cycle unit */ 72720848903SChaotian Jing timeout = (timeout + (0x1 << 20) - 1) >> 20; 728762d491aSChaotian Jing if (host->dev_comp->clk_div_bits == 8) 729762d491aSChaotian Jing sdr_get_field(host->base + MSDC_CFG, 730762d491aSChaotian Jing MSDC_CFG_CKMOD, &mode); 731762d491aSChaotian Jing else 732762d491aSChaotian Jing sdr_get_field(host->base + MSDC_CFG, 733762d491aSChaotian Jing MSDC_CFG_CKMOD_EXTRA, &mode); 73420848903SChaotian Jing /*DDR mode will double the clk cycles for data timeout */ 73520848903SChaotian Jing timeout = mode >= 2 ? timeout * 2 : timeout; 73620848903SChaotian Jing timeout = timeout > 1 ? timeout - 1 : 0; 73720848903SChaotian Jing timeout = timeout > 255 ? 255 : timeout; 73820848903SChaotian Jing } 73920848903SChaotian Jing sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, timeout); 74020848903SChaotian Jing } 74120848903SChaotian Jing 74220848903SChaotian Jing static void msdc_gate_clock(struct msdc_host *host) 74320848903SChaotian Jing { 7443c1a8844SChaotian Jing clk_disable_unprepare(host->src_clk_cg); 74520848903SChaotian Jing clk_disable_unprepare(host->src_clk); 746258bac4aSChaotian Jing clk_disable_unprepare(host->bus_clk); 74720848903SChaotian Jing clk_disable_unprepare(host->h_clk); 74820848903SChaotian Jing } 74920848903SChaotian Jing 75020848903SChaotian Jing static void msdc_ungate_clock(struct msdc_host *host) 75120848903SChaotian Jing { 75220848903SChaotian Jing clk_prepare_enable(host->h_clk); 753258bac4aSChaotian Jing clk_prepare_enable(host->bus_clk); 75420848903SChaotian Jing clk_prepare_enable(host->src_clk); 7553c1a8844SChaotian Jing clk_prepare_enable(host->src_clk_cg); 75620848903SChaotian Jing while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) 75720848903SChaotian Jing cpu_relax(); 75820848903SChaotian Jing } 75920848903SChaotian Jing 7606e622947SChaotian Jing static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) 76120848903SChaotian Jing { 76220848903SChaotian Jing u32 mode; 76320848903SChaotian Jing u32 flags; 76420848903SChaotian Jing u32 div; 76520848903SChaotian Jing u32 sclk; 76639add252SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 76720848903SChaotian Jing 76820848903SChaotian Jing if (!hz) { 76920848903SChaotian Jing dev_dbg(host->dev, "set mclk to 0\n"); 77020848903SChaotian Jing host->mclk = 0; 77156f6cbbeSChaotian Jing host->mmc->actual_clock = 0; 77220848903SChaotian Jing sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); 77320848903SChaotian Jing return; 77420848903SChaotian Jing } 77520848903SChaotian Jing 77620848903SChaotian Jing flags = readl(host->base + MSDC_INTEN); 77720848903SChaotian Jing sdr_clr_bits(host->base + MSDC_INTEN, flags); 778762d491aSChaotian Jing if (host->dev_comp->clk_div_bits == 8) 7796397b7f5SChaotian Jing sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE); 780762d491aSChaotian Jing else 781762d491aSChaotian Jing sdr_clr_bits(host->base + MSDC_CFG, 782762d491aSChaotian Jing MSDC_CFG_HS400_CK_MODE_EXTRA); 7836e622947SChaotian Jing if (timing == MMC_TIMING_UHS_DDR50 || 7846397b7f5SChaotian Jing timing == MMC_TIMING_MMC_DDR52 || 7856397b7f5SChaotian Jing timing == MMC_TIMING_MMC_HS400) { 7866397b7f5SChaotian Jing if (timing == MMC_TIMING_MMC_HS400) 7876397b7f5SChaotian Jing mode = 0x3; 7886397b7f5SChaotian Jing else 78920848903SChaotian Jing mode = 0x2; /* ddr mode and use divisor */ 7906397b7f5SChaotian Jing 79120848903SChaotian Jing if (hz >= (host->src_clk_freq >> 2)) { 79220848903SChaotian Jing div = 0; /* mean div = 1/4 */ 79320848903SChaotian Jing sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */ 79420848903SChaotian Jing } else { 79520848903SChaotian Jing div = (host->src_clk_freq + ((hz << 2) - 1)) / (hz << 2); 79620848903SChaotian Jing sclk = (host->src_clk_freq >> 2) / div; 79720848903SChaotian Jing div = (div >> 1); 79820848903SChaotian Jing } 7996397b7f5SChaotian Jing 8006397b7f5SChaotian Jing if (timing == MMC_TIMING_MMC_HS400 && 8016397b7f5SChaotian Jing hz >= (host->src_clk_freq >> 1)) { 802762d491aSChaotian Jing if (host->dev_comp->clk_div_bits == 8) 8036397b7f5SChaotian Jing sdr_set_bits(host->base + MSDC_CFG, 8046397b7f5SChaotian Jing MSDC_CFG_HS400_CK_MODE); 805762d491aSChaotian Jing else 806762d491aSChaotian Jing sdr_set_bits(host->base + MSDC_CFG, 807762d491aSChaotian Jing MSDC_CFG_HS400_CK_MODE_EXTRA); 8086397b7f5SChaotian Jing sclk = host->src_clk_freq >> 1; 8096397b7f5SChaotian Jing div = 0; /* div is ignore when bit18 is set */ 8106397b7f5SChaotian Jing } 81120848903SChaotian Jing } else if (hz >= host->src_clk_freq) { 81220848903SChaotian Jing mode = 0x1; /* no divisor */ 81320848903SChaotian Jing div = 0; 81420848903SChaotian Jing sclk = host->src_clk_freq; 81520848903SChaotian Jing } else { 81620848903SChaotian Jing mode = 0x0; /* use divisor */ 81720848903SChaotian Jing if (hz >= (host->src_clk_freq >> 1)) { 81820848903SChaotian Jing div = 0; /* mean div = 1/2 */ 81920848903SChaotian Jing sclk = host->src_clk_freq >> 1; /* sclk = clk / 2 */ 82020848903SChaotian Jing } else { 82120848903SChaotian Jing div = (host->src_clk_freq + ((hz << 2) - 1)) / (hz << 2); 82220848903SChaotian Jing sclk = (host->src_clk_freq >> 2) / div; 82320848903SChaotian Jing } 82420848903SChaotian Jing } 8253c1a8844SChaotian Jing sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); 8263c1a8844SChaotian Jing /* 8273c1a8844SChaotian Jing * As src_clk/HCLK use the same bit to gate/ungate, 8283c1a8844SChaotian Jing * So if want to only gate src_clk, need gate its parent(mux). 8293c1a8844SChaotian Jing */ 8303c1a8844SChaotian Jing if (host->src_clk_cg) 8313c1a8844SChaotian Jing clk_disable_unprepare(host->src_clk_cg); 8323c1a8844SChaotian Jing else 8333c1a8844SChaotian Jing clk_disable_unprepare(clk_get_parent(host->src_clk)); 834762d491aSChaotian Jing if (host->dev_comp->clk_div_bits == 8) 835762d491aSChaotian Jing sdr_set_field(host->base + MSDC_CFG, 836762d491aSChaotian Jing MSDC_CFG_CKMOD | MSDC_CFG_CKDIV, 83740ceda09Syong mao (mode << 8) | div); 838762d491aSChaotian Jing else 839762d491aSChaotian Jing sdr_set_field(host->base + MSDC_CFG, 840762d491aSChaotian Jing MSDC_CFG_CKMOD_EXTRA | MSDC_CFG_CKDIV_EXTRA, 841762d491aSChaotian Jing (mode << 12) | div); 8423c1a8844SChaotian Jing if (host->src_clk_cg) 8433c1a8844SChaotian Jing clk_prepare_enable(host->src_clk_cg); 8443c1a8844SChaotian Jing else 8453c1a8844SChaotian Jing clk_prepare_enable(clk_get_parent(host->src_clk)); 846762d491aSChaotian Jing 84720848903SChaotian Jing while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) 84820848903SChaotian Jing cpu_relax(); 8493c1a8844SChaotian Jing sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); 85056f6cbbeSChaotian Jing host->mmc->actual_clock = sclk; 85120848903SChaotian Jing host->mclk = hz; 8526e622947SChaotian Jing host->timing = timing; 85320848903SChaotian Jing /* need because clk changed. */ 85420848903SChaotian Jing msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); 85520848903SChaotian Jing sdr_set_bits(host->base + MSDC_INTEN, flags); 85620848903SChaotian Jing 85786beac37SChaotian Jing /* 85886beac37SChaotian Jing * mmc_select_hs400() will drop to 50Mhz and High speed mode, 85986beac37SChaotian Jing * tune result of hs200/200Mhz is not suitable for 50Mhz 86086beac37SChaotian Jing */ 86156f6cbbeSChaotian Jing if (host->mmc->actual_clock <= 52000000) { 86286beac37SChaotian Jing writel(host->def_tune_para.iocon, host->base + MSDC_IOCON); 863a2e6d1f6SChaotian Jing if (host->top_base) { 864a2e6d1f6SChaotian Jing writel(host->def_tune_para.emmc_top_control, 865a2e6d1f6SChaotian Jing host->top_base + EMMC_TOP_CONTROL); 866a2e6d1f6SChaotian Jing writel(host->def_tune_para.emmc_top_cmd, 867a2e6d1f6SChaotian Jing host->top_base + EMMC_TOP_CMD); 868a2e6d1f6SChaotian Jing } else { 869a2e6d1f6SChaotian Jing writel(host->def_tune_para.pad_tune, 870a2e6d1f6SChaotian Jing host->base + tune_reg); 871a2e6d1f6SChaotian Jing } 87286beac37SChaotian Jing } else { 87386beac37SChaotian Jing writel(host->saved_tune_para.iocon, host->base + MSDC_IOCON); 8741ede5cb8Syong mao writel(host->saved_tune_para.pad_cmd_tune, 8751ede5cb8Syong mao host->base + PAD_CMD_TUNE); 876a2e6d1f6SChaotian Jing if (host->top_base) { 877a2e6d1f6SChaotian Jing writel(host->saved_tune_para.emmc_top_control, 878a2e6d1f6SChaotian Jing host->top_base + EMMC_TOP_CONTROL); 879a2e6d1f6SChaotian Jing writel(host->saved_tune_para.emmc_top_cmd, 880a2e6d1f6SChaotian Jing host->top_base + EMMC_TOP_CMD); 881a2e6d1f6SChaotian Jing } else { 882a2e6d1f6SChaotian Jing writel(host->saved_tune_para.pad_tune, 883a2e6d1f6SChaotian Jing host->base + tune_reg); 884a2e6d1f6SChaotian Jing } 88586beac37SChaotian Jing } 88686beac37SChaotian Jing 8877f3d5852SChaotian Jing if (timing == MMC_TIMING_MMC_HS400 && 8887f3d5852SChaotian Jing host->dev_comp->hs400_tune) 8893751e008SChaotian Jing sdr_set_field(host->base + tune_reg, 8901ede5cb8Syong mao MSDC_PAD_TUNE_CMDRRDLY, 8911ede5cb8Syong mao host->hs400_cmd_int_delay); 89256f6cbbeSChaotian Jing dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->mmc->actual_clock, 89356f6cbbeSChaotian Jing timing); 89420848903SChaotian Jing } 89520848903SChaotian Jing 89620848903SChaotian Jing static inline u32 msdc_cmd_find_resp(struct msdc_host *host, 89720848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 89820848903SChaotian Jing { 89920848903SChaotian Jing u32 resp; 90020848903SChaotian Jing 90120848903SChaotian Jing switch (mmc_resp_type(cmd)) { 90220848903SChaotian Jing /* Actually, R1, R5, R6, R7 are the same */ 90320848903SChaotian Jing case MMC_RSP_R1: 90420848903SChaotian Jing resp = 0x1; 90520848903SChaotian Jing break; 90620848903SChaotian Jing case MMC_RSP_R1B: 90720848903SChaotian Jing resp = 0x7; 90820848903SChaotian Jing break; 90920848903SChaotian Jing case MMC_RSP_R2: 91020848903SChaotian Jing resp = 0x2; 91120848903SChaotian Jing break; 91220848903SChaotian Jing case MMC_RSP_R3: 91320848903SChaotian Jing resp = 0x3; 91420848903SChaotian Jing break; 91520848903SChaotian Jing case MMC_RSP_NONE: 91620848903SChaotian Jing default: 91720848903SChaotian Jing resp = 0x0; 91820848903SChaotian Jing break; 91920848903SChaotian Jing } 92020848903SChaotian Jing 92120848903SChaotian Jing return resp; 92220848903SChaotian Jing } 92320848903SChaotian Jing 92420848903SChaotian Jing static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, 92520848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 92620848903SChaotian Jing { 92720848903SChaotian Jing /* rawcmd : 92820848903SChaotian Jing * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 | 92920848903SChaotian Jing * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode 93020848903SChaotian Jing */ 93120848903SChaotian Jing u32 opcode = cmd->opcode; 93220848903SChaotian Jing u32 resp = msdc_cmd_find_resp(host, mrq, cmd); 93320848903SChaotian Jing u32 rawcmd = (opcode & 0x3f) | ((resp & 0x7) << 7); 93420848903SChaotian Jing 93520848903SChaotian Jing host->cmd_rsp = resp; 93620848903SChaotian Jing 93720848903SChaotian Jing if ((opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int) -1) || 93820848903SChaotian Jing opcode == MMC_STOP_TRANSMISSION) 93920848903SChaotian Jing rawcmd |= (0x1 << 14); 94020848903SChaotian Jing else if (opcode == SD_SWITCH_VOLTAGE) 94120848903SChaotian Jing rawcmd |= (0x1 << 30); 94220848903SChaotian Jing else if (opcode == SD_APP_SEND_SCR || 94320848903SChaotian Jing opcode == SD_APP_SEND_NUM_WR_BLKS || 94420848903SChaotian Jing (opcode == SD_SWITCH && mmc_cmd_type(cmd) == MMC_CMD_ADTC) || 94520848903SChaotian Jing (opcode == SD_APP_SD_STATUS && mmc_cmd_type(cmd) == MMC_CMD_ADTC) || 94620848903SChaotian Jing (opcode == MMC_SEND_EXT_CSD && mmc_cmd_type(cmd) == MMC_CMD_ADTC)) 94720848903SChaotian Jing rawcmd |= (0x1 << 11); 94820848903SChaotian Jing 94920848903SChaotian Jing if (cmd->data) { 95020848903SChaotian Jing struct mmc_data *data = cmd->data; 95120848903SChaotian Jing 95220848903SChaotian Jing if (mmc_op_multi(opcode)) { 95320848903SChaotian Jing if (mmc_card_mmc(host->mmc->card) && mrq->sbc && 95420848903SChaotian Jing !(mrq->sbc->arg & 0xFFFF0000)) 95520848903SChaotian Jing rawcmd |= 0x2 << 28; /* AutoCMD23 */ 95620848903SChaotian Jing } 95720848903SChaotian Jing 95820848903SChaotian Jing rawcmd |= ((data->blksz & 0xFFF) << 16); 95920848903SChaotian Jing if (data->flags & MMC_DATA_WRITE) 96020848903SChaotian Jing rawcmd |= (0x1 << 13); 96120848903SChaotian Jing if (data->blocks > 1) 96220848903SChaotian Jing rawcmd |= (0x2 << 11); 96320848903SChaotian Jing else 96420848903SChaotian Jing rawcmd |= (0x1 << 11); 96520848903SChaotian Jing /* Always use dma mode */ 96620848903SChaotian Jing sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_PIO); 96720848903SChaotian Jing 96820848903SChaotian Jing if (host->timeout_ns != data->timeout_ns || 96920848903SChaotian Jing host->timeout_clks != data->timeout_clks) 97020848903SChaotian Jing msdc_set_timeout(host, data->timeout_ns, 97120848903SChaotian Jing data->timeout_clks); 97220848903SChaotian Jing 97320848903SChaotian Jing writel(data->blocks, host->base + SDC_BLK_NUM); 97420848903SChaotian Jing } 97520848903SChaotian Jing return rawcmd; 97620848903SChaotian Jing } 97720848903SChaotian Jing 97820848903SChaotian Jing static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq, 97920848903SChaotian Jing struct mmc_command *cmd, struct mmc_data *data) 98020848903SChaotian Jing { 98120848903SChaotian Jing bool read; 98220848903SChaotian Jing 98320848903SChaotian Jing WARN_ON(host->data); 98420848903SChaotian Jing host->data = data; 98520848903SChaotian Jing read = data->flags & MMC_DATA_READ; 98620848903SChaotian Jing 98720848903SChaotian Jing mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); 98820848903SChaotian Jing msdc_dma_setup(host, &host->dma, data); 98920848903SChaotian Jing sdr_set_bits(host->base + MSDC_INTEN, data_ints_mask); 99020848903SChaotian Jing sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1); 99120848903SChaotian Jing dev_dbg(host->dev, "DMA start\n"); 99220848903SChaotian Jing dev_dbg(host->dev, "%s: cmd=%d DMA data: %d blocks; read=%d\n", 99320848903SChaotian Jing __func__, cmd->opcode, data->blocks, read); 99420848903SChaotian Jing } 99520848903SChaotian Jing 99620848903SChaotian Jing static int msdc_auto_cmd_done(struct msdc_host *host, int events, 99720848903SChaotian Jing struct mmc_command *cmd) 99820848903SChaotian Jing { 99920848903SChaotian Jing u32 *rsp = cmd->resp; 100020848903SChaotian Jing 100120848903SChaotian Jing rsp[0] = readl(host->base + SDC_ACMD_RESP); 100220848903SChaotian Jing 100320848903SChaotian Jing if (events & MSDC_INT_ACMDRDY) { 100420848903SChaotian Jing cmd->error = 0; 100520848903SChaotian Jing } else { 100620848903SChaotian Jing msdc_reset_hw(host); 100720848903SChaotian Jing if (events & MSDC_INT_ACMDCRCERR) { 100820848903SChaotian Jing cmd->error = -EILSEQ; 100920848903SChaotian Jing host->error |= REQ_STOP_EIO; 101020848903SChaotian Jing } else if (events & MSDC_INT_ACMDTMO) { 101120848903SChaotian Jing cmd->error = -ETIMEDOUT; 101220848903SChaotian Jing host->error |= REQ_STOP_TMO; 101320848903SChaotian Jing } 101420848903SChaotian Jing dev_err(host->dev, 101520848903SChaotian Jing "%s: AUTO_CMD%d arg=%08X; rsp %08X; cmd_error=%d\n", 101620848903SChaotian Jing __func__, cmd->opcode, cmd->arg, rsp[0], cmd->error); 101720848903SChaotian Jing } 101820848903SChaotian Jing return cmd->error; 101920848903SChaotian Jing } 102020848903SChaotian Jing 10219e2582e5Syong mao /** 10229e2582e5Syong mao * msdc_recheck_sdio_irq - recheck whether the SDIO irq is lost 10239e2582e5Syong mao * 10249e2582e5Syong mao * Host controller may lost interrupt in some special case. 10259e2582e5Syong mao * Add SDIO irq recheck mechanism to make sure all interrupts 10269e2582e5Syong mao * can be processed immediately 10279e2582e5Syong mao * 10289e2582e5Syong mao */ 10299e2582e5Syong mao static void msdc_recheck_sdio_irq(struct msdc_host *host) 10309e2582e5Syong mao { 10319e2582e5Syong mao u32 reg_int, reg_inten, reg_ps; 10329e2582e5Syong mao 10339e2582e5Syong mao if (host->mmc->caps & MMC_CAP_SDIO_IRQ) { 10349e2582e5Syong mao reg_inten = readl(host->base + MSDC_INTEN); 10359e2582e5Syong mao if (reg_inten & MSDC_INTEN_SDIOIRQ) { 10369e2582e5Syong mao reg_int = readl(host->base + MSDC_INT); 10379e2582e5Syong mao reg_ps = readl(host->base + MSDC_PS); 10389e2582e5Syong mao if (!(reg_int & MSDC_INT_SDIOIRQ || 10399e2582e5Syong mao reg_ps & MSDC_PS_DATA1)) { 10409e2582e5Syong mao __msdc_enable_sdio_irq(host, 0); 10419e2582e5Syong mao sdio_signal_irq(host->mmc); 10429e2582e5Syong mao } 10439e2582e5Syong mao } 10449e2582e5Syong mao } 10459e2582e5Syong mao } 10469e2582e5Syong mao 104720848903SChaotian Jing static void msdc_track_cmd_data(struct msdc_host *host, 104820848903SChaotian Jing struct mmc_command *cmd, struct mmc_data *data) 104920848903SChaotian Jing { 105020848903SChaotian Jing if (host->error) 105120848903SChaotian Jing dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", 105220848903SChaotian Jing __func__, cmd->opcode, cmd->arg, host->error); 105320848903SChaotian Jing } 105420848903SChaotian Jing 105520848903SChaotian Jing static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) 105620848903SChaotian Jing { 105720848903SChaotian Jing unsigned long flags; 105820848903SChaotian Jing bool ret; 105920848903SChaotian Jing 106020848903SChaotian Jing ret = cancel_delayed_work(&host->req_timeout); 106120848903SChaotian Jing if (!ret) { 106220848903SChaotian Jing /* delay work already running */ 106320848903SChaotian Jing return; 106420848903SChaotian Jing } 106520848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 106620848903SChaotian Jing host->mrq = NULL; 106720848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 106820848903SChaotian Jing 106920848903SChaotian Jing msdc_track_cmd_data(host, mrq->cmd, mrq->data); 107020848903SChaotian Jing if (mrq->data) 107120848903SChaotian Jing msdc_unprepare_data(host, mrq); 107220314ce3Sjjian zhou if (host->error) 107320314ce3Sjjian zhou msdc_reset_hw(host); 107420848903SChaotian Jing mmc_request_done(host->mmc, mrq); 10759e2582e5Syong mao if (host->dev_comp->recheck_sdio_irq) 10769e2582e5Syong mao msdc_recheck_sdio_irq(host); 107720848903SChaotian Jing } 107820848903SChaotian Jing 107920848903SChaotian Jing /* returns true if command is fully handled; returns false otherwise */ 108020848903SChaotian Jing static bool msdc_cmd_done(struct msdc_host *host, int events, 108120848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 108220848903SChaotian Jing { 108320848903SChaotian Jing bool done = false; 108420848903SChaotian Jing bool sbc_error; 108520848903SChaotian Jing unsigned long flags; 108620848903SChaotian Jing u32 *rsp = cmd->resp; 108720848903SChaotian Jing 108820848903SChaotian Jing if (mrq->sbc && cmd == mrq->cmd && 108920848903SChaotian Jing (events & (MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR 109020848903SChaotian Jing | MSDC_INT_ACMDTMO))) 109120848903SChaotian Jing msdc_auto_cmd_done(host, events, mrq->sbc); 109220848903SChaotian Jing 109320848903SChaotian Jing sbc_error = mrq->sbc && mrq->sbc->error; 109420848903SChaotian Jing 109520848903SChaotian Jing if (!sbc_error && !(events & (MSDC_INT_CMDRDY 109620848903SChaotian Jing | MSDC_INT_RSPCRCERR 109720848903SChaotian Jing | MSDC_INT_CMDTMO))) 109820848903SChaotian Jing return done; 109920848903SChaotian Jing 110020848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 110120848903SChaotian Jing done = !host->cmd; 110220848903SChaotian Jing host->cmd = NULL; 110320848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 110420848903SChaotian Jing 110520848903SChaotian Jing if (done) 110620848903SChaotian Jing return true; 110720848903SChaotian Jing 1108726a9aacSChaotian Jing sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask); 110920848903SChaotian Jing 111020848903SChaotian Jing if (cmd->flags & MMC_RSP_PRESENT) { 111120848903SChaotian Jing if (cmd->flags & MMC_RSP_136) { 111220848903SChaotian Jing rsp[0] = readl(host->base + SDC_RESP3); 111320848903SChaotian Jing rsp[1] = readl(host->base + SDC_RESP2); 111420848903SChaotian Jing rsp[2] = readl(host->base + SDC_RESP1); 111520848903SChaotian Jing rsp[3] = readl(host->base + SDC_RESP0); 111620848903SChaotian Jing } else { 111720848903SChaotian Jing rsp[0] = readl(host->base + SDC_RESP0); 111820848903SChaotian Jing } 111920848903SChaotian Jing } 112020848903SChaotian Jing 112120848903SChaotian Jing if (!sbc_error && !(events & MSDC_INT_CMDRDY)) { 1122da6e0f70SChaotian Jing if (events & MSDC_INT_CMDTMO || 1123da6e0f70SChaotian Jing (cmd->opcode != MMC_SEND_TUNING_BLOCK && 1124da6e0f70SChaotian Jing cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)) 1125ddc71387SChaotian Jing /* 1126ddc71387SChaotian Jing * should not clear fifo/interrupt as the tune data 1127da6e0f70SChaotian Jing * may have alreay come when cmd19/cmd21 gets response 1128da6e0f70SChaotian Jing * CRC error. 1129ddc71387SChaotian Jing */ 113020848903SChaotian Jing msdc_reset_hw(host); 113120848903SChaotian Jing if (events & MSDC_INT_RSPCRCERR) { 113220848903SChaotian Jing cmd->error = -EILSEQ; 113320848903SChaotian Jing host->error |= REQ_CMD_EIO; 113420848903SChaotian Jing } else if (events & MSDC_INT_CMDTMO) { 113520848903SChaotian Jing cmd->error = -ETIMEDOUT; 113620848903SChaotian Jing host->error |= REQ_CMD_TMO; 113720848903SChaotian Jing } 113820848903SChaotian Jing } 113920848903SChaotian Jing if (cmd->error) 114020848903SChaotian Jing dev_dbg(host->dev, 114120848903SChaotian Jing "%s: cmd=%d arg=%08X; rsp %08X; cmd_error=%d\n", 114220848903SChaotian Jing __func__, cmd->opcode, cmd->arg, rsp[0], 114320848903SChaotian Jing cmd->error); 114420848903SChaotian Jing 114520848903SChaotian Jing msdc_cmd_next(host, mrq, cmd); 114620848903SChaotian Jing return true; 114720848903SChaotian Jing } 114820848903SChaotian Jing 114920848903SChaotian Jing /* It is the core layer's responsibility to ensure card status 115020848903SChaotian Jing * is correct before issue a request. but host design do below 115120848903SChaotian Jing * checks recommended. 115220848903SChaotian Jing */ 115320848903SChaotian Jing static inline bool msdc_cmd_is_ready(struct msdc_host *host, 115420848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 115520848903SChaotian Jing { 115620848903SChaotian Jing /* The max busy time we can endure is 20ms */ 115720848903SChaotian Jing unsigned long tmo = jiffies + msecs_to_jiffies(20); 115820848903SChaotian Jing 115920848903SChaotian Jing while ((readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) && 116020848903SChaotian Jing time_before(jiffies, tmo)) 116120848903SChaotian Jing cpu_relax(); 116220848903SChaotian Jing if (readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) { 116320848903SChaotian Jing dev_err(host->dev, "CMD bus busy detected\n"); 116420848903SChaotian Jing host->error |= REQ_CMD_BUSY; 116520848903SChaotian Jing msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd); 116620848903SChaotian Jing return false; 116720848903SChaotian Jing } 116820848903SChaotian Jing 116920848903SChaotian Jing if (mmc_resp_type(cmd) == MMC_RSP_R1B || cmd->data) { 117020848903SChaotian Jing tmo = jiffies + msecs_to_jiffies(20); 117120848903SChaotian Jing /* R1B or with data, should check SDCBUSY */ 117220848903SChaotian Jing while ((readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) && 117320848903SChaotian Jing time_before(jiffies, tmo)) 117420848903SChaotian Jing cpu_relax(); 117520848903SChaotian Jing if (readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) { 117620848903SChaotian Jing dev_err(host->dev, "Controller busy detected\n"); 117720848903SChaotian Jing host->error |= REQ_CMD_BUSY; 117820848903SChaotian Jing msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd); 117920848903SChaotian Jing return false; 118020848903SChaotian Jing } 118120848903SChaotian Jing } 118220848903SChaotian Jing return true; 118320848903SChaotian Jing } 118420848903SChaotian Jing 118520848903SChaotian Jing static void msdc_start_command(struct msdc_host *host, 118620848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 118720848903SChaotian Jing { 118820848903SChaotian Jing u32 rawcmd; 11895215b2e9Sjjian zhou unsigned long flags; 119020848903SChaotian Jing 119120848903SChaotian Jing WARN_ON(host->cmd); 119220848903SChaotian Jing host->cmd = cmd; 119320848903SChaotian Jing 1194f38a9774SChaotian Jing mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT); 119520848903SChaotian Jing if (!msdc_cmd_is_ready(host, mrq, cmd)) 119620848903SChaotian Jing return; 119720848903SChaotian Jing 119820848903SChaotian Jing if ((readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16 || 119920848903SChaotian Jing readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) { 120020848903SChaotian Jing dev_err(host->dev, "TX/RX FIFO non-empty before start of IO. Reset\n"); 120120848903SChaotian Jing msdc_reset_hw(host); 120220848903SChaotian Jing } 120320848903SChaotian Jing 120420848903SChaotian Jing cmd->error = 0; 120520848903SChaotian Jing rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd); 120620848903SChaotian Jing 12075215b2e9Sjjian zhou spin_lock_irqsave(&host->lock, flags); 1208726a9aacSChaotian Jing sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask); 12095215b2e9Sjjian zhou spin_unlock_irqrestore(&host->lock, flags); 12105215b2e9Sjjian zhou 121120848903SChaotian Jing writel(cmd->arg, host->base + SDC_ARG); 121220848903SChaotian Jing writel(rawcmd, host->base + SDC_CMD); 121320848903SChaotian Jing } 121420848903SChaotian Jing 121520848903SChaotian Jing static void msdc_cmd_next(struct msdc_host *host, 121620848903SChaotian Jing struct mmc_request *mrq, struct mmc_command *cmd) 121720848903SChaotian Jing { 1218ddc71387SChaotian Jing if ((cmd->error && 1219ddc71387SChaotian Jing !(cmd->error == -EILSEQ && 1220ddc71387SChaotian Jing (cmd->opcode == MMC_SEND_TUNING_BLOCK || 1221ddc71387SChaotian Jing cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) || 1222ddc71387SChaotian Jing (mrq->sbc && mrq->sbc->error)) 122320848903SChaotian Jing msdc_request_done(host, mrq); 122420848903SChaotian Jing else if (cmd == mrq->sbc) 122520848903SChaotian Jing msdc_start_command(host, mrq, mrq->cmd); 122620848903SChaotian Jing else if (!cmd->data) 122720848903SChaotian Jing msdc_request_done(host, mrq); 122820848903SChaotian Jing else 122920848903SChaotian Jing msdc_start_data(host, mrq, cmd, cmd->data); 123020848903SChaotian Jing } 123120848903SChaotian Jing 123220848903SChaotian Jing static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) 123320848903SChaotian Jing { 123420848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 123520848903SChaotian Jing 123620848903SChaotian Jing host->error = 0; 123720848903SChaotian Jing WARN_ON(host->mrq); 123820848903SChaotian Jing host->mrq = mrq; 123920848903SChaotian Jing 124020848903SChaotian Jing if (mrq->data) 124120848903SChaotian Jing msdc_prepare_data(host, mrq); 124220848903SChaotian Jing 124320848903SChaotian Jing /* if SBC is required, we have HW option and SW option. 124420848903SChaotian Jing * if HW option is enabled, and SBC does not have "special" flags, 124520848903SChaotian Jing * use HW option, otherwise use SW option 124620848903SChaotian Jing */ 124720848903SChaotian Jing if (mrq->sbc && (!mmc_card_mmc(mmc->card) || 124820848903SChaotian Jing (mrq->sbc->arg & 0xFFFF0000))) 124920848903SChaotian Jing msdc_start_command(host, mrq, mrq->sbc); 125020848903SChaotian Jing else 125120848903SChaotian Jing msdc_start_command(host, mrq, mrq->cmd); 125220848903SChaotian Jing } 125320848903SChaotian Jing 1254d3c6aac3SLinus Walleij static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) 125520848903SChaotian Jing { 125620848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 125720848903SChaotian Jing struct mmc_data *data = mrq->data; 125820848903SChaotian Jing 125920848903SChaotian Jing if (!data) 126020848903SChaotian Jing return; 126120848903SChaotian Jing 126220848903SChaotian Jing msdc_prepare_data(host, mrq); 126320848903SChaotian Jing data->host_cookie |= MSDC_ASYNC_FLAG; 126420848903SChaotian Jing } 126520848903SChaotian Jing 126620848903SChaotian Jing static void msdc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, 126720848903SChaotian Jing int err) 126820848903SChaotian Jing { 126920848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 127020848903SChaotian Jing struct mmc_data *data; 127120848903SChaotian Jing 127220848903SChaotian Jing data = mrq->data; 127320848903SChaotian Jing if (!data) 127420848903SChaotian Jing return; 127520848903SChaotian Jing if (data->host_cookie) { 127620848903SChaotian Jing data->host_cookie &= ~MSDC_ASYNC_FLAG; 127720848903SChaotian Jing msdc_unprepare_data(host, mrq); 127820848903SChaotian Jing } 127920848903SChaotian Jing } 128020848903SChaotian Jing 128120848903SChaotian Jing static void msdc_data_xfer_next(struct msdc_host *host, 128220848903SChaotian Jing struct mmc_request *mrq, struct mmc_data *data) 128320848903SChaotian Jing { 128420848903SChaotian Jing if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && !mrq->stop->error && 12856397b7f5SChaotian Jing !mrq->sbc) 128620848903SChaotian Jing msdc_start_command(host, mrq, mrq->stop); 128720848903SChaotian Jing else 128820848903SChaotian Jing msdc_request_done(host, mrq); 128920848903SChaotian Jing } 129020848903SChaotian Jing 129120848903SChaotian Jing static bool msdc_data_xfer_done(struct msdc_host *host, u32 events, 129220848903SChaotian Jing struct mmc_request *mrq, struct mmc_data *data) 129320848903SChaotian Jing { 129420848903SChaotian Jing struct mmc_command *stop = data->stop; 129520848903SChaotian Jing unsigned long flags; 129620848903SChaotian Jing bool done; 129720848903SChaotian Jing unsigned int check_data = events & 129820848903SChaotian Jing (MSDC_INT_XFER_COMPL | MSDC_INT_DATCRCERR | MSDC_INT_DATTMO 129920848903SChaotian Jing | MSDC_INT_DMA_BDCSERR | MSDC_INT_DMA_GPDCSERR 130020848903SChaotian Jing | MSDC_INT_DMA_PROTECT); 130120848903SChaotian Jing 130220848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 130320848903SChaotian Jing done = !host->data; 130420848903SChaotian Jing if (check_data) 130520848903SChaotian Jing host->data = NULL; 130620848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 130720848903SChaotian Jing 130820848903SChaotian Jing if (done) 130920848903SChaotian Jing return true; 131020848903SChaotian Jing 131120848903SChaotian Jing if (check_data || (stop && stop->error)) { 131220848903SChaotian Jing dev_dbg(host->dev, "DMA status: 0x%8X\n", 131320848903SChaotian Jing readl(host->base + MSDC_DMA_CFG)); 131420848903SChaotian Jing sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 131520848903SChaotian Jing 1); 131620848903SChaotian Jing while (readl(host->base + MSDC_DMA_CFG) & MSDC_DMA_CFG_STS) 131720848903SChaotian Jing cpu_relax(); 131820848903SChaotian Jing sdr_clr_bits(host->base + MSDC_INTEN, data_ints_mask); 131920848903SChaotian Jing dev_dbg(host->dev, "DMA stop\n"); 132020848903SChaotian Jing 132120848903SChaotian Jing if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) { 132220848903SChaotian Jing data->bytes_xfered = data->blocks * data->blksz; 132320848903SChaotian Jing } else { 13242066fd28SChaotian Jing dev_dbg(host->dev, "interrupt events: %x\n", events); 132520848903SChaotian Jing msdc_reset_hw(host); 132620848903SChaotian Jing host->error |= REQ_DAT_ERR; 132720848903SChaotian Jing data->bytes_xfered = 0; 132820848903SChaotian Jing 132920848903SChaotian Jing if (events & MSDC_INT_DATTMO) 133020848903SChaotian Jing data->error = -ETIMEDOUT; 13316397b7f5SChaotian Jing else if (events & MSDC_INT_DATCRCERR) 13326397b7f5SChaotian Jing data->error = -EILSEQ; 133320848903SChaotian Jing 13342066fd28SChaotian Jing dev_dbg(host->dev, "%s: cmd=%d; blocks=%d", 133520848903SChaotian Jing __func__, mrq->cmd->opcode, data->blocks); 13362066fd28SChaotian Jing dev_dbg(host->dev, "data_error=%d xfer_size=%d\n", 133720848903SChaotian Jing (int)data->error, data->bytes_xfered); 133820848903SChaotian Jing } 133920848903SChaotian Jing 134020848903SChaotian Jing msdc_data_xfer_next(host, mrq, data); 134120848903SChaotian Jing done = true; 134220848903SChaotian Jing } 134320848903SChaotian Jing return done; 134420848903SChaotian Jing } 134520848903SChaotian Jing 134620848903SChaotian Jing static void msdc_set_buswidth(struct msdc_host *host, u32 width) 134720848903SChaotian Jing { 134820848903SChaotian Jing u32 val = readl(host->base + SDC_CFG); 134920848903SChaotian Jing 135020848903SChaotian Jing val &= ~SDC_CFG_BUSWIDTH; 135120848903SChaotian Jing 135220848903SChaotian Jing switch (width) { 135320848903SChaotian Jing default: 135420848903SChaotian Jing case MMC_BUS_WIDTH_1: 135520848903SChaotian Jing val |= (MSDC_BUS_1BITS << 16); 135620848903SChaotian Jing break; 135720848903SChaotian Jing case MMC_BUS_WIDTH_4: 135820848903SChaotian Jing val |= (MSDC_BUS_4BITS << 16); 135920848903SChaotian Jing break; 136020848903SChaotian Jing case MMC_BUS_WIDTH_8: 136120848903SChaotian Jing val |= (MSDC_BUS_8BITS << 16); 136220848903SChaotian Jing break; 136320848903SChaotian Jing } 136420848903SChaotian Jing 136520848903SChaotian Jing writel(val, host->base + SDC_CFG); 136620848903SChaotian Jing dev_dbg(host->dev, "Bus Width = %d", width); 136720848903SChaotian Jing } 136820848903SChaotian Jing 136920848903SChaotian Jing static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) 137020848903SChaotian Jing { 137120848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 13729cbe0fc8SMarek Vasut int ret; 137320848903SChaotian Jing 137420848903SChaotian Jing if (!IS_ERR(mmc->supply.vqmmc)) { 1375fac49ce5SNicolas Boichat if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_330 && 1376fac49ce5SNicolas Boichat ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) { 137720848903SChaotian Jing dev_err(host->dev, "Unsupported signal voltage!\n"); 137820848903SChaotian Jing return -EINVAL; 137920848903SChaotian Jing } 138020848903SChaotian Jing 1381fac49ce5SNicolas Boichat ret = mmc_regulator_set_vqmmc(mmc, ios); 13829cbe0fc8SMarek Vasut if (ret < 0) { 1383fac49ce5SNicolas Boichat dev_dbg(host->dev, "Regulator set error %d (%d)\n", 1384fac49ce5SNicolas Boichat ret, ios->signal_voltage); 13859cbe0fc8SMarek Vasut return ret; 13869cbe0fc8SMarek Vasut } 13879cbe0fc8SMarek Vasut 138820848903SChaotian Jing /* Apply different pinctrl settings for different signal voltage */ 138920848903SChaotian Jing if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) 139020848903SChaotian Jing pinctrl_select_state(host->pinctrl, host->pins_uhs); 139120848903SChaotian Jing else 139220848903SChaotian Jing pinctrl_select_state(host->pinctrl, host->pins_default); 139320848903SChaotian Jing } 13949cbe0fc8SMarek Vasut return 0; 139520848903SChaotian Jing } 139620848903SChaotian Jing 139720848903SChaotian Jing static int msdc_card_busy(struct mmc_host *mmc) 139820848903SChaotian Jing { 139920848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 140020848903SChaotian Jing u32 status = readl(host->base + MSDC_PS); 140120848903SChaotian Jing 14023bc702edSyong mao /* only check if data0 is low */ 14033bc702edSyong mao return !(status & BIT(16)); 140420848903SChaotian Jing } 140520848903SChaotian Jing 140620848903SChaotian Jing static void msdc_request_timeout(struct work_struct *work) 140720848903SChaotian Jing { 140820848903SChaotian Jing struct msdc_host *host = container_of(work, struct msdc_host, 140920848903SChaotian Jing req_timeout.work); 141020848903SChaotian Jing 141120848903SChaotian Jing /* simulate HW timeout status */ 141220848903SChaotian Jing dev_err(host->dev, "%s: aborting cmd/data/mrq\n", __func__); 141320848903SChaotian Jing if (host->mrq) { 141420848903SChaotian Jing dev_err(host->dev, "%s: aborting mrq=%p cmd=%d\n", __func__, 141520848903SChaotian Jing host->mrq, host->mrq->cmd->opcode); 141620848903SChaotian Jing if (host->cmd) { 141720848903SChaotian Jing dev_err(host->dev, "%s: aborting cmd=%d\n", 141820848903SChaotian Jing __func__, host->cmd->opcode); 141920848903SChaotian Jing msdc_cmd_done(host, MSDC_INT_CMDTMO, host->mrq, 142020848903SChaotian Jing host->cmd); 142120848903SChaotian Jing } else if (host->data) { 142220848903SChaotian Jing dev_err(host->dev, "%s: abort data: cmd%d; %d blocks\n", 142320848903SChaotian Jing __func__, host->mrq->cmd->opcode, 142420848903SChaotian Jing host->data->blocks); 142520848903SChaotian Jing msdc_data_xfer_done(host, MSDC_INT_DATTMO, host->mrq, 142620848903SChaotian Jing host->data); 142720848903SChaotian Jing } 142820848903SChaotian Jing } 142920848903SChaotian Jing } 143020848903SChaotian Jing 14318a5df8acSjjian zhou static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb) 14328a5df8acSjjian zhou { 14338a5df8acSjjian zhou if (enb) { 14348a5df8acSjjian zhou sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); 14358a5df8acSjjian zhou sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); 14369e2582e5Syong mao if (host->dev_comp->recheck_sdio_irq) 14379e2582e5Syong mao msdc_recheck_sdio_irq(host); 14388a5df8acSjjian zhou } else { 14398a5df8acSjjian zhou sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); 14408a5df8acSjjian zhou sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); 14418a5df8acSjjian zhou } 14428a5df8acSjjian zhou } 14438a5df8acSjjian zhou 14448a5df8acSjjian zhou static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) 14455215b2e9Sjjian zhou { 14465215b2e9Sjjian zhou unsigned long flags; 14475215b2e9Sjjian zhou struct msdc_host *host = mmc_priv(mmc); 14485215b2e9Sjjian zhou 14495215b2e9Sjjian zhou spin_lock_irqsave(&host->lock, flags); 14508a5df8acSjjian zhou __msdc_enable_sdio_irq(host, enb); 14515215b2e9Sjjian zhou spin_unlock_irqrestore(&host->lock, flags); 14525215b2e9Sjjian zhou 14535215b2e9Sjjian zhou if (enb) 14545215b2e9Sjjian zhou pm_runtime_get_noresume(host->dev); 14555215b2e9Sjjian zhou else 14565215b2e9Sjjian zhou pm_runtime_put_noidle(host->dev); 14575215b2e9Sjjian zhou } 14585215b2e9Sjjian zhou 145920848903SChaotian Jing static irqreturn_t msdc_irq(int irq, void *dev_id) 146020848903SChaotian Jing { 146120848903SChaotian Jing struct msdc_host *host = (struct msdc_host *) dev_id; 146220848903SChaotian Jing 146320848903SChaotian Jing while (true) { 146420848903SChaotian Jing unsigned long flags; 146520848903SChaotian Jing struct mmc_request *mrq; 146620848903SChaotian Jing struct mmc_command *cmd; 146720848903SChaotian Jing struct mmc_data *data; 146820848903SChaotian Jing u32 events, event_mask; 146920848903SChaotian Jing 147020848903SChaotian Jing spin_lock_irqsave(&host->lock, flags); 147120848903SChaotian Jing events = readl(host->base + MSDC_INT); 147220848903SChaotian Jing event_mask = readl(host->base + MSDC_INTEN); 14738a5df8acSjjian zhou if ((events & event_mask) & MSDC_INT_SDIOIRQ) 14748a5df8acSjjian zhou __msdc_enable_sdio_irq(host, 0); 147520848903SChaotian Jing /* clear interrupts */ 147620848903SChaotian Jing writel(events & event_mask, host->base + MSDC_INT); 147720848903SChaotian Jing 147820848903SChaotian Jing mrq = host->mrq; 147920848903SChaotian Jing cmd = host->cmd; 148020848903SChaotian Jing data = host->data; 148120848903SChaotian Jing spin_unlock_irqrestore(&host->lock, flags); 148220848903SChaotian Jing 14838a5df8acSjjian zhou if ((events & event_mask) & MSDC_INT_SDIOIRQ) 14845215b2e9Sjjian zhou sdio_signal_irq(host->mmc); 14855215b2e9Sjjian zhou 1486d087bde5SNeilBrown if ((events & event_mask) & MSDC_INT_CDSC) { 1487d087bde5SNeilBrown if (host->internal_cd) 1488d087bde5SNeilBrown mmc_detect_change(host->mmc, msecs_to_jiffies(20)); 1489d087bde5SNeilBrown events &= ~MSDC_INT_CDSC; 1490d087bde5SNeilBrown } 1491d087bde5SNeilBrown 14925215b2e9Sjjian zhou if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) 149320848903SChaotian Jing break; 149420848903SChaotian Jing 149520848903SChaotian Jing if (!mrq) { 149620848903SChaotian Jing dev_err(host->dev, 149720848903SChaotian Jing "%s: MRQ=NULL; events=%08X; event_mask=%08X\n", 149820848903SChaotian Jing __func__, events, event_mask); 149920848903SChaotian Jing WARN_ON(1); 150020848903SChaotian Jing break; 150120848903SChaotian Jing } 150220848903SChaotian Jing 150320848903SChaotian Jing dev_dbg(host->dev, "%s: events=%08X\n", __func__, events); 150420848903SChaotian Jing 150520848903SChaotian Jing if (cmd) 150620848903SChaotian Jing msdc_cmd_done(host, events, mrq, cmd); 150720848903SChaotian Jing else if (data) 150820848903SChaotian Jing msdc_data_xfer_done(host, events, mrq, data); 150920848903SChaotian Jing } 151020848903SChaotian Jing 151120848903SChaotian Jing return IRQ_HANDLED; 151220848903SChaotian Jing } 151320848903SChaotian Jing 151420848903SChaotian Jing static void msdc_init_hw(struct msdc_host *host) 151520848903SChaotian Jing { 151620848903SChaotian Jing u32 val; 151739add252SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 151820848903SChaotian Jing 151920848903SChaotian Jing /* Configure to MMC/SD mode, clock free running */ 152020848903SChaotian Jing sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN); 152120848903SChaotian Jing 152220848903SChaotian Jing /* Reset */ 152320848903SChaotian Jing msdc_reset_hw(host); 152420848903SChaotian Jing 152520848903SChaotian Jing /* Disable and clear all interrupts */ 152620848903SChaotian Jing writel(0, host->base + MSDC_INTEN); 152720848903SChaotian Jing val = readl(host->base + MSDC_INT); 152820848903SChaotian Jing writel(val, host->base + MSDC_INT); 152920848903SChaotian Jing 1530d087bde5SNeilBrown /* Configure card detection */ 1531d087bde5SNeilBrown if (host->internal_cd) { 1532d087bde5SNeilBrown sdr_set_field(host->base + MSDC_PS, MSDC_PS_CDDEBOUNCE, 1533d087bde5SNeilBrown DEFAULT_DEBOUNCE); 1534d087bde5SNeilBrown sdr_set_bits(host->base + MSDC_PS, MSDC_PS_CDEN); 1535d087bde5SNeilBrown sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC); 1536d087bde5SNeilBrown sdr_set_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); 1537d087bde5SNeilBrown } else { 1538d087bde5SNeilBrown sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); 1539d087bde5SNeilBrown sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); 1540d087bde5SNeilBrown sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC); 1541d087bde5SNeilBrown } 1542d087bde5SNeilBrown 1543a2e6d1f6SChaotian Jing if (host->top_base) { 1544a2e6d1f6SChaotian Jing writel(0, host->top_base + EMMC_TOP_CONTROL); 1545a2e6d1f6SChaotian Jing writel(0, host->top_base + EMMC_TOP_CMD); 1546a2e6d1f6SChaotian Jing } else { 154739add252SChaotian Jing writel(0, host->base + tune_reg); 1548a2e6d1f6SChaotian Jing } 154920848903SChaotian Jing writel(0, host->base + MSDC_IOCON); 15506397b7f5SChaotian Jing sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0); 15516397b7f5SChaotian Jing writel(0x403c0046, host->base + MSDC_PATCH_BIT); 155220848903SChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1); 15532fea5819SChaotian Jing writel(0xffff4089, host->base + MSDC_PATCH_BIT1); 15546397b7f5SChaotian Jing sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL); 1555d9dcbfc8SChaotian Jing 1556d9dcbfc8SChaotian Jing if (host->dev_comp->stop_clk_fix) { 1557d9dcbfc8SChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT1, 1558d9dcbfc8SChaotian Jing MSDC_PATCH_BIT1_STOP_DLY, 3); 1559d9dcbfc8SChaotian Jing sdr_clr_bits(host->base + SDC_FIFO_CFG, 1560d9dcbfc8SChaotian Jing SDC_FIFO_CFG_WRVALIDSEL); 1561d9dcbfc8SChaotian Jing sdr_clr_bits(host->base + SDC_FIFO_CFG, 1562d9dcbfc8SChaotian Jing SDC_FIFO_CFG_RDVALIDSEL); 1563d9dcbfc8SChaotian Jing } 1564d9dcbfc8SChaotian Jing 1565acde28c4SChaotian Jing if (host->dev_comp->busy_check) 1566acde28c4SChaotian Jing sdr_clr_bits(host->base + MSDC_PATCH_BIT1, (1 << 7)); 1567d9dcbfc8SChaotian Jing 15682fea5819SChaotian Jing if (host->dev_comp->async_fifo) { 15692fea5819SChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT2, 15702fea5819SChaotian Jing MSDC_PB2_RESPWAIT, 3); 1571d9dcbfc8SChaotian Jing if (host->dev_comp->enhance_rx) { 1572a2e6d1f6SChaotian Jing if (host->top_base) 1573a2e6d1f6SChaotian Jing sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, 1574a2e6d1f6SChaotian Jing SDC_RX_ENH_EN); 1575a2e6d1f6SChaotian Jing else 1576d9dcbfc8SChaotian Jing sdr_set_bits(host->base + SDC_ADV_CFG0, 1577d9dcbfc8SChaotian Jing SDC_RX_ENHANCE_EN); 1578d9dcbfc8SChaotian Jing } else { 15792fea5819SChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT2, 15802fea5819SChaotian Jing MSDC_PB2_RESPSTSENSEL, 2); 15812fea5819SChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT2, 15822fea5819SChaotian Jing MSDC_PB2_CRCSTSENSEL, 2); 1583d9dcbfc8SChaotian Jing } 15842fea5819SChaotian Jing /* use async fifo, then no need tune internal delay */ 15852fea5819SChaotian Jing sdr_clr_bits(host->base + MSDC_PATCH_BIT2, 15862fea5819SChaotian Jing MSDC_PATCH_BIT2_CFGRESP); 15872fea5819SChaotian Jing sdr_set_bits(host->base + MSDC_PATCH_BIT2, 15882fea5819SChaotian Jing MSDC_PATCH_BIT2_CFGCRCSTS); 15892fea5819SChaotian Jing } 15902fea5819SChaotian Jing 15912a9bde19SChaotian Jing if (host->dev_comp->support_64g) 15922a9bde19SChaotian Jing sdr_set_bits(host->base + MSDC_PATCH_BIT2, 15932a9bde19SChaotian Jing MSDC_PB2_SUPPORT_64G); 15942fea5819SChaotian Jing if (host->dev_comp->data_tune) { 1595a2e6d1f6SChaotian Jing if (host->top_base) { 1596a2e6d1f6SChaotian Jing sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, 1597a2e6d1f6SChaotian Jing PAD_DAT_RD_RXDLY_SEL); 1598a2e6d1f6SChaotian Jing sdr_clr_bits(host->top_base + EMMC_TOP_CONTROL, 1599a2e6d1f6SChaotian Jing DATA_K_VALUE_SEL); 1600a2e6d1f6SChaotian Jing sdr_set_bits(host->top_base + EMMC_TOP_CMD, 1601a2e6d1f6SChaotian Jing PAD_CMD_RD_RXDLY_SEL); 1602a2e6d1f6SChaotian Jing } else { 16032fea5819SChaotian Jing sdr_set_bits(host->base + tune_reg, 1604a2e6d1f6SChaotian Jing MSDC_PAD_TUNE_RD_SEL | 1605a2e6d1f6SChaotian Jing MSDC_PAD_TUNE_CMD_SEL); 1606a2e6d1f6SChaotian Jing } 16072fea5819SChaotian Jing } else { 16082fea5819SChaotian Jing /* choose clock tune */ 1609a2e6d1f6SChaotian Jing if (host->top_base) 1610a2e6d1f6SChaotian Jing sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, 1611a2e6d1f6SChaotian Jing PAD_RXDLY_SEL); 1612a2e6d1f6SChaotian Jing else 1613a2e6d1f6SChaotian Jing sdr_set_bits(host->base + tune_reg, 1614a2e6d1f6SChaotian Jing MSDC_PAD_TUNE_RXDLYSEL); 16152fea5819SChaotian Jing } 16166397b7f5SChaotian Jing 161720848903SChaotian Jing /* Configure to enable SDIO mode. 161820848903SChaotian Jing * it's must otherwise sdio cmd5 failed 161920848903SChaotian Jing */ 162020848903SChaotian Jing sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); 162120848903SChaotian Jing 16225215b2e9Sjjian zhou /* Config SDIO device detect interrupt function */ 162320848903SChaotian Jing sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); 162426c71a13Syong mao sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_DAT1_IRQ_TRIGGER); 162520848903SChaotian Jing 162620848903SChaotian Jing /* Configure to default data timeout */ 162720848903SChaotian Jing sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); 162820848903SChaotian Jing 162986beac37SChaotian Jing host->def_tune_para.iocon = readl(host->base + MSDC_IOCON); 16302fea5819SChaotian Jing host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON); 1631a2e6d1f6SChaotian Jing if (host->top_base) { 1632a2e6d1f6SChaotian Jing host->def_tune_para.emmc_top_control = 1633a2e6d1f6SChaotian Jing readl(host->top_base + EMMC_TOP_CONTROL); 1634a2e6d1f6SChaotian Jing host->def_tune_para.emmc_top_cmd = 1635a2e6d1f6SChaotian Jing readl(host->top_base + EMMC_TOP_CMD); 1636a2e6d1f6SChaotian Jing host->saved_tune_para.emmc_top_control = 1637a2e6d1f6SChaotian Jing readl(host->top_base + EMMC_TOP_CONTROL); 1638a2e6d1f6SChaotian Jing host->saved_tune_para.emmc_top_cmd = 1639a2e6d1f6SChaotian Jing readl(host->top_base + EMMC_TOP_CMD); 1640a2e6d1f6SChaotian Jing } else { 1641a2e6d1f6SChaotian Jing host->def_tune_para.pad_tune = readl(host->base + tune_reg); 16422fea5819SChaotian Jing host->saved_tune_para.pad_tune = readl(host->base + tune_reg); 1643a2e6d1f6SChaotian Jing } 164420848903SChaotian Jing dev_dbg(host->dev, "init hardware done!"); 164520848903SChaotian Jing } 164620848903SChaotian Jing 164720848903SChaotian Jing static void msdc_deinit_hw(struct msdc_host *host) 164820848903SChaotian Jing { 164920848903SChaotian Jing u32 val; 1650d087bde5SNeilBrown 1651d087bde5SNeilBrown if (host->internal_cd) { 1652d087bde5SNeilBrown /* Disabled card-detect */ 1653d087bde5SNeilBrown sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); 1654d087bde5SNeilBrown sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); 1655d087bde5SNeilBrown } 1656d087bde5SNeilBrown 165720848903SChaotian Jing /* Disable and clear all interrupts */ 165820848903SChaotian Jing writel(0, host->base + MSDC_INTEN); 165920848903SChaotian Jing 166020848903SChaotian Jing val = readl(host->base + MSDC_INT); 166120848903SChaotian Jing writel(val, host->base + MSDC_INT); 166220848903SChaotian Jing } 166320848903SChaotian Jing 166420848903SChaotian Jing /* init gpd and bd list in msdc_drv_probe */ 166520848903SChaotian Jing static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma) 166620848903SChaotian Jing { 166720848903SChaotian Jing struct mt_gpdma_desc *gpd = dma->gpd; 166820848903SChaotian Jing struct mt_bdma_desc *bd = dma->bd; 16692a9bde19SChaotian Jing dma_addr_t dma_addr; 167020848903SChaotian Jing int i; 167120848903SChaotian Jing 167262b0d27aSChaotian Jing memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2); 167320848903SChaotian Jing 16742a9bde19SChaotian Jing dma_addr = dma->gpd_addr + sizeof(struct mt_gpdma_desc); 167520848903SChaotian Jing gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */ 167662b0d27aSChaotian Jing /* gpd->next is must set for desc DMA 167762b0d27aSChaotian Jing * That's why must alloc 2 gpd structure. 167862b0d27aSChaotian Jing */ 16792a9bde19SChaotian Jing gpd->next = lower_32_bits(dma_addr); 16802a9bde19SChaotian Jing if (host->dev_comp->support_64g) 16812a9bde19SChaotian Jing gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 24; 16822a9bde19SChaotian Jing 16832a9bde19SChaotian Jing dma_addr = dma->bd_addr; 16842a9bde19SChaotian Jing gpd->ptr = lower_32_bits(dma->bd_addr); /* physical address */ 16852a9bde19SChaotian Jing if (host->dev_comp->support_64g) 16862a9bde19SChaotian Jing gpd->gpd_info |= (upper_32_bits(dma_addr) & 0xf) << 28; 16872a9bde19SChaotian Jing 168820848903SChaotian Jing memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM); 16892a9bde19SChaotian Jing for (i = 0; i < (MAX_BD_NUM - 1); i++) { 16902a9bde19SChaotian Jing dma_addr = dma->bd_addr + sizeof(*bd) * (i + 1); 16912a9bde19SChaotian Jing bd[i].next = lower_32_bits(dma_addr); 16922a9bde19SChaotian Jing if (host->dev_comp->support_64g) 16932a9bde19SChaotian Jing bd[i].bd_info |= (upper_32_bits(dma_addr) & 0xf) << 24; 16942a9bde19SChaotian Jing } 169520848903SChaotian Jing } 169620848903SChaotian Jing 169720848903SChaotian Jing static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 169820848903SChaotian Jing { 169920848903SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 170020848903SChaotian Jing int ret; 170120848903SChaotian Jing 170220848903SChaotian Jing msdc_set_buswidth(host, ios->bus_width); 170320848903SChaotian Jing 170420848903SChaotian Jing /* Suspend/Resume will do power off/on */ 170520848903SChaotian Jing switch (ios->power_mode) { 170620848903SChaotian Jing case MMC_POWER_UP: 170720848903SChaotian Jing if (!IS_ERR(mmc->supply.vmmc)) { 17086397b7f5SChaotian Jing msdc_init_hw(host); 170920848903SChaotian Jing ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 171020848903SChaotian Jing ios->vdd); 171120848903SChaotian Jing if (ret) { 171220848903SChaotian Jing dev_err(host->dev, "Failed to set vmmc power!\n"); 1713567979fbSUlf Hansson return; 171420848903SChaotian Jing } 171520848903SChaotian Jing } 171620848903SChaotian Jing break; 171720848903SChaotian Jing case MMC_POWER_ON: 171820848903SChaotian Jing if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { 171920848903SChaotian Jing ret = regulator_enable(mmc->supply.vqmmc); 172020848903SChaotian Jing if (ret) 172120848903SChaotian Jing dev_err(host->dev, "Failed to set vqmmc power!\n"); 172220848903SChaotian Jing else 172320848903SChaotian Jing host->vqmmc_enabled = true; 172420848903SChaotian Jing } 172520848903SChaotian Jing break; 172620848903SChaotian Jing case MMC_POWER_OFF: 172720848903SChaotian Jing if (!IS_ERR(mmc->supply.vmmc)) 172820848903SChaotian Jing mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 172920848903SChaotian Jing 173020848903SChaotian Jing if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) { 173120848903SChaotian Jing regulator_disable(mmc->supply.vqmmc); 173220848903SChaotian Jing host->vqmmc_enabled = false; 173320848903SChaotian Jing } 173420848903SChaotian Jing break; 173520848903SChaotian Jing default: 173620848903SChaotian Jing break; 173720848903SChaotian Jing } 173820848903SChaotian Jing 17396e622947SChaotian Jing if (host->mclk != ios->clock || host->timing != ios->timing) 17406e622947SChaotian Jing msdc_set_mclk(host, ios->timing, ios->clock); 174120848903SChaotian Jing } 174220848903SChaotian Jing 17436397b7f5SChaotian Jing static u32 test_delay_bit(u32 delay, u32 bit) 17446397b7f5SChaotian Jing { 17456397b7f5SChaotian Jing bit %= PAD_DELAY_MAX; 17466397b7f5SChaotian Jing return delay & (1 << bit); 17476397b7f5SChaotian Jing } 17486397b7f5SChaotian Jing 17496397b7f5SChaotian Jing static int get_delay_len(u32 delay, u32 start_bit) 17506397b7f5SChaotian Jing { 17516397b7f5SChaotian Jing int i; 17526397b7f5SChaotian Jing 17536397b7f5SChaotian Jing for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) { 17546397b7f5SChaotian Jing if (test_delay_bit(delay, start_bit + i) == 0) 17556397b7f5SChaotian Jing return i; 17566397b7f5SChaotian Jing } 17576397b7f5SChaotian Jing return PAD_DELAY_MAX - start_bit; 17586397b7f5SChaotian Jing } 17596397b7f5SChaotian Jing 17606397b7f5SChaotian Jing static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) 17616397b7f5SChaotian Jing { 17626397b7f5SChaotian Jing int start = 0, len = 0; 17636397b7f5SChaotian Jing int start_final = 0, len_final = 0; 17646397b7f5SChaotian Jing u8 final_phase = 0xff; 176562d494caSGeert Uytterhoeven struct msdc_delay_phase delay_phase = { 0, }; 17666397b7f5SChaotian Jing 17676397b7f5SChaotian Jing if (delay == 0) { 17686397b7f5SChaotian Jing dev_err(host->dev, "phase error: [map:%x]\n", delay); 17696397b7f5SChaotian Jing delay_phase.final_phase = final_phase; 17706397b7f5SChaotian Jing return delay_phase; 17716397b7f5SChaotian Jing } 17726397b7f5SChaotian Jing 17736397b7f5SChaotian Jing while (start < PAD_DELAY_MAX) { 17746397b7f5SChaotian Jing len = get_delay_len(delay, start); 17756397b7f5SChaotian Jing if (len_final < len) { 17766397b7f5SChaotian Jing start_final = start; 17776397b7f5SChaotian Jing len_final = len; 17786397b7f5SChaotian Jing } 17796397b7f5SChaotian Jing start += len ? len : 1; 17801ede5cb8Syong mao if (len >= 12 && start_final < 4) 17816397b7f5SChaotian Jing break; 17826397b7f5SChaotian Jing } 17836397b7f5SChaotian Jing 17846397b7f5SChaotian Jing /* The rule is that to find the smallest delay cell */ 17856397b7f5SChaotian Jing if (start_final == 0) 17866397b7f5SChaotian Jing final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX; 17876397b7f5SChaotian Jing else 17886397b7f5SChaotian Jing final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX; 17896397b7f5SChaotian Jing dev_info(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n", 17906397b7f5SChaotian Jing delay, len_final, final_phase); 17916397b7f5SChaotian Jing 17926397b7f5SChaotian Jing delay_phase.maxlen = len_final; 17936397b7f5SChaotian Jing delay_phase.start = start_final; 17946397b7f5SChaotian Jing delay_phase.final_phase = final_phase; 17956397b7f5SChaotian Jing return delay_phase; 17966397b7f5SChaotian Jing } 17976397b7f5SChaotian Jing 1798fd82cc30SChaotian Jing static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value) 1799fd82cc30SChaotian Jing { 1800fd82cc30SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 1801fd82cc30SChaotian Jing 1802fd82cc30SChaotian Jing if (host->top_base) 1803fd82cc30SChaotian Jing sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, 1804fd82cc30SChaotian Jing value); 1805fd82cc30SChaotian Jing else 1806fd82cc30SChaotian Jing sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, 1807fd82cc30SChaotian Jing value); 1808fd82cc30SChaotian Jing } 1809fd82cc30SChaotian Jing 1810fd82cc30SChaotian Jing static inline void msdc_set_data_delay(struct msdc_host *host, u32 value) 1811fd82cc30SChaotian Jing { 1812fd82cc30SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 1813fd82cc30SChaotian Jing 1814fd82cc30SChaotian Jing if (host->top_base) 1815fd82cc30SChaotian Jing sdr_set_field(host->top_base + EMMC_TOP_CONTROL, 1816fd82cc30SChaotian Jing PAD_DAT_RD_RXDLY, value); 1817fd82cc30SChaotian Jing else 1818fd82cc30SChaotian Jing sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, 1819fd82cc30SChaotian Jing value); 1820fd82cc30SChaotian Jing } 1821fd82cc30SChaotian Jing 18226397b7f5SChaotian Jing static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) 18236397b7f5SChaotian Jing { 18246397b7f5SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 18256397b7f5SChaotian Jing u32 rise_delay = 0, fall_delay = 0; 1826ae9c657eSChaotian Jing struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; 18271ede5cb8Syong mao struct msdc_delay_phase internal_delay_phase; 18286397b7f5SChaotian Jing u8 final_delay, final_maxlen; 18291ede5cb8Syong mao u32 internal_delay = 0; 183039add252SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 18316397b7f5SChaotian Jing int cmd_err; 18321ede5cb8Syong mao int i, j; 18331ede5cb8Syong mao 18341ede5cb8Syong mao if (mmc->ios.timing == MMC_TIMING_MMC_HS200 || 18351ede5cb8Syong mao mmc->ios.timing == MMC_TIMING_UHS_SDR104) 183639add252SChaotian Jing sdr_set_field(host->base + tune_reg, 18371ede5cb8Syong mao MSDC_PAD_TUNE_CMDRRDLY, 18381ede5cb8Syong mao host->hs200_cmd_int_delay); 18396397b7f5SChaotian Jing 18406397b7f5SChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 18416397b7f5SChaotian Jing for (i = 0 ; i < PAD_DELAY_MAX; i++) { 1842fd82cc30SChaotian Jing msdc_set_cmd_delay(host, i); 18431ede5cb8Syong mao /* 18441ede5cb8Syong mao * Using the same parameters, it may sometimes pass the test, 18451ede5cb8Syong mao * but sometimes it may fail. To make sure the parameters are 18461ede5cb8Syong mao * more stable, we test each set of parameters 3 times. 18471ede5cb8Syong mao */ 18481ede5cb8Syong mao for (j = 0; j < 3; j++) { 18496397b7f5SChaotian Jing mmc_send_tuning(mmc, opcode, &cmd_err); 18501ede5cb8Syong mao if (!cmd_err) { 18516397b7f5SChaotian Jing rise_delay |= (1 << i); 18521ede5cb8Syong mao } else { 18531ede5cb8Syong mao rise_delay &= ~(1 << i); 18541ede5cb8Syong mao break; 18551ede5cb8Syong mao } 18561ede5cb8Syong mao } 18576397b7f5SChaotian Jing } 1858ae9c657eSChaotian Jing final_rise_delay = get_best_delay(host, rise_delay); 1859ae9c657eSChaotian Jing /* if rising edge has enough margin, then do not scan falling edge */ 18606b10c9abSChaotian Jing if (final_rise_delay.maxlen >= 12 || 18616b10c9abSChaotian Jing (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) 1862ae9c657eSChaotian Jing goto skip_fall; 18636397b7f5SChaotian Jing 18646397b7f5SChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 18656397b7f5SChaotian Jing for (i = 0; i < PAD_DELAY_MAX; i++) { 1866fd82cc30SChaotian Jing msdc_set_cmd_delay(host, i); 18671ede5cb8Syong mao /* 18681ede5cb8Syong mao * Using the same parameters, it may sometimes pass the test, 18691ede5cb8Syong mao * but sometimes it may fail. To make sure the parameters are 18701ede5cb8Syong mao * more stable, we test each set of parameters 3 times. 18711ede5cb8Syong mao */ 18721ede5cb8Syong mao for (j = 0; j < 3; j++) { 18736397b7f5SChaotian Jing mmc_send_tuning(mmc, opcode, &cmd_err); 18741ede5cb8Syong mao if (!cmd_err) { 18756397b7f5SChaotian Jing fall_delay |= (1 << i); 18761ede5cb8Syong mao } else { 18771ede5cb8Syong mao fall_delay &= ~(1 << i); 18781ede5cb8Syong mao break; 18791ede5cb8Syong mao } 18801ede5cb8Syong mao } 18816397b7f5SChaotian Jing } 18826397b7f5SChaotian Jing final_fall_delay = get_best_delay(host, fall_delay); 18836397b7f5SChaotian Jing 1884ae9c657eSChaotian Jing skip_fall: 18856397b7f5SChaotian Jing final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); 18861ede5cb8Syong mao if (final_fall_delay.maxlen >= 12 && final_fall_delay.start < 4) 18871ede5cb8Syong mao final_maxlen = final_fall_delay.maxlen; 18886397b7f5SChaotian Jing if (final_maxlen == final_rise_delay.maxlen) { 18896397b7f5SChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 18906397b7f5SChaotian Jing final_delay = final_rise_delay.final_phase; 18916397b7f5SChaotian Jing } else { 18926397b7f5SChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 18936397b7f5SChaotian Jing final_delay = final_fall_delay.final_phase; 18946397b7f5SChaotian Jing } 1895fd82cc30SChaotian Jing msdc_set_cmd_delay(host, final_delay); 1896fd82cc30SChaotian Jing 18972fea5819SChaotian Jing if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay) 18981ede5cb8Syong mao goto skip_internal; 18996397b7f5SChaotian Jing 19001ede5cb8Syong mao for (i = 0; i < PAD_DELAY_MAX; i++) { 190139add252SChaotian Jing sdr_set_field(host->base + tune_reg, 19021ede5cb8Syong mao MSDC_PAD_TUNE_CMDRRDLY, i); 19031ede5cb8Syong mao mmc_send_tuning(mmc, opcode, &cmd_err); 19041ede5cb8Syong mao if (!cmd_err) 19051ede5cb8Syong mao internal_delay |= (1 << i); 19061ede5cb8Syong mao } 19071ede5cb8Syong mao dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay); 19081ede5cb8Syong mao internal_delay_phase = get_best_delay(host, internal_delay); 190939add252SChaotian Jing sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRRDLY, 19101ede5cb8Syong mao internal_delay_phase.final_phase); 19111ede5cb8Syong mao skip_internal: 19121ede5cb8Syong mao dev_dbg(host->dev, "Final cmd pad delay: %x\n", final_delay); 19131ede5cb8Syong mao return final_delay == 0xff ? -EIO : 0; 19141ede5cb8Syong mao } 19151ede5cb8Syong mao 19161ede5cb8Syong mao static int hs400_tune_response(struct mmc_host *mmc, u32 opcode) 19171ede5cb8Syong mao { 19181ede5cb8Syong mao struct msdc_host *host = mmc_priv(mmc); 19191ede5cb8Syong mao u32 cmd_delay = 0; 19201ede5cb8Syong mao struct msdc_delay_phase final_cmd_delay = { 0,}; 19211ede5cb8Syong mao u8 final_delay; 19221ede5cb8Syong mao int cmd_err; 19231ede5cb8Syong mao int i, j; 19241ede5cb8Syong mao 19251ede5cb8Syong mao /* select EMMC50 PAD CMD tune */ 19261ede5cb8Syong mao sdr_set_bits(host->base + PAD_CMD_TUNE, BIT(0)); 19278f34e5bdSChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMDTA, 2); 19281ede5cb8Syong mao 19291ede5cb8Syong mao if (mmc->ios.timing == MMC_TIMING_MMC_HS200 || 19301ede5cb8Syong mao mmc->ios.timing == MMC_TIMING_UHS_SDR104) 19311ede5cb8Syong mao sdr_set_field(host->base + MSDC_PAD_TUNE, 19321ede5cb8Syong mao MSDC_PAD_TUNE_CMDRRDLY, 19331ede5cb8Syong mao host->hs200_cmd_int_delay); 19341ede5cb8Syong mao 19351ede5cb8Syong mao if (host->hs400_cmd_resp_sel_rising) 19361ede5cb8Syong mao sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 19371ede5cb8Syong mao else 19381ede5cb8Syong mao sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 19391ede5cb8Syong mao for (i = 0 ; i < PAD_DELAY_MAX; i++) { 19401ede5cb8Syong mao sdr_set_field(host->base + PAD_CMD_TUNE, 19411ede5cb8Syong mao PAD_CMD_TUNE_RX_DLY3, i); 19421ede5cb8Syong mao /* 19431ede5cb8Syong mao * Using the same parameters, it may sometimes pass the test, 19441ede5cb8Syong mao * but sometimes it may fail. To make sure the parameters are 19451ede5cb8Syong mao * more stable, we test each set of parameters 3 times. 19461ede5cb8Syong mao */ 19471ede5cb8Syong mao for (j = 0; j < 3; j++) { 19481ede5cb8Syong mao mmc_send_tuning(mmc, opcode, &cmd_err); 19491ede5cb8Syong mao if (!cmd_err) { 19501ede5cb8Syong mao cmd_delay |= (1 << i); 19511ede5cb8Syong mao } else { 19521ede5cb8Syong mao cmd_delay &= ~(1 << i); 19531ede5cb8Syong mao break; 19541ede5cb8Syong mao } 19551ede5cb8Syong mao } 19561ede5cb8Syong mao } 19571ede5cb8Syong mao final_cmd_delay = get_best_delay(host, cmd_delay); 19581ede5cb8Syong mao sdr_set_field(host->base + PAD_CMD_TUNE, PAD_CMD_TUNE_RX_DLY3, 19591ede5cb8Syong mao final_cmd_delay.final_phase); 19601ede5cb8Syong mao final_delay = final_cmd_delay.final_phase; 19611ede5cb8Syong mao 19621ede5cb8Syong mao dev_dbg(host->dev, "Final cmd pad delay: %x\n", final_delay); 19636397b7f5SChaotian Jing return final_delay == 0xff ? -EIO : 0; 19646397b7f5SChaotian Jing } 19656397b7f5SChaotian Jing 19666397b7f5SChaotian Jing static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) 19676397b7f5SChaotian Jing { 19686397b7f5SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 19696397b7f5SChaotian Jing u32 rise_delay = 0, fall_delay = 0; 1970ae9c657eSChaotian Jing struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; 19716397b7f5SChaotian Jing u8 final_delay, final_maxlen; 19726397b7f5SChaotian Jing int i, ret; 19736397b7f5SChaotian Jing 1974d17bb71cSChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL, 1975d17bb71cSChaotian Jing host->latch_ck); 19766397b7f5SChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); 19776397b7f5SChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); 19786397b7f5SChaotian Jing for (i = 0 ; i < PAD_DELAY_MAX; i++) { 1979fd82cc30SChaotian Jing msdc_set_data_delay(host, i); 19806397b7f5SChaotian Jing ret = mmc_send_tuning(mmc, opcode, NULL); 19816397b7f5SChaotian Jing if (!ret) 19826397b7f5SChaotian Jing rise_delay |= (1 << i); 19836397b7f5SChaotian Jing } 1984ae9c657eSChaotian Jing final_rise_delay = get_best_delay(host, rise_delay); 1985ae9c657eSChaotian Jing /* if rising edge has enough margin, then do not scan falling edge */ 19861ede5cb8Syong mao if (final_rise_delay.maxlen >= 12 || 1987ae9c657eSChaotian Jing (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) 1988ae9c657eSChaotian Jing goto skip_fall; 19896397b7f5SChaotian Jing 19906397b7f5SChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); 19916397b7f5SChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); 19926397b7f5SChaotian Jing for (i = 0; i < PAD_DELAY_MAX; i++) { 1993fd82cc30SChaotian Jing msdc_set_data_delay(host, i); 19946397b7f5SChaotian Jing ret = mmc_send_tuning(mmc, opcode, NULL); 19956397b7f5SChaotian Jing if (!ret) 19966397b7f5SChaotian Jing fall_delay |= (1 << i); 19976397b7f5SChaotian Jing } 19986397b7f5SChaotian Jing final_fall_delay = get_best_delay(host, fall_delay); 19996397b7f5SChaotian Jing 2000ae9c657eSChaotian Jing skip_fall: 20016397b7f5SChaotian Jing final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); 20026397b7f5SChaotian Jing if (final_maxlen == final_rise_delay.maxlen) { 20036397b7f5SChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); 20046397b7f5SChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); 20056397b7f5SChaotian Jing final_delay = final_rise_delay.final_phase; 20066397b7f5SChaotian Jing } else { 20076397b7f5SChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); 20086397b7f5SChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); 20096397b7f5SChaotian Jing final_delay = final_fall_delay.final_phase; 20106397b7f5SChaotian Jing } 2011fd82cc30SChaotian Jing msdc_set_data_delay(host, final_delay); 20126397b7f5SChaotian Jing 20131ede5cb8Syong mao dev_dbg(host->dev, "Final data pad delay: %x\n", final_delay); 20146397b7f5SChaotian Jing return final_delay == 0xff ? -EIO : 0; 20156397b7f5SChaotian Jing } 20166397b7f5SChaotian Jing 201786601d0eSChaotian Jing /* 201886601d0eSChaotian Jing * MSDC IP which supports data tune + async fifo can do CMD/DAT tune 201986601d0eSChaotian Jing * together, which can save the tuning time. 202086601d0eSChaotian Jing */ 202186601d0eSChaotian Jing static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) 202286601d0eSChaotian Jing { 202386601d0eSChaotian Jing struct msdc_host *host = mmc_priv(mmc); 202486601d0eSChaotian Jing u32 rise_delay = 0, fall_delay = 0; 202586601d0eSChaotian Jing struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,}; 202686601d0eSChaotian Jing u8 final_delay, final_maxlen; 202786601d0eSChaotian Jing int i, ret; 202886601d0eSChaotian Jing 202986601d0eSChaotian Jing sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL, 203086601d0eSChaotian Jing host->latch_ck); 203186601d0eSChaotian Jing 203286601d0eSChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 203386601d0eSChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, 203486601d0eSChaotian Jing MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); 203586601d0eSChaotian Jing for (i = 0 ; i < PAD_DELAY_MAX; i++) { 2036fd82cc30SChaotian Jing msdc_set_cmd_delay(host, i); 2037fd82cc30SChaotian Jing msdc_set_data_delay(host, i); 203886601d0eSChaotian Jing ret = mmc_send_tuning(mmc, opcode, NULL); 203986601d0eSChaotian Jing if (!ret) 204086601d0eSChaotian Jing rise_delay |= (1 << i); 204186601d0eSChaotian Jing } 204286601d0eSChaotian Jing final_rise_delay = get_best_delay(host, rise_delay); 204386601d0eSChaotian Jing /* if rising edge has enough margin, then do not scan falling edge */ 204486601d0eSChaotian Jing if (final_rise_delay.maxlen >= 12 || 204586601d0eSChaotian Jing (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) 204686601d0eSChaotian Jing goto skip_fall; 204786601d0eSChaotian Jing 204886601d0eSChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 204986601d0eSChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, 205086601d0eSChaotian Jing MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); 205186601d0eSChaotian Jing for (i = 0; i < PAD_DELAY_MAX; i++) { 2052fd82cc30SChaotian Jing msdc_set_cmd_delay(host, i); 2053fd82cc30SChaotian Jing msdc_set_data_delay(host, i); 205486601d0eSChaotian Jing ret = mmc_send_tuning(mmc, opcode, NULL); 205586601d0eSChaotian Jing if (!ret) 205686601d0eSChaotian Jing fall_delay |= (1 << i); 205786601d0eSChaotian Jing } 205886601d0eSChaotian Jing final_fall_delay = get_best_delay(host, fall_delay); 205986601d0eSChaotian Jing 206086601d0eSChaotian Jing skip_fall: 206186601d0eSChaotian Jing final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); 206286601d0eSChaotian Jing if (final_maxlen == final_rise_delay.maxlen) { 206386601d0eSChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 206486601d0eSChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, 206586601d0eSChaotian Jing MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); 206686601d0eSChaotian Jing final_delay = final_rise_delay.final_phase; 206786601d0eSChaotian Jing } else { 206886601d0eSChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); 206986601d0eSChaotian Jing sdr_set_bits(host->base + MSDC_IOCON, 207086601d0eSChaotian Jing MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); 207186601d0eSChaotian Jing final_delay = final_fall_delay.final_phase; 207286601d0eSChaotian Jing } 207386601d0eSChaotian Jing 2074fd82cc30SChaotian Jing msdc_set_cmd_delay(host, final_delay); 2075fd82cc30SChaotian Jing msdc_set_data_delay(host, final_delay); 2076a2e6d1f6SChaotian Jing 207786601d0eSChaotian Jing dev_dbg(host->dev, "Final pad delay: %x\n", final_delay); 207886601d0eSChaotian Jing return final_delay == 0xff ? -EIO : 0; 207986601d0eSChaotian Jing } 208086601d0eSChaotian Jing 20816397b7f5SChaotian Jing static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode) 20826397b7f5SChaotian Jing { 20836397b7f5SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 20846397b7f5SChaotian Jing int ret; 208539add252SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 20866397b7f5SChaotian Jing 208786601d0eSChaotian Jing if (host->dev_comp->data_tune && host->dev_comp->async_fifo) { 208886601d0eSChaotian Jing ret = msdc_tune_together(mmc, opcode); 208986601d0eSChaotian Jing if (host->hs400_mode) { 209086601d0eSChaotian Jing sdr_clr_bits(host->base + MSDC_IOCON, 209186601d0eSChaotian Jing MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); 2092fd82cc30SChaotian Jing msdc_set_data_delay(host, 0); 209386601d0eSChaotian Jing } 209486601d0eSChaotian Jing goto tune_done; 209586601d0eSChaotian Jing } 20967f3d5852SChaotian Jing if (host->hs400_mode && 20977f3d5852SChaotian Jing host->dev_comp->hs400_tune) 20981ede5cb8Syong mao ret = hs400_tune_response(mmc, opcode); 20991ede5cb8Syong mao else 21006397b7f5SChaotian Jing ret = msdc_tune_response(mmc, opcode); 21016397b7f5SChaotian Jing if (ret == -EIO) { 21026397b7f5SChaotian Jing dev_err(host->dev, "Tune response fail!\n"); 2103567979fbSUlf Hansson return ret; 21046397b7f5SChaotian Jing } 21055462ff39SChaotian Jing if (host->hs400_mode == false) { 21066397b7f5SChaotian Jing ret = msdc_tune_data(mmc, opcode); 21076397b7f5SChaotian Jing if (ret == -EIO) 21086397b7f5SChaotian Jing dev_err(host->dev, "Tune data fail!\n"); 21095462ff39SChaotian Jing } 21106397b7f5SChaotian Jing 211186601d0eSChaotian Jing tune_done: 211286beac37SChaotian Jing host->saved_tune_para.iocon = readl(host->base + MSDC_IOCON); 211339add252SChaotian Jing host->saved_tune_para.pad_tune = readl(host->base + tune_reg); 21141ede5cb8Syong mao host->saved_tune_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE); 2115a2e6d1f6SChaotian Jing if (host->top_base) { 2116a2e6d1f6SChaotian Jing host->saved_tune_para.emmc_top_control = readl(host->top_base + 2117a2e6d1f6SChaotian Jing EMMC_TOP_CONTROL); 2118a2e6d1f6SChaotian Jing host->saved_tune_para.emmc_top_cmd = readl(host->top_base + 2119a2e6d1f6SChaotian Jing EMMC_TOP_CMD); 2120a2e6d1f6SChaotian Jing } 21216397b7f5SChaotian Jing return ret; 21226397b7f5SChaotian Jing } 21236397b7f5SChaotian Jing 21246397b7f5SChaotian Jing static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) 21256397b7f5SChaotian Jing { 21266397b7f5SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 21275462ff39SChaotian Jing host->hs400_mode = true; 21286397b7f5SChaotian Jing 2129a2e6d1f6SChaotian Jing if (host->top_base) 2130a2e6d1f6SChaotian Jing writel(host->hs400_ds_delay, 2131a2e6d1f6SChaotian Jing host->top_base + EMMC50_PAD_DS_TUNE); 2132a2e6d1f6SChaotian Jing else 21336397b7f5SChaotian Jing writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE); 21342fea5819SChaotian Jing /* hs400 mode must set it to 0 */ 21352fea5819SChaotian Jing sdr_clr_bits(host->base + MSDC_PATCH_BIT2, MSDC_PATCH_BIT2_CFGCRCSTS); 2136c8609b22SChaotian Jing /* to improve read performance, set outstanding to 2 */ 2137c8609b22SChaotian Jing sdr_set_field(host->base + EMMC50_CFG3, EMMC50_CFG3_OUTS_WR, 2); 2138c8609b22SChaotian Jing 21396397b7f5SChaotian Jing return 0; 21406397b7f5SChaotian Jing } 21416397b7f5SChaotian Jing 2142c9b5061eSChaotian Jing static void msdc_hw_reset(struct mmc_host *mmc) 2143c9b5061eSChaotian Jing { 2144c9b5061eSChaotian Jing struct msdc_host *host = mmc_priv(mmc); 2145c9b5061eSChaotian Jing 2146c9b5061eSChaotian Jing sdr_set_bits(host->base + EMMC_IOCON, 1); 2147c9b5061eSChaotian Jing udelay(10); /* 10us is enough */ 2148c9b5061eSChaotian Jing sdr_clr_bits(host->base + EMMC_IOCON, 1); 2149c9b5061eSChaotian Jing } 2150c9b5061eSChaotian Jing 21515215b2e9Sjjian zhou static void msdc_ack_sdio_irq(struct mmc_host *mmc) 21525215b2e9Sjjian zhou { 21538a5df8acSjjian zhou unsigned long flags; 21548a5df8acSjjian zhou struct msdc_host *host = mmc_priv(mmc); 21558a5df8acSjjian zhou 21568a5df8acSjjian zhou spin_lock_irqsave(&host->lock, flags); 21578a5df8acSjjian zhou __msdc_enable_sdio_irq(host, 1); 21588a5df8acSjjian zhou spin_unlock_irqrestore(&host->lock, flags); 21595215b2e9Sjjian zhou } 21605215b2e9Sjjian zhou 2161d087bde5SNeilBrown static int msdc_get_cd(struct mmc_host *mmc) 2162d087bde5SNeilBrown { 2163d087bde5SNeilBrown struct msdc_host *host = mmc_priv(mmc); 2164d087bde5SNeilBrown int val; 2165d087bde5SNeilBrown 2166d087bde5SNeilBrown if (mmc->caps & MMC_CAP_NONREMOVABLE) 2167d087bde5SNeilBrown return 1; 2168d087bde5SNeilBrown 2169d087bde5SNeilBrown if (!host->internal_cd) 2170d087bde5SNeilBrown return mmc_gpio_get_cd(mmc); 2171d087bde5SNeilBrown 2172d087bde5SNeilBrown val = readl(host->base + MSDC_PS) & MSDC_PS_CDSTS; 2173d087bde5SNeilBrown if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) 2174d087bde5SNeilBrown return !!val; 2175d087bde5SNeilBrown else 2176d087bde5SNeilBrown return !val; 2177d087bde5SNeilBrown } 2178d087bde5SNeilBrown 2179be7815d6SJulia Lawall static const struct mmc_host_ops mt_msdc_ops = { 218020848903SChaotian Jing .post_req = msdc_post_req, 218120848903SChaotian Jing .pre_req = msdc_pre_req, 218220848903SChaotian Jing .request = msdc_ops_request, 218320848903SChaotian Jing .set_ios = msdc_ops_set_ios, 21848d53e412SChaotian Jing .get_ro = mmc_gpio_get_ro, 2185d087bde5SNeilBrown .get_cd = msdc_get_cd, 21865215b2e9Sjjian zhou .enable_sdio_irq = msdc_enable_sdio_irq, 21875215b2e9Sjjian zhou .ack_sdio_irq = msdc_ack_sdio_irq, 218820848903SChaotian Jing .start_signal_voltage_switch = msdc_ops_switch_volt, 218920848903SChaotian Jing .card_busy = msdc_card_busy, 21906397b7f5SChaotian Jing .execute_tuning = msdc_execute_tuning, 21916397b7f5SChaotian Jing .prepare_hs400_tuning = msdc_prepare_hs400_tuning, 2192c9b5061eSChaotian Jing .hw_reset = msdc_hw_reset, 219320848903SChaotian Jing }; 219420848903SChaotian Jing 21951ede5cb8Syong mao static void msdc_of_property_parse(struct platform_device *pdev, 21961ede5cb8Syong mao struct msdc_host *host) 21971ede5cb8Syong mao { 2198d17bb71cSChaotian Jing of_property_read_u32(pdev->dev.of_node, "mediatek,latch-ck", 2199d17bb71cSChaotian Jing &host->latch_ck); 2200d17bb71cSChaotian Jing 22011ede5cb8Syong mao of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay", 22021ede5cb8Syong mao &host->hs400_ds_delay); 22031ede5cb8Syong mao 22041ede5cb8Syong mao of_property_read_u32(pdev->dev.of_node, "mediatek,hs200-cmd-int-delay", 22051ede5cb8Syong mao &host->hs200_cmd_int_delay); 22061ede5cb8Syong mao 22071ede5cb8Syong mao of_property_read_u32(pdev->dev.of_node, "mediatek,hs400-cmd-int-delay", 22081ede5cb8Syong mao &host->hs400_cmd_int_delay); 22091ede5cb8Syong mao 22101ede5cb8Syong mao if (of_property_read_bool(pdev->dev.of_node, 22111ede5cb8Syong mao "mediatek,hs400-cmd-resp-sel-rising")) 22121ede5cb8Syong mao host->hs400_cmd_resp_sel_rising = true; 22131ede5cb8Syong mao else 22141ede5cb8Syong mao host->hs400_cmd_resp_sel_rising = false; 22151ede5cb8Syong mao } 22161ede5cb8Syong mao 221720848903SChaotian Jing static int msdc_drv_probe(struct platform_device *pdev) 221820848903SChaotian Jing { 221920848903SChaotian Jing struct mmc_host *mmc; 222020848903SChaotian Jing struct msdc_host *host; 222120848903SChaotian Jing struct resource *res; 222220848903SChaotian Jing int ret; 222320848903SChaotian Jing 222420848903SChaotian Jing if (!pdev->dev.of_node) { 222520848903SChaotian Jing dev_err(&pdev->dev, "No DT found\n"); 222620848903SChaotian Jing return -EINVAL; 222720848903SChaotian Jing } 2228762d491aSChaotian Jing 222920848903SChaotian Jing /* Allocate MMC host for this device */ 223020848903SChaotian Jing mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); 223120848903SChaotian Jing if (!mmc) 223220848903SChaotian Jing return -ENOMEM; 223320848903SChaotian Jing 223420848903SChaotian Jing host = mmc_priv(mmc); 223520848903SChaotian Jing ret = mmc_of_parse(mmc); 223620848903SChaotian Jing if (ret) 223720848903SChaotian Jing goto host_free; 223820848903SChaotian Jing 2239bc068d38SYangtao Li host->base = devm_platform_ioremap_resource(pdev, 0); 224020848903SChaotian Jing if (IS_ERR(host->base)) { 224120848903SChaotian Jing ret = PTR_ERR(host->base); 224220848903SChaotian Jing goto host_free; 224320848903SChaotian Jing } 224420848903SChaotian Jing 2245a2e6d1f6SChaotian Jing res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 2246b65be635SFabien Parent if (res) { 2247a2e6d1f6SChaotian Jing host->top_base = devm_ioremap_resource(&pdev->dev, res); 2248a2e6d1f6SChaotian Jing if (IS_ERR(host->top_base)) 2249a2e6d1f6SChaotian Jing host->top_base = NULL; 2250b65be635SFabien Parent } 2251a2e6d1f6SChaotian Jing 225220848903SChaotian Jing ret = mmc_regulator_get_supply(mmc); 22532f98ef63SWolfram Sang if (ret) 225420848903SChaotian Jing goto host_free; 225520848903SChaotian Jing 225620848903SChaotian Jing host->src_clk = devm_clk_get(&pdev->dev, "source"); 225720848903SChaotian Jing if (IS_ERR(host->src_clk)) { 225820848903SChaotian Jing ret = PTR_ERR(host->src_clk); 225920848903SChaotian Jing goto host_free; 226020848903SChaotian Jing } 226120848903SChaotian Jing 226220848903SChaotian Jing host->h_clk = devm_clk_get(&pdev->dev, "hclk"); 226320848903SChaotian Jing if (IS_ERR(host->h_clk)) { 226420848903SChaotian Jing ret = PTR_ERR(host->h_clk); 226520848903SChaotian Jing goto host_free; 226620848903SChaotian Jing } 226720848903SChaotian Jing 2268258bac4aSChaotian Jing host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); 2269258bac4aSChaotian Jing if (IS_ERR(host->bus_clk)) 2270258bac4aSChaotian Jing host->bus_clk = NULL; 22713c1a8844SChaotian Jing /*source clock control gate is optional clock*/ 22723c1a8844SChaotian Jing host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg"); 22733c1a8844SChaotian Jing if (IS_ERR(host->src_clk_cg)) 22743c1a8844SChaotian Jing host->src_clk_cg = NULL; 22753c1a8844SChaotian Jing 227620848903SChaotian Jing host->irq = platform_get_irq(pdev, 0); 227720848903SChaotian Jing if (host->irq < 0) { 227820848903SChaotian Jing ret = -EINVAL; 227920848903SChaotian Jing goto host_free; 228020848903SChaotian Jing } 228120848903SChaotian Jing 228220848903SChaotian Jing host->pinctrl = devm_pinctrl_get(&pdev->dev); 228320848903SChaotian Jing if (IS_ERR(host->pinctrl)) { 228420848903SChaotian Jing ret = PTR_ERR(host->pinctrl); 228520848903SChaotian Jing dev_err(&pdev->dev, "Cannot find pinctrl!\n"); 228620848903SChaotian Jing goto host_free; 228720848903SChaotian Jing } 228820848903SChaotian Jing 228920848903SChaotian Jing host->pins_default = pinctrl_lookup_state(host->pinctrl, "default"); 229020848903SChaotian Jing if (IS_ERR(host->pins_default)) { 229120848903SChaotian Jing ret = PTR_ERR(host->pins_default); 229220848903SChaotian Jing dev_err(&pdev->dev, "Cannot find pinctrl default!\n"); 229320848903SChaotian Jing goto host_free; 229420848903SChaotian Jing } 229520848903SChaotian Jing 229620848903SChaotian Jing host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); 229720848903SChaotian Jing if (IS_ERR(host->pins_uhs)) { 229820848903SChaotian Jing ret = PTR_ERR(host->pins_uhs); 229920848903SChaotian Jing dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n"); 230020848903SChaotian Jing goto host_free; 230120848903SChaotian Jing } 230220848903SChaotian Jing 23031ede5cb8Syong mao msdc_of_property_parse(pdev, host); 23046397b7f5SChaotian Jing 230520848903SChaotian Jing host->dev = &pdev->dev; 2306909b3456SRyder Lee host->dev_comp = of_device_get_match_data(&pdev->dev); 230720848903SChaotian Jing host->mmc = mmc; 230820848903SChaotian Jing host->src_clk_freq = clk_get_rate(host->src_clk); 230920848903SChaotian Jing /* Set host parameters to mmc */ 231020848903SChaotian Jing mmc->ops = &mt_msdc_ops; 2311762d491aSChaotian Jing if (host->dev_comp->clk_div_bits == 8) 231240ceda09Syong mao mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 255); 2313762d491aSChaotian Jing else 2314762d491aSChaotian Jing mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095); 231520848903SChaotian Jing 2316d087bde5SNeilBrown if (!(mmc->caps & MMC_CAP_NONREMOVABLE) && 2317d087bde5SNeilBrown !mmc_can_gpio_cd(mmc) && 2318d087bde5SNeilBrown host->dev_comp->use_internal_cd) { 2319d087bde5SNeilBrown /* 2320d087bde5SNeilBrown * Is removable but no GPIO declared, so 2321d087bde5SNeilBrown * use internal functionality. 2322d087bde5SNeilBrown */ 2323d087bde5SNeilBrown host->internal_cd = true; 2324d087bde5SNeilBrown } 2325d087bde5SNeilBrown 23265215b2e9Sjjian zhou if (mmc->caps & MMC_CAP_SDIO_IRQ) 23275215b2e9Sjjian zhou mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; 23285215b2e9Sjjian zhou 23291be64c79SUlf Hansson mmc->caps |= MMC_CAP_CMD23; 233020848903SChaotian Jing /* MMC core transfer sizes tunable parameters */ 233120848903SChaotian Jing mmc->max_segs = MAX_BD_NUM; 23326ef042bdSChaotian Jing if (host->dev_comp->support_64g) 23336ef042bdSChaotian Jing mmc->max_seg_size = BDMA_DESC_BUFLEN_EXT; 23346ef042bdSChaotian Jing else 233520848903SChaotian Jing mmc->max_seg_size = BDMA_DESC_BUFLEN; 233620848903SChaotian Jing mmc->max_blk_size = 2048; 233720848903SChaotian Jing mmc->max_req_size = 512 * 1024; 233820848903SChaotian Jing mmc->max_blk_count = mmc->max_req_size / 512; 23392a9bde19SChaotian Jing if (host->dev_comp->support_64g) 23402a9bde19SChaotian Jing host->dma_mask = DMA_BIT_MASK(36); 23412a9bde19SChaotian Jing else 234220848903SChaotian Jing host->dma_mask = DMA_BIT_MASK(32); 234320848903SChaotian Jing mmc_dev(mmc)->dma_mask = &host->dma_mask; 234420848903SChaotian Jing 234520848903SChaotian Jing host->timeout_clks = 3 * 1048576; 234620848903SChaotian Jing host->dma.gpd = dma_alloc_coherent(&pdev->dev, 234762b0d27aSChaotian Jing 2 * sizeof(struct mt_gpdma_desc), 234820848903SChaotian Jing &host->dma.gpd_addr, GFP_KERNEL); 234920848903SChaotian Jing host->dma.bd = dma_alloc_coherent(&pdev->dev, 235020848903SChaotian Jing MAX_BD_NUM * sizeof(struct mt_bdma_desc), 235120848903SChaotian Jing &host->dma.bd_addr, GFP_KERNEL); 235220848903SChaotian Jing if (!host->dma.gpd || !host->dma.bd) { 235320848903SChaotian Jing ret = -ENOMEM; 235420848903SChaotian Jing goto release_mem; 235520848903SChaotian Jing } 235620848903SChaotian Jing msdc_init_gpd_bd(host, &host->dma); 235720848903SChaotian Jing INIT_DELAYED_WORK(&host->req_timeout, msdc_request_timeout); 235820848903SChaotian Jing spin_lock_init(&host->lock); 235920848903SChaotian Jing 236020848903SChaotian Jing platform_set_drvdata(pdev, mmc); 236120848903SChaotian Jing msdc_ungate_clock(host); 236220848903SChaotian Jing msdc_init_hw(host); 236320848903SChaotian Jing 236420848903SChaotian Jing ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq, 236542edb0d5SNeilBrown IRQF_TRIGGER_NONE, pdev->name, host); 236620848903SChaotian Jing if (ret) 236720848903SChaotian Jing goto release; 236820848903SChaotian Jing 23694b8a43e9SChaotian Jing pm_runtime_set_active(host->dev); 23704b8a43e9SChaotian Jing pm_runtime_set_autosuspend_delay(host->dev, MTK_MMC_AUTOSUSPEND_DELAY); 23714b8a43e9SChaotian Jing pm_runtime_use_autosuspend(host->dev); 23724b8a43e9SChaotian Jing pm_runtime_enable(host->dev); 237320848903SChaotian Jing ret = mmc_add_host(mmc); 23744b8a43e9SChaotian Jing 237520848903SChaotian Jing if (ret) 23764b8a43e9SChaotian Jing goto end; 237720848903SChaotian Jing 237820848903SChaotian Jing return 0; 23794b8a43e9SChaotian Jing end: 23804b8a43e9SChaotian Jing pm_runtime_disable(host->dev); 238120848903SChaotian Jing release: 238220848903SChaotian Jing platform_set_drvdata(pdev, NULL); 238320848903SChaotian Jing msdc_deinit_hw(host); 238420848903SChaotian Jing msdc_gate_clock(host); 238520848903SChaotian Jing release_mem: 238620848903SChaotian Jing if (host->dma.gpd) 238720848903SChaotian Jing dma_free_coherent(&pdev->dev, 238862b0d27aSChaotian Jing 2 * sizeof(struct mt_gpdma_desc), 238920848903SChaotian Jing host->dma.gpd, host->dma.gpd_addr); 239020848903SChaotian Jing if (host->dma.bd) 239120848903SChaotian Jing dma_free_coherent(&pdev->dev, 239220848903SChaotian Jing MAX_BD_NUM * sizeof(struct mt_bdma_desc), 239320848903SChaotian Jing host->dma.bd, host->dma.bd_addr); 239420848903SChaotian Jing host_free: 239520848903SChaotian Jing mmc_free_host(mmc); 239620848903SChaotian Jing 239720848903SChaotian Jing return ret; 239820848903SChaotian Jing } 239920848903SChaotian Jing 240020848903SChaotian Jing static int msdc_drv_remove(struct platform_device *pdev) 240120848903SChaotian Jing { 240220848903SChaotian Jing struct mmc_host *mmc; 240320848903SChaotian Jing struct msdc_host *host; 240420848903SChaotian Jing 240520848903SChaotian Jing mmc = platform_get_drvdata(pdev); 240620848903SChaotian Jing host = mmc_priv(mmc); 240720848903SChaotian Jing 24084b8a43e9SChaotian Jing pm_runtime_get_sync(host->dev); 24094b8a43e9SChaotian Jing 241020848903SChaotian Jing platform_set_drvdata(pdev, NULL); 241120848903SChaotian Jing mmc_remove_host(host->mmc); 241220848903SChaotian Jing msdc_deinit_hw(host); 241320848903SChaotian Jing msdc_gate_clock(host); 241420848903SChaotian Jing 24154b8a43e9SChaotian Jing pm_runtime_disable(host->dev); 24164b8a43e9SChaotian Jing pm_runtime_put_noidle(host->dev); 241720848903SChaotian Jing dma_free_coherent(&pdev->dev, 241816f2e0c6SPhong LE 2 * sizeof(struct mt_gpdma_desc), 241920848903SChaotian Jing host->dma.gpd, host->dma.gpd_addr); 242020848903SChaotian Jing dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), 242120848903SChaotian Jing host->dma.bd, host->dma.bd_addr); 242220848903SChaotian Jing 242320848903SChaotian Jing mmc_free_host(host->mmc); 242420848903SChaotian Jing 242520848903SChaotian Jing return 0; 242620848903SChaotian Jing } 242720848903SChaotian Jing 24284b8a43e9SChaotian Jing #ifdef CONFIG_PM 24294b8a43e9SChaotian Jing static void msdc_save_reg(struct msdc_host *host) 24304b8a43e9SChaotian Jing { 243139add252SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 243239add252SChaotian Jing 24334b8a43e9SChaotian Jing host->save_para.msdc_cfg = readl(host->base + MSDC_CFG); 24344b8a43e9SChaotian Jing host->save_para.iocon = readl(host->base + MSDC_IOCON); 24354b8a43e9SChaotian Jing host->save_para.sdc_cfg = readl(host->base + SDC_CFG); 24364b8a43e9SChaotian Jing host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT); 24374b8a43e9SChaotian Jing host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1); 24382fea5819SChaotian Jing host->save_para.patch_bit2 = readl(host->base + MSDC_PATCH_BIT2); 24396397b7f5SChaotian Jing host->save_para.pad_ds_tune = readl(host->base + PAD_DS_TUNE); 24401ede5cb8Syong mao host->save_para.pad_cmd_tune = readl(host->base + PAD_CMD_TUNE); 24416397b7f5SChaotian Jing host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0); 2442c8609b22SChaotian Jing host->save_para.emmc50_cfg3 = readl(host->base + EMMC50_CFG3); 2443d9dcbfc8SChaotian Jing host->save_para.sdc_fifo_cfg = readl(host->base + SDC_FIFO_CFG); 2444a2e6d1f6SChaotian Jing if (host->top_base) { 2445a2e6d1f6SChaotian Jing host->save_para.emmc_top_control = 2446a2e6d1f6SChaotian Jing readl(host->top_base + EMMC_TOP_CONTROL); 2447a2e6d1f6SChaotian Jing host->save_para.emmc_top_cmd = 2448a2e6d1f6SChaotian Jing readl(host->top_base + EMMC_TOP_CMD); 2449a2e6d1f6SChaotian Jing host->save_para.emmc50_pad_ds_tune = 2450a2e6d1f6SChaotian Jing readl(host->top_base + EMMC50_PAD_DS_TUNE); 2451a2e6d1f6SChaotian Jing } else { 2452a2e6d1f6SChaotian Jing host->save_para.pad_tune = readl(host->base + tune_reg); 2453a2e6d1f6SChaotian Jing } 24544b8a43e9SChaotian Jing } 24554b8a43e9SChaotian Jing 24564b8a43e9SChaotian Jing static void msdc_restore_reg(struct msdc_host *host) 24574b8a43e9SChaotian Jing { 245839add252SChaotian Jing u32 tune_reg = host->dev_comp->pad_tune_reg; 245939add252SChaotian Jing 24604b8a43e9SChaotian Jing writel(host->save_para.msdc_cfg, host->base + MSDC_CFG); 24614b8a43e9SChaotian Jing writel(host->save_para.iocon, host->base + MSDC_IOCON); 24624b8a43e9SChaotian Jing writel(host->save_para.sdc_cfg, host->base + SDC_CFG); 24634b8a43e9SChaotian Jing writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT); 24644b8a43e9SChaotian Jing writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1); 24652fea5819SChaotian Jing writel(host->save_para.patch_bit2, host->base + MSDC_PATCH_BIT2); 24666397b7f5SChaotian Jing writel(host->save_para.pad_ds_tune, host->base + PAD_DS_TUNE); 24671ede5cb8Syong mao writel(host->save_para.pad_cmd_tune, host->base + PAD_CMD_TUNE); 24686397b7f5SChaotian Jing writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0); 2469c8609b22SChaotian Jing writel(host->save_para.emmc50_cfg3, host->base + EMMC50_CFG3); 2470d9dcbfc8SChaotian Jing writel(host->save_para.sdc_fifo_cfg, host->base + SDC_FIFO_CFG); 2471a2e6d1f6SChaotian Jing if (host->top_base) { 2472a2e6d1f6SChaotian Jing writel(host->save_para.emmc_top_control, 2473a2e6d1f6SChaotian Jing host->top_base + EMMC_TOP_CONTROL); 2474a2e6d1f6SChaotian Jing writel(host->save_para.emmc_top_cmd, 2475a2e6d1f6SChaotian Jing host->top_base + EMMC_TOP_CMD); 2476a2e6d1f6SChaotian Jing writel(host->save_para.emmc50_pad_ds_tune, 2477a2e6d1f6SChaotian Jing host->top_base + EMMC50_PAD_DS_TUNE); 2478a2e6d1f6SChaotian Jing } else { 2479a2e6d1f6SChaotian Jing writel(host->save_para.pad_tune, host->base + tune_reg); 2480a2e6d1f6SChaotian Jing } 24811c81d69dSUlf Hansson 24821c81d69dSUlf Hansson if (sdio_irq_claimed(host->mmc)) 24831c81d69dSUlf Hansson __msdc_enable_sdio_irq(host, 1); 24844b8a43e9SChaotian Jing } 24854b8a43e9SChaotian Jing 24864b8a43e9SChaotian Jing static int msdc_runtime_suspend(struct device *dev) 24874b8a43e9SChaotian Jing { 24884b8a43e9SChaotian Jing struct mmc_host *mmc = dev_get_drvdata(dev); 24894b8a43e9SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 24904b8a43e9SChaotian Jing 24914b8a43e9SChaotian Jing msdc_save_reg(host); 24924b8a43e9SChaotian Jing msdc_gate_clock(host); 24934b8a43e9SChaotian Jing return 0; 24944b8a43e9SChaotian Jing } 24954b8a43e9SChaotian Jing 24964b8a43e9SChaotian Jing static int msdc_runtime_resume(struct device *dev) 24974b8a43e9SChaotian Jing { 24984b8a43e9SChaotian Jing struct mmc_host *mmc = dev_get_drvdata(dev); 24994b8a43e9SChaotian Jing struct msdc_host *host = mmc_priv(mmc); 25004b8a43e9SChaotian Jing 25014b8a43e9SChaotian Jing msdc_ungate_clock(host); 25024b8a43e9SChaotian Jing msdc_restore_reg(host); 25034b8a43e9SChaotian Jing return 0; 25044b8a43e9SChaotian Jing } 25054b8a43e9SChaotian Jing #endif 25064b8a43e9SChaotian Jing 25074b8a43e9SChaotian Jing static const struct dev_pm_ops msdc_dev_pm_ops = { 25084b8a43e9SChaotian Jing SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 25094b8a43e9SChaotian Jing pm_runtime_force_resume) 25104b8a43e9SChaotian Jing SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL) 25114b8a43e9SChaotian Jing }; 25124b8a43e9SChaotian Jing 251320848903SChaotian Jing static struct platform_driver mt_msdc_driver = { 251420848903SChaotian Jing .probe = msdc_drv_probe, 251520848903SChaotian Jing .remove = msdc_drv_remove, 251620848903SChaotian Jing .driver = { 251720848903SChaotian Jing .name = "mtk-msdc", 251820848903SChaotian Jing .of_match_table = msdc_of_ids, 25194b8a43e9SChaotian Jing .pm = &msdc_dev_pm_ops, 252020848903SChaotian Jing }, 252120848903SChaotian Jing }; 252220848903SChaotian Jing 252320848903SChaotian Jing module_platform_driver(mt_msdc_driver); 252420848903SChaotian Jing MODULE_LICENSE("GPL v2"); 252520848903SChaotian Jing MODULE_DESCRIPTION("MediaTek SD/MMC Card Driver"); 2526