1f95f3850SWill Newton /* 2f95f3850SWill Newton * Synopsys DesignWare Multimedia Card Interface driver 3f95f3850SWill Newton * (Based on NXP driver for lpc 31xx) 4f95f3850SWill Newton * 5f95f3850SWill Newton * Copyright (C) 2009 NXP Semiconductors 6f95f3850SWill Newton * Copyright (C) 2009, 2010 Imagination Technologies Ltd. 7f95f3850SWill Newton * 8f95f3850SWill Newton * This program is free software; you can redistribute it and/or modify 9f95f3850SWill Newton * it under the terms of the GNU General Public License as published by 10f95f3850SWill Newton * the Free Software Foundation; either version 2 of the License, or 11f95f3850SWill Newton * (at your option) any later version. 12f95f3850SWill Newton */ 13f95f3850SWill Newton 14f95f3850SWill Newton #include <linux/blkdev.h> 15f95f3850SWill Newton #include <linux/clk.h> 16f95f3850SWill Newton #include <linux/debugfs.h> 17f95f3850SWill Newton #include <linux/device.h> 18f95f3850SWill Newton #include <linux/dma-mapping.h> 19f95f3850SWill Newton #include <linux/err.h> 20f95f3850SWill Newton #include <linux/init.h> 21f95f3850SWill Newton #include <linux/interrupt.h> 22b6d2d81cSShawn Lin #include <linux/iopoll.h> 23f95f3850SWill Newton #include <linux/ioport.h> 24f95f3850SWill Newton #include <linux/module.h> 25f95f3850SWill Newton #include <linux/platform_device.h> 26a6db2c86SDouglas Anderson #include <linux/pm_runtime.h> 27f95f3850SWill Newton #include <linux/seq_file.h> 28f95f3850SWill Newton #include <linux/slab.h> 29f95f3850SWill Newton #include <linux/stat.h> 30f95f3850SWill Newton #include <linux/delay.h> 31f95f3850SWill Newton #include <linux/irq.h> 32b24c8b26SDoug Anderson #include <linux/mmc/card.h> 33f95f3850SWill Newton #include <linux/mmc/host.h> 34f95f3850SWill Newton #include <linux/mmc/mmc.h> 3501730558SDoug Anderson #include <linux/mmc/sd.h> 3690c2143aSSeungwon Jeon #include <linux/mmc/sdio.h> 37f95f3850SWill Newton #include <linux/bitops.h> 38c07946a3SJaehoon Chung #include <linux/regulator/consumer.h> 39c91eab4bSThomas Abraham #include <linux/of.h> 4055a6ceb2SDoug Anderson #include <linux/of_gpio.h> 41bf626e55SZhangfei Gao #include <linux/mmc/slot-gpio.h> 42f95f3850SWill Newton 43f95f3850SWill Newton #include "dw_mmc.h" 44f95f3850SWill Newton 45f95f3850SWill Newton /* Common flag combinations */ 463f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ 47f95f3850SWill Newton SDMMC_INT_HTO | SDMMC_INT_SBE | \ 487a3c5677SDoug Anderson SDMMC_INT_EBE | SDMMC_INT_HLE) 49f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ 507a3c5677SDoug Anderson SDMMC_INT_RESP_ERR | SDMMC_INT_HLE) 51f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ 527a3c5677SDoug Anderson DW_MCI_CMD_ERROR_FLAGS) 53f95f3850SWill Newton #define DW_MCI_SEND_STATUS 1 54f95f3850SWill Newton #define DW_MCI_RECV_STATUS 2 55f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD 16 56f95f3850SWill Newton 571f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */ 5872e83577SJaehoon Chung #define DW_MCI_FREQ_MIN 100000 /* unit: HZ */ 591f44a2a5SSeungwon Jeon 60fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ 61fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ 62fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ 63fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_TI) 64fc79a4d6SJoonyoung Shim 65cc190d4cSShawn Lin #define DESC_RING_BUF_SZ PAGE_SIZE 66cc190d4cSShawn Lin 6769d99fdcSPrabu Thangamuthu struct idmac_desc_64addr { 6869d99fdcSPrabu Thangamuthu u32 des0; /* Control Descriptor */ 69b6d2d81cSShawn Lin #define IDMAC_OWN_CLR64(x) \ 70b6d2d81cSShawn Lin !((x) & cpu_to_le32(IDMAC_DES0_OWN)) 7169d99fdcSPrabu Thangamuthu 7269d99fdcSPrabu Thangamuthu u32 des1; /* Reserved */ 7369d99fdcSPrabu Thangamuthu 7469d99fdcSPrabu Thangamuthu u32 des2; /*Buffer sizes */ 7569d99fdcSPrabu Thangamuthu #define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ 766687c42fSBen Dooks ((d)->des2 = ((d)->des2 & cpu_to_le32(0x03ffe000)) | \ 776687c42fSBen Dooks ((cpu_to_le32(s)) & cpu_to_le32(0x1fff))) 7869d99fdcSPrabu Thangamuthu 7969d99fdcSPrabu Thangamuthu u32 des3; /* Reserved */ 8069d99fdcSPrabu Thangamuthu 8169d99fdcSPrabu Thangamuthu u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/ 8269d99fdcSPrabu Thangamuthu u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/ 8369d99fdcSPrabu Thangamuthu 8469d99fdcSPrabu Thangamuthu u32 des6; /* Lower 32-bits of Next Descriptor Address */ 8569d99fdcSPrabu Thangamuthu u32 des7; /* Upper 32-bits of Next Descriptor Address */ 8669d99fdcSPrabu Thangamuthu }; 8769d99fdcSPrabu Thangamuthu 88f95f3850SWill Newton struct idmac_desc { 896687c42fSBen Dooks __le32 des0; /* Control Descriptor */ 90f95f3850SWill Newton #define IDMAC_DES0_DIC BIT(1) 91f95f3850SWill Newton #define IDMAC_DES0_LD BIT(2) 92f95f3850SWill Newton #define IDMAC_DES0_FD BIT(3) 93f95f3850SWill Newton #define IDMAC_DES0_CH BIT(4) 94f95f3850SWill Newton #define IDMAC_DES0_ER BIT(5) 95f95f3850SWill Newton #define IDMAC_DES0_CES BIT(30) 96f95f3850SWill Newton #define IDMAC_DES0_OWN BIT(31) 97f95f3850SWill Newton 986687c42fSBen Dooks __le32 des1; /* Buffer sizes */ 99f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \ 100e5306c3aSBen Dooks ((d)->des1 = ((d)->des1 & cpu_to_le32(0x03ffe000)) | (cpu_to_le32((s) & 0x1fff))) 101f95f3850SWill Newton 1026687c42fSBen Dooks __le32 des2; /* buffer 1 physical address */ 103f95f3850SWill Newton 1046687c42fSBen Dooks __le32 des3; /* buffer 2 physical address */ 105f95f3850SWill Newton }; 1065959b32eSAlexey Brodkin 1075959b32eSAlexey Brodkin /* Each descriptor can transfer up to 4KB of data in chained mode */ 1085959b32eSAlexey Brodkin #define DW_MCI_DESC_DATA_LENGTH 0x1000 109f95f3850SWill Newton 1100bdbd0e8SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc); 11156f6911cSShawn Lin static int dw_mci_get_cd(struct mmc_host *mmc); 11231bff450SSeungwon Jeon 113f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 114f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 115f95f3850SWill Newton { 116f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 117f95f3850SWill Newton struct mmc_request *mrq; 118f95f3850SWill Newton struct mmc_command *cmd; 119f95f3850SWill Newton struct mmc_command *stop; 120f95f3850SWill Newton struct mmc_data *data; 121f95f3850SWill Newton 122f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 123f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 124f95f3850SWill Newton mrq = slot->mrq; 125f95f3850SWill Newton 126f95f3850SWill Newton if (mrq) { 127f95f3850SWill Newton cmd = mrq->cmd; 128f95f3850SWill Newton data = mrq->data; 129f95f3850SWill Newton stop = mrq->stop; 130f95f3850SWill Newton 131f95f3850SWill Newton if (cmd) 132f95f3850SWill Newton seq_printf(s, 133f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 134f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 135f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 136f95f3850SWill Newton cmd->resp[2], cmd->error); 137f95f3850SWill Newton if (data) 138f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 139f95f3850SWill Newton data->bytes_xfered, data->blocks, 140f95f3850SWill Newton data->blksz, data->flags, data->error); 141f95f3850SWill Newton if (stop) 142f95f3850SWill Newton seq_printf(s, 143f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 144f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 145f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 146f95f3850SWill Newton stop->resp[2], stop->error); 147f95f3850SWill Newton } 148f95f3850SWill Newton 149f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 150f95f3850SWill Newton 151f95f3850SWill Newton return 0; 152f95f3850SWill Newton } 153f95f3850SWill Newton 154f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 155f95f3850SWill Newton { 156f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 157f95f3850SWill Newton } 158f95f3850SWill Newton 159f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 160f95f3850SWill Newton .owner = THIS_MODULE, 161f95f3850SWill Newton .open = dw_mci_req_open, 162f95f3850SWill Newton .read = seq_read, 163f95f3850SWill Newton .llseek = seq_lseek, 164f95f3850SWill Newton .release = single_release, 165f95f3850SWill Newton }; 166f95f3850SWill Newton 167f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 168f95f3850SWill Newton { 16921657ebdSJaehoon Chung struct dw_mci *host = s->private; 17021657ebdSJaehoon Chung 17121657ebdSJaehoon Chung seq_printf(s, "STATUS:\t0x%08x\n", mci_readl(host, STATUS)); 17221657ebdSJaehoon Chung seq_printf(s, "RINTSTS:\t0x%08x\n", mci_readl(host, RINTSTS)); 17321657ebdSJaehoon Chung seq_printf(s, "CMD:\t0x%08x\n", mci_readl(host, CMD)); 17421657ebdSJaehoon Chung seq_printf(s, "CTRL:\t0x%08x\n", mci_readl(host, CTRL)); 17521657ebdSJaehoon Chung seq_printf(s, "INTMASK:\t0x%08x\n", mci_readl(host, INTMASK)); 17621657ebdSJaehoon Chung seq_printf(s, "CLKENA:\t0x%08x\n", mci_readl(host, CLKENA)); 177f95f3850SWill Newton 178f95f3850SWill Newton return 0; 179f95f3850SWill Newton } 180f95f3850SWill Newton 181f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 182f95f3850SWill Newton { 183f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 184f95f3850SWill Newton } 185f95f3850SWill Newton 186f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 187f95f3850SWill Newton .owner = THIS_MODULE, 188f95f3850SWill Newton .open = dw_mci_regs_open, 189f95f3850SWill Newton .read = seq_read, 190f95f3850SWill Newton .llseek = seq_lseek, 191f95f3850SWill Newton .release = single_release, 192f95f3850SWill Newton }; 193f95f3850SWill Newton 194f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 195f95f3850SWill Newton { 196f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 197f95f3850SWill Newton struct dw_mci *host = slot->host; 198f95f3850SWill Newton struct dentry *root; 199f95f3850SWill Newton struct dentry *node; 200f95f3850SWill Newton 201f95f3850SWill Newton root = mmc->debugfs_root; 202f95f3850SWill Newton if (!root) 203f95f3850SWill Newton return; 204f95f3850SWill Newton 205f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 206f95f3850SWill Newton &dw_mci_regs_fops); 207f95f3850SWill Newton if (!node) 208f95f3850SWill Newton goto err; 209f95f3850SWill Newton 210f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 211f95f3850SWill Newton &dw_mci_req_fops); 212f95f3850SWill Newton if (!node) 213f95f3850SWill Newton goto err; 214f95f3850SWill Newton 215f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 216f95f3850SWill Newton if (!node) 217f95f3850SWill Newton goto err; 218f95f3850SWill Newton 219f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 220f95f3850SWill Newton (u32 *)&host->pending_events); 221f95f3850SWill Newton if (!node) 222f95f3850SWill Newton goto err; 223f95f3850SWill Newton 224f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 225f95f3850SWill Newton (u32 *)&host->completed_events); 226f95f3850SWill Newton if (!node) 227f95f3850SWill Newton goto err; 228f95f3850SWill Newton 229f95f3850SWill Newton return; 230f95f3850SWill Newton 231f95f3850SWill Newton err: 232f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 233f95f3850SWill Newton } 234f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 235f95f3850SWill Newton 23601730558SDoug Anderson static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg); 237*8e6db1f6SShawn Lin static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) 238*8e6db1f6SShawn Lin { 239*8e6db1f6SShawn Lin u32 ctrl; 240*8e6db1f6SShawn Lin 241*8e6db1f6SShawn Lin ctrl = mci_readl(host, CTRL); 242*8e6db1f6SShawn Lin ctrl |= reset; 243*8e6db1f6SShawn Lin mci_writel(host, CTRL, ctrl); 244*8e6db1f6SShawn Lin 245*8e6db1f6SShawn Lin /* wait till resets clear */ 246*8e6db1f6SShawn Lin if (readl_poll_timeout_atomic(host->regs + SDMMC_CTRL, ctrl, 247*8e6db1f6SShawn Lin !(ctrl & reset), 248*8e6db1f6SShawn Lin 1, 500 * USEC_PER_MSEC)) { 249*8e6db1f6SShawn Lin dev_err(host->dev, 250*8e6db1f6SShawn Lin "Timeout resetting block (ctrl reset %#x)\n", 251*8e6db1f6SShawn Lin ctrl & reset); 252*8e6db1f6SShawn Lin return false; 253*8e6db1f6SShawn Lin } 254*8e6db1f6SShawn Lin 255*8e6db1f6SShawn Lin return true; 256*8e6db1f6SShawn Lin } 25701730558SDoug Anderson 258f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 259f95f3850SWill Newton { 260800d78bfSThomas Abraham struct dw_mci_slot *slot = mmc_priv(mmc); 26101730558SDoug Anderson struct dw_mci *host = slot->host; 262f95f3850SWill Newton u32 cmdr; 263f95f3850SWill Newton 2640e3a22c0SShawn Lin cmd->error = -EINPROGRESS; 265f95f3850SWill Newton cmdr = cmd->opcode; 266f95f3850SWill Newton 26790c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 26890c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 26990c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 27090c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 27190c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 272f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 2734a1b27adSJaehoon Chung else if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 274f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 275f95f3850SWill Newton 27601730558SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 27701730558SDoug Anderson u32 clk_en_a; 27801730558SDoug Anderson 27901730558SDoug Anderson /* Special bit makes CMD11 not die */ 28001730558SDoug Anderson cmdr |= SDMMC_CMD_VOLT_SWITCH; 28101730558SDoug Anderson 28201730558SDoug Anderson /* Change state to continue to handle CMD11 weirdness */ 28301730558SDoug Anderson WARN_ON(slot->host->state != STATE_SENDING_CMD); 28401730558SDoug Anderson slot->host->state = STATE_SENDING_CMD11; 28501730558SDoug Anderson 28601730558SDoug Anderson /* 28701730558SDoug Anderson * We need to disable low power mode (automatic clock stop) 28801730558SDoug Anderson * while doing voltage switch so we don't confuse the card, 28901730558SDoug Anderson * since stopping the clock is a specific part of the UHS 29001730558SDoug Anderson * voltage change dance. 29101730558SDoug Anderson * 29201730558SDoug Anderson * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be 29301730558SDoug Anderson * unconditionally turned back on in dw_mci_setup_bus() if it's 29401730558SDoug Anderson * ever called with a non-zero clock. That shouldn't happen 29501730558SDoug Anderson * until the voltage change is all done. 29601730558SDoug Anderson */ 29701730558SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 29801730558SDoug Anderson clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id); 29901730558SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 30001730558SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 30101730558SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 30201730558SDoug Anderson } 30301730558SDoug Anderson 304f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 305f95f3850SWill Newton /* We expect a response, so set this bit */ 306f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 307f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 308f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 309f95f3850SWill Newton } 310f95f3850SWill Newton 311f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 312f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 313f95f3850SWill Newton 3140349c085SJaehoon Chung if (cmd->data) { 315f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 3160349c085SJaehoon Chung if (cmd->data->flags & MMC_DATA_WRITE) 317f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 318f95f3850SWill Newton } 319f95f3850SWill Newton 320aaaaeb7aSJaehoon Chung if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &slot->flags)) 321aaaaeb7aSJaehoon Chung cmdr |= SDMMC_CMD_USE_HOLD_REG; 322800d78bfSThomas Abraham 323f95f3850SWill Newton return cmdr; 324f95f3850SWill Newton } 325f95f3850SWill Newton 32690c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) 32790c2143aSSeungwon Jeon { 32890c2143aSSeungwon Jeon struct mmc_command *stop; 32990c2143aSSeungwon Jeon u32 cmdr; 33090c2143aSSeungwon Jeon 33190c2143aSSeungwon Jeon if (!cmd->data) 33290c2143aSSeungwon Jeon return 0; 33390c2143aSSeungwon Jeon 33490c2143aSSeungwon Jeon stop = &host->stop_abort; 33590c2143aSSeungwon Jeon cmdr = cmd->opcode; 33690c2143aSSeungwon Jeon memset(stop, 0, sizeof(struct mmc_command)); 33790c2143aSSeungwon Jeon 33890c2143aSSeungwon Jeon if (cmdr == MMC_READ_SINGLE_BLOCK || 33990c2143aSSeungwon Jeon cmdr == MMC_READ_MULTIPLE_BLOCK || 34090c2143aSSeungwon Jeon cmdr == MMC_WRITE_BLOCK || 3416c2c6506SUlf Hansson cmdr == MMC_WRITE_MULTIPLE_BLOCK || 3426c2c6506SUlf Hansson cmdr == MMC_SEND_TUNING_BLOCK || 3436c2c6506SUlf Hansson cmdr == MMC_SEND_TUNING_BLOCK_HS200) { 34490c2143aSSeungwon Jeon stop->opcode = MMC_STOP_TRANSMISSION; 34590c2143aSSeungwon Jeon stop->arg = 0; 34690c2143aSSeungwon Jeon stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 34790c2143aSSeungwon Jeon } else if (cmdr == SD_IO_RW_EXTENDED) { 34890c2143aSSeungwon Jeon stop->opcode = SD_IO_RW_DIRECT; 34990c2143aSSeungwon Jeon stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | 35090c2143aSSeungwon Jeon ((cmd->arg >> 28) & 0x7); 35190c2143aSSeungwon Jeon stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; 35290c2143aSSeungwon Jeon } else { 35390c2143aSSeungwon Jeon return 0; 35490c2143aSSeungwon Jeon } 35590c2143aSSeungwon Jeon 35690c2143aSSeungwon Jeon cmdr = stop->opcode | SDMMC_CMD_STOP | 35790c2143aSSeungwon Jeon SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; 35890c2143aSSeungwon Jeon 3598c005b40SJaehoon Chung if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags)) 3608c005b40SJaehoon Chung cmdr |= SDMMC_CMD_USE_HOLD_REG; 3618c005b40SJaehoon Chung 36290c2143aSSeungwon Jeon return cmdr; 36390c2143aSSeungwon Jeon } 36490c2143aSSeungwon Jeon 3650bdbd0e8SDoug Anderson static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) 3660bdbd0e8SDoug Anderson { 367b6d2d81cSShawn Lin u32 status; 3680bdbd0e8SDoug Anderson 3690bdbd0e8SDoug Anderson /* 3700bdbd0e8SDoug Anderson * Databook says that before issuing a new data transfer command 3710bdbd0e8SDoug Anderson * we need to check to see if the card is busy. Data transfer commands 3720bdbd0e8SDoug Anderson * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that. 3730bdbd0e8SDoug Anderson * 3740bdbd0e8SDoug Anderson * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is 3750bdbd0e8SDoug Anderson * expected. 3760bdbd0e8SDoug Anderson */ 3770bdbd0e8SDoug Anderson if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) && 3780bdbd0e8SDoug Anderson !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) { 379b6d2d81cSShawn Lin if (readl_poll_timeout_atomic(host->regs + SDMMC_STATUS, 380b6d2d81cSShawn Lin status, 381b6d2d81cSShawn Lin !(status & SDMMC_STATUS_BUSY), 382b6d2d81cSShawn Lin 10, 500 * USEC_PER_MSEC)) 3830bdbd0e8SDoug Anderson dev_err(host->dev, "Busy; trying anyway\n"); 3840bdbd0e8SDoug Anderson } 3850bdbd0e8SDoug Anderson } 3860bdbd0e8SDoug Anderson 387f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 388f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 389f95f3850SWill Newton { 390f95f3850SWill Newton host->cmd = cmd; 3914a90920cSThomas Abraham dev_vdbg(host->dev, 392f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 393f95f3850SWill Newton cmd->arg, cmd_flags); 394f95f3850SWill Newton 395f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 3960e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 3970bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd_flags); 398f95f3850SWill Newton 399f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 400f95f3850SWill Newton } 401f95f3850SWill Newton 40290c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 403f95f3850SWill Newton { 404e13c3c08SJaehoon Chung struct mmc_command *stop = &host->stop_abort; 4050e3a22c0SShawn Lin 40690c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 407f95f3850SWill Newton } 408f95f3850SWill Newton 409f95f3850SWill Newton /* DMA interface functions */ 410f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 411f95f3850SWill Newton { 41203e8cb53SJames Hogan if (host->using_dma) { 413f95f3850SWill Newton host->dma_ops->stop(host); 414f95f3850SWill Newton host->dma_ops->cleanup(host); 415aa50f259SSeungwon Jeon } 416aa50f259SSeungwon Jeon 417f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 418f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 419f95f3850SWill Newton } 420f95f3850SWill Newton 4219aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 4229aa51408SSeungwon Jeon { 4239aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 4249aa51408SSeungwon Jeon return DMA_TO_DEVICE; 4259aa51408SSeungwon Jeon else 4269aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 4279aa51408SSeungwon Jeon } 4289aa51408SSeungwon Jeon 429f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 430f95f3850SWill Newton { 431f95f3850SWill Newton struct mmc_data *data = host->data; 432f95f3850SWill Newton 433a4cc7eb4SJaehoon Chung if (data && data->host_cookie == COOKIE_MAPPED) { 4344a90920cSThomas Abraham dma_unmap_sg(host->dev, 4359aa51408SSeungwon Jeon data->sg, 4369aa51408SSeungwon Jeon data->sg_len, 4379aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 438a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 439a4cc7eb4SJaehoon Chung } 440f95f3850SWill Newton } 441f95f3850SWill Newton 4425ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host) 4435ce9d961SSeungwon Jeon { 4445ce9d961SSeungwon Jeon u32 bmod = mci_readl(host, BMOD); 4455ce9d961SSeungwon Jeon /* Software reset of DMA */ 4465ce9d961SSeungwon Jeon bmod |= SDMMC_IDMAC_SWRESET; 4475ce9d961SSeungwon Jeon mci_writel(host, BMOD, bmod); 4485ce9d961SSeungwon Jeon } 4495ce9d961SSeungwon Jeon 450f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 451f95f3850SWill Newton { 452f95f3850SWill Newton u32 temp; 453f95f3850SWill Newton 454f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 455f95f3850SWill Newton temp = mci_readl(host, CTRL); 456f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 457f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 458f95f3850SWill Newton mci_writel(host, CTRL, temp); 459f95f3850SWill Newton 460f95f3850SWill Newton /* Stop the IDMAC running */ 461f95f3850SWill Newton temp = mci_readl(host, BMOD); 462a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 4635ce9d961SSeungwon Jeon temp |= SDMMC_IDMAC_SWRESET; 464f95f3850SWill Newton mci_writel(host, BMOD, temp); 465f95f3850SWill Newton } 466f95f3850SWill Newton 4673fc7eaefSShawn Lin static void dw_mci_dmac_complete_dma(void *arg) 468f95f3850SWill Newton { 4693fc7eaefSShawn Lin struct dw_mci *host = arg; 470f95f3850SWill Newton struct mmc_data *data = host->data; 471f95f3850SWill Newton 4724a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 473f95f3850SWill Newton 4743fc7eaefSShawn Lin if ((host->use_dma == TRANS_MODE_EDMAC) && 4753fc7eaefSShawn Lin data && (data->flags & MMC_DATA_READ)) 4763fc7eaefSShawn Lin /* Invalidate cache after read */ 4773fc7eaefSShawn Lin dma_sync_sg_for_cpu(mmc_dev(host->cur_slot->mmc), 4783fc7eaefSShawn Lin data->sg, 4793fc7eaefSShawn Lin data->sg_len, 4803fc7eaefSShawn Lin DMA_FROM_DEVICE); 4813fc7eaefSShawn Lin 482f95f3850SWill Newton host->dma_ops->cleanup(host); 483f95f3850SWill Newton 484f95f3850SWill Newton /* 485f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 486f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 487f95f3850SWill Newton */ 488f95f3850SWill Newton if (data) { 489f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 490f95f3850SWill Newton tasklet_schedule(&host->tasklet); 491f95f3850SWill Newton } 492f95f3850SWill Newton } 493f95f3850SWill Newton 494f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 495f95f3850SWill Newton { 496897b69e7SSeungwon Jeon int i; 497f95f3850SWill Newton 49869d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 49969d99fdcSPrabu Thangamuthu struct idmac_desc_64addr *p; 50069d99fdcSPrabu Thangamuthu /* Number of descriptors in the ring buffer */ 501cc190d4cSShawn Lin host->ring_size = 502cc190d4cSShawn Lin DESC_RING_BUF_SZ / sizeof(struct idmac_desc_64addr); 50369d99fdcSPrabu Thangamuthu 50469d99fdcSPrabu Thangamuthu /* Forward link the descriptor list */ 50569d99fdcSPrabu Thangamuthu for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; 50669d99fdcSPrabu Thangamuthu i++, p++) { 50769d99fdcSPrabu Thangamuthu p->des6 = (host->sg_dma + 50869d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 50969d99fdcSPrabu Thangamuthu (i + 1))) & 0xffffffff; 51069d99fdcSPrabu Thangamuthu 51169d99fdcSPrabu Thangamuthu p->des7 = (u64)(host->sg_dma + 51269d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 51369d99fdcSPrabu Thangamuthu (i + 1))) >> 32; 51469d99fdcSPrabu Thangamuthu /* Initialize reserved and buffer size fields to "0" */ 51569d99fdcSPrabu Thangamuthu p->des1 = 0; 51669d99fdcSPrabu Thangamuthu p->des2 = 0; 51769d99fdcSPrabu Thangamuthu p->des3 = 0; 51869d99fdcSPrabu Thangamuthu } 51969d99fdcSPrabu Thangamuthu 52069d99fdcSPrabu Thangamuthu /* Set the last descriptor as the end-of-ring descriptor */ 52169d99fdcSPrabu Thangamuthu p->des6 = host->sg_dma & 0xffffffff; 52269d99fdcSPrabu Thangamuthu p->des7 = (u64)host->sg_dma >> 32; 52369d99fdcSPrabu Thangamuthu p->des0 = IDMAC_DES0_ER; 52469d99fdcSPrabu Thangamuthu 52569d99fdcSPrabu Thangamuthu } else { 52669d99fdcSPrabu Thangamuthu struct idmac_desc *p; 527f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 528cc190d4cSShawn Lin host->ring_size = 529cc190d4cSShawn Lin DESC_RING_BUF_SZ / sizeof(struct idmac_desc); 530f95f3850SWill Newton 531f95f3850SWill Newton /* Forward link the descriptor list */ 5320e3a22c0SShawn Lin for (i = 0, p = host->sg_cpu; 5330e3a22c0SShawn Lin i < host->ring_size - 1; 5340e3a22c0SShawn Lin i++, p++) { 5356687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma + 5366687c42fSBen Dooks (sizeof(struct idmac_desc) * (i + 1))); 5374b244724SZhangfei Gao p->des1 = 0; 5384b244724SZhangfei Gao } 539f95f3850SWill Newton 540f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 5416687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma); 5426687c42fSBen Dooks p->des0 = cpu_to_le32(IDMAC_DES0_ER); 54369d99fdcSPrabu Thangamuthu } 544f95f3850SWill Newton 5455ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 546141a712aSSeungwon Jeon 54769d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 54869d99fdcSPrabu Thangamuthu /* Mask out interrupts - get Tx & Rx complete only */ 54969d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, IDMAC_INT_CLR); 55069d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI | 55169d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 55269d99fdcSPrabu Thangamuthu 55369d99fdcSPrabu Thangamuthu /* Set the descriptor base address */ 55469d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff); 55569d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32); 55669d99fdcSPrabu Thangamuthu 55769d99fdcSPrabu Thangamuthu } else { 558f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 559fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 56069d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | 56169d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 562f95f3850SWill Newton 563f95f3850SWill Newton /* Set the descriptor base address */ 564f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 56569d99fdcSPrabu Thangamuthu } 56669d99fdcSPrabu Thangamuthu 567f95f3850SWill Newton return 0; 568f95f3850SWill Newton } 569f95f3850SWill Newton 5703b2a067bSShawn Lin static inline int dw_mci_prepare_desc64(struct dw_mci *host, 5713b2a067bSShawn Lin struct mmc_data *data, 5723b2a067bSShawn Lin unsigned int sg_len) 5733b2a067bSShawn Lin { 5743b2a067bSShawn Lin unsigned int desc_len; 5753b2a067bSShawn Lin struct idmac_desc_64addr *desc_first, *desc_last, *desc; 576b6d2d81cSShawn Lin u32 val; 5773b2a067bSShawn Lin int i; 5783b2a067bSShawn Lin 5793b2a067bSShawn Lin desc_first = desc_last = desc = host->sg_cpu; 5803b2a067bSShawn Lin 5813b2a067bSShawn Lin for (i = 0; i < sg_len; i++) { 5823b2a067bSShawn Lin unsigned int length = sg_dma_len(&data->sg[i]); 5833b2a067bSShawn Lin 5843b2a067bSShawn Lin u64 mem_addr = sg_dma_address(&data->sg[i]); 5853b2a067bSShawn Lin 5863b2a067bSShawn Lin for ( ; length ; desc++) { 5873b2a067bSShawn Lin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 5883b2a067bSShawn Lin length : DW_MCI_DESC_DATA_LENGTH; 5893b2a067bSShawn Lin 5903b2a067bSShawn Lin length -= desc_len; 5913b2a067bSShawn Lin 5923b2a067bSShawn Lin /* 5933b2a067bSShawn Lin * Wait for the former clear OWN bit operation 5943b2a067bSShawn Lin * of IDMAC to make sure that this descriptor 5953b2a067bSShawn Lin * isn't still owned by IDMAC as IDMAC's write 5963b2a067bSShawn Lin * ops and CPU's read ops are asynchronous. 5973b2a067bSShawn Lin */ 598b6d2d81cSShawn Lin if (readl_poll_timeout_atomic(&desc->des0, val, 599b6d2d81cSShawn Lin !(val & IDMAC_DES0_OWN), 600b6d2d81cSShawn Lin 10, 100 * USEC_PER_MSEC)) 6013b2a067bSShawn Lin goto err_own_bit; 6023b2a067bSShawn Lin 6033b2a067bSShawn Lin /* 6043b2a067bSShawn Lin * Set the OWN bit and disable interrupts 6053b2a067bSShawn Lin * for this descriptor 6063b2a067bSShawn Lin */ 6073b2a067bSShawn Lin desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | 6083b2a067bSShawn Lin IDMAC_DES0_CH; 6093b2a067bSShawn Lin 6103b2a067bSShawn Lin /* Buffer length */ 6113b2a067bSShawn Lin IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len); 6123b2a067bSShawn Lin 6133b2a067bSShawn Lin /* Physical address to DMA to/from */ 6143b2a067bSShawn Lin desc->des4 = mem_addr & 0xffffffff; 6153b2a067bSShawn Lin desc->des5 = mem_addr >> 32; 6163b2a067bSShawn Lin 6173b2a067bSShawn Lin /* Update physical address for the next desc */ 6183b2a067bSShawn Lin mem_addr += desc_len; 6193b2a067bSShawn Lin 6203b2a067bSShawn Lin /* Save pointer to the last descriptor */ 6213b2a067bSShawn Lin desc_last = desc; 6223b2a067bSShawn Lin } 6233b2a067bSShawn Lin } 6243b2a067bSShawn Lin 6253b2a067bSShawn Lin /* Set first descriptor */ 6263b2a067bSShawn Lin desc_first->des0 |= IDMAC_DES0_FD; 6273b2a067bSShawn Lin 6283b2a067bSShawn Lin /* Set last descriptor */ 6293b2a067bSShawn Lin desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 6303b2a067bSShawn Lin desc_last->des0 |= IDMAC_DES0_LD; 6313b2a067bSShawn Lin 6323b2a067bSShawn Lin return 0; 6333b2a067bSShawn Lin err_own_bit: 6343b2a067bSShawn Lin /* restore the descriptor chain as it's polluted */ 63526be9d70SColin Ian King dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n"); 636cc190d4cSShawn Lin memset(host->sg_cpu, 0, DESC_RING_BUF_SZ); 6373b2a067bSShawn Lin dw_mci_idmac_init(host); 6383b2a067bSShawn Lin return -EINVAL; 6393b2a067bSShawn Lin } 6403b2a067bSShawn Lin 6413b2a067bSShawn Lin 6423b2a067bSShawn Lin static inline int dw_mci_prepare_desc32(struct dw_mci *host, 6433b2a067bSShawn Lin struct mmc_data *data, 6443b2a067bSShawn Lin unsigned int sg_len) 6453b2a067bSShawn Lin { 6463b2a067bSShawn Lin unsigned int desc_len; 6473b2a067bSShawn Lin struct idmac_desc *desc_first, *desc_last, *desc; 648b6d2d81cSShawn Lin u32 val; 6493b2a067bSShawn Lin int i; 6503b2a067bSShawn Lin 6513b2a067bSShawn Lin desc_first = desc_last = desc = host->sg_cpu; 6523b2a067bSShawn Lin 6533b2a067bSShawn Lin for (i = 0; i < sg_len; i++) { 6543b2a067bSShawn Lin unsigned int length = sg_dma_len(&data->sg[i]); 6553b2a067bSShawn Lin 6563b2a067bSShawn Lin u32 mem_addr = sg_dma_address(&data->sg[i]); 6573b2a067bSShawn Lin 6583b2a067bSShawn Lin for ( ; length ; desc++) { 6593b2a067bSShawn Lin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 6603b2a067bSShawn Lin length : DW_MCI_DESC_DATA_LENGTH; 6613b2a067bSShawn Lin 6623b2a067bSShawn Lin length -= desc_len; 6633b2a067bSShawn Lin 6643b2a067bSShawn Lin /* 6653b2a067bSShawn Lin * Wait for the former clear OWN bit operation 6663b2a067bSShawn Lin * of IDMAC to make sure that this descriptor 6673b2a067bSShawn Lin * isn't still owned by IDMAC as IDMAC's write 6683b2a067bSShawn Lin * ops and CPU's read ops are asynchronous. 6693b2a067bSShawn Lin */ 670b6d2d81cSShawn Lin if (readl_poll_timeout_atomic(&desc->des0, val, 671b6d2d81cSShawn Lin IDMAC_OWN_CLR64(val), 672b6d2d81cSShawn Lin 10, 673b6d2d81cSShawn Lin 100 * USEC_PER_MSEC)) 6743b2a067bSShawn Lin goto err_own_bit; 6753b2a067bSShawn Lin 6763b2a067bSShawn Lin /* 6773b2a067bSShawn Lin * Set the OWN bit and disable interrupts 6783b2a067bSShawn Lin * for this descriptor 6793b2a067bSShawn Lin */ 6803b2a067bSShawn Lin desc->des0 = cpu_to_le32(IDMAC_DES0_OWN | 6813b2a067bSShawn Lin IDMAC_DES0_DIC | 6823b2a067bSShawn Lin IDMAC_DES0_CH); 6833b2a067bSShawn Lin 6843b2a067bSShawn Lin /* Buffer length */ 6853b2a067bSShawn Lin IDMAC_SET_BUFFER1_SIZE(desc, desc_len); 6863b2a067bSShawn Lin 6873b2a067bSShawn Lin /* Physical address to DMA to/from */ 6883b2a067bSShawn Lin desc->des2 = cpu_to_le32(mem_addr); 6893b2a067bSShawn Lin 6903b2a067bSShawn Lin /* Update physical address for the next desc */ 6913b2a067bSShawn Lin mem_addr += desc_len; 6923b2a067bSShawn Lin 6933b2a067bSShawn Lin /* Save pointer to the last descriptor */ 6943b2a067bSShawn Lin desc_last = desc; 6953b2a067bSShawn Lin } 6963b2a067bSShawn Lin } 6973b2a067bSShawn Lin 6983b2a067bSShawn Lin /* Set first descriptor */ 6993b2a067bSShawn Lin desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD); 7003b2a067bSShawn Lin 7013b2a067bSShawn Lin /* Set last descriptor */ 7023b2a067bSShawn Lin desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | 7033b2a067bSShawn Lin IDMAC_DES0_DIC)); 7043b2a067bSShawn Lin desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD); 7053b2a067bSShawn Lin 7063b2a067bSShawn Lin return 0; 7073b2a067bSShawn Lin err_own_bit: 7083b2a067bSShawn Lin /* restore the descriptor chain as it's polluted */ 70926be9d70SColin Ian King dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n"); 710cc190d4cSShawn Lin memset(host->sg_cpu, 0, DESC_RING_BUF_SZ); 7113b2a067bSShawn Lin dw_mci_idmac_init(host); 7123b2a067bSShawn Lin return -EINVAL; 7133b2a067bSShawn Lin } 7143b2a067bSShawn Lin 7153b2a067bSShawn Lin static int dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 7163b2a067bSShawn Lin { 7173b2a067bSShawn Lin u32 temp; 7183b2a067bSShawn Lin int ret; 7193b2a067bSShawn Lin 7203b2a067bSShawn Lin if (host->dma_64bit_address == 1) 7213b2a067bSShawn Lin ret = dw_mci_prepare_desc64(host, host->data, sg_len); 7223b2a067bSShawn Lin else 7233b2a067bSShawn Lin ret = dw_mci_prepare_desc32(host, host->data, sg_len); 7243b2a067bSShawn Lin 7253b2a067bSShawn Lin if (ret) 7263b2a067bSShawn Lin goto out; 7273b2a067bSShawn Lin 7283b2a067bSShawn Lin /* drain writebuffer */ 7293b2a067bSShawn Lin wmb(); 7303b2a067bSShawn Lin 7313b2a067bSShawn Lin /* Make sure to reset DMA in case we did PIO before this */ 7323b2a067bSShawn Lin dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET); 7333b2a067bSShawn Lin dw_mci_idmac_reset(host); 7343b2a067bSShawn Lin 7353b2a067bSShawn Lin /* Select IDMAC interface */ 7363b2a067bSShawn Lin temp = mci_readl(host, CTRL); 7373b2a067bSShawn Lin temp |= SDMMC_CTRL_USE_IDMAC; 7383b2a067bSShawn Lin mci_writel(host, CTRL, temp); 7393b2a067bSShawn Lin 7403b2a067bSShawn Lin /* drain writebuffer */ 7413b2a067bSShawn Lin wmb(); 7423b2a067bSShawn Lin 7433b2a067bSShawn Lin /* Enable the IDMAC */ 7443b2a067bSShawn Lin temp = mci_readl(host, BMOD); 7453b2a067bSShawn Lin temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 7463b2a067bSShawn Lin mci_writel(host, BMOD, temp); 7473b2a067bSShawn Lin 7483b2a067bSShawn Lin /* Start it running */ 7493b2a067bSShawn Lin mci_writel(host, PLDMND, 1); 7503b2a067bSShawn Lin 7513b2a067bSShawn Lin out: 7523b2a067bSShawn Lin return ret; 7533b2a067bSShawn Lin } 7543b2a067bSShawn Lin 7558e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 756885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 757885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 758885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 7593fc7eaefSShawn Lin .complete = dw_mci_dmac_complete_dma, 760885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 761885c3e80SSeungwon Jeon }; 7623fc7eaefSShawn Lin 7633fc7eaefSShawn Lin static void dw_mci_edmac_stop_dma(struct dw_mci *host) 7643fc7eaefSShawn Lin { 765ab925a31SShawn Lin dmaengine_terminate_async(host->dms->ch); 7663fc7eaefSShawn Lin } 7673fc7eaefSShawn Lin 7683fc7eaefSShawn Lin static int dw_mci_edmac_start_dma(struct dw_mci *host, 7693fc7eaefSShawn Lin unsigned int sg_len) 7703fc7eaefSShawn Lin { 7713fc7eaefSShawn Lin struct dma_slave_config cfg; 7723fc7eaefSShawn Lin struct dma_async_tx_descriptor *desc = NULL; 7733fc7eaefSShawn Lin struct scatterlist *sgl = host->data->sg; 7743fc7eaefSShawn Lin const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 7753fc7eaefSShawn Lin u32 sg_elems = host->data->sg_len; 7763fc7eaefSShawn Lin u32 fifoth_val; 7773fc7eaefSShawn Lin u32 fifo_offset = host->fifo_reg - host->regs; 7783fc7eaefSShawn Lin int ret = 0; 7793fc7eaefSShawn Lin 7803fc7eaefSShawn Lin /* Set external dma config: burst size, burst width */ 781260b3164SArnd Bergmann cfg.dst_addr = host->phy_regs + fifo_offset; 7823fc7eaefSShawn Lin cfg.src_addr = cfg.dst_addr; 7833fc7eaefSShawn Lin cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 7843fc7eaefSShawn Lin cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 7853fc7eaefSShawn Lin 7863fc7eaefSShawn Lin /* Match burst msize with external dma config */ 7873fc7eaefSShawn Lin fifoth_val = mci_readl(host, FIFOTH); 7883fc7eaefSShawn Lin cfg.dst_maxburst = mszs[(fifoth_val >> 28) & 0x7]; 7893fc7eaefSShawn Lin cfg.src_maxburst = cfg.dst_maxburst; 7903fc7eaefSShawn Lin 7913fc7eaefSShawn Lin if (host->data->flags & MMC_DATA_WRITE) 7923fc7eaefSShawn Lin cfg.direction = DMA_MEM_TO_DEV; 7933fc7eaefSShawn Lin else 7943fc7eaefSShawn Lin cfg.direction = DMA_DEV_TO_MEM; 7953fc7eaefSShawn Lin 7963fc7eaefSShawn Lin ret = dmaengine_slave_config(host->dms->ch, &cfg); 7973fc7eaefSShawn Lin if (ret) { 7983fc7eaefSShawn Lin dev_err(host->dev, "Failed to config edmac.\n"); 7993fc7eaefSShawn Lin return -EBUSY; 8003fc7eaefSShawn Lin } 8013fc7eaefSShawn Lin 8023fc7eaefSShawn Lin desc = dmaengine_prep_slave_sg(host->dms->ch, sgl, 8033fc7eaefSShawn Lin sg_len, cfg.direction, 8043fc7eaefSShawn Lin DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 8053fc7eaefSShawn Lin if (!desc) { 8063fc7eaefSShawn Lin dev_err(host->dev, "Can't prepare slave sg.\n"); 8073fc7eaefSShawn Lin return -EBUSY; 8083fc7eaefSShawn Lin } 8093fc7eaefSShawn Lin 8103fc7eaefSShawn Lin /* Set dw_mci_dmac_complete_dma as callback */ 8113fc7eaefSShawn Lin desc->callback = dw_mci_dmac_complete_dma; 8123fc7eaefSShawn Lin desc->callback_param = (void *)host; 8133fc7eaefSShawn Lin dmaengine_submit(desc); 8143fc7eaefSShawn Lin 8153fc7eaefSShawn Lin /* Flush cache before write */ 8163fc7eaefSShawn Lin if (host->data->flags & MMC_DATA_WRITE) 8173fc7eaefSShawn Lin dma_sync_sg_for_device(mmc_dev(host->cur_slot->mmc), sgl, 8183fc7eaefSShawn Lin sg_elems, DMA_TO_DEVICE); 8193fc7eaefSShawn Lin 8203fc7eaefSShawn Lin dma_async_issue_pending(host->dms->ch); 8213fc7eaefSShawn Lin 8223fc7eaefSShawn Lin return 0; 8233fc7eaefSShawn Lin } 8243fc7eaefSShawn Lin 8253fc7eaefSShawn Lin static int dw_mci_edmac_init(struct dw_mci *host) 8263fc7eaefSShawn Lin { 8273fc7eaefSShawn Lin /* Request external dma channel */ 8283fc7eaefSShawn Lin host->dms = kzalloc(sizeof(struct dw_mci_dma_slave), GFP_KERNEL); 8293fc7eaefSShawn Lin if (!host->dms) 8303fc7eaefSShawn Lin return -ENOMEM; 8313fc7eaefSShawn Lin 8323fc7eaefSShawn Lin host->dms->ch = dma_request_slave_channel(host->dev, "rx-tx"); 8333fc7eaefSShawn Lin if (!host->dms->ch) { 8344539d36eSDan Carpenter dev_err(host->dev, "Failed to get external DMA channel.\n"); 8353fc7eaefSShawn Lin kfree(host->dms); 8363fc7eaefSShawn Lin host->dms = NULL; 8373fc7eaefSShawn Lin return -ENXIO; 8383fc7eaefSShawn Lin } 8393fc7eaefSShawn Lin 8403fc7eaefSShawn Lin return 0; 8413fc7eaefSShawn Lin } 8423fc7eaefSShawn Lin 8433fc7eaefSShawn Lin static void dw_mci_edmac_exit(struct dw_mci *host) 8443fc7eaefSShawn Lin { 8453fc7eaefSShawn Lin if (host->dms) { 8463fc7eaefSShawn Lin if (host->dms->ch) { 8473fc7eaefSShawn Lin dma_release_channel(host->dms->ch); 8483fc7eaefSShawn Lin host->dms->ch = NULL; 8493fc7eaefSShawn Lin } 8503fc7eaefSShawn Lin kfree(host->dms); 8513fc7eaefSShawn Lin host->dms = NULL; 8523fc7eaefSShawn Lin } 8533fc7eaefSShawn Lin } 8543fc7eaefSShawn Lin 8553fc7eaefSShawn Lin static const struct dw_mci_dma_ops dw_mci_edmac_ops = { 8563fc7eaefSShawn Lin .init = dw_mci_edmac_init, 8573fc7eaefSShawn Lin .exit = dw_mci_edmac_exit, 8583fc7eaefSShawn Lin .start = dw_mci_edmac_start_dma, 8593fc7eaefSShawn Lin .stop = dw_mci_edmac_stop_dma, 8603fc7eaefSShawn Lin .complete = dw_mci_dmac_complete_dma, 8613fc7eaefSShawn Lin .cleanup = dw_mci_dma_cleanup, 8623fc7eaefSShawn Lin }; 863885c3e80SSeungwon Jeon 8649aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 8659aa51408SSeungwon Jeon struct mmc_data *data, 866a4cc7eb4SJaehoon Chung int cookie) 867f95f3850SWill Newton { 868f95f3850SWill Newton struct scatterlist *sg; 8699aa51408SSeungwon Jeon unsigned int i, sg_len; 870f95f3850SWill Newton 871a4cc7eb4SJaehoon Chung if (data->host_cookie == COOKIE_PRE_MAPPED) 872a4cc7eb4SJaehoon Chung return data->sg_len; 873f95f3850SWill Newton 874f95f3850SWill Newton /* 875f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 876f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 877f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 878f95f3850SWill Newton */ 879f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 880f95f3850SWill Newton return -EINVAL; 8819aa51408SSeungwon Jeon 882f95f3850SWill Newton if (data->blksz & 3) 883f95f3850SWill Newton return -EINVAL; 884f95f3850SWill Newton 885f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 886f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 887f95f3850SWill Newton return -EINVAL; 888f95f3850SWill Newton } 889f95f3850SWill Newton 8904a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 8919aa51408SSeungwon Jeon data->sg, 8929aa51408SSeungwon Jeon data->sg_len, 8939aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 8949aa51408SSeungwon Jeon if (sg_len == 0) 8959aa51408SSeungwon Jeon return -EINVAL; 8969aa51408SSeungwon Jeon 897a4cc7eb4SJaehoon Chung data->host_cookie = cookie; 8989aa51408SSeungwon Jeon 8999aa51408SSeungwon Jeon return sg_len; 9009aa51408SSeungwon Jeon } 9019aa51408SSeungwon Jeon 9029aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 903d3c6aac3SLinus Walleij struct mmc_request *mrq) 9049aa51408SSeungwon Jeon { 9059aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 9069aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 9079aa51408SSeungwon Jeon 9089aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 9099aa51408SSeungwon Jeon return; 9109aa51408SSeungwon Jeon 911a4cc7eb4SJaehoon Chung /* This data might be unmapped at this time */ 912a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 9139aa51408SSeungwon Jeon 914a4cc7eb4SJaehoon Chung if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 915a4cc7eb4SJaehoon Chung COOKIE_PRE_MAPPED) < 0) 916a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 9179aa51408SSeungwon Jeon } 9189aa51408SSeungwon Jeon 9199aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 9209aa51408SSeungwon Jeon struct mmc_request *mrq, 9219aa51408SSeungwon Jeon int err) 9229aa51408SSeungwon Jeon { 9239aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 9249aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 9259aa51408SSeungwon Jeon 9269aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 9279aa51408SSeungwon Jeon return; 9289aa51408SSeungwon Jeon 929a4cc7eb4SJaehoon Chung if (data->host_cookie != COOKIE_UNMAPPED) 9304a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 9319aa51408SSeungwon Jeon data->sg, 9329aa51408SSeungwon Jeon data->sg_len, 9339aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 934a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 9359aa51408SSeungwon Jeon } 9369aa51408SSeungwon Jeon 93752426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 93852426899SSeungwon Jeon { 93952426899SSeungwon Jeon unsigned int blksz = data->blksz; 94052426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 94152426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 94252426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 94352426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 9440e3a22c0SShawn Lin int idx = ARRAY_SIZE(mszs) - 1; 94552426899SSeungwon Jeon 9463fc7eaefSShawn Lin /* pio should ship this scenario */ 9473fc7eaefSShawn Lin if (!host->use_dma) 9483fc7eaefSShawn Lin return; 9493fc7eaefSShawn Lin 95052426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 95152426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 95252426899SSeungwon Jeon 95352426899SSeungwon Jeon /* 95452426899SSeungwon Jeon * MSIZE is '1', 95552426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 95652426899SSeungwon Jeon */ 95720753569SShawn Lin if (blksz % fifo_width) 95852426899SSeungwon Jeon goto done; 95952426899SSeungwon Jeon 96052426899SSeungwon Jeon do { 96152426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 96252426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 96352426899SSeungwon Jeon msize = idx; 96452426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 96552426899SSeungwon Jeon break; 96652426899SSeungwon Jeon } 96752426899SSeungwon Jeon } while (--idx > 0); 96852426899SSeungwon Jeon /* 96952426899SSeungwon Jeon * If idx is '0', it won't be tried 97052426899SSeungwon Jeon * Thus, initial values are uesed 97152426899SSeungwon Jeon */ 97252426899SSeungwon Jeon done: 97352426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 97452426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 97552426899SSeungwon Jeon } 97652426899SSeungwon Jeon 9777e4bf1bcSJaehoon Chung static void dw_mci_ctrl_thld(struct dw_mci *host, struct mmc_data *data) 978f1d2736cSSeungwon Jeon { 979f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 980f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 981f1d2736cSSeungwon Jeon u16 thld_size; 9827e4bf1bcSJaehoon Chung u8 enable; 983f1d2736cSSeungwon Jeon 98466dfd101SJames Hogan /* 98566dfd101SJames Hogan * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is 98666dfd101SJames Hogan * in the FIFO region, so we really shouldn't access it). 98766dfd101SJames Hogan */ 9887e4bf1bcSJaehoon Chung if (host->verid < DW_MMC_240A || 9897e4bf1bcSJaehoon Chung (host->verid < DW_MMC_280A && data->flags & MMC_DATA_WRITE)) 99066dfd101SJames Hogan return; 99166dfd101SJames Hogan 9927e4bf1bcSJaehoon Chung /* 9937e4bf1bcSJaehoon Chung * Card write Threshold is introduced since 2.80a 9947e4bf1bcSJaehoon Chung * It's used when HS400 mode is enabled. 9957e4bf1bcSJaehoon Chung */ 9967e4bf1bcSJaehoon Chung if (data->flags & MMC_DATA_WRITE && 9977e4bf1bcSJaehoon Chung !(host->timing != MMC_TIMING_MMC_HS400)) 9987e4bf1bcSJaehoon Chung return; 9997e4bf1bcSJaehoon Chung 10007e4bf1bcSJaehoon Chung if (data->flags & MMC_DATA_WRITE) 10017e4bf1bcSJaehoon Chung enable = SDMMC_CARD_WR_THR_EN; 10027e4bf1bcSJaehoon Chung else 10037e4bf1bcSJaehoon Chung enable = SDMMC_CARD_RD_THR_EN; 10047e4bf1bcSJaehoon Chung 1005f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 1006f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 1007f1d2736cSSeungwon Jeon goto disable; 1008f1d2736cSSeungwon Jeon 1009f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 1010f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 1011f1d2736cSSeungwon Jeon 1012f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 1013f1d2736cSSeungwon Jeon goto disable; 1014f1d2736cSSeungwon Jeon 1015f1d2736cSSeungwon Jeon /* 1016f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 1017f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 1018f1d2736cSSeungwon Jeon * Currently just choose blksz. 1019f1d2736cSSeungwon Jeon */ 1020f1d2736cSSeungwon Jeon thld_size = blksz; 10217e4bf1bcSJaehoon Chung mci_writel(host, CDTHRCTL, SDMMC_SET_THLD(thld_size, enable)); 1022f1d2736cSSeungwon Jeon return; 1023f1d2736cSSeungwon Jeon 1024f1d2736cSSeungwon Jeon disable: 10257e4bf1bcSJaehoon Chung mci_writel(host, CDTHRCTL, 0); 1026f1d2736cSSeungwon Jeon } 1027f1d2736cSSeungwon Jeon 10289aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 10299aa51408SSeungwon Jeon { 1030f8c58c11SDoug Anderson unsigned long irqflags; 10319aa51408SSeungwon Jeon int sg_len; 10329aa51408SSeungwon Jeon u32 temp; 10339aa51408SSeungwon Jeon 10349aa51408SSeungwon Jeon host->using_dma = 0; 10359aa51408SSeungwon Jeon 10369aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 10379aa51408SSeungwon Jeon if (!host->use_dma) 10389aa51408SSeungwon Jeon return -ENODEV; 10399aa51408SSeungwon Jeon 1040a4cc7eb4SJaehoon Chung sg_len = dw_mci_pre_dma_transfer(host, data, COOKIE_MAPPED); 1041a99aa9b9SSeungwon Jeon if (sg_len < 0) { 1042a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 10439aa51408SSeungwon Jeon return sg_len; 1044a99aa9b9SSeungwon Jeon } 10459aa51408SSeungwon Jeon 104603e8cb53SJames Hogan host->using_dma = 1; 104703e8cb53SJames Hogan 10483fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 10494a90920cSThomas Abraham dev_vdbg(host->dev, 1050f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 10513fc7eaefSShawn Lin (unsigned long)host->sg_cpu, 10523fc7eaefSShawn Lin (unsigned long)host->sg_dma, 1053f95f3850SWill Newton sg_len); 1054f95f3850SWill Newton 105552426899SSeungwon Jeon /* 105652426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 105752426899SSeungwon Jeon * If current block size is same with previous size, 105852426899SSeungwon Jeon * no need to update fifoth. 105952426899SSeungwon Jeon */ 106052426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 106152426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 106252426899SSeungwon Jeon 1063f95f3850SWill Newton /* Enable the DMA interface */ 1064f95f3850SWill Newton temp = mci_readl(host, CTRL); 1065f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 1066f95f3850SWill Newton mci_writel(host, CTRL, temp); 1067f95f3850SWill Newton 1068f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 1069f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1070f95f3850SWill Newton temp = mci_readl(host, INTMASK); 1071f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 1072f95f3850SWill Newton mci_writel(host, INTMASK, temp); 1073f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 1074f95f3850SWill Newton 10753fc7eaefSShawn Lin if (host->dma_ops->start(host, sg_len)) { 1076647f80a1SJaehoon Chung host->dma_ops->stop(host); 1077d12d0cb1SShawn Lin /* We can't do DMA, try PIO for this one */ 1078d12d0cb1SShawn Lin dev_dbg(host->dev, 1079d12d0cb1SShawn Lin "%s: fall back to PIO mode for current transfer\n", 1080d12d0cb1SShawn Lin __func__); 10813fc7eaefSShawn Lin return -ENODEV; 10823fc7eaefSShawn Lin } 1083f95f3850SWill Newton 1084f95f3850SWill Newton return 0; 1085f95f3850SWill Newton } 1086f95f3850SWill Newton 1087f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 1088f95f3850SWill Newton { 1089f8c58c11SDoug Anderson unsigned long irqflags; 10900e3a22c0SShawn Lin int flags = SG_MITER_ATOMIC; 1091f95f3850SWill Newton u32 temp; 1092f95f3850SWill Newton 1093f95f3850SWill Newton data->error = -EINPROGRESS; 1094f95f3850SWill Newton 1095f95f3850SWill Newton WARN_ON(host->data); 1096f95f3850SWill Newton host->sg = NULL; 1097f95f3850SWill Newton host->data = data; 1098f95f3850SWill Newton 10997e4bf1bcSJaehoon Chung if (data->flags & MMC_DATA_READ) 110055c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 11017e4bf1bcSJaehoon Chung else 110255c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 11037e4bf1bcSJaehoon Chung 11047e4bf1bcSJaehoon Chung dw_mci_ctrl_thld(host, data); 110555c5efbcSJames Hogan 1106f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 1107f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 1108f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 1109f9c2a0dcSSeungwon Jeon else 1110f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 1111f9c2a0dcSSeungwon Jeon 1112f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 1113f95f3850SWill Newton host->sg = data->sg; 111434b664a2SJames Hogan host->part_buf_start = 0; 111534b664a2SJames Hogan host->part_buf_count = 0; 1116f95f3850SWill Newton 1117b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 1118f8c58c11SDoug Anderson 1119f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1120f95f3850SWill Newton temp = mci_readl(host, INTMASK); 1121f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 1122f95f3850SWill Newton mci_writel(host, INTMASK, temp); 1123f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 1124f95f3850SWill Newton 1125f95f3850SWill Newton temp = mci_readl(host, CTRL); 1126f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 1127f95f3850SWill Newton mci_writel(host, CTRL, temp); 112852426899SSeungwon Jeon 112952426899SSeungwon Jeon /* 1130d6fced83SJun Nie * Use the initial fifoth_val for PIO mode. If wm_algined 1131d6fced83SJun Nie * is set, we set watermark same as data size. 113252426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 113352426899SSeungwon Jeon * prev_blksz should be invalidated. 113452426899SSeungwon Jeon */ 1135d6fced83SJun Nie if (host->wm_aligned) 1136d6fced83SJun Nie dw_mci_adjust_fifoth(host, data); 1137d6fced83SJun Nie else 113852426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 113952426899SSeungwon Jeon host->prev_blksz = 0; 114052426899SSeungwon Jeon } else { 114152426899SSeungwon Jeon /* 114252426899SSeungwon Jeon * Keep the current block size. 114352426899SSeungwon Jeon * It will be used to decide whether to update 114452426899SSeungwon Jeon * fifoth register next time. 114552426899SSeungwon Jeon */ 114652426899SSeungwon Jeon host->prev_blksz = data->blksz; 1147f95f3850SWill Newton } 1148f95f3850SWill Newton } 1149f95f3850SWill Newton 1150f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 1151f95f3850SWill Newton { 1152f95f3850SWill Newton struct dw_mci *host = slot->host; 1153f95f3850SWill Newton unsigned int cmd_status = 0; 1154f95f3850SWill Newton 1155f95f3850SWill Newton mci_writel(host, CMDARG, arg); 11560e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 11570bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd); 1158f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 1159f95f3850SWill Newton 1160b6d2d81cSShawn Lin if (readl_poll_timeout_atomic(host->regs + SDMMC_CMD, cmd_status, 1161b6d2d81cSShawn Lin !(cmd_status & SDMMC_CMD_START), 1162b6d2d81cSShawn Lin 1, 500 * USEC_PER_MSEC)) 1163f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 1164f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 1165f95f3850SWill Newton cmd, arg, cmd_status); 1166f95f3850SWill Newton } 1167f95f3850SWill Newton 1168ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 1169f95f3850SWill Newton { 1170f95f3850SWill Newton struct dw_mci *host = slot->host; 1171fdf492a1SDoug Anderson unsigned int clock = slot->clock; 1172f95f3850SWill Newton u32 div; 11739623b5b9SDoug Anderson u32 clk_en_a; 117401730558SDoug Anderson u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT; 117501730558SDoug Anderson 117601730558SDoug Anderson /* We must continue to set bit 28 in CMD until the change is complete */ 117701730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) 117801730558SDoug Anderson sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; 1179f95f3850SWill Newton 1180fdf492a1SDoug Anderson if (!clock) { 1181fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 118201730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1183fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 1184fdf492a1SDoug Anderson div = host->bus_hz / clock; 1185fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 1186f95f3850SWill Newton /* 1187f95f3850SWill Newton * move the + 1 after the divide to prevent 1188f95f3850SWill Newton * over-clocking the card. 1189f95f3850SWill Newton */ 1190e419990bSSeungwon Jeon div += 1; 1191e419990bSSeungwon Jeon 1192fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 1193f95f3850SWill Newton 1194e6cd7a8eSJaehoon Chung if ((clock != slot->__clk_old && 1195e6cd7a8eSJaehoon Chung !test_bit(DW_MMC_CARD_NEEDS_POLL, &slot->flags)) || 1196e6cd7a8eSJaehoon Chung force_clkinit) { 1197ce69e2feSShawn Lin /* Silent the verbose log if calling from PM context */ 1198ce69e2feSShawn Lin if (!force_clkinit) 1199f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 1200fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 1201fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 1202fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 1203fdf492a1SDoug Anderson host->bus_hz, div); 1204f95f3850SWill Newton 1205e6cd7a8eSJaehoon Chung /* 1206e6cd7a8eSJaehoon Chung * If card is polling, display the message only 1207e6cd7a8eSJaehoon Chung * one time at boot time. 1208e6cd7a8eSJaehoon Chung */ 1209e6cd7a8eSJaehoon Chung if (slot->mmc->caps & MMC_CAP_NEEDS_POLL && 1210e6cd7a8eSJaehoon Chung slot->mmc->f_min == clock) 1211e6cd7a8eSJaehoon Chung set_bit(DW_MMC_CARD_NEEDS_POLL, &slot->flags); 1212e6cd7a8eSJaehoon Chung } 1213e6cd7a8eSJaehoon Chung 1214f95f3850SWill Newton /* disable clock */ 1215f95f3850SWill Newton mci_writel(host, CLKENA, 0); 1216f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 1217f95f3850SWill Newton 1218f95f3850SWill Newton /* inform CIU */ 121901730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1220f95f3850SWill Newton 1221f95f3850SWill Newton /* set clock to desired speed */ 1222f95f3850SWill Newton mci_writel(host, CLKDIV, div); 1223f95f3850SWill Newton 1224f95f3850SWill Newton /* inform CIU */ 122501730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1226f95f3850SWill Newton 12279623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 12289623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 1229b24c8b26SDoug Anderson if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) 12309623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 12319623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 1232f95f3850SWill Newton 1233f95f3850SWill Newton /* inform CIU */ 123401730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1235005d675aSJaehoon Chung 1236005d675aSJaehoon Chung /* keep the last clock value that was requested from core */ 1237005d675aSJaehoon Chung slot->__clk_old = clock; 1238f95f3850SWill Newton } 1239f95f3850SWill Newton 1240fdf492a1SDoug Anderson host->current_speed = clock; 1241fdf492a1SDoug Anderson 1242f95f3850SWill Newton /* Set the current slot bus width */ 12431d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 1244f95f3850SWill Newton } 1245f95f3850SWill Newton 1246053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 1247053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 1248053b3ce6SSeungwon Jeon struct mmc_command *cmd) 1249f95f3850SWill Newton { 1250f95f3850SWill Newton struct mmc_request *mrq; 1251f95f3850SWill Newton struct mmc_data *data; 1252f95f3850SWill Newton u32 cmdflags; 1253f95f3850SWill Newton 1254f95f3850SWill Newton mrq = slot->mrq; 1255f95f3850SWill Newton 1256f95f3850SWill Newton host->cur_slot = slot; 1257f95f3850SWill Newton host->mrq = mrq; 1258f95f3850SWill Newton 1259f95f3850SWill Newton host->pending_events = 0; 1260f95f3850SWill Newton host->completed_events = 0; 1261e352c813SSeungwon Jeon host->cmd_status = 0; 1262f95f3850SWill Newton host->data_status = 0; 1263e352c813SSeungwon Jeon host->dir_status = 0; 1264f95f3850SWill Newton 1265053b3ce6SSeungwon Jeon data = cmd->data; 1266f95f3850SWill Newton if (data) { 1267f16afa88SJaehoon Chung mci_writel(host, TMOUT, 0xFFFFFFFF); 1268f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 1269f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 1270f95f3850SWill Newton } 1271f95f3850SWill Newton 1272f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 1273f95f3850SWill Newton 1274f95f3850SWill Newton /* this is the first command, send the initialization clock */ 1275f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 1276f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 1277f95f3850SWill Newton 1278f95f3850SWill Newton if (data) { 1279f95f3850SWill Newton dw_mci_submit_data(host, data); 12800e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 1281f95f3850SWill Newton } 1282f95f3850SWill Newton 1283f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 1284f95f3850SWill Newton 12855c935165SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 128649ba0302SDoug Anderson unsigned long irqflags; 128749ba0302SDoug Anderson 12885c935165SDoug Anderson /* 12898886a6fdSDoug Anderson * Databook says to fail after 2ms w/ no response, but evidence 12908886a6fdSDoug Anderson * shows that sometimes the cmd11 interrupt takes over 130ms. 12918886a6fdSDoug Anderson * We'll set to 500ms, plus an extra jiffy just in case jiffies 12928886a6fdSDoug Anderson * is just about to roll over. 129349ba0302SDoug Anderson * 129449ba0302SDoug Anderson * We do this whole thing under spinlock and only if the 129549ba0302SDoug Anderson * command hasn't already completed (indicating the the irq 129649ba0302SDoug Anderson * already ran so we don't want the timeout). 12975c935165SDoug Anderson */ 129849ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 129949ba0302SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) 13005c935165SDoug Anderson mod_timer(&host->cmd11_timer, 13018886a6fdSDoug Anderson jiffies + msecs_to_jiffies(500) + 1); 130249ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 13035c935165SDoug Anderson } 13045c935165SDoug Anderson 130590c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 1306f95f3850SWill Newton } 1307f95f3850SWill Newton 1308053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 1309053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 1310053b3ce6SSeungwon Jeon { 1311053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 1312053b3ce6SSeungwon Jeon struct mmc_command *cmd; 1313053b3ce6SSeungwon Jeon 1314053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 1315053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 1316053b3ce6SSeungwon Jeon } 1317053b3ce6SSeungwon Jeon 13187456caaeSJames Hogan /* must be called with host->lock held */ 1319f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 1320f95f3850SWill Newton struct mmc_request *mrq) 1321f95f3850SWill Newton { 1322f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 1323f95f3850SWill Newton host->state); 1324f95f3850SWill Newton 1325f95f3850SWill Newton slot->mrq = mrq; 1326f95f3850SWill Newton 132701730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) { 132801730558SDoug Anderson dev_warn(&slot->mmc->class_dev, 132901730558SDoug Anderson "Voltage change didn't complete\n"); 133001730558SDoug Anderson /* 133101730558SDoug Anderson * this case isn't expected to happen, so we can 133201730558SDoug Anderson * either crash here or just try to continue on 133301730558SDoug Anderson * in the closest possible state 133401730558SDoug Anderson */ 133501730558SDoug Anderson host->state = STATE_IDLE; 133601730558SDoug Anderson } 133701730558SDoug Anderson 1338f95f3850SWill Newton if (host->state == STATE_IDLE) { 1339f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1340f95f3850SWill Newton dw_mci_start_request(host, slot); 1341f95f3850SWill Newton } else { 1342f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 1343f95f3850SWill Newton } 1344f95f3850SWill Newton } 1345f95f3850SWill Newton 1346f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1347f95f3850SWill Newton { 1348f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1349f95f3850SWill Newton struct dw_mci *host = slot->host; 1350f95f3850SWill Newton 1351f95f3850SWill Newton WARN_ON(slot->mrq); 1352f95f3850SWill Newton 13537456caaeSJames Hogan /* 13547456caaeSJames Hogan * The check for card presence and queueing of the request must be 13557456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 13567456caaeSJames Hogan * request wouldn't fail until another card was inserted. 13577456caaeSJames Hogan */ 13587456caaeSJames Hogan 135956f6911cSShawn Lin if (!dw_mci_get_cd(mmc)) { 1360f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1361f95f3850SWill Newton mmc_request_done(mmc, mrq); 1362f95f3850SWill Newton return; 1363f95f3850SWill Newton } 1364f95f3850SWill Newton 136556f6911cSShawn Lin spin_lock_bh(&host->lock); 136656f6911cSShawn Lin 1367f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 13687456caaeSJames Hogan 13697456caaeSJames Hogan spin_unlock_bh(&host->lock); 1370f95f3850SWill Newton } 1371f95f3850SWill Newton 1372f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1373f95f3850SWill Newton { 1374f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1375e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 137641babf75SJaehoon Chung u32 regs; 137751da2240SYuvaraj CD int ret; 1378f95f3850SWill Newton 1379f95f3850SWill Newton switch (ios->bus_width) { 1380f95f3850SWill Newton case MMC_BUS_WIDTH_4: 1381f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 1382f95f3850SWill Newton break; 1383c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 1384c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 1385c9b2a06fSJaehoon Chung break; 1386b2f7cb45SJaehoon Chung default: 1387b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 1388b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 1389f95f3850SWill Newton } 1390f95f3850SWill Newton 139141babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 13923f514291SSeungwon Jeon 13933f514291SSeungwon Jeon /* DDR mode set */ 139480113132SSeungwon Jeon if (ios->timing == MMC_TIMING_MMC_DDR52 || 13957cc8d580SJaehoon Chung ios->timing == MMC_TIMING_UHS_DDR50 || 139680113132SSeungwon Jeon ios->timing == MMC_TIMING_MMC_HS400) 1397c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 13983f514291SSeungwon Jeon else 1399c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 14003f514291SSeungwon Jeon 140141babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 1402f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 140341babf75SJaehoon Chung 1404f95f3850SWill Newton /* 1405f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 1406f95f3850SWill Newton * core ios update when finding the minimum. 1407f95f3850SWill Newton */ 1408f95f3850SWill Newton slot->clock = ios->clock; 1409f95f3850SWill Newton 1410cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 1411cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 1412800d78bfSThomas Abraham 1413f95f3850SWill Newton switch (ios->power_mode) { 1414f95f3850SWill Newton case MMC_POWER_UP: 141551da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) { 141651da2240SYuvaraj CD ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 141751da2240SYuvaraj CD ios->vdd); 141851da2240SYuvaraj CD if (ret) { 141951da2240SYuvaraj CD dev_err(slot->host->dev, 142051da2240SYuvaraj CD "failed to enable vmmc regulator\n"); 142151da2240SYuvaraj CD /*return, if failed turn on vmmc*/ 142251da2240SYuvaraj CD return; 142351da2240SYuvaraj CD } 142451da2240SYuvaraj CD } 142529d0d161SDoug Anderson set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 142629d0d161SDoug Anderson regs = mci_readl(slot->host, PWREN); 142729d0d161SDoug Anderson regs |= (1 << slot->id); 142829d0d161SDoug Anderson mci_writel(slot->host, PWREN, regs); 142929d0d161SDoug Anderson break; 143029d0d161SDoug Anderson case MMC_POWER_ON: 1431d1f1dd86SDoug Anderson if (!slot->host->vqmmc_enabled) { 1432d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 143351da2240SYuvaraj CD ret = regulator_enable(mmc->supply.vqmmc); 143451da2240SYuvaraj CD if (ret < 0) 143551da2240SYuvaraj CD dev_err(slot->host->dev, 1436d1f1dd86SDoug Anderson "failed to enable vqmmc\n"); 143751da2240SYuvaraj CD else 143851da2240SYuvaraj CD slot->host->vqmmc_enabled = true; 1439d1f1dd86SDoug Anderson 1440d1f1dd86SDoug Anderson } else { 1441d1f1dd86SDoug Anderson /* Keep track so we don't reset again */ 1442d1f1dd86SDoug Anderson slot->host->vqmmc_enabled = true; 1443d1f1dd86SDoug Anderson } 1444d1f1dd86SDoug Anderson 1445d1f1dd86SDoug Anderson /* Reset our state machine after powering on */ 1446d1f1dd86SDoug Anderson dw_mci_ctrl_reset(slot->host, 1447d1f1dd86SDoug Anderson SDMMC_CTRL_ALL_RESET_FLAGS); 144851da2240SYuvaraj CD } 1449655babbdSDoug Anderson 1450655babbdSDoug Anderson /* Adjust clock / bus width after power is up */ 1451655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1452655babbdSDoug Anderson 1453e6f34e2fSJames Hogan break; 1454e6f34e2fSJames Hogan case MMC_POWER_OFF: 1455655babbdSDoug Anderson /* Turn clock off before power goes down */ 1456655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1457655babbdSDoug Anderson 145851da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) 145951da2240SYuvaraj CD mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 146051da2240SYuvaraj CD 1461d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) 146251da2240SYuvaraj CD regulator_disable(mmc->supply.vqmmc); 146351da2240SYuvaraj CD slot->host->vqmmc_enabled = false; 146451da2240SYuvaraj CD 14654366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 14664366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 14674366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1468f95f3850SWill Newton break; 1469f95f3850SWill Newton default: 1470f95f3850SWill Newton break; 1471f95f3850SWill Newton } 1472655babbdSDoug Anderson 1473655babbdSDoug Anderson if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) 1474655babbdSDoug Anderson slot->host->state = STATE_IDLE; 1475f95f3850SWill Newton } 1476f95f3850SWill Newton 147701730558SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc) 147801730558SDoug Anderson { 147901730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 148001730558SDoug Anderson u32 status; 148101730558SDoug Anderson 148201730558SDoug Anderson /* 148301730558SDoug Anderson * Check the busy bit which is low when DAT[3:0] 148401730558SDoug Anderson * (the data lines) are 0000 148501730558SDoug Anderson */ 148601730558SDoug Anderson status = mci_readl(slot->host, STATUS); 148701730558SDoug Anderson 148801730558SDoug Anderson return !!(status & SDMMC_STATUS_BUSY); 148901730558SDoug Anderson } 149001730558SDoug Anderson 149101730558SDoug Anderson static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) 149201730558SDoug Anderson { 149301730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 149401730558SDoug Anderson struct dw_mci *host = slot->host; 14958f7849c4SZhangfei Gao const struct dw_mci_drv_data *drv_data = host->drv_data; 149601730558SDoug Anderson u32 uhs; 149701730558SDoug Anderson u32 v18 = SDMMC_UHS_18V << slot->id; 149801730558SDoug Anderson int ret; 149901730558SDoug Anderson 15008f7849c4SZhangfei Gao if (drv_data && drv_data->switch_voltage) 15018f7849c4SZhangfei Gao return drv_data->switch_voltage(mmc, ios); 15028f7849c4SZhangfei Gao 150301730558SDoug Anderson /* 150401730558SDoug Anderson * Program the voltage. Note that some instances of dw_mmc may use 150501730558SDoug Anderson * the UHS_REG for this. For other instances (like exynos) the UHS_REG 150601730558SDoug Anderson * does no harm but you need to set the regulator directly. Try both. 150701730558SDoug Anderson */ 150801730558SDoug Anderson uhs = mci_readl(host, UHS_REG); 1509e0848f5dSDouglas Anderson if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) 151001730558SDoug Anderson uhs &= ~v18; 1511e0848f5dSDouglas Anderson else 151201730558SDoug Anderson uhs |= v18; 1513e0848f5dSDouglas Anderson 151401730558SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 1515e0848f5dSDouglas Anderson ret = mmc_regulator_set_vqmmc(mmc, ios); 151601730558SDoug Anderson 151701730558SDoug Anderson if (ret) { 1518b19caf37SDoug Anderson dev_dbg(&mmc->class_dev, 1519e0848f5dSDouglas Anderson "Regulator set error %d - %s V\n", 1520e0848f5dSDouglas Anderson ret, uhs & v18 ? "1.8" : "3.3"); 152101730558SDoug Anderson return ret; 152201730558SDoug Anderson } 152301730558SDoug Anderson } 152401730558SDoug Anderson mci_writel(host, UHS_REG, uhs); 152501730558SDoug Anderson 152601730558SDoug Anderson return 0; 152701730558SDoug Anderson } 152801730558SDoug Anderson 1529f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 1530f95f3850SWill Newton { 1531f95f3850SWill Newton int read_only; 1532f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 15339795a846SJaehoon Chung int gpio_ro = mmc_gpio_get_ro(mmc); 1534f95f3850SWill Newton 1535f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 1536287980e4SArnd Bergmann if (gpio_ro >= 0) 15379795a846SJaehoon Chung read_only = gpio_ro; 1538f95f3850SWill Newton else 1539f95f3850SWill Newton read_only = 1540f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1541f95f3850SWill Newton 1542f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1543f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1544f95f3850SWill Newton 1545f95f3850SWill Newton return read_only; 1546f95f3850SWill Newton } 1547f95f3850SWill Newton 1548f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1549f95f3850SWill Newton { 1550f95f3850SWill Newton int present; 1551f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 15527cf347bdSZhangfei Gao struct dw_mci *host = slot->host; 15537cf347bdSZhangfei Gao int gpio_cd = mmc_gpio_get_cd(mmc); 1554f95f3850SWill Newton 1555f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 1556d10111cfSJaehoon Chung if (((mmc->caps & MMC_CAP_NEEDS_POLL) 1557d10111cfSJaehoon Chung || !mmc_card_is_removable(mmc))) { 1558fc3d7720SJaehoon Chung present = 1; 1559d10111cfSJaehoon Chung 1560d10111cfSJaehoon Chung if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { 1561d10111cfSJaehoon Chung if (mmc->caps & MMC_CAP_NEEDS_POLL) { 1562d10111cfSJaehoon Chung dev_info(&mmc->class_dev, 1563d10111cfSJaehoon Chung "card is polling.\n"); 1564d10111cfSJaehoon Chung } else { 1565d10111cfSJaehoon Chung dev_info(&mmc->class_dev, 1566d10111cfSJaehoon Chung "card is non-removable.\n"); 1567d10111cfSJaehoon Chung } 1568d10111cfSJaehoon Chung set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1569d10111cfSJaehoon Chung } 1570d10111cfSJaehoon Chung 1571d10111cfSJaehoon Chung return present; 1572d10111cfSJaehoon Chung } else if (gpio_cd >= 0) 15737cf347bdSZhangfei Gao present = gpio_cd; 1574f95f3850SWill Newton else 1575f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1576f95f3850SWill Newton == 0 ? 1 : 0; 1577f95f3850SWill Newton 15787cf347bdSZhangfei Gao spin_lock_bh(&host->lock); 15791f4d5079SJaehoon Chung if (present && !test_and_set_bit(DW_MMC_CARD_PRESENT, &slot->flags)) 1580f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 15811c238a95SJaehoon Chung else if (!present && 15821c238a95SJaehoon Chung !test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags)) 1583f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 15847cf347bdSZhangfei Gao spin_unlock_bh(&host->lock); 1585f95f3850SWill Newton 1586f95f3850SWill Newton return present; 1587f95f3850SWill Newton } 1588f95f3850SWill Newton 1589935a665eSShawn Lin static void dw_mci_hw_reset(struct mmc_host *mmc) 1590935a665eSShawn Lin { 1591935a665eSShawn Lin struct dw_mci_slot *slot = mmc_priv(mmc); 1592935a665eSShawn Lin struct dw_mci *host = slot->host; 1593935a665eSShawn Lin int reset; 1594935a665eSShawn Lin 1595935a665eSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 1596935a665eSShawn Lin dw_mci_idmac_reset(host); 1597935a665eSShawn Lin 1598935a665eSShawn Lin if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET | 1599935a665eSShawn Lin SDMMC_CTRL_FIFO_RESET)) 1600935a665eSShawn Lin return; 1601935a665eSShawn Lin 1602935a665eSShawn Lin /* 1603935a665eSShawn Lin * According to eMMC spec, card reset procedure: 1604935a665eSShawn Lin * tRstW >= 1us: RST_n pulse width 1605935a665eSShawn Lin * tRSCA >= 200us: RST_n to Command time 1606935a665eSShawn Lin * tRSTH >= 1us: RST_n high period 1607935a665eSShawn Lin */ 1608935a665eSShawn Lin reset = mci_readl(host, RST_N); 1609935a665eSShawn Lin reset &= ~(SDMMC_RST_HWACTIVE << slot->id); 1610935a665eSShawn Lin mci_writel(host, RST_N, reset); 1611935a665eSShawn Lin usleep_range(1, 2); 1612935a665eSShawn Lin reset |= SDMMC_RST_HWACTIVE << slot->id; 1613935a665eSShawn Lin mci_writel(host, RST_N, reset); 1614935a665eSShawn Lin usleep_range(200, 300); 1615935a665eSShawn Lin } 1616935a665eSShawn Lin 1617b24c8b26SDoug Anderson static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) 1618b24c8b26SDoug Anderson { 1619b24c8b26SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 1620b24c8b26SDoug Anderson struct dw_mci *host = slot->host; 1621b24c8b26SDoug Anderson 16229623b5b9SDoug Anderson /* 16239623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 16249623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 16259623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 16269623b5b9SDoug Anderson */ 1627b24c8b26SDoug Anderson if (mmc->caps & MMC_CAP_SDIO_IRQ) { 16289623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 1629b24c8b26SDoug Anderson u32 clk_en_a_old; 1630b24c8b26SDoug Anderson u32 clk_en_a; 16319623b5b9SDoug Anderson 1632b24c8b26SDoug Anderson clk_en_a_old = mci_readl(host, CLKENA); 16339623b5b9SDoug Anderson 1634b24c8b26SDoug Anderson if (card->type == MMC_TYPE_SDIO || 1635b24c8b26SDoug Anderson card->type == MMC_TYPE_SD_COMBO) { 1636a6db2c86SDouglas Anderson if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) { 1637a6db2c86SDouglas Anderson pm_runtime_get_noresume(mmc->parent); 1638b24c8b26SDoug Anderson set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1639a6db2c86SDouglas Anderson } 1640b24c8b26SDoug Anderson clk_en_a = clk_en_a_old & ~clken_low_pwr; 1641b24c8b26SDoug Anderson } else { 1642a6db2c86SDouglas Anderson if (test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) { 1643a6db2c86SDouglas Anderson pm_runtime_put_noidle(mmc->parent); 1644b24c8b26SDoug Anderson clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1645a6db2c86SDouglas Anderson } 1646b24c8b26SDoug Anderson clk_en_a = clk_en_a_old | clken_low_pwr; 1647b24c8b26SDoug Anderson } 1648b24c8b26SDoug Anderson 1649b24c8b26SDoug Anderson if (clk_en_a != clk_en_a_old) { 1650b24c8b26SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 16519623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 16529623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 16539623b5b9SDoug Anderson } 16549623b5b9SDoug Anderson } 1655b24c8b26SDoug Anderson } 16569623b5b9SDoug Anderson 16571a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 16581a5c8e1fSShashidhar Hiremath { 16591a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 16601a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 1661f8c58c11SDoug Anderson unsigned long irqflags; 16621a5c8e1fSShashidhar Hiremath u32 int_mask; 16631a5c8e1fSShashidhar Hiremath 1664f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1665f8c58c11SDoug Anderson 16661a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 16671a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 1668b24c8b26SDoug Anderson if (enb) 1669b24c8b26SDoug Anderson int_mask |= SDMMC_INT_SDIO(slot->sdio_id); 1670b24c8b26SDoug Anderson else 1671b24c8b26SDoug Anderson int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id); 1672b24c8b26SDoug Anderson mci_writel(host, INTMASK, int_mask); 1673f8c58c11SDoug Anderson 1674f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 16751a5c8e1fSShashidhar Hiremath } 16761a5c8e1fSShashidhar Hiremath 16770976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 16780976f16dSSeungwon Jeon { 16790976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 16800976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 16810976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 16820e3a22c0SShawn Lin int err = -EINVAL; 16830976f16dSSeungwon Jeon 16840976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 16859979dbe5SChaotian Jing err = drv_data->execute_tuning(slot, opcode); 16860976f16dSSeungwon Jeon return err; 16870976f16dSSeungwon Jeon } 16880976f16dSSeungwon Jeon 16890e3a22c0SShawn Lin static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, 16900e3a22c0SShawn Lin struct mmc_ios *ios) 169180113132SSeungwon Jeon { 169280113132SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 169380113132SSeungwon Jeon struct dw_mci *host = slot->host; 169480113132SSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 169580113132SSeungwon Jeon 169680113132SSeungwon Jeon if (drv_data && drv_data->prepare_hs400_tuning) 169780113132SSeungwon Jeon return drv_data->prepare_hs400_tuning(host, ios); 169880113132SSeungwon Jeon 169980113132SSeungwon Jeon return 0; 170080113132SSeungwon Jeon } 170180113132SSeungwon Jeon 17024e7392b2SShawn Lin static bool dw_mci_reset(struct dw_mci *host) 17034e7392b2SShawn Lin { 17044e7392b2SShawn Lin u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; 17054e7392b2SShawn Lin bool ret = false; 17064e7392b2SShawn Lin 17074e7392b2SShawn Lin /* 17084e7392b2SShawn Lin * Resetting generates a block interrupt, hence setting 17094e7392b2SShawn Lin * the scatter-gather pointer to NULL. 17104e7392b2SShawn Lin */ 17114e7392b2SShawn Lin if (host->sg) { 17124e7392b2SShawn Lin sg_miter_stop(&host->sg_miter); 17134e7392b2SShawn Lin host->sg = NULL; 17144e7392b2SShawn Lin } 17154e7392b2SShawn Lin 17164e7392b2SShawn Lin if (host->use_dma) 17174e7392b2SShawn Lin flags |= SDMMC_CTRL_DMA_RESET; 17184e7392b2SShawn Lin 17194e7392b2SShawn Lin if (dw_mci_ctrl_reset(host, flags)) { 17204e7392b2SShawn Lin /* 17214e7392b2SShawn Lin * In all cases we clear the RAWINTS register to clear any 17224e7392b2SShawn Lin * interrupts. 17234e7392b2SShawn Lin */ 17244e7392b2SShawn Lin mci_writel(host, RINTSTS, 0xFFFFFFFF); 17254e7392b2SShawn Lin 17264e7392b2SShawn Lin /* if using dma we wait for dma_req to clear */ 17274e7392b2SShawn Lin if (host->use_dma) { 17284e7392b2SShawn Lin u32 status; 17294e7392b2SShawn Lin 17304e7392b2SShawn Lin if (readl_poll_timeout_atomic(host->regs + SDMMC_STATUS, 17314e7392b2SShawn Lin status, 17324e7392b2SShawn Lin !(status & SDMMC_STATUS_DMA_REQ), 17334e7392b2SShawn Lin 1, 500 * USEC_PER_MSEC)) { 17344e7392b2SShawn Lin dev_err(host->dev, 17354e7392b2SShawn Lin "%s: Timeout waiting for dma_req to clear during reset\n", 17364e7392b2SShawn Lin __func__); 17374e7392b2SShawn Lin goto ciu_out; 17384e7392b2SShawn Lin } 17394e7392b2SShawn Lin 17404e7392b2SShawn Lin /* when using DMA next we reset the fifo again */ 17414e7392b2SShawn Lin if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) 17424e7392b2SShawn Lin goto ciu_out; 17434e7392b2SShawn Lin } 17444e7392b2SShawn Lin } else { 17454e7392b2SShawn Lin /* if the controller reset bit did clear, then set clock regs */ 17464e7392b2SShawn Lin if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { 17474e7392b2SShawn Lin dev_err(host->dev, 17484e7392b2SShawn Lin "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n", 17494e7392b2SShawn Lin __func__); 17504e7392b2SShawn Lin goto ciu_out; 17514e7392b2SShawn Lin } 17524e7392b2SShawn Lin } 17534e7392b2SShawn Lin 17544e7392b2SShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 17554e7392b2SShawn Lin /* It is also recommended that we reset and reprogram idmac */ 17564e7392b2SShawn Lin dw_mci_idmac_reset(host); 17574e7392b2SShawn Lin 17584e7392b2SShawn Lin ret = true; 17594e7392b2SShawn Lin 17604e7392b2SShawn Lin ciu_out: 17614e7392b2SShawn Lin /* After a CTRL reset we need to have CIU set clock registers */ 17624e7392b2SShawn Lin mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); 17634e7392b2SShawn Lin 17644e7392b2SShawn Lin return ret; 17654e7392b2SShawn Lin } 17664e7392b2SShawn Lin 1767f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1768f95f3850SWill Newton .request = dw_mci_request, 17699aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 17709aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1771f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1772f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1773f95f3850SWill Newton .get_cd = dw_mci_get_cd, 1774935a665eSShawn Lin .hw_reset = dw_mci_hw_reset, 17751a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 17760976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 177701730558SDoug Anderson .card_busy = dw_mci_card_busy, 177801730558SDoug Anderson .start_signal_voltage_switch = dw_mci_switch_voltage, 1779b24c8b26SDoug Anderson .init_card = dw_mci_init_card, 178080113132SSeungwon Jeon .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, 1781f95f3850SWill Newton }; 1782f95f3850SWill Newton 1783f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1784f95f3850SWill Newton __releases(&host->lock) 1785f95f3850SWill Newton __acquires(&host->lock) 1786f95f3850SWill Newton { 1787f95f3850SWill Newton struct dw_mci_slot *slot; 1788f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1789f95f3850SWill Newton 1790f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1791f95f3850SWill Newton 1792f95f3850SWill Newton host->cur_slot->mrq = NULL; 1793f95f3850SWill Newton host->mrq = NULL; 1794f95f3850SWill Newton if (!list_empty(&host->queue)) { 1795f95f3850SWill Newton slot = list_entry(host->queue.next, 1796f95f3850SWill Newton struct dw_mci_slot, queue_node); 1797f95f3850SWill Newton list_del(&slot->queue_node); 17984a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1799f95f3850SWill Newton mmc_hostname(slot->mmc)); 1800f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1801f95f3850SWill Newton dw_mci_start_request(host, slot); 1802f95f3850SWill Newton } else { 18034a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 180401730558SDoug Anderson 180501730558SDoug Anderson if (host->state == STATE_SENDING_CMD11) 180601730558SDoug Anderson host->state = STATE_WAITING_CMD11_DONE; 180701730558SDoug Anderson else 1808f95f3850SWill Newton host->state = STATE_IDLE; 1809f95f3850SWill Newton } 1810f95f3850SWill Newton 1811f95f3850SWill Newton spin_unlock(&host->lock); 1812f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1813f95f3850SWill Newton spin_lock(&host->lock); 1814f95f3850SWill Newton } 1815f95f3850SWill Newton 1816e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1817f95f3850SWill Newton { 1818f95f3850SWill Newton u32 status = host->cmd_status; 1819f95f3850SWill Newton 1820f95f3850SWill Newton host->cmd_status = 0; 1821f95f3850SWill Newton 1822f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1823f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1824f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1825f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1826f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1827f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1828f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1829f95f3850SWill Newton } else { 1830f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1831f95f3850SWill Newton cmd->resp[1] = 0; 1832f95f3850SWill Newton cmd->resp[2] = 0; 1833f95f3850SWill Newton cmd->resp[3] = 0; 1834f95f3850SWill Newton } 1835f95f3850SWill Newton } 1836f95f3850SWill Newton 1837f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1838f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1839f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1840f95f3850SWill Newton cmd->error = -EILSEQ; 1841f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1842f95f3850SWill Newton cmd->error = -EIO; 1843f95f3850SWill Newton else 1844f95f3850SWill Newton cmd->error = 0; 1845f95f3850SWill Newton 1846e352c813SSeungwon Jeon return cmd->error; 1847e352c813SSeungwon Jeon } 1848e352c813SSeungwon Jeon 1849e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) 1850e352c813SSeungwon Jeon { 185131bff450SSeungwon Jeon u32 status = host->data_status; 1852e352c813SSeungwon Jeon 1853e352c813SSeungwon Jeon if (status & DW_MCI_DATA_ERROR_FLAGS) { 1854e352c813SSeungwon Jeon if (status & SDMMC_INT_DRTO) { 1855e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1856e352c813SSeungwon Jeon } else if (status & SDMMC_INT_DCRC) { 1857e352c813SSeungwon Jeon data->error = -EILSEQ; 1858e352c813SSeungwon Jeon } else if (status & SDMMC_INT_EBE) { 1859e352c813SSeungwon Jeon if (host->dir_status == 1860e352c813SSeungwon Jeon DW_MCI_SEND_STATUS) { 1861e352c813SSeungwon Jeon /* 1862e352c813SSeungwon Jeon * No data CRC status was returned. 1863e352c813SSeungwon Jeon * The number of bytes transferred 1864e352c813SSeungwon Jeon * will be exaggerated in PIO mode. 1865e352c813SSeungwon Jeon */ 1866e352c813SSeungwon Jeon data->bytes_xfered = 0; 1867e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1868e352c813SSeungwon Jeon } else if (host->dir_status == 1869e352c813SSeungwon Jeon DW_MCI_RECV_STATUS) { 1870e7a1dec1SShawn Lin data->error = -EILSEQ; 1871e352c813SSeungwon Jeon } 1872e352c813SSeungwon Jeon } else { 1873e352c813SSeungwon Jeon /* SDMMC_INT_SBE is included */ 1874e7a1dec1SShawn Lin data->error = -EILSEQ; 1875e352c813SSeungwon Jeon } 1876e352c813SSeungwon Jeon 1877e6cc0123SDoug Anderson dev_dbg(host->dev, "data error, status 0x%08x\n", status); 1878e352c813SSeungwon Jeon 1879e352c813SSeungwon Jeon /* 1880e352c813SSeungwon Jeon * After an error, there may be data lingering 188131bff450SSeungwon Jeon * in the FIFO 1882e352c813SSeungwon Jeon */ 18833a33a94cSSonny Rao dw_mci_reset(host); 1884e352c813SSeungwon Jeon } else { 1885e352c813SSeungwon Jeon data->bytes_xfered = data->blocks * data->blksz; 1886e352c813SSeungwon Jeon data->error = 0; 1887e352c813SSeungwon Jeon } 1888e352c813SSeungwon Jeon 1889e352c813SSeungwon Jeon return data->error; 1890f95f3850SWill Newton } 1891f95f3850SWill Newton 189257e10486SAddy Ke static void dw_mci_set_drto(struct dw_mci *host) 189357e10486SAddy Ke { 189457e10486SAddy Ke unsigned int drto_clks; 189557e10486SAddy Ke unsigned int drto_ms; 189657e10486SAddy Ke 189757e10486SAddy Ke drto_clks = mci_readl(host, TMOUT) >> 8; 189857e10486SAddy Ke drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000); 189957e10486SAddy Ke 190057e10486SAddy Ke /* add a bit spare time */ 190157e10486SAddy Ke drto_ms += 10; 190257e10486SAddy Ke 190357e10486SAddy Ke mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms)); 190457e10486SAddy Ke } 190557e10486SAddy Ke 1906f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1907f95f3850SWill Newton { 1908f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1909f95f3850SWill Newton struct mmc_data *data; 1910f95f3850SWill Newton struct mmc_command *cmd; 1911e352c813SSeungwon Jeon struct mmc_request *mrq; 1912f95f3850SWill Newton enum dw_mci_state state; 1913f95f3850SWill Newton enum dw_mci_state prev_state; 1914e352c813SSeungwon Jeon unsigned int err; 1915f95f3850SWill Newton 1916f95f3850SWill Newton spin_lock(&host->lock); 1917f95f3850SWill Newton 1918f95f3850SWill Newton state = host->state; 1919f95f3850SWill Newton data = host->data; 1920e352c813SSeungwon Jeon mrq = host->mrq; 1921f95f3850SWill Newton 1922f95f3850SWill Newton do { 1923f95f3850SWill Newton prev_state = state; 1924f95f3850SWill Newton 1925f95f3850SWill Newton switch (state) { 1926f95f3850SWill Newton case STATE_IDLE: 192701730558SDoug Anderson case STATE_WAITING_CMD11_DONE: 1928f95f3850SWill Newton break; 1929f95f3850SWill Newton 193001730558SDoug Anderson case STATE_SENDING_CMD11: 1931f95f3850SWill Newton case STATE_SENDING_CMD: 1932f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1933f95f3850SWill Newton &host->pending_events)) 1934f95f3850SWill Newton break; 1935f95f3850SWill Newton 1936f95f3850SWill Newton cmd = host->cmd; 1937f95f3850SWill Newton host->cmd = NULL; 1938f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1939e352c813SSeungwon Jeon err = dw_mci_command_complete(host, cmd); 1940e352c813SSeungwon Jeon if (cmd == mrq->sbc && !err) { 1941053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1942053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1943e352c813SSeungwon Jeon mrq->cmd); 1944053b3ce6SSeungwon Jeon goto unlock; 1945053b3ce6SSeungwon Jeon } 1946053b3ce6SSeungwon Jeon 1947e352c813SSeungwon Jeon if (cmd->data && err) { 194846d17952SDoug Anderson /* 194946d17952SDoug Anderson * During UHS tuning sequence, sending the stop 195046d17952SDoug Anderson * command after the response CRC error would 195146d17952SDoug Anderson * throw the system into a confused state 195246d17952SDoug Anderson * causing all future tuning phases to report 195346d17952SDoug Anderson * failure. 195446d17952SDoug Anderson * 195546d17952SDoug Anderson * In such case controller will move into a data 195646d17952SDoug Anderson * transfer state after a response error or 195746d17952SDoug Anderson * response CRC error. Let's let that finish 195846d17952SDoug Anderson * before trying to send a stop, so we'll go to 195946d17952SDoug Anderson * STATE_SENDING_DATA. 196046d17952SDoug Anderson * 196146d17952SDoug Anderson * Although letting the data transfer take place 196246d17952SDoug Anderson * will waste a bit of time (we already know 196346d17952SDoug Anderson * the command was bad), it can't cause any 196446d17952SDoug Anderson * errors since it's possible it would have 196546d17952SDoug Anderson * taken place anyway if this tasklet got 196646d17952SDoug Anderson * delayed. Allowing the transfer to take place 196746d17952SDoug Anderson * avoids races and keeps things simple. 196846d17952SDoug Anderson */ 196946d17952SDoug Anderson if ((err != -ETIMEDOUT) && 197046d17952SDoug Anderson (cmd->opcode == MMC_SEND_TUNING_BLOCK)) { 197146d17952SDoug Anderson state = STATE_SENDING_DATA; 197246d17952SDoug Anderson continue; 197346d17952SDoug Anderson } 197446d17952SDoug Anderson 197571abb133SSeungwon Jeon dw_mci_stop_dma(host); 197690c2143aSSeungwon Jeon send_stop_abort(host, data); 197771abb133SSeungwon Jeon state = STATE_SENDING_STOP; 197871abb133SSeungwon Jeon break; 197971abb133SSeungwon Jeon } 198071abb133SSeungwon Jeon 1981e352c813SSeungwon Jeon if (!cmd->data || err) { 1982e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1983f95f3850SWill Newton goto unlock; 1984f95f3850SWill Newton } 1985f95f3850SWill Newton 1986f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1987f95f3850SWill Newton /* fall through */ 1988f95f3850SWill Newton 1989f95f3850SWill Newton case STATE_SENDING_DATA: 19902aa35465SDoug Anderson /* 19912aa35465SDoug Anderson * We could get a data error and never a transfer 19922aa35465SDoug Anderson * complete so we'd better check for it here. 19932aa35465SDoug Anderson * 19942aa35465SDoug Anderson * Note that we don't really care if we also got a 19952aa35465SDoug Anderson * transfer complete; stopping the DMA and sending an 19962aa35465SDoug Anderson * abort won't hurt. 19972aa35465SDoug Anderson */ 1998f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1999f95f3850SWill Newton &host->pending_events)) { 2000f95f3850SWill Newton dw_mci_stop_dma(host); 2001e13c3c08SJaehoon Chung if (!(host->data_status & (SDMMC_INT_DRTO | 2002bdb9a90bSaddy ke SDMMC_INT_EBE))) 200390c2143aSSeungwon Jeon send_stop_abort(host, data); 2004f95f3850SWill Newton state = STATE_DATA_ERROR; 2005f95f3850SWill Newton break; 2006f95f3850SWill Newton } 2007f95f3850SWill Newton 2008f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 200957e10486SAddy Ke &host->pending_events)) { 201057e10486SAddy Ke /* 201157e10486SAddy Ke * If all data-related interrupts don't come 201257e10486SAddy Ke * within the given time in reading data state. 201357e10486SAddy Ke */ 201416a34574SJaehoon Chung if (host->dir_status == DW_MCI_RECV_STATUS) 201557e10486SAddy Ke dw_mci_set_drto(host); 2016f95f3850SWill Newton break; 201757e10486SAddy Ke } 2018f95f3850SWill Newton 2019f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 20202aa35465SDoug Anderson 20212aa35465SDoug Anderson /* 20222aa35465SDoug Anderson * Handle an EVENT_DATA_ERROR that might have shown up 20232aa35465SDoug Anderson * before the transfer completed. This might not have 20242aa35465SDoug Anderson * been caught by the check above because the interrupt 20252aa35465SDoug Anderson * could have gone off between the previous check and 20262aa35465SDoug Anderson * the check for transfer complete. 20272aa35465SDoug Anderson * 20282aa35465SDoug Anderson * Technically this ought not be needed assuming we 20292aa35465SDoug Anderson * get a DATA_COMPLETE eventually (we'll notice the 20302aa35465SDoug Anderson * error and end the request), but it shouldn't hurt. 20312aa35465SDoug Anderson * 20322aa35465SDoug Anderson * This has the advantage of sending the stop command. 20332aa35465SDoug Anderson */ 20342aa35465SDoug Anderson if (test_and_clear_bit(EVENT_DATA_ERROR, 20352aa35465SDoug Anderson &host->pending_events)) { 20362aa35465SDoug Anderson dw_mci_stop_dma(host); 2037e13c3c08SJaehoon Chung if (!(host->data_status & (SDMMC_INT_DRTO | 2038bdb9a90bSaddy ke SDMMC_INT_EBE))) 20392aa35465SDoug Anderson send_stop_abort(host, data); 20402aa35465SDoug Anderson state = STATE_DATA_ERROR; 20412aa35465SDoug Anderson break; 20422aa35465SDoug Anderson } 2043f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 20442aa35465SDoug Anderson 2045f95f3850SWill Newton /* fall through */ 2046f95f3850SWill Newton 2047f95f3850SWill Newton case STATE_DATA_BUSY: 2048f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 204957e10486SAddy Ke &host->pending_events)) { 205057e10486SAddy Ke /* 205157e10486SAddy Ke * If data error interrupt comes but data over 205257e10486SAddy Ke * interrupt doesn't come within the given time. 205357e10486SAddy Ke * in reading data state. 205457e10486SAddy Ke */ 205516a34574SJaehoon Chung if (host->dir_status == DW_MCI_RECV_STATUS) 205657e10486SAddy Ke dw_mci_set_drto(host); 2057f95f3850SWill Newton break; 205857e10486SAddy Ke } 2059f95f3850SWill Newton 2060f95f3850SWill Newton host->data = NULL; 2061f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 2062e352c813SSeungwon Jeon err = dw_mci_data_complete(host, data); 2063f95f3850SWill Newton 2064e352c813SSeungwon Jeon if (!err) { 2065e352c813SSeungwon Jeon if (!data->stop || mrq->sbc) { 206617c8bc85SSachin Kamat if (mrq->sbc && data->stop) 2067053b3ce6SSeungwon Jeon data->stop->error = 0; 2068e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 2069053b3ce6SSeungwon Jeon goto unlock; 2070053b3ce6SSeungwon Jeon } 2071053b3ce6SSeungwon Jeon 207290c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 2073e352c813SSeungwon Jeon if (data->stop) 207490c2143aSSeungwon Jeon send_stop_abort(host, data); 20752aa35465SDoug Anderson } else { 20762aa35465SDoug Anderson /* 20772aa35465SDoug Anderson * If we don't have a command complete now we'll 20782aa35465SDoug Anderson * never get one since we just reset everything; 20792aa35465SDoug Anderson * better end the request. 20802aa35465SDoug Anderson * 20812aa35465SDoug Anderson * If we do have a command complete we'll fall 20822aa35465SDoug Anderson * through to the SENDING_STOP command and 20832aa35465SDoug Anderson * everything will be peachy keen. 20842aa35465SDoug Anderson */ 20852aa35465SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, 20862aa35465SDoug Anderson &host->pending_events)) { 20872aa35465SDoug Anderson host->cmd = NULL; 20882aa35465SDoug Anderson dw_mci_request_end(host, mrq); 20892aa35465SDoug Anderson goto unlock; 20902aa35465SDoug Anderson } 209190c2143aSSeungwon Jeon } 2092e352c813SSeungwon Jeon 2093e352c813SSeungwon Jeon /* 2094e352c813SSeungwon Jeon * If err has non-zero, 2095e352c813SSeungwon Jeon * stop-abort command has been already issued. 2096e352c813SSeungwon Jeon */ 2097e352c813SSeungwon Jeon prev_state = state = STATE_SENDING_STOP; 2098e352c813SSeungwon Jeon 2099f95f3850SWill Newton /* fall through */ 2100f95f3850SWill Newton 2101f95f3850SWill Newton case STATE_SENDING_STOP: 2102f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 2103f95f3850SWill Newton &host->pending_events)) 2104f95f3850SWill Newton break; 2105f95f3850SWill Newton 210671abb133SSeungwon Jeon /* CMD error in data command */ 210731bff450SSeungwon Jeon if (mrq->cmd->error && mrq->data) 21083a33a94cSSonny Rao dw_mci_reset(host); 210971abb133SSeungwon Jeon 2110f95f3850SWill Newton host->cmd = NULL; 211171abb133SSeungwon Jeon host->data = NULL; 211290c2143aSSeungwon Jeon 2113e13c3c08SJaehoon Chung if (!mrq->sbc && mrq->stop) 2114e352c813SSeungwon Jeon dw_mci_command_complete(host, mrq->stop); 211590c2143aSSeungwon Jeon else 211690c2143aSSeungwon Jeon host->cmd_status = 0; 211790c2143aSSeungwon Jeon 2118e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 2119f95f3850SWill Newton goto unlock; 2120f95f3850SWill Newton 2121f95f3850SWill Newton case STATE_DATA_ERROR: 2122f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 2123f95f3850SWill Newton &host->pending_events)) 2124f95f3850SWill Newton break; 2125f95f3850SWill Newton 2126f95f3850SWill Newton state = STATE_DATA_BUSY; 2127f95f3850SWill Newton break; 2128f95f3850SWill Newton } 2129f95f3850SWill Newton } while (state != prev_state); 2130f95f3850SWill Newton 2131f95f3850SWill Newton host->state = state; 2132f95f3850SWill Newton unlock: 2133f95f3850SWill Newton spin_unlock(&host->lock); 2134f95f3850SWill Newton 2135f95f3850SWill Newton } 2136f95f3850SWill Newton 213734b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 213834b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 213934b664a2SJames Hogan { 214034b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 214134b664a2SJames Hogan host->part_buf_count = cnt; 214234b664a2SJames Hogan } 214334b664a2SJames Hogan 214434b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 214534b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 214634b664a2SJames Hogan { 214734b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 214834b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 214934b664a2SJames Hogan host->part_buf_count += cnt; 215034b664a2SJames Hogan return cnt; 215134b664a2SJames Hogan } 215234b664a2SJames Hogan 215334b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 215434b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 215534b664a2SJames Hogan { 21560e3a22c0SShawn Lin cnt = min_t(int, cnt, host->part_buf_count); 215734b664a2SJames Hogan if (cnt) { 215834b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 215934b664a2SJames Hogan cnt); 216034b664a2SJames Hogan host->part_buf_count -= cnt; 216134b664a2SJames Hogan host->part_buf_start += cnt; 216234b664a2SJames Hogan } 216334b664a2SJames Hogan return cnt; 216434b664a2SJames Hogan } 216534b664a2SJames Hogan 216634b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 216734b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 216834b664a2SJames Hogan { 216934b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 217034b664a2SJames Hogan host->part_buf_start = cnt; 217134b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 217234b664a2SJames Hogan } 217334b664a2SJames Hogan 2174f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 2175f95f3850SWill Newton { 2176cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2177cfbeb59cSMarkos Chandras int init_cnt = cnt; 2178cfbeb59cSMarkos Chandras 217934b664a2SJames Hogan /* try and push anything in the part_buf */ 218034b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 218134b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 21820e3a22c0SShawn Lin 218334b664a2SJames Hogan buf += len; 218434b664a2SJames Hogan cnt -= len; 2185cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 218676184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 218734b664a2SJames Hogan host->part_buf_count = 0; 218834b664a2SJames Hogan } 218934b664a2SJames Hogan } 219034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 219134b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 219234b664a2SJames Hogan while (cnt >= 2) { 219334b664a2SJames Hogan u16 aligned_buf[64]; 219434b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 219534b664a2SJames Hogan int items = len >> 1; 219634b664a2SJames Hogan int i; 219734b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 219834b664a2SJames Hogan memcpy(aligned_buf, buf, len); 219934b664a2SJames Hogan buf += len; 220034b664a2SJames Hogan cnt -= len; 220134b664a2SJames Hogan /* push data from aligned buffer into fifo */ 220234b664a2SJames Hogan for (i = 0; i < items; ++i) 220376184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, aligned_buf[i]); 220434b664a2SJames Hogan } 220534b664a2SJames Hogan } else 220634b664a2SJames Hogan #endif 220734b664a2SJames Hogan { 220834b664a2SJames Hogan u16 *pdata = buf; 22090e3a22c0SShawn Lin 221034b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 221176184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, *pdata++); 221234b664a2SJames Hogan buf = pdata; 221334b664a2SJames Hogan } 221434b664a2SJames Hogan /* put anything remaining in the part_buf */ 221534b664a2SJames Hogan if (cnt) { 221634b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2217cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2218cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2219cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 222076184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 2221f95f3850SWill Newton } 2222f95f3850SWill Newton } 2223f95f3850SWill Newton 2224f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 2225f95f3850SWill Newton { 222634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 222734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 222834b664a2SJames Hogan while (cnt >= 2) { 222934b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 223034b664a2SJames Hogan u16 aligned_buf[64]; 223134b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 223234b664a2SJames Hogan int items = len >> 1; 223334b664a2SJames Hogan int i; 22340e3a22c0SShawn Lin 223534b664a2SJames Hogan for (i = 0; i < items; ++i) 223676184ac1SBen Dooks aligned_buf[i] = mci_fifo_readw(host->fifo_reg); 223734b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 223834b664a2SJames Hogan memcpy(buf, aligned_buf, len); 223934b664a2SJames Hogan buf += len; 224034b664a2SJames Hogan cnt -= len; 224134b664a2SJames Hogan } 224234b664a2SJames Hogan } else 224334b664a2SJames Hogan #endif 224434b664a2SJames Hogan { 224534b664a2SJames Hogan u16 *pdata = buf; 22460e3a22c0SShawn Lin 224734b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 224876184ac1SBen Dooks *pdata++ = mci_fifo_readw(host->fifo_reg); 224934b664a2SJames Hogan buf = pdata; 225034b664a2SJames Hogan } 225134b664a2SJames Hogan if (cnt) { 225276184ac1SBen Dooks host->part_buf16 = mci_fifo_readw(host->fifo_reg); 225334b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 2254f95f3850SWill Newton } 2255f95f3850SWill Newton } 2256f95f3850SWill Newton 2257f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 2258f95f3850SWill Newton { 2259cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2260cfbeb59cSMarkos Chandras int init_cnt = cnt; 2261cfbeb59cSMarkos Chandras 226234b664a2SJames Hogan /* try and push anything in the part_buf */ 226334b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 226434b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 22650e3a22c0SShawn Lin 226634b664a2SJames Hogan buf += len; 226734b664a2SJames Hogan cnt -= len; 2268cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 226976184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 227034b664a2SJames Hogan host->part_buf_count = 0; 227134b664a2SJames Hogan } 227234b664a2SJames Hogan } 227334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 227434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 227534b664a2SJames Hogan while (cnt >= 4) { 227634b664a2SJames Hogan u32 aligned_buf[32]; 227734b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 227834b664a2SJames Hogan int items = len >> 2; 227934b664a2SJames Hogan int i; 228034b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 228134b664a2SJames Hogan memcpy(aligned_buf, buf, len); 228234b664a2SJames Hogan buf += len; 228334b664a2SJames Hogan cnt -= len; 228434b664a2SJames Hogan /* push data from aligned buffer into fifo */ 228534b664a2SJames Hogan for (i = 0; i < items; ++i) 228676184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, aligned_buf[i]); 228734b664a2SJames Hogan } 228834b664a2SJames Hogan } else 228934b664a2SJames Hogan #endif 229034b664a2SJames Hogan { 229134b664a2SJames Hogan u32 *pdata = buf; 22920e3a22c0SShawn Lin 229334b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 229476184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, *pdata++); 229534b664a2SJames Hogan buf = pdata; 229634b664a2SJames Hogan } 229734b664a2SJames Hogan /* put anything remaining in the part_buf */ 229834b664a2SJames Hogan if (cnt) { 229934b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2300cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2301cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2302cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 230376184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 2304f95f3850SWill Newton } 2305f95f3850SWill Newton } 2306f95f3850SWill Newton 2307f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 2308f95f3850SWill Newton { 230934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 231034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 231134b664a2SJames Hogan while (cnt >= 4) { 231234b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 231334b664a2SJames Hogan u32 aligned_buf[32]; 231434b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 231534b664a2SJames Hogan int items = len >> 2; 231634b664a2SJames Hogan int i; 23170e3a22c0SShawn Lin 231834b664a2SJames Hogan for (i = 0; i < items; ++i) 231976184ac1SBen Dooks aligned_buf[i] = mci_fifo_readl(host->fifo_reg); 232034b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 232134b664a2SJames Hogan memcpy(buf, aligned_buf, len); 232234b664a2SJames Hogan buf += len; 232334b664a2SJames Hogan cnt -= len; 232434b664a2SJames Hogan } 232534b664a2SJames Hogan } else 232634b664a2SJames Hogan #endif 232734b664a2SJames Hogan { 232834b664a2SJames Hogan u32 *pdata = buf; 23290e3a22c0SShawn Lin 233034b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 233176184ac1SBen Dooks *pdata++ = mci_fifo_readl(host->fifo_reg); 233234b664a2SJames Hogan buf = pdata; 233334b664a2SJames Hogan } 233434b664a2SJames Hogan if (cnt) { 233576184ac1SBen Dooks host->part_buf32 = mci_fifo_readl(host->fifo_reg); 233634b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 2337f95f3850SWill Newton } 2338f95f3850SWill Newton } 2339f95f3850SWill Newton 2340f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 2341f95f3850SWill Newton { 2342cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2343cfbeb59cSMarkos Chandras int init_cnt = cnt; 2344cfbeb59cSMarkos Chandras 234534b664a2SJames Hogan /* try and push anything in the part_buf */ 234634b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 234734b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 23480e3a22c0SShawn Lin 234934b664a2SJames Hogan buf += len; 235034b664a2SJames Hogan cnt -= len; 2351c09fbd74SSeungwon Jeon 2352cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 235376184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 235434b664a2SJames Hogan host->part_buf_count = 0; 235534b664a2SJames Hogan } 235634b664a2SJames Hogan } 235734b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 235834b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 235934b664a2SJames Hogan while (cnt >= 8) { 236034b664a2SJames Hogan u64 aligned_buf[16]; 236134b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 236234b664a2SJames Hogan int items = len >> 3; 236334b664a2SJames Hogan int i; 236434b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 236534b664a2SJames Hogan memcpy(aligned_buf, buf, len); 236634b664a2SJames Hogan buf += len; 236734b664a2SJames Hogan cnt -= len; 236834b664a2SJames Hogan /* push data from aligned buffer into fifo */ 236934b664a2SJames Hogan for (i = 0; i < items; ++i) 237076184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, aligned_buf[i]); 237134b664a2SJames Hogan } 237234b664a2SJames Hogan } else 237334b664a2SJames Hogan #endif 237434b664a2SJames Hogan { 237534b664a2SJames Hogan u64 *pdata = buf; 23760e3a22c0SShawn Lin 237734b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 237876184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, *pdata++); 237934b664a2SJames Hogan buf = pdata; 238034b664a2SJames Hogan } 238134b664a2SJames Hogan /* put anything remaining in the part_buf */ 238234b664a2SJames Hogan if (cnt) { 238334b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2384cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2385cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2386cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 238776184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 2388f95f3850SWill Newton } 2389f95f3850SWill Newton } 2390f95f3850SWill Newton 2391f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 2392f95f3850SWill Newton { 239334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 239434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 239534b664a2SJames Hogan while (cnt >= 8) { 239634b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 239734b664a2SJames Hogan u64 aligned_buf[16]; 239834b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 239934b664a2SJames Hogan int items = len >> 3; 240034b664a2SJames Hogan int i; 24010e3a22c0SShawn Lin 240234b664a2SJames Hogan for (i = 0; i < items; ++i) 240376184ac1SBen Dooks aligned_buf[i] = mci_fifo_readq(host->fifo_reg); 240476184ac1SBen Dooks 240534b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 240634b664a2SJames Hogan memcpy(buf, aligned_buf, len); 240734b664a2SJames Hogan buf += len; 240834b664a2SJames Hogan cnt -= len; 2409f95f3850SWill Newton } 241034b664a2SJames Hogan } else 241134b664a2SJames Hogan #endif 241234b664a2SJames Hogan { 241334b664a2SJames Hogan u64 *pdata = buf; 24140e3a22c0SShawn Lin 241534b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 241676184ac1SBen Dooks *pdata++ = mci_fifo_readq(host->fifo_reg); 241734b664a2SJames Hogan buf = pdata; 241834b664a2SJames Hogan } 241934b664a2SJames Hogan if (cnt) { 242076184ac1SBen Dooks host->part_buf = mci_fifo_readq(host->fifo_reg); 242134b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 242234b664a2SJames Hogan } 242334b664a2SJames Hogan } 242434b664a2SJames Hogan 242534b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 242634b664a2SJames Hogan { 242734b664a2SJames Hogan int len; 242834b664a2SJames Hogan 242934b664a2SJames Hogan /* get remaining partial bytes */ 243034b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 243134b664a2SJames Hogan if (unlikely(len == cnt)) 243234b664a2SJames Hogan return; 243334b664a2SJames Hogan buf += len; 243434b664a2SJames Hogan cnt -= len; 243534b664a2SJames Hogan 243634b664a2SJames Hogan /* get the rest of the data */ 243734b664a2SJames Hogan host->pull_data(host, buf, cnt); 2438f95f3850SWill Newton } 2439f95f3850SWill Newton 244087a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 2441f95f3850SWill Newton { 2442f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2443f9c2a0dcSSeungwon Jeon void *buf; 2444f9c2a0dcSSeungwon Jeon unsigned int offset; 2445f95f3850SWill Newton struct mmc_data *data = host->data; 2446f95f3850SWill Newton int shift = host->data_shift; 2447f95f3850SWill Newton u32 status; 24483e4b0d8bSMarkos Chandras unsigned int len; 2449f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2450f95f3850SWill Newton 2451f95f3850SWill Newton do { 2452f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2453f9c2a0dcSSeungwon Jeon goto done; 2454f95f3850SWill Newton 24554225fc85SImre Deak host->sg = sg_miter->piter.sg; 2456f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2457f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2458f9c2a0dcSSeungwon Jeon offset = 0; 2459f9c2a0dcSSeungwon Jeon 2460f9c2a0dcSSeungwon Jeon do { 2461f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 2462f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 2463f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2464f9c2a0dcSSeungwon Jeon if (!len) 2465f9c2a0dcSSeungwon Jeon break; 2466f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 24673e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2468f95f3850SWill Newton offset += len; 2469f9c2a0dcSSeungwon Jeon remain -= len; 2470f9c2a0dcSSeungwon Jeon } while (remain); 2471f95f3850SWill Newton 2472e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2473f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2474f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 247587a74d39SKyoungil Kim /* if the RXDR is ready read again */ 247687a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 247787a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 2478f9c2a0dcSSeungwon Jeon 2479f9c2a0dcSSeungwon Jeon if (!remain) { 2480f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2481f9c2a0dcSSeungwon Jeon goto done; 2482f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2483f9c2a0dcSSeungwon Jeon } 2484f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2485f95f3850SWill Newton return; 2486f95f3850SWill Newton 2487f95f3850SWill Newton done: 2488f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2489f9c2a0dcSSeungwon Jeon host->sg = NULL; 24900e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2491f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2492f95f3850SWill Newton } 2493f95f3850SWill Newton 2494f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 2495f95f3850SWill Newton { 2496f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2497f9c2a0dcSSeungwon Jeon void *buf; 2498f9c2a0dcSSeungwon Jeon unsigned int offset; 2499f95f3850SWill Newton struct mmc_data *data = host->data; 2500f95f3850SWill Newton int shift = host->data_shift; 2501f95f3850SWill Newton u32 status; 25023e4b0d8bSMarkos Chandras unsigned int len; 2503f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 2504f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2505f95f3850SWill Newton 2506f95f3850SWill Newton do { 2507f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2508f9c2a0dcSSeungwon Jeon goto done; 2509f95f3850SWill Newton 25104225fc85SImre Deak host->sg = sg_miter->piter.sg; 2511f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2512f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2513f9c2a0dcSSeungwon Jeon offset = 0; 2514f9c2a0dcSSeungwon Jeon 2515f9c2a0dcSSeungwon Jeon do { 2516f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 2517f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 2518f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 2519f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2520f9c2a0dcSSeungwon Jeon if (!len) 2521f9c2a0dcSSeungwon Jeon break; 2522f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 25233e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2524f95f3850SWill Newton offset += len; 2525f9c2a0dcSSeungwon Jeon remain -= len; 2526f9c2a0dcSSeungwon Jeon } while (remain); 2527f95f3850SWill Newton 2528e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2529f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2530f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2531f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 2532f9c2a0dcSSeungwon Jeon 2533f9c2a0dcSSeungwon Jeon if (!remain) { 2534f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2535f9c2a0dcSSeungwon Jeon goto done; 2536f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2537f9c2a0dcSSeungwon Jeon } 2538f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2539f95f3850SWill Newton return; 2540f95f3850SWill Newton 2541f95f3850SWill Newton done: 2542f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2543f9c2a0dcSSeungwon Jeon host->sg = NULL; 25440e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2545f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2546f95f3850SWill Newton } 2547f95f3850SWill Newton 2548f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 2549f95f3850SWill Newton { 2550f95f3850SWill Newton if (!host->cmd_status) 2551f95f3850SWill Newton host->cmd_status = status; 2552f95f3850SWill Newton 25530e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2554f95f3850SWill Newton 2555f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2556f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2557f95f3850SWill Newton } 2558f95f3850SWill Newton 25596130e7a9SDoug Anderson static void dw_mci_handle_cd(struct dw_mci *host) 25606130e7a9SDoug Anderson { 25616130e7a9SDoug Anderson int i; 25626130e7a9SDoug Anderson 25636130e7a9SDoug Anderson for (i = 0; i < host->num_slots; i++) { 25646130e7a9SDoug Anderson struct dw_mci_slot *slot = host->slot[i]; 25656130e7a9SDoug Anderson 25666130e7a9SDoug Anderson if (!slot) 25676130e7a9SDoug Anderson continue; 25686130e7a9SDoug Anderson 25696130e7a9SDoug Anderson if (slot->mmc->ops->card_event) 25706130e7a9SDoug Anderson slot->mmc->ops->card_event(slot->mmc); 25716130e7a9SDoug Anderson mmc_detect_change(slot->mmc, 25726130e7a9SDoug Anderson msecs_to_jiffies(host->pdata->detect_delay_ms)); 25736130e7a9SDoug Anderson } 25746130e7a9SDoug Anderson } 25756130e7a9SDoug Anderson 2576f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 2577f95f3850SWill Newton { 2578f95f3850SWill Newton struct dw_mci *host = dev_id; 2579182c9081SSeungwon Jeon u32 pending; 25801a5c8e1fSShashidhar Hiremath int i; 2581f95f3850SWill Newton 2582f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 2583f95f3850SWill Newton 2584476d79f1SDoug Anderson if (pending) { 258501730558SDoug Anderson /* Check volt switch first, since it can look like an error */ 258601730558SDoug Anderson if ((host->state == STATE_SENDING_CMD11) && 258701730558SDoug Anderson (pending & SDMMC_INT_VOLT_SWITCH)) { 258849ba0302SDoug Anderson unsigned long irqflags; 25895c935165SDoug Anderson 259001730558SDoug Anderson mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); 259101730558SDoug Anderson pending &= ~SDMMC_INT_VOLT_SWITCH; 259249ba0302SDoug Anderson 259349ba0302SDoug Anderson /* 259449ba0302SDoug Anderson * Hold the lock; we know cmd11_timer can't be kicked 259549ba0302SDoug Anderson * off after the lock is released, so safe to delete. 259649ba0302SDoug Anderson */ 259749ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 259801730558SDoug Anderson dw_mci_cmd_interrupt(host, pending); 259949ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 260049ba0302SDoug Anderson 260149ba0302SDoug Anderson del_timer(&host->cmd11_timer); 260201730558SDoug Anderson } 260301730558SDoug Anderson 2604f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 2605f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 2606182c9081SSeungwon Jeon host->cmd_status = pending; 26070e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2608f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2609f95f3850SWill Newton } 2610f95f3850SWill Newton 2611f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 2612f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 2613f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 2614182c9081SSeungwon Jeon host->data_status = pending; 26150e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2616f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 2617f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2618f95f3850SWill Newton } 2619f95f3850SWill Newton 2620f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 262157e10486SAddy Ke del_timer(&host->dto_timer); 262257e10486SAddy Ke 2623f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 2624f95f3850SWill Newton if (!host->data_status) 2625182c9081SSeungwon Jeon host->data_status = pending; 26260e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2627f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 2628f95f3850SWill Newton if (host->sg != NULL) 262987a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 2630f95f3850SWill Newton } 2631f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 2632f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2633f95f3850SWill Newton } 2634f95f3850SWill Newton 2635f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 2636f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 2637b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 263887a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 2639f95f3850SWill Newton } 2640f95f3850SWill Newton 2641f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 2642f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2643b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 2644f95f3850SWill Newton dw_mci_write_data_pio(host); 2645f95f3850SWill Newton } 2646f95f3850SWill Newton 2647f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 2648f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 2649182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 2650f95f3850SWill Newton } 2651f95f3850SWill Newton 2652f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 2653f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 26546130e7a9SDoug Anderson dw_mci_handle_cd(host); 2655f95f3850SWill Newton } 2656f95f3850SWill Newton 26571a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 26581a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 26591a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 2660ed2540efSDoug Anderson 2661ed2540efSDoug Anderson if (!slot) 2662ed2540efSDoug Anderson continue; 2663ed2540efSDoug Anderson 266476756234SAddy Ke if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { 266576756234SAddy Ke mci_writel(host, RINTSTS, 266676756234SAddy Ke SDMMC_INT_SDIO(slot->sdio_id)); 26671a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 26681a5c8e1fSShashidhar Hiremath } 26691a5c8e1fSShashidhar Hiremath } 26701a5c8e1fSShashidhar Hiremath 26711fb5f68aSMarkos Chandras } 2672f95f3850SWill Newton 26733fc7eaefSShawn Lin if (host->use_dma != TRANS_MODE_IDMAC) 26743fc7eaefSShawn Lin return IRQ_HANDLED; 26753fc7eaefSShawn Lin 26763fc7eaefSShawn Lin /* Handle IDMA interrupts */ 267769d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 267869d99fdcSPrabu Thangamuthu pending = mci_readl(host, IDSTS64); 267969d99fdcSPrabu Thangamuthu if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 268069d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | 268169d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 268269d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); 2683faecf411SShawn Lin if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) 26843fc7eaefSShawn Lin host->dma_ops->complete((void *)host); 268569d99fdcSPrabu Thangamuthu } 268669d99fdcSPrabu Thangamuthu } else { 2687f95f3850SWill Newton pending = mci_readl(host, IDSTS); 2688f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 268969d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | 269069d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 2691f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 2692faecf411SShawn Lin if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) 26933fc7eaefSShawn Lin host->dma_ops->complete((void *)host); 2694f95f3850SWill Newton } 269569d99fdcSPrabu Thangamuthu } 2696f95f3850SWill Newton 2697f95f3850SWill Newton return IRQ_HANDLED; 2698f95f3850SWill Newton } 2699f95f3850SWill Newton 270036c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2701f95f3850SWill Newton { 2702f95f3850SWill Newton struct mmc_host *mmc; 2703f95f3850SWill Newton struct dw_mci_slot *slot; 2704e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2705800d78bfSThomas Abraham int ctrl_id, ret; 27061f44a2a5SSeungwon Jeon u32 freq[2]; 2707f95f3850SWill Newton 27084a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2709f95f3850SWill Newton if (!mmc) 2710f95f3850SWill Newton return -ENOMEM; 2711f95f3850SWill Newton 2712f95f3850SWill Newton slot = mmc_priv(mmc); 2713f95f3850SWill Newton slot->id = id; 271476756234SAddy Ke slot->sdio_id = host->sdio_id0 + id; 2715f95f3850SWill Newton slot->mmc = mmc; 2716f95f3850SWill Newton slot->host = host; 2717c91eab4bSThomas Abraham host->slot[id] = slot; 2718f95f3850SWill Newton 2719f95f3850SWill Newton mmc->ops = &dw_mci_ops; 27201f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 27211f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 27221f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 27231f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 27241f44a2a5SSeungwon Jeon } else { 2725b023030fSJaehoon Chung dev_info(host->dev, 2726b023030fSJaehoon Chung "'clock-freq-min-max' property was deprecated.\n"); 27271f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 27281f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 27291f44a2a5SSeungwon Jeon } 2730f95f3850SWill Newton 273151da2240SYuvaraj CD /*if there are external regulators, get them*/ 273251da2240SYuvaraj CD ret = mmc_regulator_get_supply(mmc); 273351da2240SYuvaraj CD if (ret == -EPROBE_DEFER) 27343cf890fcSDoug Anderson goto err_host_allocated; 273551da2240SYuvaraj CD 273651da2240SYuvaraj CD if (!mmc->ocr_avail) 2737f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2738f95f3850SWill Newton 2739fc3d7720SJaehoon Chung if (host->pdata->caps) 2740fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2741fc3d7720SJaehoon Chung 27426024e166SJaehoon Chung /* 27436024e166SJaehoon Chung * Support MMC_CAP_ERASE by default. 27446024e166SJaehoon Chung * It needs to use trim/discard/erase commands. 27456024e166SJaehoon Chung */ 27466024e166SJaehoon Chung mmc->caps |= MMC_CAP_ERASE; 27476024e166SJaehoon Chung 2748ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2749ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2750ab269128SAbhilash Kesavan 2751800d78bfSThomas Abraham if (host->dev->of_node) { 2752800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2753800d78bfSThomas Abraham if (ctrl_id < 0) 2754800d78bfSThomas Abraham ctrl_id = 0; 2755800d78bfSThomas Abraham } else { 2756800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2757800d78bfSThomas Abraham } 2758cb27a843SJames Hogan if (drv_data && drv_data->caps) 2759cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2760800d78bfSThomas Abraham 27614f408cc6SSeungwon Jeon if (host->pdata->caps2) 27624f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 27634f408cc6SSeungwon Jeon 27643cf890fcSDoug Anderson ret = mmc_of_parse(mmc); 27653cf890fcSDoug Anderson if (ret) 27663cf890fcSDoug Anderson goto err_host_allocated; 2767f95f3850SWill Newton 2768f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 27693fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) { 2770a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2771225faf87SJaehoon Chung mmc->max_blk_size = 65535; 2772575c319dSHeiko Stuebner mmc->max_seg_size = 0x1000; 27731a25b1b4SSeungwon Jeon mmc->max_req_size = mmc->max_seg_size * host->ring_size; 27741a25b1b4SSeungwon Jeon mmc->max_blk_count = mmc->max_req_size / 512; 27753fc7eaefSShawn Lin } else if (host->use_dma == TRANS_MODE_EDMAC) { 27763fc7eaefSShawn Lin mmc->max_segs = 64; 2777225faf87SJaehoon Chung mmc->max_blk_size = 65535; 27783fc7eaefSShawn Lin mmc->max_blk_count = 65535; 27793fc7eaefSShawn Lin mmc->max_req_size = 27803fc7eaefSShawn Lin mmc->max_blk_size * mmc->max_blk_count; 27813fc7eaefSShawn Lin mmc->max_seg_size = mmc->max_req_size; 2782575c319dSHeiko Stuebner } else { 27833fc7eaefSShawn Lin /* TRANS_MODE_PIO */ 2784f95f3850SWill Newton mmc->max_segs = 64; 2785225faf87SJaehoon Chung mmc->max_blk_size = 65535; /* BLKSIZ is 16 bits */ 2786f95f3850SWill Newton mmc->max_blk_count = 512; 2787575c319dSHeiko Stuebner mmc->max_req_size = mmc->max_blk_size * 2788575c319dSHeiko Stuebner mmc->max_blk_count; 2789f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2790575c319dSHeiko Stuebner } 2791f95f3850SWill Newton 2792c0834a58SShawn Lin dw_mci_get_cd(mmc); 2793ae0eb348SJaehoon Chung 27940cea529dSJaehoon Chung ret = mmc_add_host(mmc); 27950cea529dSJaehoon Chung if (ret) 27963cf890fcSDoug Anderson goto err_host_allocated; 2797f95f3850SWill Newton 2798f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2799f95f3850SWill Newton dw_mci_init_debugfs(slot); 2800f95f3850SWill Newton #endif 2801f95f3850SWill Newton 2802f95f3850SWill Newton return 0; 2803800d78bfSThomas Abraham 28043cf890fcSDoug Anderson err_host_allocated: 2805800d78bfSThomas Abraham mmc_free_host(mmc); 280651da2240SYuvaraj CD return ret; 2807f95f3850SWill Newton } 2808f95f3850SWill Newton 2809f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2810f95f3850SWill Newton { 2811f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2812f95f3850SWill Newton mmc_remove_host(slot->mmc); 2813f95f3850SWill Newton slot->host->slot[id] = NULL; 2814f95f3850SWill Newton mmc_free_host(slot->mmc); 2815f95f3850SWill Newton } 2816f95f3850SWill Newton 2817f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2818f95f3850SWill Newton { 281969d99fdcSPrabu Thangamuthu int addr_config; 28203fc7eaefSShawn Lin struct device *dev = host->dev; 28213fc7eaefSShawn Lin struct device_node *np = dev->of_node; 28223fc7eaefSShawn Lin 28233fc7eaefSShawn Lin /* 28243fc7eaefSShawn Lin * Check tansfer mode from HCON[17:16] 28253fc7eaefSShawn Lin * Clear the ambiguous description of dw_mmc databook: 28263fc7eaefSShawn Lin * 2b'00: No DMA Interface -> Actually means using Internal DMA block 28273fc7eaefSShawn Lin * 2b'01: DesignWare DMA Interface -> Synopsys DW-DMA block 28283fc7eaefSShawn Lin * 2b'10: Generic DMA Interface -> non-Synopsys generic DMA block 28293fc7eaefSShawn Lin * 2b'11: Non DW DMA Interface -> pio only 28303fc7eaefSShawn Lin * Compared to DesignWare DMA Interface, Generic DMA Interface has a 28313fc7eaefSShawn Lin * simpler request/acknowledge handshake mechanism and both of them 28323fc7eaefSShawn Lin * are regarded as external dma master for dw_mmc. 28333fc7eaefSShawn Lin */ 28343fc7eaefSShawn Lin host->use_dma = SDMMC_GET_TRANS_MODE(mci_readl(host, HCON)); 28353fc7eaefSShawn Lin if (host->use_dma == DMA_INTERFACE_IDMA) { 28363fc7eaefSShawn Lin host->use_dma = TRANS_MODE_IDMAC; 28373fc7eaefSShawn Lin } else if (host->use_dma == DMA_INTERFACE_DWDMA || 28383fc7eaefSShawn Lin host->use_dma == DMA_INTERFACE_GDMA) { 28393fc7eaefSShawn Lin host->use_dma = TRANS_MODE_EDMAC; 28403fc7eaefSShawn Lin } else { 28413fc7eaefSShawn Lin goto no_dma; 28423fc7eaefSShawn Lin } 28433fc7eaefSShawn Lin 28443fc7eaefSShawn Lin /* Determine which DMA interface to use */ 28453fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) { 28463fc7eaefSShawn Lin /* 28473fc7eaefSShawn Lin * Check ADDR_CONFIG bit in HCON to find 28483fc7eaefSShawn Lin * IDMAC address bus width 28493fc7eaefSShawn Lin */ 285070692752SShawn Lin addr_config = SDMMC_GET_ADDR_CONFIG(mci_readl(host, HCON)); 285169d99fdcSPrabu Thangamuthu 285269d99fdcSPrabu Thangamuthu if (addr_config == 1) { 285369d99fdcSPrabu Thangamuthu /* host supports IDMAC in 64-bit address mode */ 285469d99fdcSPrabu Thangamuthu host->dma_64bit_address = 1; 28553fc7eaefSShawn Lin dev_info(host->dev, 28563fc7eaefSShawn Lin "IDMAC supports 64-bit address mode.\n"); 285769d99fdcSPrabu Thangamuthu if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) 28583fc7eaefSShawn Lin dma_set_coherent_mask(host->dev, 28593fc7eaefSShawn Lin DMA_BIT_MASK(64)); 286069d99fdcSPrabu Thangamuthu } else { 286169d99fdcSPrabu Thangamuthu /* host supports IDMAC in 32-bit address mode */ 286269d99fdcSPrabu Thangamuthu host->dma_64bit_address = 0; 28633fc7eaefSShawn Lin dev_info(host->dev, 28643fc7eaefSShawn Lin "IDMAC supports 32-bit address mode.\n"); 286569d99fdcSPrabu Thangamuthu } 286669d99fdcSPrabu Thangamuthu 2867f95f3850SWill Newton /* Alloc memory for sg translation */ 2868cc190d4cSShawn Lin host->sg_cpu = dmam_alloc_coherent(host->dev, 2869cc190d4cSShawn Lin DESC_RING_BUF_SZ, 2870f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2871f95f3850SWill Newton if (!host->sg_cpu) { 28723fc7eaefSShawn Lin dev_err(host->dev, 28733fc7eaefSShawn Lin "%s: could not alloc DMA memory\n", 2874f95f3850SWill Newton __func__); 2875f95f3850SWill Newton goto no_dma; 2876f95f3850SWill Newton } 2877f95f3850SWill Newton 2878f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 287900956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 28803fc7eaefSShawn Lin } else { 28813fc7eaefSShawn Lin /* TRANS_MODE_EDMAC: check dma bindings again */ 28823fc7eaefSShawn Lin if ((of_property_count_strings(np, "dma-names") < 0) || 28833fc7eaefSShawn Lin (!of_find_property(np, "dmas", NULL))) { 2884f95f3850SWill Newton goto no_dma; 28853fc7eaefSShawn Lin } 28863fc7eaefSShawn Lin host->dma_ops = &dw_mci_edmac_ops; 28873fc7eaefSShawn Lin dev_info(host->dev, "Using external DMA controller.\n"); 28883fc7eaefSShawn Lin } 2889f95f3850SWill Newton 2890e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2891e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2892f95f3850SWill Newton if (host->dma_ops->init(host)) { 28930e3a22c0SShawn Lin dev_err(host->dev, "%s: Unable to initialize DMA Controller.\n", 28940e3a22c0SShawn Lin __func__); 2895f95f3850SWill Newton goto no_dma; 2896f95f3850SWill Newton } 2897f95f3850SWill Newton } else { 28984a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2899f95f3850SWill Newton goto no_dma; 2900f95f3850SWill Newton } 2901f95f3850SWill Newton 2902f95f3850SWill Newton return; 2903f95f3850SWill Newton 2904f95f3850SWill Newton no_dma: 29054a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 29063fc7eaefSShawn Lin host->use_dma = TRANS_MODE_PIO; 2907f95f3850SWill Newton } 2908f95f3850SWill Newton 29095c935165SDoug Anderson static void dw_mci_cmd11_timer(unsigned long arg) 29105c935165SDoug Anderson { 29115c935165SDoug Anderson struct dw_mci *host = (struct dw_mci *)arg; 29125c935165SDoug Anderson 2913fd674198SDoug Anderson if (host->state != STATE_SENDING_CMD11) { 2914fd674198SDoug Anderson dev_warn(host->dev, "Unexpected CMD11 timeout\n"); 2915fd674198SDoug Anderson return; 2916fd674198SDoug Anderson } 29175c935165SDoug Anderson 29185c935165SDoug Anderson host->cmd_status = SDMMC_INT_RTO; 29195c935165SDoug Anderson set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 29205c935165SDoug Anderson tasklet_schedule(&host->tasklet); 29215c935165SDoug Anderson } 29225c935165SDoug Anderson 292357e10486SAddy Ke static void dw_mci_dto_timer(unsigned long arg) 292457e10486SAddy Ke { 292557e10486SAddy Ke struct dw_mci *host = (struct dw_mci *)arg; 292657e10486SAddy Ke 292757e10486SAddy Ke switch (host->state) { 292857e10486SAddy Ke case STATE_SENDING_DATA: 292957e10486SAddy Ke case STATE_DATA_BUSY: 293057e10486SAddy Ke /* 293157e10486SAddy Ke * If DTO interrupt does NOT come in sending data state, 293257e10486SAddy Ke * we should notify the driver to terminate current transfer 293357e10486SAddy Ke * and report a data timeout to the core. 293457e10486SAddy Ke */ 293557e10486SAddy Ke host->data_status = SDMMC_INT_DRTO; 293657e10486SAddy Ke set_bit(EVENT_DATA_ERROR, &host->pending_events); 293757e10486SAddy Ke set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 293857e10486SAddy Ke tasklet_schedule(&host->tasklet); 293957e10486SAddy Ke break; 294057e10486SAddy Ke default: 294157e10486SAddy Ke break; 294257e10486SAddy Ke } 294357e10486SAddy Ke } 294457e10486SAddy Ke 2945c91eab4bSThomas Abraham #ifdef CONFIG_OF 2946c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2947c91eab4bSThomas Abraham { 2948c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2949c91eab4bSThomas Abraham struct device *dev = host->dev; 2950c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2951e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2952e8cc37b8SShawn Lin int ret; 29533c6d89eaSDoug Anderson u32 clock_frequency; 2954c91eab4bSThomas Abraham 2955c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2956bf3707eaSBeomho Seo if (!pdata) 2957c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2958c91eab4bSThomas Abraham 2959d6786fefSGuodong Xu /* find reset controller when exist */ 29603a667e3fSJaehoon Chung pdata->rstc = devm_reset_control_get_optional(dev, "reset"); 2961d6786fefSGuodong Xu if (IS_ERR(pdata->rstc)) { 2962d6786fefSGuodong Xu if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER) 2963d6786fefSGuodong Xu return ERR_PTR(-EPROBE_DEFER); 2964d6786fefSGuodong Xu } 2965d6786fefSGuodong Xu 2966c91eab4bSThomas Abraham /* find out number of slots supported */ 29678a629d26SShawn Lin of_property_read_u32(np, "num-slots", &pdata->num_slots); 2968c91eab4bSThomas Abraham 2969c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 29700e3a22c0SShawn Lin dev_info(dev, 29710e3a22c0SShawn Lin "fifo-depth property not found, using value of FIFOTH register as default\n"); 2972c91eab4bSThomas Abraham 2973c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2974c91eab4bSThomas Abraham 2975a0361c1aSJun Nie of_property_read_u32(np, "data-addr", &host->data_addr_override); 2976a0361c1aSJun Nie 2977d6fced83SJun Nie if (of_get_property(np, "fifo-watermark-aligned", NULL)) 2978d6fced83SJun Nie host->wm_aligned = true; 2979d6fced83SJun Nie 29803c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 29813c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 29823c6d89eaSDoug Anderson 2983cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2984cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2985800d78bfSThomas Abraham if (ret) 2986800d78bfSThomas Abraham return ERR_PTR(ret); 2987800d78bfSThomas Abraham } 2988800d78bfSThomas Abraham 2989c91eab4bSThomas Abraham return pdata; 2990c91eab4bSThomas Abraham } 2991c91eab4bSThomas Abraham 2992c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2993c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2994c91eab4bSThomas Abraham { 2995c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2996c91eab4bSThomas Abraham } 2997c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2998c91eab4bSThomas Abraham 2999fa0c3283SDoug Anderson static void dw_mci_enable_cd(struct dw_mci *host) 3000fa0c3283SDoug Anderson { 3001fa0c3283SDoug Anderson unsigned long irqflags; 3002fa0c3283SDoug Anderson u32 temp; 3003fa0c3283SDoug Anderson int i; 3004e8cc37b8SShawn Lin struct dw_mci_slot *slot; 3005fa0c3283SDoug Anderson 3006e8cc37b8SShawn Lin /* 3007e8cc37b8SShawn Lin * No need for CD if all slots have a non-error GPIO 3008e8cc37b8SShawn Lin * as well as broken card detection is found. 3009e8cc37b8SShawn Lin */ 3010fa0c3283SDoug Anderson for (i = 0; i < host->num_slots; i++) { 3011e8cc37b8SShawn Lin slot = host->slot[i]; 3012e8cc37b8SShawn Lin if (slot->mmc->caps & MMC_CAP_NEEDS_POLL) 3013e8cc37b8SShawn Lin return; 3014fa0c3283SDoug Anderson 3015287980e4SArnd Bergmann if (mmc_gpio_get_cd(slot->mmc) < 0) 3016fa0c3283SDoug Anderson break; 3017fa0c3283SDoug Anderson } 3018fa0c3283SDoug Anderson if (i == host->num_slots) 3019fa0c3283SDoug Anderson return; 3020fa0c3283SDoug Anderson 3021fa0c3283SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 3022fa0c3283SDoug Anderson temp = mci_readl(host, INTMASK); 3023fa0c3283SDoug Anderson temp |= SDMMC_INT_CD; 3024fa0c3283SDoug Anderson mci_writel(host, INTMASK, temp); 3025fa0c3283SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 3026fa0c3283SDoug Anderson } 3027fa0c3283SDoug Anderson 302862ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 3029f95f3850SWill Newton { 3030e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 303162ca8034SShashidhar Hiremath int width, i, ret = 0; 3032f95f3850SWill Newton u32 fifo_size; 30331c2215b7SThomas Abraham int init_slots = 0; 3034f95f3850SWill Newton 3035c91eab4bSThomas Abraham if (!host->pdata) { 3036c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 3037d6786fefSGuodong Xu if (PTR_ERR(host->pdata) == -EPROBE_DEFER) { 3038d6786fefSGuodong Xu return -EPROBE_DEFER; 3039d6786fefSGuodong Xu } else if (IS_ERR(host->pdata)) { 3040c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 3041c91eab4bSThomas Abraham return -EINVAL; 3042c91eab4bSThomas Abraham } 3043f95f3850SWill Newton } 3044f95f3850SWill Newton 3045780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 3046f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 3047f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 3048f90a0612SThomas Abraham } else { 3049f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 3050f90a0612SThomas Abraham if (ret) { 3051f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 3052f90a0612SThomas Abraham return ret; 3053f90a0612SThomas Abraham } 3054f95f3850SWill Newton } 3055f95f3850SWill Newton 3056780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 3057f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 3058f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 30593c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 3060f90a0612SThomas Abraham } else { 3061f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 3062f90a0612SThomas Abraham if (ret) { 3063f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 3064f90a0612SThomas Abraham goto err_clk_biu; 3065f90a0612SThomas Abraham } 3066f90a0612SThomas Abraham 30673c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 30683c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 30693c6d89eaSDoug Anderson if (ret) 30703c6d89eaSDoug Anderson dev_warn(host->dev, 3071612de4c1SJaehoon Chung "Unable to set bus rate to %uHz\n", 30723c6d89eaSDoug Anderson host->pdata->bus_hz); 30733c6d89eaSDoug Anderson } 3074f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 30753c6d89eaSDoug Anderson } 3076f90a0612SThomas Abraham 3077612de4c1SJaehoon Chung if (!host->bus_hz) { 3078612de4c1SJaehoon Chung dev_err(host->dev, 3079612de4c1SJaehoon Chung "Platform data must supply bus speed\n"); 3080612de4c1SJaehoon Chung ret = -ENODEV; 3081612de4c1SJaehoon Chung goto err_clk_ciu; 3082612de4c1SJaehoon Chung } 3083612de4c1SJaehoon Chung 3084002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 3085002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 3086002f0d5cSYuvaraj Kumar C D if (ret) { 3087002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 3088002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 3089002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 3090002f0d5cSYuvaraj Kumar C D } 3091002f0d5cSYuvaraj Kumar C D } 3092002f0d5cSYuvaraj Kumar C D 3093d6786fefSGuodong Xu if (!IS_ERR(host->pdata->rstc)) { 3094d6786fefSGuodong Xu reset_control_assert(host->pdata->rstc); 3095d6786fefSGuodong Xu usleep_range(10, 50); 3096d6786fefSGuodong Xu reset_control_deassert(host->pdata->rstc); 3097d6786fefSGuodong Xu } 3098d6786fefSGuodong Xu 30995c935165SDoug Anderson setup_timer(&host->cmd11_timer, 31005c935165SDoug Anderson dw_mci_cmd11_timer, (unsigned long)host); 31015c935165SDoug Anderson 310257e10486SAddy Ke setup_timer(&host->dto_timer, 310357e10486SAddy Ke dw_mci_dto_timer, (unsigned long)host); 310457e10486SAddy Ke 3105f95f3850SWill Newton spin_lock_init(&host->lock); 3106f8c58c11SDoug Anderson spin_lock_init(&host->irq_lock); 3107f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 3108f95f3850SWill Newton 3109f95f3850SWill Newton /* 3110f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 3111f95f3850SWill Newton * the correct values. 3112f95f3850SWill Newton */ 311370692752SShawn Lin i = SDMMC_GET_HDATA_WIDTH(mci_readl(host, HCON)); 3114f95f3850SWill Newton if (!i) { 3115f95f3850SWill Newton host->push_data = dw_mci_push_data16; 3116f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 3117f95f3850SWill Newton width = 16; 3118f95f3850SWill Newton host->data_shift = 1; 3119f95f3850SWill Newton } else if (i == 2) { 3120f95f3850SWill Newton host->push_data = dw_mci_push_data64; 3121f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 3122f95f3850SWill Newton width = 64; 3123f95f3850SWill Newton host->data_shift = 3; 3124f95f3850SWill Newton } else { 3125f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 3126f95f3850SWill Newton WARN((i != 1), 3127f95f3850SWill Newton "HCON reports a reserved host data width!\n" 3128f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 3129f95f3850SWill Newton host->push_data = dw_mci_push_data32; 3130f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 3131f95f3850SWill Newton width = 32; 3132f95f3850SWill Newton host->data_shift = 2; 3133f95f3850SWill Newton } 3134f95f3850SWill Newton 3135f95f3850SWill Newton /* Reset all blocks */ 31363744415cSShawn Lin if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 31373744415cSShawn Lin ret = -ENODEV; 31383744415cSShawn Lin goto err_clk_ciu; 31393744415cSShawn Lin } 3140141a712aSSeungwon Jeon 3141141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 3142141a712aSSeungwon Jeon dw_mci_init_dma(host); 3143f95f3850SWill Newton 3144f95f3850SWill Newton /* Clear the interrupts for the host controller */ 3145f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 3146f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 3147f95f3850SWill Newton 3148f95f3850SWill Newton /* Put in max timeout */ 3149f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 3150f95f3850SWill Newton 3151f95f3850SWill Newton /* 3152f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 3153f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 3154f95f3850SWill Newton */ 3155b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 3156b86d8253SJames Hogan /* 3157b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 3158b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 3159b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 3160b86d8253SJames Hogan * should put it in the platform data. 3161b86d8253SJames Hogan */ 3162f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 31638234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 3164b86d8253SJames Hogan } else { 3165b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 3166b86d8253SJames Hogan } 3167b86d8253SJames Hogan host->fifo_depth = fifo_size; 316852426899SSeungwon Jeon host->fifoth_val = 316952426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 3170e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 3171f95f3850SWill Newton 3172f95f3850SWill Newton /* disable clock to CIU */ 3173f95f3850SWill Newton mci_writel(host, CLKENA, 0); 3174f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 3175f95f3850SWill Newton 317663008768SJames Hogan /* 317763008768SJames Hogan * In 2.40a spec, Data offset is changed. 317863008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 317963008768SJames Hogan */ 318063008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 318163008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 318263008768SJames Hogan 3183a0361c1aSJun Nie if (host->data_addr_override) 3184a0361c1aSJun Nie host->fifo_reg = host->regs + host->data_addr_override; 3185a0361c1aSJun Nie else if (host->verid < DW_MMC_240A) 318676184ac1SBen Dooks host->fifo_reg = host->regs + DATA_OFFSET; 318763008768SJames Hogan else 318876184ac1SBen Dooks host->fifo_reg = host->regs + DATA_240A_OFFSET; 318963008768SJames Hogan 3190f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 3191780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 3192780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 3193f95f3850SWill Newton if (ret) 31946130e7a9SDoug Anderson goto err_dmaunmap; 3195f95f3850SWill Newton 3196f95f3850SWill Newton if (host->pdata->num_slots) 3197f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 3198f95f3850SWill Newton else 31998a629d26SShawn Lin host->num_slots = 1; 32008a629d26SShawn Lin 32018a629d26SShawn Lin if (host->num_slots < 1 || 32028a629d26SShawn Lin host->num_slots > SDMMC_GET_SLOT_NUM(mci_readl(host, HCON))) { 32038a629d26SShawn Lin dev_err(host->dev, 32048a629d26SShawn Lin "Platform data must supply correct num_slots.\n"); 32058a629d26SShawn Lin ret = -ENODEV; 32068a629d26SShawn Lin goto err_clk_ciu; 32078a629d26SShawn Lin } 3208f95f3850SWill Newton 32092da1d7f2SYuvaraj CD /* 3210fa0c3283SDoug Anderson * Enable interrupts for command done, data over, data empty, 32112da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 32122da1d7f2SYuvaraj CD */ 32132da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 32142da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 3215fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 32160e3a22c0SShawn Lin /* Enable mci interrupt */ 32170e3a22c0SShawn Lin mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 32182da1d7f2SYuvaraj CD 32190e3a22c0SShawn Lin dev_info(host->dev, 32200e3a22c0SShawn Lin "DW MMC controller at irq %d,%d bit host data width,%u deep fifo\n", 32212da1d7f2SYuvaraj CD host->irq, width, fifo_size); 32222da1d7f2SYuvaraj CD 3223f95f3850SWill Newton /* We need at least one slot to succeed */ 3224f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 3225f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 32261c2215b7SThomas Abraham if (ret) 32271c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 32281c2215b7SThomas Abraham else 32291c2215b7SThomas Abraham init_slots++; 3230f95f3850SWill Newton } 32311c2215b7SThomas Abraham 32321c2215b7SThomas Abraham if (init_slots) { 32331c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 32341c2215b7SThomas Abraham } else { 32350e3a22c0SShawn Lin dev_dbg(host->dev, 32360e3a22c0SShawn Lin "attempted to initialize %d slots, but failed on all\n", 32370e3a22c0SShawn Lin host->num_slots); 32386130e7a9SDoug Anderson goto err_dmaunmap; 3239f95f3850SWill Newton } 3240f95f3850SWill Newton 3241b793f658SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3242b793f658SDoug Anderson dw_mci_enable_cd(host); 3243b793f658SDoug Anderson 3244f95f3850SWill Newton return 0; 3245f95f3850SWill Newton 3246f95f3850SWill Newton err_dmaunmap: 3247f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3248f95f3850SWill Newton host->dma_ops->exit(host); 3249f90a0612SThomas Abraham 3250d6786fefSGuodong Xu if (!IS_ERR(host->pdata->rstc)) 3251d6786fefSGuodong Xu reset_control_assert(host->pdata->rstc); 3252d6786fefSGuodong Xu 3253f90a0612SThomas Abraham err_clk_ciu: 3254f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3255780f22afSSeungwon Jeon 3256f90a0612SThomas Abraham err_clk_biu: 3257f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3258780f22afSSeungwon Jeon 3259f95f3850SWill Newton return ret; 3260f95f3850SWill Newton } 326162ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 3262f95f3850SWill Newton 326362ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 3264f95f3850SWill Newton { 3265f95f3850SWill Newton int i; 3266f95f3850SWill Newton 3267f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 32684a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 3269f95f3850SWill Newton if (host->slot[i]) 3270f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 3271f95f3850SWill Newton } 3272f95f3850SWill Newton 3273048fd7e6SPrabu Thangamuthu mci_writel(host, RINTSTS, 0xFFFFFFFF); 3274048fd7e6SPrabu Thangamuthu mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 3275048fd7e6SPrabu Thangamuthu 3276f95f3850SWill Newton /* disable clock to CIU */ 3277f95f3850SWill Newton mci_writel(host, CLKENA, 0); 3278f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 3279f95f3850SWill Newton 3280f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3281f95f3850SWill Newton host->dma_ops->exit(host); 3282f95f3850SWill Newton 3283d6786fefSGuodong Xu if (!IS_ERR(host->pdata->rstc)) 3284d6786fefSGuodong Xu reset_control_assert(host->pdata->rstc); 3285d6786fefSGuodong Xu 3286f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3287f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3288f95f3850SWill Newton } 328962ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 329062ca8034SShashidhar Hiremath 329162ca8034SShashidhar Hiremath 3292f95f3850SWill Newton 3293e9ed8835SShawn Lin #ifdef CONFIG_PM 3294ed24e1ffSShawn Lin int dw_mci_runtime_suspend(struct device *dev) 3295f95f3850SWill Newton { 3296ed24e1ffSShawn Lin struct dw_mci *host = dev_get_drvdata(dev); 3297ed24e1ffSShawn Lin 32983fc7eaefSShawn Lin if (host->use_dma && host->dma_ops->exit) 32993fc7eaefSShawn Lin host->dma_ops->exit(host); 33003fc7eaefSShawn Lin 3301ed24e1ffSShawn Lin clk_disable_unprepare(host->ciu_clk); 3302ed24e1ffSShawn Lin 3303ed24e1ffSShawn Lin if (host->cur_slot && 3304ed24e1ffSShawn Lin (mmc_can_gpio_cd(host->cur_slot->mmc) || 3305ed24e1ffSShawn Lin !mmc_card_is_removable(host->cur_slot->mmc))) 3306ed24e1ffSShawn Lin clk_disable_unprepare(host->biu_clk); 3307ed24e1ffSShawn Lin 3308f95f3850SWill Newton return 0; 3309f95f3850SWill Newton } 3310ed24e1ffSShawn Lin EXPORT_SYMBOL(dw_mci_runtime_suspend); 3311f95f3850SWill Newton 3312ed24e1ffSShawn Lin int dw_mci_runtime_resume(struct device *dev) 3313f95f3850SWill Newton { 3314ed24e1ffSShawn Lin int i, ret = 0; 3315ed24e1ffSShawn Lin struct dw_mci *host = dev_get_drvdata(dev); 3316f95f3850SWill Newton 3317ed24e1ffSShawn Lin if (host->cur_slot && 3318ed24e1ffSShawn Lin (mmc_can_gpio_cd(host->cur_slot->mmc) || 3319ed24e1ffSShawn Lin !mmc_card_is_removable(host->cur_slot->mmc))) { 3320ed24e1ffSShawn Lin ret = clk_prepare_enable(host->biu_clk); 3321ed24e1ffSShawn Lin if (ret) 3322e61cf118SJaehoon Chung return ret; 3323e61cf118SJaehoon Chung } 3324e61cf118SJaehoon Chung 3325ed24e1ffSShawn Lin ret = clk_prepare_enable(host->ciu_clk); 3326ed24e1ffSShawn Lin if (ret) 3327df9bcc2bSJoonyoung Shim goto err; 3328df9bcc2bSJoonyoung Shim 3329df9bcc2bSJoonyoung Shim if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 3330df9bcc2bSJoonyoung Shim clk_disable_unprepare(host->ciu_clk); 3331df9bcc2bSJoonyoung Shim ret = -ENODEV; 3332df9bcc2bSJoonyoung Shim goto err; 3333df9bcc2bSJoonyoung Shim } 3334ed24e1ffSShawn Lin 33353bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 3336141a712aSSeungwon Jeon host->dma_ops->init(host); 3337141a712aSSeungwon Jeon 333852426899SSeungwon Jeon /* 333952426899SSeungwon Jeon * Restore the initial value at FIFOTH register 334052426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 334152426899SSeungwon Jeon */ 3342e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 334352426899SSeungwon Jeon host->prev_blksz = 0; 3344e61cf118SJaehoon Chung 33452eb2944fSDoug Anderson /* Put in max timeout */ 33462eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 33472eb2944fSDoug Anderson 3348e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 3349e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 3350e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 3351fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 3352e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 3353e61cf118SJaehoon Chung 3354f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 3355f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 33560e3a22c0SShawn Lin 3357f95f3850SWill Newton if (!slot) 3358f95f3850SWill Newton continue; 3359e9748e03SZiyuan Xu if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) 3360ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 3361e9748e03SZiyuan Xu 3362e9748e03SZiyuan Xu /* Force setup bus to guarantee available clock output */ 3363ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 3364ab269128SAbhilash Kesavan } 3365fa0c3283SDoug Anderson 3366fa0c3283SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3367fa0c3283SDoug Anderson dw_mci_enable_cd(host); 3368fa0c3283SDoug Anderson 3369df9bcc2bSJoonyoung Shim return 0; 3370df9bcc2bSJoonyoung Shim 3371df9bcc2bSJoonyoung Shim err: 3372df9bcc2bSJoonyoung Shim if (host->cur_slot && 3373df9bcc2bSJoonyoung Shim (mmc_can_gpio_cd(host->cur_slot->mmc) || 3374df9bcc2bSJoonyoung Shim !mmc_card_is_removable(host->cur_slot->mmc))) 3375df9bcc2bSJoonyoung Shim clk_disable_unprepare(host->biu_clk); 3376df9bcc2bSJoonyoung Shim 33771f5c51d7SShawn Lin return ret; 33781f5c51d7SShawn Lin } 3379e9ed8835SShawn Lin EXPORT_SYMBOL(dw_mci_runtime_resume); 3380e9ed8835SShawn Lin #endif /* CONFIG_PM */ 33816fe8890dSJaehoon Chung 3382f95f3850SWill Newton static int __init dw_mci_init(void) 3383f95f3850SWill Newton { 33848e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 338562ca8034SShashidhar Hiremath return 0; 3386f95f3850SWill Newton } 3387f95f3850SWill Newton 3388f95f3850SWill Newton static void __exit dw_mci_exit(void) 3389f95f3850SWill Newton { 3390f95f3850SWill Newton } 3391f95f3850SWill Newton 3392f95f3850SWill Newton module_init(dw_mci_init); 3393f95f3850SWill Newton module_exit(dw_mci_exit); 3394f95f3850SWill Newton 3395f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 3396f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 3397f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 3398f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 3399