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> 22f95f3850SWill Newton #include <linux/ioport.h> 23f95f3850SWill Newton #include <linux/module.h> 24f95f3850SWill Newton #include <linux/platform_device.h> 25f95f3850SWill Newton #include <linux/seq_file.h> 26f95f3850SWill Newton #include <linux/slab.h> 27f95f3850SWill Newton #include <linux/stat.h> 28f95f3850SWill Newton #include <linux/delay.h> 29f95f3850SWill Newton #include <linux/irq.h> 30b24c8b26SDoug Anderson #include <linux/mmc/card.h> 31f95f3850SWill Newton #include <linux/mmc/host.h> 32f95f3850SWill Newton #include <linux/mmc/mmc.h> 3301730558SDoug Anderson #include <linux/mmc/sd.h> 3490c2143aSSeungwon Jeon #include <linux/mmc/sdio.h> 35f95f3850SWill Newton #include <linux/mmc/dw_mmc.h> 36f95f3850SWill Newton #include <linux/bitops.h> 37c07946a3SJaehoon Chung #include <linux/regulator/consumer.h> 38c91eab4bSThomas Abraham #include <linux/of.h> 3955a6ceb2SDoug Anderson #include <linux/of_gpio.h> 40bf626e55SZhangfei Gao #include <linux/mmc/slot-gpio.h> 41f95f3850SWill Newton 42f95f3850SWill Newton #include "dw_mmc.h" 43f95f3850SWill Newton 44f95f3850SWill Newton /* Common flag combinations */ 453f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ 46f95f3850SWill Newton SDMMC_INT_HTO | SDMMC_INT_SBE | \ 477a3c5677SDoug Anderson SDMMC_INT_EBE | SDMMC_INT_HLE) 48f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ 497a3c5677SDoug Anderson SDMMC_INT_RESP_ERR | SDMMC_INT_HLE) 50f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ 517a3c5677SDoug Anderson DW_MCI_CMD_ERROR_FLAGS) 52f95f3850SWill Newton #define DW_MCI_SEND_STATUS 1 53f95f3850SWill Newton #define DW_MCI_RECV_STATUS 2 54f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD 16 55f95f3850SWill Newton 561f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */ 5772e83577SJaehoon Chung #define DW_MCI_FREQ_MIN 100000 /* unit: HZ */ 581f44a2a5SSeungwon Jeon 59fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ 60fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ 61fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ 62fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_TI) 63fc79a4d6SJoonyoung Shim 64cc190d4cSShawn Lin #define DESC_RING_BUF_SZ PAGE_SIZE 65cc190d4cSShawn Lin 6669d99fdcSPrabu Thangamuthu struct idmac_desc_64addr { 6769d99fdcSPrabu Thangamuthu u32 des0; /* Control Descriptor */ 6869d99fdcSPrabu Thangamuthu 6969d99fdcSPrabu Thangamuthu u32 des1; /* Reserved */ 7069d99fdcSPrabu Thangamuthu 7169d99fdcSPrabu Thangamuthu u32 des2; /*Buffer sizes */ 7269d99fdcSPrabu Thangamuthu #define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ 736687c42fSBen Dooks ((d)->des2 = ((d)->des2 & cpu_to_le32(0x03ffe000)) | \ 746687c42fSBen Dooks ((cpu_to_le32(s)) & cpu_to_le32(0x1fff))) 7569d99fdcSPrabu Thangamuthu 7669d99fdcSPrabu Thangamuthu u32 des3; /* Reserved */ 7769d99fdcSPrabu Thangamuthu 7869d99fdcSPrabu Thangamuthu u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/ 7969d99fdcSPrabu Thangamuthu u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/ 8069d99fdcSPrabu Thangamuthu 8169d99fdcSPrabu Thangamuthu u32 des6; /* Lower 32-bits of Next Descriptor Address */ 8269d99fdcSPrabu Thangamuthu u32 des7; /* Upper 32-bits of Next Descriptor Address */ 8369d99fdcSPrabu Thangamuthu }; 8469d99fdcSPrabu Thangamuthu 85f95f3850SWill Newton struct idmac_desc { 866687c42fSBen Dooks __le32 des0; /* Control Descriptor */ 87f95f3850SWill Newton #define IDMAC_DES0_DIC BIT(1) 88f95f3850SWill Newton #define IDMAC_DES0_LD BIT(2) 89f95f3850SWill Newton #define IDMAC_DES0_FD BIT(3) 90f95f3850SWill Newton #define IDMAC_DES0_CH BIT(4) 91f95f3850SWill Newton #define IDMAC_DES0_ER BIT(5) 92f95f3850SWill Newton #define IDMAC_DES0_CES BIT(30) 93f95f3850SWill Newton #define IDMAC_DES0_OWN BIT(31) 94f95f3850SWill Newton 956687c42fSBen Dooks __le32 des1; /* Buffer sizes */ 96f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \ 97e5306c3aSBen Dooks ((d)->des1 = ((d)->des1 & cpu_to_le32(0x03ffe000)) | (cpu_to_le32((s) & 0x1fff))) 98f95f3850SWill Newton 996687c42fSBen Dooks __le32 des2; /* buffer 1 physical address */ 100f95f3850SWill Newton 1016687c42fSBen Dooks __le32 des3; /* buffer 2 physical address */ 102f95f3850SWill Newton }; 1035959b32eSAlexey Brodkin 1045959b32eSAlexey Brodkin /* Each descriptor can transfer up to 4KB of data in chained mode */ 1055959b32eSAlexey Brodkin #define DW_MCI_DESC_DATA_LENGTH 0x1000 106f95f3850SWill Newton 1073a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host); 108536f6b91SSonny Rao static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); 1090bdbd0e8SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc); 11056f6911cSShawn Lin static int dw_mci_get_cd(struct mmc_host *mmc); 11131bff450SSeungwon Jeon 112f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 113f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 114f95f3850SWill Newton { 115f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 116f95f3850SWill Newton struct mmc_request *mrq; 117f95f3850SWill Newton struct mmc_command *cmd; 118f95f3850SWill Newton struct mmc_command *stop; 119f95f3850SWill Newton struct mmc_data *data; 120f95f3850SWill Newton 121f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 122f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 123f95f3850SWill Newton mrq = slot->mrq; 124f95f3850SWill Newton 125f95f3850SWill Newton if (mrq) { 126f95f3850SWill Newton cmd = mrq->cmd; 127f95f3850SWill Newton data = mrq->data; 128f95f3850SWill Newton stop = mrq->stop; 129f95f3850SWill Newton 130f95f3850SWill Newton if (cmd) 131f95f3850SWill Newton seq_printf(s, 132f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 133f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 134f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 135f95f3850SWill Newton cmd->resp[2], cmd->error); 136f95f3850SWill Newton if (data) 137f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 138f95f3850SWill Newton data->bytes_xfered, data->blocks, 139f95f3850SWill Newton data->blksz, data->flags, data->error); 140f95f3850SWill Newton if (stop) 141f95f3850SWill Newton seq_printf(s, 142f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 143f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 144f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 145f95f3850SWill Newton stop->resp[2], stop->error); 146f95f3850SWill Newton } 147f95f3850SWill Newton 148f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 149f95f3850SWill Newton 150f95f3850SWill Newton return 0; 151f95f3850SWill Newton } 152f95f3850SWill Newton 153f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 154f95f3850SWill Newton { 155f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 156f95f3850SWill Newton } 157f95f3850SWill Newton 158f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 159f95f3850SWill Newton .owner = THIS_MODULE, 160f95f3850SWill Newton .open = dw_mci_req_open, 161f95f3850SWill Newton .read = seq_read, 162f95f3850SWill Newton .llseek = seq_lseek, 163f95f3850SWill Newton .release = single_release, 164f95f3850SWill Newton }; 165f95f3850SWill Newton 166f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 167f95f3850SWill Newton { 16821657ebdSJaehoon Chung struct dw_mci *host = s->private; 16921657ebdSJaehoon Chung 17021657ebdSJaehoon Chung seq_printf(s, "STATUS:\t0x%08x\n", mci_readl(host, STATUS)); 17121657ebdSJaehoon Chung seq_printf(s, "RINTSTS:\t0x%08x\n", mci_readl(host, RINTSTS)); 17221657ebdSJaehoon Chung seq_printf(s, "CMD:\t0x%08x\n", mci_readl(host, CMD)); 17321657ebdSJaehoon Chung seq_printf(s, "CTRL:\t0x%08x\n", mci_readl(host, CTRL)); 17421657ebdSJaehoon Chung seq_printf(s, "INTMASK:\t0x%08x\n", mci_readl(host, INTMASK)); 17521657ebdSJaehoon Chung seq_printf(s, "CLKENA:\t0x%08x\n", mci_readl(host, CLKENA)); 176f95f3850SWill Newton 177f95f3850SWill Newton return 0; 178f95f3850SWill Newton } 179f95f3850SWill Newton 180f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 181f95f3850SWill Newton { 182f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 183f95f3850SWill Newton } 184f95f3850SWill Newton 185f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 186f95f3850SWill Newton .owner = THIS_MODULE, 187f95f3850SWill Newton .open = dw_mci_regs_open, 188f95f3850SWill Newton .read = seq_read, 189f95f3850SWill Newton .llseek = seq_lseek, 190f95f3850SWill Newton .release = single_release, 191f95f3850SWill Newton }; 192f95f3850SWill Newton 193f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 194f95f3850SWill Newton { 195f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 196f95f3850SWill Newton struct dw_mci *host = slot->host; 197f95f3850SWill Newton struct dentry *root; 198f95f3850SWill Newton struct dentry *node; 199f95f3850SWill Newton 200f95f3850SWill Newton root = mmc->debugfs_root; 201f95f3850SWill Newton if (!root) 202f95f3850SWill Newton return; 203f95f3850SWill Newton 204f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 205f95f3850SWill Newton &dw_mci_regs_fops); 206f95f3850SWill Newton if (!node) 207f95f3850SWill Newton goto err; 208f95f3850SWill Newton 209f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 210f95f3850SWill Newton &dw_mci_req_fops); 211f95f3850SWill Newton if (!node) 212f95f3850SWill Newton goto err; 213f95f3850SWill Newton 214f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 215f95f3850SWill Newton if (!node) 216f95f3850SWill Newton goto err; 217f95f3850SWill Newton 218f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 219f95f3850SWill Newton (u32 *)&host->pending_events); 220f95f3850SWill Newton if (!node) 221f95f3850SWill Newton goto err; 222f95f3850SWill Newton 223f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 224f95f3850SWill Newton (u32 *)&host->completed_events); 225f95f3850SWill Newton if (!node) 226f95f3850SWill Newton goto err; 227f95f3850SWill Newton 228f95f3850SWill Newton return; 229f95f3850SWill Newton 230f95f3850SWill Newton err: 231f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 232f95f3850SWill Newton } 233f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 234f95f3850SWill Newton 23501730558SDoug Anderson static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg); 23601730558SDoug Anderson 237f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 238f95f3850SWill Newton { 239800d78bfSThomas Abraham struct dw_mci_slot *slot = mmc_priv(mmc); 24001730558SDoug Anderson struct dw_mci *host = slot->host; 241f95f3850SWill Newton u32 cmdr; 242f95f3850SWill Newton 2430e3a22c0SShawn Lin cmd->error = -EINPROGRESS; 244f95f3850SWill Newton cmdr = cmd->opcode; 245f95f3850SWill Newton 24690c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 24790c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 24890c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 24990c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 25090c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 251f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 2524a1b27adSJaehoon Chung else if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 253f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 254f95f3850SWill Newton 25501730558SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 25601730558SDoug Anderson u32 clk_en_a; 25701730558SDoug Anderson 25801730558SDoug Anderson /* Special bit makes CMD11 not die */ 25901730558SDoug Anderson cmdr |= SDMMC_CMD_VOLT_SWITCH; 26001730558SDoug Anderson 26101730558SDoug Anderson /* Change state to continue to handle CMD11 weirdness */ 26201730558SDoug Anderson WARN_ON(slot->host->state != STATE_SENDING_CMD); 26301730558SDoug Anderson slot->host->state = STATE_SENDING_CMD11; 26401730558SDoug Anderson 26501730558SDoug Anderson /* 26601730558SDoug Anderson * We need to disable low power mode (automatic clock stop) 26701730558SDoug Anderson * while doing voltage switch so we don't confuse the card, 26801730558SDoug Anderson * since stopping the clock is a specific part of the UHS 26901730558SDoug Anderson * voltage change dance. 27001730558SDoug Anderson * 27101730558SDoug Anderson * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be 27201730558SDoug Anderson * unconditionally turned back on in dw_mci_setup_bus() if it's 27301730558SDoug Anderson * ever called with a non-zero clock. That shouldn't happen 27401730558SDoug Anderson * until the voltage change is all done. 27501730558SDoug Anderson */ 27601730558SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 27701730558SDoug Anderson clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id); 27801730558SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 27901730558SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 28001730558SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 28101730558SDoug Anderson } 28201730558SDoug Anderson 283f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 284f95f3850SWill Newton /* We expect a response, so set this bit */ 285f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 286f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 287f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 288f95f3850SWill Newton } 289f95f3850SWill Newton 290f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 291f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 292f95f3850SWill Newton 2930349c085SJaehoon Chung if (cmd->data) { 294f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 2950349c085SJaehoon Chung if (cmd->data->flags & MMC_DATA_WRITE) 296f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 297f95f3850SWill Newton } 298f95f3850SWill Newton 299aaaaeb7aSJaehoon Chung if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &slot->flags)) 300aaaaeb7aSJaehoon Chung cmdr |= SDMMC_CMD_USE_HOLD_REG; 301800d78bfSThomas Abraham 302f95f3850SWill Newton return cmdr; 303f95f3850SWill Newton } 304f95f3850SWill Newton 30590c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) 30690c2143aSSeungwon Jeon { 30790c2143aSSeungwon Jeon struct mmc_command *stop; 30890c2143aSSeungwon Jeon u32 cmdr; 30990c2143aSSeungwon Jeon 31090c2143aSSeungwon Jeon if (!cmd->data) 31190c2143aSSeungwon Jeon return 0; 31290c2143aSSeungwon Jeon 31390c2143aSSeungwon Jeon stop = &host->stop_abort; 31490c2143aSSeungwon Jeon cmdr = cmd->opcode; 31590c2143aSSeungwon Jeon memset(stop, 0, sizeof(struct mmc_command)); 31690c2143aSSeungwon Jeon 31790c2143aSSeungwon Jeon if (cmdr == MMC_READ_SINGLE_BLOCK || 31890c2143aSSeungwon Jeon cmdr == MMC_READ_MULTIPLE_BLOCK || 31990c2143aSSeungwon Jeon cmdr == MMC_WRITE_BLOCK || 3206c2c6506SUlf Hansson cmdr == MMC_WRITE_MULTIPLE_BLOCK || 3216c2c6506SUlf Hansson cmdr == MMC_SEND_TUNING_BLOCK || 3226c2c6506SUlf Hansson cmdr == MMC_SEND_TUNING_BLOCK_HS200) { 32390c2143aSSeungwon Jeon stop->opcode = MMC_STOP_TRANSMISSION; 32490c2143aSSeungwon Jeon stop->arg = 0; 32590c2143aSSeungwon Jeon stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 32690c2143aSSeungwon Jeon } else if (cmdr == SD_IO_RW_EXTENDED) { 32790c2143aSSeungwon Jeon stop->opcode = SD_IO_RW_DIRECT; 32890c2143aSSeungwon Jeon stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | 32990c2143aSSeungwon Jeon ((cmd->arg >> 28) & 0x7); 33090c2143aSSeungwon Jeon stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; 33190c2143aSSeungwon Jeon } else { 33290c2143aSSeungwon Jeon return 0; 33390c2143aSSeungwon Jeon } 33490c2143aSSeungwon Jeon 33590c2143aSSeungwon Jeon cmdr = stop->opcode | SDMMC_CMD_STOP | 33690c2143aSSeungwon Jeon SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; 33790c2143aSSeungwon Jeon 3388c005b40SJaehoon Chung if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags)) 3398c005b40SJaehoon Chung cmdr |= SDMMC_CMD_USE_HOLD_REG; 3408c005b40SJaehoon Chung 34190c2143aSSeungwon Jeon return cmdr; 34290c2143aSSeungwon Jeon } 34390c2143aSSeungwon Jeon 3440bdbd0e8SDoug Anderson static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) 3450bdbd0e8SDoug Anderson { 3460bdbd0e8SDoug Anderson unsigned long timeout = jiffies + msecs_to_jiffies(500); 3470bdbd0e8SDoug Anderson 3480bdbd0e8SDoug Anderson /* 3490bdbd0e8SDoug Anderson * Databook says that before issuing a new data transfer command 3500bdbd0e8SDoug Anderson * we need to check to see if the card is busy. Data transfer commands 3510bdbd0e8SDoug Anderson * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that. 3520bdbd0e8SDoug Anderson * 3530bdbd0e8SDoug Anderson * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is 3540bdbd0e8SDoug Anderson * expected. 3550bdbd0e8SDoug Anderson */ 3560bdbd0e8SDoug Anderson if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) && 3570bdbd0e8SDoug Anderson !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) { 3580bdbd0e8SDoug Anderson while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) { 3590bdbd0e8SDoug Anderson if (time_after(jiffies, timeout)) { 3600bdbd0e8SDoug Anderson /* Command will fail; we'll pass error then */ 3610bdbd0e8SDoug Anderson dev_err(host->dev, "Busy; trying anyway\n"); 3620bdbd0e8SDoug Anderson break; 3630bdbd0e8SDoug Anderson } 3640bdbd0e8SDoug Anderson udelay(10); 3650bdbd0e8SDoug Anderson } 3660bdbd0e8SDoug Anderson } 3670bdbd0e8SDoug Anderson } 3680bdbd0e8SDoug Anderson 369f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 370f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 371f95f3850SWill Newton { 372f95f3850SWill Newton host->cmd = cmd; 3734a90920cSThomas Abraham dev_vdbg(host->dev, 374f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 375f95f3850SWill Newton cmd->arg, cmd_flags); 376f95f3850SWill Newton 377f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 3780e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 3790bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd_flags); 380f95f3850SWill Newton 381f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 382f95f3850SWill Newton } 383f95f3850SWill Newton 38490c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 385f95f3850SWill Newton { 386e13c3c08SJaehoon Chung struct mmc_command *stop = &host->stop_abort; 3870e3a22c0SShawn Lin 38890c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 389f95f3850SWill Newton } 390f95f3850SWill Newton 391f95f3850SWill Newton /* DMA interface functions */ 392f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 393f95f3850SWill Newton { 39403e8cb53SJames Hogan if (host->using_dma) { 395f95f3850SWill Newton host->dma_ops->stop(host); 396f95f3850SWill Newton host->dma_ops->cleanup(host); 397aa50f259SSeungwon Jeon } 398aa50f259SSeungwon Jeon 399f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 400f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 401f95f3850SWill Newton } 402f95f3850SWill Newton 4039aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 4049aa51408SSeungwon Jeon { 4059aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 4069aa51408SSeungwon Jeon return DMA_TO_DEVICE; 4079aa51408SSeungwon Jeon else 4089aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 4099aa51408SSeungwon Jeon } 4109aa51408SSeungwon Jeon 411f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 412f95f3850SWill Newton { 413f95f3850SWill Newton struct mmc_data *data = host->data; 414f95f3850SWill Newton 415a4cc7eb4SJaehoon Chung if (data && data->host_cookie == COOKIE_MAPPED) { 4164a90920cSThomas Abraham dma_unmap_sg(host->dev, 4179aa51408SSeungwon Jeon data->sg, 4189aa51408SSeungwon Jeon data->sg_len, 4199aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 420a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 421a4cc7eb4SJaehoon Chung } 422f95f3850SWill Newton } 423f95f3850SWill Newton 4245ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host) 4255ce9d961SSeungwon Jeon { 4265ce9d961SSeungwon Jeon u32 bmod = mci_readl(host, BMOD); 4275ce9d961SSeungwon Jeon /* Software reset of DMA */ 4285ce9d961SSeungwon Jeon bmod |= SDMMC_IDMAC_SWRESET; 4295ce9d961SSeungwon Jeon mci_writel(host, BMOD, bmod); 4305ce9d961SSeungwon Jeon } 4315ce9d961SSeungwon Jeon 432f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 433f95f3850SWill Newton { 434f95f3850SWill Newton u32 temp; 435f95f3850SWill Newton 436f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 437f95f3850SWill Newton temp = mci_readl(host, CTRL); 438f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 439f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 440f95f3850SWill Newton mci_writel(host, CTRL, temp); 441f95f3850SWill Newton 442f95f3850SWill Newton /* Stop the IDMAC running */ 443f95f3850SWill Newton temp = mci_readl(host, BMOD); 444a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 4455ce9d961SSeungwon Jeon temp |= SDMMC_IDMAC_SWRESET; 446f95f3850SWill Newton mci_writel(host, BMOD, temp); 447f95f3850SWill Newton } 448f95f3850SWill Newton 4493fc7eaefSShawn Lin static void dw_mci_dmac_complete_dma(void *arg) 450f95f3850SWill Newton { 4513fc7eaefSShawn Lin struct dw_mci *host = arg; 452f95f3850SWill Newton struct mmc_data *data = host->data; 453f95f3850SWill Newton 4544a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 455f95f3850SWill Newton 4563fc7eaefSShawn Lin if ((host->use_dma == TRANS_MODE_EDMAC) && 4573fc7eaefSShawn Lin data && (data->flags & MMC_DATA_READ)) 4583fc7eaefSShawn Lin /* Invalidate cache after read */ 4593fc7eaefSShawn Lin dma_sync_sg_for_cpu(mmc_dev(host->cur_slot->mmc), 4603fc7eaefSShawn Lin data->sg, 4613fc7eaefSShawn Lin data->sg_len, 4623fc7eaefSShawn Lin DMA_FROM_DEVICE); 4633fc7eaefSShawn Lin 464f95f3850SWill Newton host->dma_ops->cleanup(host); 465f95f3850SWill Newton 466f95f3850SWill Newton /* 467f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 468f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 469f95f3850SWill Newton */ 470f95f3850SWill Newton if (data) { 471f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 472f95f3850SWill Newton tasklet_schedule(&host->tasklet); 473f95f3850SWill Newton } 474f95f3850SWill Newton } 475f95f3850SWill Newton 476f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 477f95f3850SWill Newton { 478897b69e7SSeungwon Jeon int i; 479f95f3850SWill Newton 48069d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 48169d99fdcSPrabu Thangamuthu struct idmac_desc_64addr *p; 48269d99fdcSPrabu Thangamuthu /* Number of descriptors in the ring buffer */ 483cc190d4cSShawn Lin host->ring_size = 484cc190d4cSShawn Lin DESC_RING_BUF_SZ / sizeof(struct idmac_desc_64addr); 48569d99fdcSPrabu Thangamuthu 48669d99fdcSPrabu Thangamuthu /* Forward link the descriptor list */ 48769d99fdcSPrabu Thangamuthu for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; 48869d99fdcSPrabu Thangamuthu i++, p++) { 48969d99fdcSPrabu Thangamuthu p->des6 = (host->sg_dma + 49069d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 49169d99fdcSPrabu Thangamuthu (i + 1))) & 0xffffffff; 49269d99fdcSPrabu Thangamuthu 49369d99fdcSPrabu Thangamuthu p->des7 = (u64)(host->sg_dma + 49469d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 49569d99fdcSPrabu Thangamuthu (i + 1))) >> 32; 49669d99fdcSPrabu Thangamuthu /* Initialize reserved and buffer size fields to "0" */ 49769d99fdcSPrabu Thangamuthu p->des1 = 0; 49869d99fdcSPrabu Thangamuthu p->des2 = 0; 49969d99fdcSPrabu Thangamuthu p->des3 = 0; 50069d99fdcSPrabu Thangamuthu } 50169d99fdcSPrabu Thangamuthu 50269d99fdcSPrabu Thangamuthu /* Set the last descriptor as the end-of-ring descriptor */ 50369d99fdcSPrabu Thangamuthu p->des6 = host->sg_dma & 0xffffffff; 50469d99fdcSPrabu Thangamuthu p->des7 = (u64)host->sg_dma >> 32; 50569d99fdcSPrabu Thangamuthu p->des0 = IDMAC_DES0_ER; 50669d99fdcSPrabu Thangamuthu 50769d99fdcSPrabu Thangamuthu } else { 50869d99fdcSPrabu Thangamuthu struct idmac_desc *p; 509f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 510cc190d4cSShawn Lin host->ring_size = 511cc190d4cSShawn Lin DESC_RING_BUF_SZ / sizeof(struct idmac_desc); 512f95f3850SWill Newton 513f95f3850SWill Newton /* Forward link the descriptor list */ 5140e3a22c0SShawn Lin for (i = 0, p = host->sg_cpu; 5150e3a22c0SShawn Lin i < host->ring_size - 1; 5160e3a22c0SShawn Lin i++, p++) { 5176687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma + 5186687c42fSBen Dooks (sizeof(struct idmac_desc) * (i + 1))); 5194b244724SZhangfei Gao p->des1 = 0; 5204b244724SZhangfei Gao } 521f95f3850SWill Newton 522f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 5236687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma); 5246687c42fSBen Dooks p->des0 = cpu_to_le32(IDMAC_DES0_ER); 52569d99fdcSPrabu Thangamuthu } 526f95f3850SWill Newton 5275ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 528141a712aSSeungwon Jeon 52969d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 53069d99fdcSPrabu Thangamuthu /* Mask out interrupts - get Tx & Rx complete only */ 53169d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, IDMAC_INT_CLR); 53269d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI | 53369d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 53469d99fdcSPrabu Thangamuthu 53569d99fdcSPrabu Thangamuthu /* Set the descriptor base address */ 53669d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff); 53769d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32); 53869d99fdcSPrabu Thangamuthu 53969d99fdcSPrabu Thangamuthu } else { 540f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 541fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 54269d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | 54369d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 544f95f3850SWill Newton 545f95f3850SWill Newton /* Set the descriptor base address */ 546f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 54769d99fdcSPrabu Thangamuthu } 54869d99fdcSPrabu Thangamuthu 549f95f3850SWill Newton return 0; 550f95f3850SWill Newton } 551f95f3850SWill Newton 5523b2a067bSShawn Lin static inline int dw_mci_prepare_desc64(struct dw_mci *host, 5533b2a067bSShawn Lin struct mmc_data *data, 5543b2a067bSShawn Lin unsigned int sg_len) 5553b2a067bSShawn Lin { 5563b2a067bSShawn Lin unsigned int desc_len; 5573b2a067bSShawn Lin struct idmac_desc_64addr *desc_first, *desc_last, *desc; 5583b2a067bSShawn Lin unsigned long timeout; 5593b2a067bSShawn Lin int i; 5603b2a067bSShawn Lin 5613b2a067bSShawn Lin desc_first = desc_last = desc = host->sg_cpu; 5623b2a067bSShawn Lin 5633b2a067bSShawn Lin for (i = 0; i < sg_len; i++) { 5643b2a067bSShawn Lin unsigned int length = sg_dma_len(&data->sg[i]); 5653b2a067bSShawn Lin 5663b2a067bSShawn Lin u64 mem_addr = sg_dma_address(&data->sg[i]); 5673b2a067bSShawn Lin 5683b2a067bSShawn Lin for ( ; length ; desc++) { 5693b2a067bSShawn Lin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 5703b2a067bSShawn Lin length : DW_MCI_DESC_DATA_LENGTH; 5713b2a067bSShawn Lin 5723b2a067bSShawn Lin length -= desc_len; 5733b2a067bSShawn Lin 5743b2a067bSShawn Lin /* 5753b2a067bSShawn Lin * Wait for the former clear OWN bit operation 5763b2a067bSShawn Lin * of IDMAC to make sure that this descriptor 5773b2a067bSShawn Lin * isn't still owned by IDMAC as IDMAC's write 5783b2a067bSShawn Lin * ops and CPU's read ops are asynchronous. 5793b2a067bSShawn Lin */ 5803b2a067bSShawn Lin timeout = jiffies + msecs_to_jiffies(100); 5813b2a067bSShawn Lin while (readl(&desc->des0) & IDMAC_DES0_OWN) { 5823b2a067bSShawn Lin if (time_after(jiffies, timeout)) 5833b2a067bSShawn Lin goto err_own_bit; 5843b2a067bSShawn Lin udelay(10); 5853b2a067bSShawn Lin } 5863b2a067bSShawn Lin 5873b2a067bSShawn Lin /* 5883b2a067bSShawn Lin * Set the OWN bit and disable interrupts 5893b2a067bSShawn Lin * for this descriptor 5903b2a067bSShawn Lin */ 5913b2a067bSShawn Lin desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | 5923b2a067bSShawn Lin IDMAC_DES0_CH; 5933b2a067bSShawn Lin 5943b2a067bSShawn Lin /* Buffer length */ 5953b2a067bSShawn Lin IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len); 5963b2a067bSShawn Lin 5973b2a067bSShawn Lin /* Physical address to DMA to/from */ 5983b2a067bSShawn Lin desc->des4 = mem_addr & 0xffffffff; 5993b2a067bSShawn Lin desc->des5 = mem_addr >> 32; 6003b2a067bSShawn Lin 6013b2a067bSShawn Lin /* Update physical address for the next desc */ 6023b2a067bSShawn Lin mem_addr += desc_len; 6033b2a067bSShawn Lin 6043b2a067bSShawn Lin /* Save pointer to the last descriptor */ 6053b2a067bSShawn Lin desc_last = desc; 6063b2a067bSShawn Lin } 6073b2a067bSShawn Lin } 6083b2a067bSShawn Lin 6093b2a067bSShawn Lin /* Set first descriptor */ 6103b2a067bSShawn Lin desc_first->des0 |= IDMAC_DES0_FD; 6113b2a067bSShawn Lin 6123b2a067bSShawn Lin /* Set last descriptor */ 6133b2a067bSShawn Lin desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 6143b2a067bSShawn Lin desc_last->des0 |= IDMAC_DES0_LD; 6153b2a067bSShawn Lin 6163b2a067bSShawn Lin return 0; 6173b2a067bSShawn Lin err_own_bit: 6183b2a067bSShawn Lin /* restore the descriptor chain as it's polluted */ 61926be9d70SColin Ian King dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n"); 620cc190d4cSShawn Lin memset(host->sg_cpu, 0, DESC_RING_BUF_SZ); 6213b2a067bSShawn Lin dw_mci_idmac_init(host); 6223b2a067bSShawn Lin return -EINVAL; 6233b2a067bSShawn Lin } 6243b2a067bSShawn Lin 6253b2a067bSShawn Lin 6263b2a067bSShawn Lin static inline int dw_mci_prepare_desc32(struct dw_mci *host, 6273b2a067bSShawn Lin struct mmc_data *data, 6283b2a067bSShawn Lin unsigned int sg_len) 6293b2a067bSShawn Lin { 6303b2a067bSShawn Lin unsigned int desc_len; 6313b2a067bSShawn Lin struct idmac_desc *desc_first, *desc_last, *desc; 6323b2a067bSShawn Lin unsigned long timeout; 6333b2a067bSShawn Lin int i; 6343b2a067bSShawn Lin 6353b2a067bSShawn Lin desc_first = desc_last = desc = host->sg_cpu; 6363b2a067bSShawn Lin 6373b2a067bSShawn Lin for (i = 0; i < sg_len; i++) { 6383b2a067bSShawn Lin unsigned int length = sg_dma_len(&data->sg[i]); 6393b2a067bSShawn Lin 6403b2a067bSShawn Lin u32 mem_addr = sg_dma_address(&data->sg[i]); 6413b2a067bSShawn Lin 6423b2a067bSShawn Lin for ( ; length ; desc++) { 6433b2a067bSShawn Lin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 6443b2a067bSShawn Lin length : DW_MCI_DESC_DATA_LENGTH; 6453b2a067bSShawn Lin 6463b2a067bSShawn Lin length -= desc_len; 6473b2a067bSShawn Lin 6483b2a067bSShawn Lin /* 6493b2a067bSShawn Lin * Wait for the former clear OWN bit operation 6503b2a067bSShawn Lin * of IDMAC to make sure that this descriptor 6513b2a067bSShawn Lin * isn't still owned by IDMAC as IDMAC's write 6523b2a067bSShawn Lin * ops and CPU's read ops are asynchronous. 6533b2a067bSShawn Lin */ 6543b2a067bSShawn Lin timeout = jiffies + msecs_to_jiffies(100); 6553b2a067bSShawn Lin while (readl(&desc->des0) & 6563b2a067bSShawn Lin cpu_to_le32(IDMAC_DES0_OWN)) { 6573b2a067bSShawn Lin if (time_after(jiffies, timeout)) 6583b2a067bSShawn Lin goto err_own_bit; 6593b2a067bSShawn Lin udelay(10); 6603b2a067bSShawn Lin } 6613b2a067bSShawn Lin 6623b2a067bSShawn Lin /* 6633b2a067bSShawn Lin * Set the OWN bit and disable interrupts 6643b2a067bSShawn Lin * for this descriptor 6653b2a067bSShawn Lin */ 6663b2a067bSShawn Lin desc->des0 = cpu_to_le32(IDMAC_DES0_OWN | 6673b2a067bSShawn Lin IDMAC_DES0_DIC | 6683b2a067bSShawn Lin IDMAC_DES0_CH); 6693b2a067bSShawn Lin 6703b2a067bSShawn Lin /* Buffer length */ 6713b2a067bSShawn Lin IDMAC_SET_BUFFER1_SIZE(desc, desc_len); 6723b2a067bSShawn Lin 6733b2a067bSShawn Lin /* Physical address to DMA to/from */ 6743b2a067bSShawn Lin desc->des2 = cpu_to_le32(mem_addr); 6753b2a067bSShawn Lin 6763b2a067bSShawn Lin /* Update physical address for the next desc */ 6773b2a067bSShawn Lin mem_addr += desc_len; 6783b2a067bSShawn Lin 6793b2a067bSShawn Lin /* Save pointer to the last descriptor */ 6803b2a067bSShawn Lin desc_last = desc; 6813b2a067bSShawn Lin } 6823b2a067bSShawn Lin } 6833b2a067bSShawn Lin 6843b2a067bSShawn Lin /* Set first descriptor */ 6853b2a067bSShawn Lin desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD); 6863b2a067bSShawn Lin 6873b2a067bSShawn Lin /* Set last descriptor */ 6883b2a067bSShawn Lin desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | 6893b2a067bSShawn Lin IDMAC_DES0_DIC)); 6903b2a067bSShawn Lin desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD); 6913b2a067bSShawn Lin 6923b2a067bSShawn Lin return 0; 6933b2a067bSShawn Lin err_own_bit: 6943b2a067bSShawn Lin /* restore the descriptor chain as it's polluted */ 69526be9d70SColin Ian King dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n"); 696cc190d4cSShawn Lin memset(host->sg_cpu, 0, DESC_RING_BUF_SZ); 6973b2a067bSShawn Lin dw_mci_idmac_init(host); 6983b2a067bSShawn Lin return -EINVAL; 6993b2a067bSShawn Lin } 7003b2a067bSShawn Lin 7013b2a067bSShawn Lin static int dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 7023b2a067bSShawn Lin { 7033b2a067bSShawn Lin u32 temp; 7043b2a067bSShawn Lin int ret; 7053b2a067bSShawn Lin 7063b2a067bSShawn Lin if (host->dma_64bit_address == 1) 7073b2a067bSShawn Lin ret = dw_mci_prepare_desc64(host, host->data, sg_len); 7083b2a067bSShawn Lin else 7093b2a067bSShawn Lin ret = dw_mci_prepare_desc32(host, host->data, sg_len); 7103b2a067bSShawn Lin 7113b2a067bSShawn Lin if (ret) 7123b2a067bSShawn Lin goto out; 7133b2a067bSShawn Lin 7143b2a067bSShawn Lin /* drain writebuffer */ 7153b2a067bSShawn Lin wmb(); 7163b2a067bSShawn Lin 7173b2a067bSShawn Lin /* Make sure to reset DMA in case we did PIO before this */ 7183b2a067bSShawn Lin dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET); 7193b2a067bSShawn Lin dw_mci_idmac_reset(host); 7203b2a067bSShawn Lin 7213b2a067bSShawn Lin /* Select IDMAC interface */ 7223b2a067bSShawn Lin temp = mci_readl(host, CTRL); 7233b2a067bSShawn Lin temp |= SDMMC_CTRL_USE_IDMAC; 7243b2a067bSShawn Lin mci_writel(host, CTRL, temp); 7253b2a067bSShawn Lin 7263b2a067bSShawn Lin /* drain writebuffer */ 7273b2a067bSShawn Lin wmb(); 7283b2a067bSShawn Lin 7293b2a067bSShawn Lin /* Enable the IDMAC */ 7303b2a067bSShawn Lin temp = mci_readl(host, BMOD); 7313b2a067bSShawn Lin temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 7323b2a067bSShawn Lin mci_writel(host, BMOD, temp); 7333b2a067bSShawn Lin 7343b2a067bSShawn Lin /* Start it running */ 7353b2a067bSShawn Lin mci_writel(host, PLDMND, 1); 7363b2a067bSShawn Lin 7373b2a067bSShawn Lin out: 7383b2a067bSShawn Lin return ret; 7393b2a067bSShawn Lin } 7403b2a067bSShawn Lin 7418e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 742885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 743885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 744885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 7453fc7eaefSShawn Lin .complete = dw_mci_dmac_complete_dma, 746885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 747885c3e80SSeungwon Jeon }; 7483fc7eaefSShawn Lin 7493fc7eaefSShawn Lin static void dw_mci_edmac_stop_dma(struct dw_mci *host) 7503fc7eaefSShawn Lin { 751ab925a31SShawn Lin dmaengine_terminate_async(host->dms->ch); 7523fc7eaefSShawn Lin } 7533fc7eaefSShawn Lin 7543fc7eaefSShawn Lin static int dw_mci_edmac_start_dma(struct dw_mci *host, 7553fc7eaefSShawn Lin unsigned int sg_len) 7563fc7eaefSShawn Lin { 7573fc7eaefSShawn Lin struct dma_slave_config cfg; 7583fc7eaefSShawn Lin struct dma_async_tx_descriptor *desc = NULL; 7593fc7eaefSShawn Lin struct scatterlist *sgl = host->data->sg; 7603fc7eaefSShawn Lin const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 7613fc7eaefSShawn Lin u32 sg_elems = host->data->sg_len; 7623fc7eaefSShawn Lin u32 fifoth_val; 7633fc7eaefSShawn Lin u32 fifo_offset = host->fifo_reg - host->regs; 7643fc7eaefSShawn Lin int ret = 0; 7653fc7eaefSShawn Lin 7663fc7eaefSShawn Lin /* Set external dma config: burst size, burst width */ 767260b3164SArnd Bergmann cfg.dst_addr = host->phy_regs + fifo_offset; 7683fc7eaefSShawn Lin cfg.src_addr = cfg.dst_addr; 7693fc7eaefSShawn Lin cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 7703fc7eaefSShawn Lin cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 7713fc7eaefSShawn Lin 7723fc7eaefSShawn Lin /* Match burst msize with external dma config */ 7733fc7eaefSShawn Lin fifoth_val = mci_readl(host, FIFOTH); 7743fc7eaefSShawn Lin cfg.dst_maxburst = mszs[(fifoth_val >> 28) & 0x7]; 7753fc7eaefSShawn Lin cfg.src_maxburst = cfg.dst_maxburst; 7763fc7eaefSShawn Lin 7773fc7eaefSShawn Lin if (host->data->flags & MMC_DATA_WRITE) 7783fc7eaefSShawn Lin cfg.direction = DMA_MEM_TO_DEV; 7793fc7eaefSShawn Lin else 7803fc7eaefSShawn Lin cfg.direction = DMA_DEV_TO_MEM; 7813fc7eaefSShawn Lin 7823fc7eaefSShawn Lin ret = dmaengine_slave_config(host->dms->ch, &cfg); 7833fc7eaefSShawn Lin if (ret) { 7843fc7eaefSShawn Lin dev_err(host->dev, "Failed to config edmac.\n"); 7853fc7eaefSShawn Lin return -EBUSY; 7863fc7eaefSShawn Lin } 7873fc7eaefSShawn Lin 7883fc7eaefSShawn Lin desc = dmaengine_prep_slave_sg(host->dms->ch, sgl, 7893fc7eaefSShawn Lin sg_len, cfg.direction, 7903fc7eaefSShawn Lin DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 7913fc7eaefSShawn Lin if (!desc) { 7923fc7eaefSShawn Lin dev_err(host->dev, "Can't prepare slave sg.\n"); 7933fc7eaefSShawn Lin return -EBUSY; 7943fc7eaefSShawn Lin } 7953fc7eaefSShawn Lin 7963fc7eaefSShawn Lin /* Set dw_mci_dmac_complete_dma as callback */ 7973fc7eaefSShawn Lin desc->callback = dw_mci_dmac_complete_dma; 7983fc7eaefSShawn Lin desc->callback_param = (void *)host; 7993fc7eaefSShawn Lin dmaengine_submit(desc); 8003fc7eaefSShawn Lin 8013fc7eaefSShawn Lin /* Flush cache before write */ 8023fc7eaefSShawn Lin if (host->data->flags & MMC_DATA_WRITE) 8033fc7eaefSShawn Lin dma_sync_sg_for_device(mmc_dev(host->cur_slot->mmc), sgl, 8043fc7eaefSShawn Lin sg_elems, DMA_TO_DEVICE); 8053fc7eaefSShawn Lin 8063fc7eaefSShawn Lin dma_async_issue_pending(host->dms->ch); 8073fc7eaefSShawn Lin 8083fc7eaefSShawn Lin return 0; 8093fc7eaefSShawn Lin } 8103fc7eaefSShawn Lin 8113fc7eaefSShawn Lin static int dw_mci_edmac_init(struct dw_mci *host) 8123fc7eaefSShawn Lin { 8133fc7eaefSShawn Lin /* Request external dma channel */ 8143fc7eaefSShawn Lin host->dms = kzalloc(sizeof(struct dw_mci_dma_slave), GFP_KERNEL); 8153fc7eaefSShawn Lin if (!host->dms) 8163fc7eaefSShawn Lin return -ENOMEM; 8173fc7eaefSShawn Lin 8183fc7eaefSShawn Lin host->dms->ch = dma_request_slave_channel(host->dev, "rx-tx"); 8193fc7eaefSShawn Lin if (!host->dms->ch) { 8204539d36eSDan Carpenter dev_err(host->dev, "Failed to get external DMA channel.\n"); 8213fc7eaefSShawn Lin kfree(host->dms); 8223fc7eaefSShawn Lin host->dms = NULL; 8233fc7eaefSShawn Lin return -ENXIO; 8243fc7eaefSShawn Lin } 8253fc7eaefSShawn Lin 8263fc7eaefSShawn Lin return 0; 8273fc7eaefSShawn Lin } 8283fc7eaefSShawn Lin 8293fc7eaefSShawn Lin static void dw_mci_edmac_exit(struct dw_mci *host) 8303fc7eaefSShawn Lin { 8313fc7eaefSShawn Lin if (host->dms) { 8323fc7eaefSShawn Lin if (host->dms->ch) { 8333fc7eaefSShawn Lin dma_release_channel(host->dms->ch); 8343fc7eaefSShawn Lin host->dms->ch = NULL; 8353fc7eaefSShawn Lin } 8363fc7eaefSShawn Lin kfree(host->dms); 8373fc7eaefSShawn Lin host->dms = NULL; 8383fc7eaefSShawn Lin } 8393fc7eaefSShawn Lin } 8403fc7eaefSShawn Lin 8413fc7eaefSShawn Lin static const struct dw_mci_dma_ops dw_mci_edmac_ops = { 8423fc7eaefSShawn Lin .init = dw_mci_edmac_init, 8433fc7eaefSShawn Lin .exit = dw_mci_edmac_exit, 8443fc7eaefSShawn Lin .start = dw_mci_edmac_start_dma, 8453fc7eaefSShawn Lin .stop = dw_mci_edmac_stop_dma, 8463fc7eaefSShawn Lin .complete = dw_mci_dmac_complete_dma, 8473fc7eaefSShawn Lin .cleanup = dw_mci_dma_cleanup, 8483fc7eaefSShawn Lin }; 849885c3e80SSeungwon Jeon 8509aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 8519aa51408SSeungwon Jeon struct mmc_data *data, 852a4cc7eb4SJaehoon Chung int cookie) 853f95f3850SWill Newton { 854f95f3850SWill Newton struct scatterlist *sg; 8559aa51408SSeungwon Jeon unsigned int i, sg_len; 856f95f3850SWill Newton 857a4cc7eb4SJaehoon Chung if (data->host_cookie == COOKIE_PRE_MAPPED) 858a4cc7eb4SJaehoon Chung return data->sg_len; 859f95f3850SWill Newton 860f95f3850SWill Newton /* 861f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 862f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 863f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 864f95f3850SWill Newton */ 865f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 866f95f3850SWill Newton return -EINVAL; 8679aa51408SSeungwon Jeon 868f95f3850SWill Newton if (data->blksz & 3) 869f95f3850SWill Newton return -EINVAL; 870f95f3850SWill Newton 871f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 872f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 873f95f3850SWill Newton return -EINVAL; 874f95f3850SWill Newton } 875f95f3850SWill Newton 8764a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 8779aa51408SSeungwon Jeon data->sg, 8789aa51408SSeungwon Jeon data->sg_len, 8799aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 8809aa51408SSeungwon Jeon if (sg_len == 0) 8819aa51408SSeungwon Jeon return -EINVAL; 8829aa51408SSeungwon Jeon 883a4cc7eb4SJaehoon Chung data->host_cookie = cookie; 8849aa51408SSeungwon Jeon 8859aa51408SSeungwon Jeon return sg_len; 8869aa51408SSeungwon Jeon } 8879aa51408SSeungwon Jeon 8889aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 889d3c6aac3SLinus Walleij struct mmc_request *mrq) 8909aa51408SSeungwon Jeon { 8919aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 8929aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 8939aa51408SSeungwon Jeon 8949aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 8959aa51408SSeungwon Jeon return; 8969aa51408SSeungwon Jeon 897a4cc7eb4SJaehoon Chung /* This data might be unmapped at this time */ 898a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 8999aa51408SSeungwon Jeon 900a4cc7eb4SJaehoon Chung if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 901a4cc7eb4SJaehoon Chung COOKIE_PRE_MAPPED) < 0) 902a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 9039aa51408SSeungwon Jeon } 9049aa51408SSeungwon Jeon 9059aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 9069aa51408SSeungwon Jeon struct mmc_request *mrq, 9079aa51408SSeungwon Jeon int err) 9089aa51408SSeungwon Jeon { 9099aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 9109aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 9119aa51408SSeungwon Jeon 9129aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 9139aa51408SSeungwon Jeon return; 9149aa51408SSeungwon Jeon 915a4cc7eb4SJaehoon Chung if (data->host_cookie != COOKIE_UNMAPPED) 9164a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 9179aa51408SSeungwon Jeon data->sg, 9189aa51408SSeungwon Jeon data->sg_len, 9199aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 920a4cc7eb4SJaehoon Chung data->host_cookie = COOKIE_UNMAPPED; 9219aa51408SSeungwon Jeon } 9229aa51408SSeungwon Jeon 92352426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 92452426899SSeungwon Jeon { 92552426899SSeungwon Jeon unsigned int blksz = data->blksz; 92652426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 92752426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 92852426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 92952426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 9300e3a22c0SShawn Lin int idx = ARRAY_SIZE(mszs) - 1; 93152426899SSeungwon Jeon 9323fc7eaefSShawn Lin /* pio should ship this scenario */ 9333fc7eaefSShawn Lin if (!host->use_dma) 9343fc7eaefSShawn Lin return; 9353fc7eaefSShawn Lin 93652426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 93752426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 93852426899SSeungwon Jeon 93952426899SSeungwon Jeon /* 94052426899SSeungwon Jeon * MSIZE is '1', 94152426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 94252426899SSeungwon Jeon */ 94320753569SShawn Lin if (blksz % fifo_width) 94452426899SSeungwon Jeon goto done; 94552426899SSeungwon Jeon 94652426899SSeungwon Jeon do { 94752426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 94852426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 94952426899SSeungwon Jeon msize = idx; 95052426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 95152426899SSeungwon Jeon break; 95252426899SSeungwon Jeon } 95352426899SSeungwon Jeon } while (--idx > 0); 95452426899SSeungwon Jeon /* 95552426899SSeungwon Jeon * If idx is '0', it won't be tried 95652426899SSeungwon Jeon * Thus, initial values are uesed 95752426899SSeungwon Jeon */ 95852426899SSeungwon Jeon done: 95952426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 96052426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 96152426899SSeungwon Jeon } 96252426899SSeungwon Jeon 9637e4bf1bcSJaehoon Chung static void dw_mci_ctrl_thld(struct dw_mci *host, struct mmc_data *data) 964f1d2736cSSeungwon Jeon { 965f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 966f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 967f1d2736cSSeungwon Jeon u16 thld_size; 9687e4bf1bcSJaehoon Chung u8 enable; 969f1d2736cSSeungwon Jeon 97066dfd101SJames Hogan /* 97166dfd101SJames Hogan * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is 97266dfd101SJames Hogan * in the FIFO region, so we really shouldn't access it). 97366dfd101SJames Hogan */ 9747e4bf1bcSJaehoon Chung if (host->verid < DW_MMC_240A || 9757e4bf1bcSJaehoon Chung (host->verid < DW_MMC_280A && data->flags & MMC_DATA_WRITE)) 97666dfd101SJames Hogan return; 97766dfd101SJames Hogan 9787e4bf1bcSJaehoon Chung /* 9797e4bf1bcSJaehoon Chung * Card write Threshold is introduced since 2.80a 9807e4bf1bcSJaehoon Chung * It's used when HS400 mode is enabled. 9817e4bf1bcSJaehoon Chung */ 9827e4bf1bcSJaehoon Chung if (data->flags & MMC_DATA_WRITE && 9837e4bf1bcSJaehoon Chung !(host->timing != MMC_TIMING_MMC_HS400)) 9847e4bf1bcSJaehoon Chung return; 9857e4bf1bcSJaehoon Chung 9867e4bf1bcSJaehoon Chung if (data->flags & MMC_DATA_WRITE) 9877e4bf1bcSJaehoon Chung enable = SDMMC_CARD_WR_THR_EN; 9887e4bf1bcSJaehoon Chung else 9897e4bf1bcSJaehoon Chung enable = SDMMC_CARD_RD_THR_EN; 9907e4bf1bcSJaehoon Chung 991f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 992f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 993f1d2736cSSeungwon Jeon goto disable; 994f1d2736cSSeungwon Jeon 995f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 996f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 997f1d2736cSSeungwon Jeon 998f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 999f1d2736cSSeungwon Jeon goto disable; 1000f1d2736cSSeungwon Jeon 1001f1d2736cSSeungwon Jeon /* 1002f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 1003f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 1004f1d2736cSSeungwon Jeon * Currently just choose blksz. 1005f1d2736cSSeungwon Jeon */ 1006f1d2736cSSeungwon Jeon thld_size = blksz; 10077e4bf1bcSJaehoon Chung mci_writel(host, CDTHRCTL, SDMMC_SET_THLD(thld_size, enable)); 1008f1d2736cSSeungwon Jeon return; 1009f1d2736cSSeungwon Jeon 1010f1d2736cSSeungwon Jeon disable: 10117e4bf1bcSJaehoon Chung mci_writel(host, CDTHRCTL, 0); 1012f1d2736cSSeungwon Jeon } 1013f1d2736cSSeungwon Jeon 10149aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 10159aa51408SSeungwon Jeon { 1016f8c58c11SDoug Anderson unsigned long irqflags; 10179aa51408SSeungwon Jeon int sg_len; 10189aa51408SSeungwon Jeon u32 temp; 10199aa51408SSeungwon Jeon 10209aa51408SSeungwon Jeon host->using_dma = 0; 10219aa51408SSeungwon Jeon 10229aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 10239aa51408SSeungwon Jeon if (!host->use_dma) 10249aa51408SSeungwon Jeon return -ENODEV; 10259aa51408SSeungwon Jeon 1026a4cc7eb4SJaehoon Chung sg_len = dw_mci_pre_dma_transfer(host, data, COOKIE_MAPPED); 1027a99aa9b9SSeungwon Jeon if (sg_len < 0) { 1028a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 10299aa51408SSeungwon Jeon return sg_len; 1030a99aa9b9SSeungwon Jeon } 10319aa51408SSeungwon Jeon 103203e8cb53SJames Hogan host->using_dma = 1; 103303e8cb53SJames Hogan 10343fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 10354a90920cSThomas Abraham dev_vdbg(host->dev, 1036f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 10373fc7eaefSShawn Lin (unsigned long)host->sg_cpu, 10383fc7eaefSShawn Lin (unsigned long)host->sg_dma, 1039f95f3850SWill Newton sg_len); 1040f95f3850SWill Newton 104152426899SSeungwon Jeon /* 104252426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 104352426899SSeungwon Jeon * If current block size is same with previous size, 104452426899SSeungwon Jeon * no need to update fifoth. 104552426899SSeungwon Jeon */ 104652426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 104752426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 104852426899SSeungwon Jeon 1049f95f3850SWill Newton /* Enable the DMA interface */ 1050f95f3850SWill Newton temp = mci_readl(host, CTRL); 1051f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 1052f95f3850SWill Newton mci_writel(host, CTRL, temp); 1053f95f3850SWill Newton 1054f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 1055f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1056f95f3850SWill Newton temp = mci_readl(host, INTMASK); 1057f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 1058f95f3850SWill Newton mci_writel(host, INTMASK, temp); 1059f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 1060f95f3850SWill Newton 10613fc7eaefSShawn Lin if (host->dma_ops->start(host, sg_len)) { 1062647f80a1SJaehoon Chung host->dma_ops->stop(host); 1063d12d0cb1SShawn Lin /* We can't do DMA, try PIO for this one */ 1064d12d0cb1SShawn Lin dev_dbg(host->dev, 1065d12d0cb1SShawn Lin "%s: fall back to PIO mode for current transfer\n", 1066d12d0cb1SShawn Lin __func__); 10673fc7eaefSShawn Lin return -ENODEV; 10683fc7eaefSShawn Lin } 1069f95f3850SWill Newton 1070f95f3850SWill Newton return 0; 1071f95f3850SWill Newton } 1072f95f3850SWill Newton 1073f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 1074f95f3850SWill Newton { 1075f8c58c11SDoug Anderson unsigned long irqflags; 10760e3a22c0SShawn Lin int flags = SG_MITER_ATOMIC; 1077f95f3850SWill Newton u32 temp; 1078f95f3850SWill Newton 1079f95f3850SWill Newton data->error = -EINPROGRESS; 1080f95f3850SWill Newton 1081f95f3850SWill Newton WARN_ON(host->data); 1082f95f3850SWill Newton host->sg = NULL; 1083f95f3850SWill Newton host->data = data; 1084f95f3850SWill Newton 10857e4bf1bcSJaehoon Chung if (data->flags & MMC_DATA_READ) 108655c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 10877e4bf1bcSJaehoon Chung else 108855c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 10897e4bf1bcSJaehoon Chung 10907e4bf1bcSJaehoon Chung dw_mci_ctrl_thld(host, data); 109155c5efbcSJames Hogan 1092f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 1093f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 1094f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 1095f9c2a0dcSSeungwon Jeon else 1096f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 1097f9c2a0dcSSeungwon Jeon 1098f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 1099f95f3850SWill Newton host->sg = data->sg; 110034b664a2SJames Hogan host->part_buf_start = 0; 110134b664a2SJames Hogan host->part_buf_count = 0; 1102f95f3850SWill Newton 1103b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 1104f8c58c11SDoug Anderson 1105f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1106f95f3850SWill Newton temp = mci_readl(host, INTMASK); 1107f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 1108f95f3850SWill Newton mci_writel(host, INTMASK, temp); 1109f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 1110f95f3850SWill Newton 1111f95f3850SWill Newton temp = mci_readl(host, CTRL); 1112f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 1113f95f3850SWill Newton mci_writel(host, CTRL, temp); 111452426899SSeungwon Jeon 111552426899SSeungwon Jeon /* 111652426899SSeungwon Jeon * Use the initial fifoth_val for PIO mode. 111752426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 111852426899SSeungwon Jeon * prev_blksz should be invalidated. 111952426899SSeungwon Jeon */ 112052426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 112152426899SSeungwon Jeon host->prev_blksz = 0; 112252426899SSeungwon Jeon } else { 112352426899SSeungwon Jeon /* 112452426899SSeungwon Jeon * Keep the current block size. 112552426899SSeungwon Jeon * It will be used to decide whether to update 112652426899SSeungwon Jeon * fifoth register next time. 112752426899SSeungwon Jeon */ 112852426899SSeungwon Jeon host->prev_blksz = data->blksz; 1129f95f3850SWill Newton } 1130f95f3850SWill Newton } 1131f95f3850SWill Newton 1132f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 1133f95f3850SWill Newton { 1134f95f3850SWill Newton struct dw_mci *host = slot->host; 1135f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 1136f95f3850SWill Newton unsigned int cmd_status = 0; 1137f95f3850SWill Newton 1138f95f3850SWill Newton mci_writel(host, CMDARG, arg); 11390e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 11400bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd); 1141f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 1142f95f3850SWill Newton 1143f95f3850SWill Newton while (time_before(jiffies, timeout)) { 1144f95f3850SWill Newton cmd_status = mci_readl(host, CMD); 1145f95f3850SWill Newton if (!(cmd_status & SDMMC_CMD_START)) 1146f95f3850SWill Newton return; 1147f95f3850SWill Newton } 1148f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 1149f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 1150f95f3850SWill Newton cmd, arg, cmd_status); 1151f95f3850SWill Newton } 1152f95f3850SWill Newton 1153ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 1154f95f3850SWill Newton { 1155f95f3850SWill Newton struct dw_mci *host = slot->host; 1156fdf492a1SDoug Anderson unsigned int clock = slot->clock; 1157f95f3850SWill Newton u32 div; 11589623b5b9SDoug Anderson u32 clk_en_a; 115901730558SDoug Anderson u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT; 116001730558SDoug Anderson 116101730558SDoug Anderson /* We must continue to set bit 28 in CMD until the change is complete */ 116201730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) 116301730558SDoug Anderson sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; 1164f95f3850SWill Newton 1165fdf492a1SDoug Anderson if (!clock) { 1166fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 116701730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1168fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 1169fdf492a1SDoug Anderson div = host->bus_hz / clock; 1170fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 1171f95f3850SWill Newton /* 1172f95f3850SWill Newton * move the + 1 after the divide to prevent 1173f95f3850SWill Newton * over-clocking the card. 1174f95f3850SWill Newton */ 1175e419990bSSeungwon Jeon div += 1; 1176e419990bSSeungwon Jeon 1177fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 1178f95f3850SWill Newton 1179005d675aSJaehoon Chung if (clock != slot->__clk_old || force_clkinit) 1180f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 1181fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 1182fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 1183fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 1184fdf492a1SDoug Anderson host->bus_hz, div); 1185f95f3850SWill Newton 1186f95f3850SWill Newton /* disable clock */ 1187f95f3850SWill Newton mci_writel(host, CLKENA, 0); 1188f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 1189f95f3850SWill Newton 1190f95f3850SWill Newton /* inform CIU */ 119101730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1192f95f3850SWill Newton 1193f95f3850SWill Newton /* set clock to desired speed */ 1194f95f3850SWill Newton mci_writel(host, CLKDIV, div); 1195f95f3850SWill Newton 1196f95f3850SWill Newton /* inform CIU */ 119701730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1198f95f3850SWill Newton 11999623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 12009623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 1201b24c8b26SDoug Anderson if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) 12029623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 12039623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 1204f95f3850SWill Newton 1205f95f3850SWill Newton /* inform CIU */ 120601730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1207005d675aSJaehoon Chung 1208005d675aSJaehoon Chung /* keep the last clock value that was requested from core */ 1209005d675aSJaehoon Chung slot->__clk_old = clock; 1210f95f3850SWill Newton } 1211f95f3850SWill Newton 1212fdf492a1SDoug Anderson host->current_speed = clock; 1213fdf492a1SDoug Anderson 1214f95f3850SWill Newton /* Set the current slot bus width */ 12151d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 1216f95f3850SWill Newton } 1217f95f3850SWill Newton 1218053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 1219053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 1220053b3ce6SSeungwon Jeon struct mmc_command *cmd) 1221f95f3850SWill Newton { 1222f95f3850SWill Newton struct mmc_request *mrq; 1223f95f3850SWill Newton struct mmc_data *data; 1224f95f3850SWill Newton u32 cmdflags; 1225f95f3850SWill Newton 1226f95f3850SWill Newton mrq = slot->mrq; 1227f95f3850SWill Newton 1228f95f3850SWill Newton host->cur_slot = slot; 1229f95f3850SWill Newton host->mrq = mrq; 1230f95f3850SWill Newton 1231f95f3850SWill Newton host->pending_events = 0; 1232f95f3850SWill Newton host->completed_events = 0; 1233e352c813SSeungwon Jeon host->cmd_status = 0; 1234f95f3850SWill Newton host->data_status = 0; 1235e352c813SSeungwon Jeon host->dir_status = 0; 1236f95f3850SWill Newton 1237053b3ce6SSeungwon Jeon data = cmd->data; 1238f95f3850SWill Newton if (data) { 1239f16afa88SJaehoon Chung mci_writel(host, TMOUT, 0xFFFFFFFF); 1240f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 1241f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 1242f95f3850SWill Newton } 1243f95f3850SWill Newton 1244f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 1245f95f3850SWill Newton 1246f95f3850SWill Newton /* this is the first command, send the initialization clock */ 1247f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 1248f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 1249f95f3850SWill Newton 1250f95f3850SWill Newton if (data) { 1251f95f3850SWill Newton dw_mci_submit_data(host, data); 12520e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 1253f95f3850SWill Newton } 1254f95f3850SWill Newton 1255f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 1256f95f3850SWill Newton 12575c935165SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 125849ba0302SDoug Anderson unsigned long irqflags; 125949ba0302SDoug Anderson 12605c935165SDoug Anderson /* 12618886a6fdSDoug Anderson * Databook says to fail after 2ms w/ no response, but evidence 12628886a6fdSDoug Anderson * shows that sometimes the cmd11 interrupt takes over 130ms. 12638886a6fdSDoug Anderson * We'll set to 500ms, plus an extra jiffy just in case jiffies 12648886a6fdSDoug Anderson * is just about to roll over. 126549ba0302SDoug Anderson * 126649ba0302SDoug Anderson * We do this whole thing under spinlock and only if the 126749ba0302SDoug Anderson * command hasn't already completed (indicating the the irq 126849ba0302SDoug Anderson * already ran so we don't want the timeout). 12695c935165SDoug Anderson */ 127049ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 127149ba0302SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) 12725c935165SDoug Anderson mod_timer(&host->cmd11_timer, 12738886a6fdSDoug Anderson jiffies + msecs_to_jiffies(500) + 1); 127449ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 12755c935165SDoug Anderson } 12765c935165SDoug Anderson 127790c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 1278f95f3850SWill Newton } 1279f95f3850SWill Newton 1280053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 1281053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 1282053b3ce6SSeungwon Jeon { 1283053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 1284053b3ce6SSeungwon Jeon struct mmc_command *cmd; 1285053b3ce6SSeungwon Jeon 1286053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 1287053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 1288053b3ce6SSeungwon Jeon } 1289053b3ce6SSeungwon Jeon 12907456caaeSJames Hogan /* must be called with host->lock held */ 1291f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 1292f95f3850SWill Newton struct mmc_request *mrq) 1293f95f3850SWill Newton { 1294f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 1295f95f3850SWill Newton host->state); 1296f95f3850SWill Newton 1297f95f3850SWill Newton slot->mrq = mrq; 1298f95f3850SWill Newton 129901730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) { 130001730558SDoug Anderson dev_warn(&slot->mmc->class_dev, 130101730558SDoug Anderson "Voltage change didn't complete\n"); 130201730558SDoug Anderson /* 130301730558SDoug Anderson * this case isn't expected to happen, so we can 130401730558SDoug Anderson * either crash here or just try to continue on 130501730558SDoug Anderson * in the closest possible state 130601730558SDoug Anderson */ 130701730558SDoug Anderson host->state = STATE_IDLE; 130801730558SDoug Anderson } 130901730558SDoug Anderson 1310f95f3850SWill Newton if (host->state == STATE_IDLE) { 1311f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1312f95f3850SWill Newton dw_mci_start_request(host, slot); 1313f95f3850SWill Newton } else { 1314f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 1315f95f3850SWill Newton } 1316f95f3850SWill Newton } 1317f95f3850SWill Newton 1318f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1319f95f3850SWill Newton { 1320f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1321f95f3850SWill Newton struct dw_mci *host = slot->host; 1322f95f3850SWill Newton 1323f95f3850SWill Newton WARN_ON(slot->mrq); 1324f95f3850SWill Newton 13257456caaeSJames Hogan /* 13267456caaeSJames Hogan * The check for card presence and queueing of the request must be 13277456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 13287456caaeSJames Hogan * request wouldn't fail until another card was inserted. 13297456caaeSJames Hogan */ 13307456caaeSJames Hogan 133156f6911cSShawn Lin if (!dw_mci_get_cd(mmc)) { 1332f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1333f95f3850SWill Newton mmc_request_done(mmc, mrq); 1334f95f3850SWill Newton return; 1335f95f3850SWill Newton } 1336f95f3850SWill Newton 133756f6911cSShawn Lin spin_lock_bh(&host->lock); 133856f6911cSShawn Lin 1339f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 13407456caaeSJames Hogan 13417456caaeSJames Hogan spin_unlock_bh(&host->lock); 1342f95f3850SWill Newton } 1343f95f3850SWill Newton 1344f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1345f95f3850SWill Newton { 1346f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1347e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 134841babf75SJaehoon Chung u32 regs; 134951da2240SYuvaraj CD int ret; 1350f95f3850SWill Newton 1351f95f3850SWill Newton switch (ios->bus_width) { 1352f95f3850SWill Newton case MMC_BUS_WIDTH_4: 1353f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 1354f95f3850SWill Newton break; 1355c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 1356c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 1357c9b2a06fSJaehoon Chung break; 1358b2f7cb45SJaehoon Chung default: 1359b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 1360b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 1361f95f3850SWill Newton } 1362f95f3850SWill Newton 136341babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 13643f514291SSeungwon Jeon 13653f514291SSeungwon Jeon /* DDR mode set */ 136680113132SSeungwon Jeon if (ios->timing == MMC_TIMING_MMC_DDR52 || 13677cc8d580SJaehoon Chung ios->timing == MMC_TIMING_UHS_DDR50 || 136880113132SSeungwon Jeon ios->timing == MMC_TIMING_MMC_HS400) 1369c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 13703f514291SSeungwon Jeon else 1371c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 13723f514291SSeungwon Jeon 137341babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 1374f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 137541babf75SJaehoon Chung 1376f95f3850SWill Newton /* 1377f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 1378f95f3850SWill Newton * core ios update when finding the minimum. 1379f95f3850SWill Newton */ 1380f95f3850SWill Newton slot->clock = ios->clock; 1381f95f3850SWill Newton 1382cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 1383cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 1384800d78bfSThomas Abraham 1385f95f3850SWill Newton switch (ios->power_mode) { 1386f95f3850SWill Newton case MMC_POWER_UP: 138751da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) { 138851da2240SYuvaraj CD ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 138951da2240SYuvaraj CD ios->vdd); 139051da2240SYuvaraj CD if (ret) { 139151da2240SYuvaraj CD dev_err(slot->host->dev, 139251da2240SYuvaraj CD "failed to enable vmmc regulator\n"); 139351da2240SYuvaraj CD /*return, if failed turn on vmmc*/ 139451da2240SYuvaraj CD return; 139551da2240SYuvaraj CD } 139651da2240SYuvaraj CD } 139729d0d161SDoug Anderson set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 139829d0d161SDoug Anderson regs = mci_readl(slot->host, PWREN); 139929d0d161SDoug Anderson regs |= (1 << slot->id); 140029d0d161SDoug Anderson mci_writel(slot->host, PWREN, regs); 140129d0d161SDoug Anderson break; 140229d0d161SDoug Anderson case MMC_POWER_ON: 1403d1f1dd86SDoug Anderson if (!slot->host->vqmmc_enabled) { 1404d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 140551da2240SYuvaraj CD ret = regulator_enable(mmc->supply.vqmmc); 140651da2240SYuvaraj CD if (ret < 0) 140751da2240SYuvaraj CD dev_err(slot->host->dev, 1408d1f1dd86SDoug Anderson "failed to enable vqmmc\n"); 140951da2240SYuvaraj CD else 141051da2240SYuvaraj CD slot->host->vqmmc_enabled = true; 1411d1f1dd86SDoug Anderson 1412d1f1dd86SDoug Anderson } else { 1413d1f1dd86SDoug Anderson /* Keep track so we don't reset again */ 1414d1f1dd86SDoug Anderson slot->host->vqmmc_enabled = true; 1415d1f1dd86SDoug Anderson } 1416d1f1dd86SDoug Anderson 1417d1f1dd86SDoug Anderson /* Reset our state machine after powering on */ 1418d1f1dd86SDoug Anderson dw_mci_ctrl_reset(slot->host, 1419d1f1dd86SDoug Anderson SDMMC_CTRL_ALL_RESET_FLAGS); 142051da2240SYuvaraj CD } 1421655babbdSDoug Anderson 1422655babbdSDoug Anderson /* Adjust clock / bus width after power is up */ 1423655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1424655babbdSDoug Anderson 1425e6f34e2fSJames Hogan break; 1426e6f34e2fSJames Hogan case MMC_POWER_OFF: 1427655babbdSDoug Anderson /* Turn clock off before power goes down */ 1428655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1429655babbdSDoug Anderson 143051da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) 143151da2240SYuvaraj CD mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 143251da2240SYuvaraj CD 1433d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) 143451da2240SYuvaraj CD regulator_disable(mmc->supply.vqmmc); 143551da2240SYuvaraj CD slot->host->vqmmc_enabled = false; 143651da2240SYuvaraj CD 14374366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 14384366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 14394366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1440f95f3850SWill Newton break; 1441f95f3850SWill Newton default: 1442f95f3850SWill Newton break; 1443f95f3850SWill Newton } 1444655babbdSDoug Anderson 1445655babbdSDoug Anderson if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) 1446655babbdSDoug Anderson slot->host->state = STATE_IDLE; 1447f95f3850SWill Newton } 1448f95f3850SWill Newton 144901730558SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc) 145001730558SDoug Anderson { 145101730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 145201730558SDoug Anderson u32 status; 145301730558SDoug Anderson 145401730558SDoug Anderson /* 145501730558SDoug Anderson * Check the busy bit which is low when DAT[3:0] 145601730558SDoug Anderson * (the data lines) are 0000 145701730558SDoug Anderson */ 145801730558SDoug Anderson status = mci_readl(slot->host, STATUS); 145901730558SDoug Anderson 146001730558SDoug Anderson return !!(status & SDMMC_STATUS_BUSY); 146101730558SDoug Anderson } 146201730558SDoug Anderson 146301730558SDoug Anderson static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) 146401730558SDoug Anderson { 146501730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 146601730558SDoug Anderson struct dw_mci *host = slot->host; 14678f7849c4SZhangfei Gao const struct dw_mci_drv_data *drv_data = host->drv_data; 146801730558SDoug Anderson u32 uhs; 146901730558SDoug Anderson u32 v18 = SDMMC_UHS_18V << slot->id; 147001730558SDoug Anderson int ret; 147101730558SDoug Anderson 14728f7849c4SZhangfei Gao if (drv_data && drv_data->switch_voltage) 14738f7849c4SZhangfei Gao return drv_data->switch_voltage(mmc, ios); 14748f7849c4SZhangfei Gao 147501730558SDoug Anderson /* 147601730558SDoug Anderson * Program the voltage. Note that some instances of dw_mmc may use 147701730558SDoug Anderson * the UHS_REG for this. For other instances (like exynos) the UHS_REG 147801730558SDoug Anderson * does no harm but you need to set the regulator directly. Try both. 147901730558SDoug Anderson */ 148001730558SDoug Anderson uhs = mci_readl(host, UHS_REG); 1481e0848f5dSDouglas Anderson if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) 148201730558SDoug Anderson uhs &= ~v18; 1483e0848f5dSDouglas Anderson else 148401730558SDoug Anderson uhs |= v18; 1485e0848f5dSDouglas Anderson 148601730558SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 1487e0848f5dSDouglas Anderson ret = mmc_regulator_set_vqmmc(mmc, ios); 148801730558SDoug Anderson 148901730558SDoug Anderson if (ret) { 1490b19caf37SDoug Anderson dev_dbg(&mmc->class_dev, 1491e0848f5dSDouglas Anderson "Regulator set error %d - %s V\n", 1492e0848f5dSDouglas Anderson ret, uhs & v18 ? "1.8" : "3.3"); 149301730558SDoug Anderson return ret; 149401730558SDoug Anderson } 149501730558SDoug Anderson } 149601730558SDoug Anderson mci_writel(host, UHS_REG, uhs); 149701730558SDoug Anderson 149801730558SDoug Anderson return 0; 149901730558SDoug Anderson } 150001730558SDoug Anderson 1501f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 1502f95f3850SWill Newton { 1503f95f3850SWill Newton int read_only; 1504f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 15059795a846SJaehoon Chung int gpio_ro = mmc_gpio_get_ro(mmc); 1506f95f3850SWill Newton 1507f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 1508287980e4SArnd Bergmann if (gpio_ro >= 0) 15099795a846SJaehoon Chung read_only = gpio_ro; 1510f95f3850SWill Newton else 1511f95f3850SWill Newton read_only = 1512f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1513f95f3850SWill Newton 1514f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1515f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1516f95f3850SWill Newton 1517f95f3850SWill Newton return read_only; 1518f95f3850SWill Newton } 1519f95f3850SWill Newton 1520f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1521f95f3850SWill Newton { 1522f95f3850SWill Newton int present; 1523f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 15247cf347bdSZhangfei Gao struct dw_mci *host = slot->host; 15257cf347bdSZhangfei Gao int gpio_cd = mmc_gpio_get_cd(mmc); 1526f95f3850SWill Newton 1527f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 1528860951c5SJaehoon Chung if ((mmc->caps & MMC_CAP_NEEDS_POLL) || !mmc_card_is_removable(mmc)) 1529fc3d7720SJaehoon Chung present = 1; 1530287980e4SArnd Bergmann else if (gpio_cd >= 0) 15317cf347bdSZhangfei Gao present = gpio_cd; 1532f95f3850SWill Newton else 1533f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1534f95f3850SWill Newton == 0 ? 1 : 0; 1535f95f3850SWill Newton 15367cf347bdSZhangfei Gao spin_lock_bh(&host->lock); 15371f4d5079SJaehoon Chung if (present && !test_and_set_bit(DW_MMC_CARD_PRESENT, &slot->flags)) 1538f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 15391f4d5079SJaehoon Chung else if (!test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags)) 1540f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 15417cf347bdSZhangfei Gao spin_unlock_bh(&host->lock); 1542f95f3850SWill Newton 1543f95f3850SWill Newton return present; 1544f95f3850SWill Newton } 1545f95f3850SWill Newton 1546935a665eSShawn Lin static void dw_mci_hw_reset(struct mmc_host *mmc) 1547935a665eSShawn Lin { 1548935a665eSShawn Lin struct dw_mci_slot *slot = mmc_priv(mmc); 1549935a665eSShawn Lin struct dw_mci *host = slot->host; 1550935a665eSShawn Lin int reset; 1551935a665eSShawn Lin 1552935a665eSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 1553935a665eSShawn Lin dw_mci_idmac_reset(host); 1554935a665eSShawn Lin 1555935a665eSShawn Lin if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET | 1556935a665eSShawn Lin SDMMC_CTRL_FIFO_RESET)) 1557935a665eSShawn Lin return; 1558935a665eSShawn Lin 1559935a665eSShawn Lin /* 1560935a665eSShawn Lin * According to eMMC spec, card reset procedure: 1561935a665eSShawn Lin * tRstW >= 1us: RST_n pulse width 1562935a665eSShawn Lin * tRSCA >= 200us: RST_n to Command time 1563935a665eSShawn Lin * tRSTH >= 1us: RST_n high period 1564935a665eSShawn Lin */ 1565935a665eSShawn Lin reset = mci_readl(host, RST_N); 1566935a665eSShawn Lin reset &= ~(SDMMC_RST_HWACTIVE << slot->id); 1567935a665eSShawn Lin mci_writel(host, RST_N, reset); 1568935a665eSShawn Lin usleep_range(1, 2); 1569935a665eSShawn Lin reset |= SDMMC_RST_HWACTIVE << slot->id; 1570935a665eSShawn Lin mci_writel(host, RST_N, reset); 1571935a665eSShawn Lin usleep_range(200, 300); 1572935a665eSShawn Lin } 1573935a665eSShawn Lin 1574b24c8b26SDoug Anderson static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) 1575b24c8b26SDoug Anderson { 1576b24c8b26SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 1577b24c8b26SDoug Anderson struct dw_mci *host = slot->host; 1578b24c8b26SDoug Anderson 15799623b5b9SDoug Anderson /* 15809623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 15819623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 15829623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 15839623b5b9SDoug Anderson */ 1584b24c8b26SDoug Anderson if (mmc->caps & MMC_CAP_SDIO_IRQ) { 15859623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 1586b24c8b26SDoug Anderson u32 clk_en_a_old; 1587b24c8b26SDoug Anderson u32 clk_en_a; 15889623b5b9SDoug Anderson 1589b24c8b26SDoug Anderson clk_en_a_old = mci_readl(host, CLKENA); 15909623b5b9SDoug Anderson 1591b24c8b26SDoug Anderson if (card->type == MMC_TYPE_SDIO || 1592b24c8b26SDoug Anderson card->type == MMC_TYPE_SD_COMBO) { 1593b24c8b26SDoug Anderson set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1594b24c8b26SDoug Anderson clk_en_a = clk_en_a_old & ~clken_low_pwr; 1595b24c8b26SDoug Anderson } else { 1596b24c8b26SDoug Anderson clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1597b24c8b26SDoug Anderson clk_en_a = clk_en_a_old | clken_low_pwr; 1598b24c8b26SDoug Anderson } 1599b24c8b26SDoug Anderson 1600b24c8b26SDoug Anderson if (clk_en_a != clk_en_a_old) { 1601b24c8b26SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 16029623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 16039623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 16049623b5b9SDoug Anderson } 16059623b5b9SDoug Anderson } 1606b24c8b26SDoug Anderson } 16079623b5b9SDoug Anderson 16081a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 16091a5c8e1fSShashidhar Hiremath { 16101a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 16111a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 1612f8c58c11SDoug Anderson unsigned long irqflags; 16131a5c8e1fSShashidhar Hiremath u32 int_mask; 16141a5c8e1fSShashidhar Hiremath 1615f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1616f8c58c11SDoug Anderson 16171a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 16181a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 1619b24c8b26SDoug Anderson if (enb) 1620b24c8b26SDoug Anderson int_mask |= SDMMC_INT_SDIO(slot->sdio_id); 1621b24c8b26SDoug Anderson else 1622b24c8b26SDoug Anderson int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id); 1623b24c8b26SDoug Anderson mci_writel(host, INTMASK, int_mask); 1624f8c58c11SDoug Anderson 1625f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 16261a5c8e1fSShashidhar Hiremath } 16271a5c8e1fSShashidhar Hiremath 16280976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 16290976f16dSSeungwon Jeon { 16300976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 16310976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 16320976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 16330e3a22c0SShawn Lin int err = -EINVAL; 16340976f16dSSeungwon Jeon 16350976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 16369979dbe5SChaotian Jing err = drv_data->execute_tuning(slot, opcode); 16370976f16dSSeungwon Jeon return err; 16380976f16dSSeungwon Jeon } 16390976f16dSSeungwon Jeon 16400e3a22c0SShawn Lin static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, 16410e3a22c0SShawn Lin struct mmc_ios *ios) 164280113132SSeungwon Jeon { 164380113132SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 164480113132SSeungwon Jeon struct dw_mci *host = slot->host; 164580113132SSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 164680113132SSeungwon Jeon 164780113132SSeungwon Jeon if (drv_data && drv_data->prepare_hs400_tuning) 164880113132SSeungwon Jeon return drv_data->prepare_hs400_tuning(host, ios); 164980113132SSeungwon Jeon 165080113132SSeungwon Jeon return 0; 165180113132SSeungwon Jeon } 165280113132SSeungwon Jeon 1653f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1654f95f3850SWill Newton .request = dw_mci_request, 16559aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 16569aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1657f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1658f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1659f95f3850SWill Newton .get_cd = dw_mci_get_cd, 1660935a665eSShawn Lin .hw_reset = dw_mci_hw_reset, 16611a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 16620976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 166301730558SDoug Anderson .card_busy = dw_mci_card_busy, 166401730558SDoug Anderson .start_signal_voltage_switch = dw_mci_switch_voltage, 1665b24c8b26SDoug Anderson .init_card = dw_mci_init_card, 166680113132SSeungwon Jeon .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, 1667f95f3850SWill Newton }; 1668f95f3850SWill Newton 1669f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1670f95f3850SWill Newton __releases(&host->lock) 1671f95f3850SWill Newton __acquires(&host->lock) 1672f95f3850SWill Newton { 1673f95f3850SWill Newton struct dw_mci_slot *slot; 1674f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1675f95f3850SWill Newton 1676f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1677f95f3850SWill Newton 1678f95f3850SWill Newton host->cur_slot->mrq = NULL; 1679f95f3850SWill Newton host->mrq = NULL; 1680f95f3850SWill Newton if (!list_empty(&host->queue)) { 1681f95f3850SWill Newton slot = list_entry(host->queue.next, 1682f95f3850SWill Newton struct dw_mci_slot, queue_node); 1683f95f3850SWill Newton list_del(&slot->queue_node); 16844a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1685f95f3850SWill Newton mmc_hostname(slot->mmc)); 1686f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1687f95f3850SWill Newton dw_mci_start_request(host, slot); 1688f95f3850SWill Newton } else { 16894a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 169001730558SDoug Anderson 169101730558SDoug Anderson if (host->state == STATE_SENDING_CMD11) 169201730558SDoug Anderson host->state = STATE_WAITING_CMD11_DONE; 169301730558SDoug Anderson else 1694f95f3850SWill Newton host->state = STATE_IDLE; 1695f95f3850SWill Newton } 1696f95f3850SWill Newton 1697f95f3850SWill Newton spin_unlock(&host->lock); 1698f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1699f95f3850SWill Newton spin_lock(&host->lock); 1700f95f3850SWill Newton } 1701f95f3850SWill Newton 1702e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1703f95f3850SWill Newton { 1704f95f3850SWill Newton u32 status = host->cmd_status; 1705f95f3850SWill Newton 1706f95f3850SWill Newton host->cmd_status = 0; 1707f95f3850SWill Newton 1708f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1709f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1710f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1711f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1712f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1713f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1714f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1715f95f3850SWill Newton } else { 1716f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1717f95f3850SWill Newton cmd->resp[1] = 0; 1718f95f3850SWill Newton cmd->resp[2] = 0; 1719f95f3850SWill Newton cmd->resp[3] = 0; 1720f95f3850SWill Newton } 1721f95f3850SWill Newton } 1722f95f3850SWill Newton 1723f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1724f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1725f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1726f95f3850SWill Newton cmd->error = -EILSEQ; 1727f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1728f95f3850SWill Newton cmd->error = -EIO; 1729f95f3850SWill Newton else 1730f95f3850SWill Newton cmd->error = 0; 1731f95f3850SWill Newton 1732e352c813SSeungwon Jeon return cmd->error; 1733e352c813SSeungwon Jeon } 1734e352c813SSeungwon Jeon 1735e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) 1736e352c813SSeungwon Jeon { 173731bff450SSeungwon Jeon u32 status = host->data_status; 1738e352c813SSeungwon Jeon 1739e352c813SSeungwon Jeon if (status & DW_MCI_DATA_ERROR_FLAGS) { 1740e352c813SSeungwon Jeon if (status & SDMMC_INT_DRTO) { 1741e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1742e352c813SSeungwon Jeon } else if (status & SDMMC_INT_DCRC) { 1743e352c813SSeungwon Jeon data->error = -EILSEQ; 1744e352c813SSeungwon Jeon } else if (status & SDMMC_INT_EBE) { 1745e352c813SSeungwon Jeon if (host->dir_status == 1746e352c813SSeungwon Jeon DW_MCI_SEND_STATUS) { 1747e352c813SSeungwon Jeon /* 1748e352c813SSeungwon Jeon * No data CRC status was returned. 1749e352c813SSeungwon Jeon * The number of bytes transferred 1750e352c813SSeungwon Jeon * will be exaggerated in PIO mode. 1751e352c813SSeungwon Jeon */ 1752e352c813SSeungwon Jeon data->bytes_xfered = 0; 1753e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1754e352c813SSeungwon Jeon } else if (host->dir_status == 1755e352c813SSeungwon Jeon DW_MCI_RECV_STATUS) { 1756e7a1dec1SShawn Lin data->error = -EILSEQ; 1757e352c813SSeungwon Jeon } 1758e352c813SSeungwon Jeon } else { 1759e352c813SSeungwon Jeon /* SDMMC_INT_SBE is included */ 1760e7a1dec1SShawn Lin data->error = -EILSEQ; 1761e352c813SSeungwon Jeon } 1762e352c813SSeungwon Jeon 1763e6cc0123SDoug Anderson dev_dbg(host->dev, "data error, status 0x%08x\n", status); 1764e352c813SSeungwon Jeon 1765e352c813SSeungwon Jeon /* 1766e352c813SSeungwon Jeon * After an error, there may be data lingering 176731bff450SSeungwon Jeon * in the FIFO 1768e352c813SSeungwon Jeon */ 17693a33a94cSSonny Rao dw_mci_reset(host); 1770e352c813SSeungwon Jeon } else { 1771e352c813SSeungwon Jeon data->bytes_xfered = data->blocks * data->blksz; 1772e352c813SSeungwon Jeon data->error = 0; 1773e352c813SSeungwon Jeon } 1774e352c813SSeungwon Jeon 1775e352c813SSeungwon Jeon return data->error; 1776f95f3850SWill Newton } 1777f95f3850SWill Newton 177857e10486SAddy Ke static void dw_mci_set_drto(struct dw_mci *host) 177957e10486SAddy Ke { 178057e10486SAddy Ke unsigned int drto_clks; 178157e10486SAddy Ke unsigned int drto_ms; 178257e10486SAddy Ke 178357e10486SAddy Ke drto_clks = mci_readl(host, TMOUT) >> 8; 178457e10486SAddy Ke drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000); 178557e10486SAddy Ke 178657e10486SAddy Ke /* add a bit spare time */ 178757e10486SAddy Ke drto_ms += 10; 178857e10486SAddy Ke 178957e10486SAddy Ke mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms)); 179057e10486SAddy Ke } 179157e10486SAddy Ke 1792f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1793f95f3850SWill Newton { 1794f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1795f95f3850SWill Newton struct mmc_data *data; 1796f95f3850SWill Newton struct mmc_command *cmd; 1797e352c813SSeungwon Jeon struct mmc_request *mrq; 1798f95f3850SWill Newton enum dw_mci_state state; 1799f95f3850SWill Newton enum dw_mci_state prev_state; 1800e352c813SSeungwon Jeon unsigned int err; 1801f95f3850SWill Newton 1802f95f3850SWill Newton spin_lock(&host->lock); 1803f95f3850SWill Newton 1804f95f3850SWill Newton state = host->state; 1805f95f3850SWill Newton data = host->data; 1806e352c813SSeungwon Jeon mrq = host->mrq; 1807f95f3850SWill Newton 1808f95f3850SWill Newton do { 1809f95f3850SWill Newton prev_state = state; 1810f95f3850SWill Newton 1811f95f3850SWill Newton switch (state) { 1812f95f3850SWill Newton case STATE_IDLE: 181301730558SDoug Anderson case STATE_WAITING_CMD11_DONE: 1814f95f3850SWill Newton break; 1815f95f3850SWill Newton 181601730558SDoug Anderson case STATE_SENDING_CMD11: 1817f95f3850SWill Newton case STATE_SENDING_CMD: 1818f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1819f95f3850SWill Newton &host->pending_events)) 1820f95f3850SWill Newton break; 1821f95f3850SWill Newton 1822f95f3850SWill Newton cmd = host->cmd; 1823f95f3850SWill Newton host->cmd = NULL; 1824f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1825e352c813SSeungwon Jeon err = dw_mci_command_complete(host, cmd); 1826e352c813SSeungwon Jeon if (cmd == mrq->sbc && !err) { 1827053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1828053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1829e352c813SSeungwon Jeon mrq->cmd); 1830053b3ce6SSeungwon Jeon goto unlock; 1831053b3ce6SSeungwon Jeon } 1832053b3ce6SSeungwon Jeon 1833e352c813SSeungwon Jeon if (cmd->data && err) { 183446d17952SDoug Anderson /* 183546d17952SDoug Anderson * During UHS tuning sequence, sending the stop 183646d17952SDoug Anderson * command after the response CRC error would 183746d17952SDoug Anderson * throw the system into a confused state 183846d17952SDoug Anderson * causing all future tuning phases to report 183946d17952SDoug Anderson * failure. 184046d17952SDoug Anderson * 184146d17952SDoug Anderson * In such case controller will move into a data 184246d17952SDoug Anderson * transfer state after a response error or 184346d17952SDoug Anderson * response CRC error. Let's let that finish 184446d17952SDoug Anderson * before trying to send a stop, so we'll go to 184546d17952SDoug Anderson * STATE_SENDING_DATA. 184646d17952SDoug Anderson * 184746d17952SDoug Anderson * Although letting the data transfer take place 184846d17952SDoug Anderson * will waste a bit of time (we already know 184946d17952SDoug Anderson * the command was bad), it can't cause any 185046d17952SDoug Anderson * errors since it's possible it would have 185146d17952SDoug Anderson * taken place anyway if this tasklet got 185246d17952SDoug Anderson * delayed. Allowing the transfer to take place 185346d17952SDoug Anderson * avoids races and keeps things simple. 185446d17952SDoug Anderson */ 185546d17952SDoug Anderson if ((err != -ETIMEDOUT) && 185646d17952SDoug Anderson (cmd->opcode == MMC_SEND_TUNING_BLOCK)) { 185746d17952SDoug Anderson state = STATE_SENDING_DATA; 185846d17952SDoug Anderson continue; 185946d17952SDoug Anderson } 186046d17952SDoug Anderson 186171abb133SSeungwon Jeon dw_mci_stop_dma(host); 186290c2143aSSeungwon Jeon send_stop_abort(host, data); 186371abb133SSeungwon Jeon state = STATE_SENDING_STOP; 186471abb133SSeungwon Jeon break; 186571abb133SSeungwon Jeon } 186671abb133SSeungwon Jeon 1867e352c813SSeungwon Jeon if (!cmd->data || err) { 1868e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1869f95f3850SWill Newton goto unlock; 1870f95f3850SWill Newton } 1871f95f3850SWill Newton 1872f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1873f95f3850SWill Newton /* fall through */ 1874f95f3850SWill Newton 1875f95f3850SWill Newton case STATE_SENDING_DATA: 18762aa35465SDoug Anderson /* 18772aa35465SDoug Anderson * We could get a data error and never a transfer 18782aa35465SDoug Anderson * complete so we'd better check for it here. 18792aa35465SDoug Anderson * 18802aa35465SDoug Anderson * Note that we don't really care if we also got a 18812aa35465SDoug Anderson * transfer complete; stopping the DMA and sending an 18822aa35465SDoug Anderson * abort won't hurt. 18832aa35465SDoug Anderson */ 1884f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1885f95f3850SWill Newton &host->pending_events)) { 1886f95f3850SWill Newton dw_mci_stop_dma(host); 1887e13c3c08SJaehoon Chung if (!(host->data_status & (SDMMC_INT_DRTO | 1888bdb9a90bSaddy ke SDMMC_INT_EBE))) 188990c2143aSSeungwon Jeon send_stop_abort(host, data); 1890f95f3850SWill Newton state = STATE_DATA_ERROR; 1891f95f3850SWill Newton break; 1892f95f3850SWill Newton } 1893f95f3850SWill Newton 1894f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 189557e10486SAddy Ke &host->pending_events)) { 189657e10486SAddy Ke /* 189757e10486SAddy Ke * If all data-related interrupts don't come 189857e10486SAddy Ke * within the given time in reading data state. 189957e10486SAddy Ke */ 190016a34574SJaehoon Chung if (host->dir_status == DW_MCI_RECV_STATUS) 190157e10486SAddy Ke dw_mci_set_drto(host); 1902f95f3850SWill Newton break; 190357e10486SAddy Ke } 1904f95f3850SWill Newton 1905f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 19062aa35465SDoug Anderson 19072aa35465SDoug Anderson /* 19082aa35465SDoug Anderson * Handle an EVENT_DATA_ERROR that might have shown up 19092aa35465SDoug Anderson * before the transfer completed. This might not have 19102aa35465SDoug Anderson * been caught by the check above because the interrupt 19112aa35465SDoug Anderson * could have gone off between the previous check and 19122aa35465SDoug Anderson * the check for transfer complete. 19132aa35465SDoug Anderson * 19142aa35465SDoug Anderson * Technically this ought not be needed assuming we 19152aa35465SDoug Anderson * get a DATA_COMPLETE eventually (we'll notice the 19162aa35465SDoug Anderson * error and end the request), but it shouldn't hurt. 19172aa35465SDoug Anderson * 19182aa35465SDoug Anderson * This has the advantage of sending the stop command. 19192aa35465SDoug Anderson */ 19202aa35465SDoug Anderson if (test_and_clear_bit(EVENT_DATA_ERROR, 19212aa35465SDoug Anderson &host->pending_events)) { 19222aa35465SDoug Anderson dw_mci_stop_dma(host); 1923e13c3c08SJaehoon Chung if (!(host->data_status & (SDMMC_INT_DRTO | 1924bdb9a90bSaddy ke SDMMC_INT_EBE))) 19252aa35465SDoug Anderson send_stop_abort(host, data); 19262aa35465SDoug Anderson state = STATE_DATA_ERROR; 19272aa35465SDoug Anderson break; 19282aa35465SDoug Anderson } 1929f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 19302aa35465SDoug Anderson 1931f95f3850SWill Newton /* fall through */ 1932f95f3850SWill Newton 1933f95f3850SWill Newton case STATE_DATA_BUSY: 1934f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 193557e10486SAddy Ke &host->pending_events)) { 193657e10486SAddy Ke /* 193757e10486SAddy Ke * If data error interrupt comes but data over 193857e10486SAddy Ke * interrupt doesn't come within the given time. 193957e10486SAddy Ke * in reading data state. 194057e10486SAddy Ke */ 194116a34574SJaehoon Chung if (host->dir_status == DW_MCI_RECV_STATUS) 194257e10486SAddy Ke dw_mci_set_drto(host); 1943f95f3850SWill Newton break; 194457e10486SAddy Ke } 1945f95f3850SWill Newton 1946f95f3850SWill Newton host->data = NULL; 1947f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 1948e352c813SSeungwon Jeon err = dw_mci_data_complete(host, data); 1949f95f3850SWill Newton 1950e352c813SSeungwon Jeon if (!err) { 1951e352c813SSeungwon Jeon if (!data->stop || mrq->sbc) { 195217c8bc85SSachin Kamat if (mrq->sbc && data->stop) 1953053b3ce6SSeungwon Jeon data->stop->error = 0; 1954e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1955053b3ce6SSeungwon Jeon goto unlock; 1956053b3ce6SSeungwon Jeon } 1957053b3ce6SSeungwon Jeon 195890c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 1959e352c813SSeungwon Jeon if (data->stop) 196090c2143aSSeungwon Jeon send_stop_abort(host, data); 19612aa35465SDoug Anderson } else { 19622aa35465SDoug Anderson /* 19632aa35465SDoug Anderson * If we don't have a command complete now we'll 19642aa35465SDoug Anderson * never get one since we just reset everything; 19652aa35465SDoug Anderson * better end the request. 19662aa35465SDoug Anderson * 19672aa35465SDoug Anderson * If we do have a command complete we'll fall 19682aa35465SDoug Anderson * through to the SENDING_STOP command and 19692aa35465SDoug Anderson * everything will be peachy keen. 19702aa35465SDoug Anderson */ 19712aa35465SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, 19722aa35465SDoug Anderson &host->pending_events)) { 19732aa35465SDoug Anderson host->cmd = NULL; 19742aa35465SDoug Anderson dw_mci_request_end(host, mrq); 19752aa35465SDoug Anderson goto unlock; 19762aa35465SDoug Anderson } 197790c2143aSSeungwon Jeon } 1978e352c813SSeungwon Jeon 1979e352c813SSeungwon Jeon /* 1980e352c813SSeungwon Jeon * If err has non-zero, 1981e352c813SSeungwon Jeon * stop-abort command has been already issued. 1982e352c813SSeungwon Jeon */ 1983e352c813SSeungwon Jeon prev_state = state = STATE_SENDING_STOP; 1984e352c813SSeungwon Jeon 1985f95f3850SWill Newton /* fall through */ 1986f95f3850SWill Newton 1987f95f3850SWill Newton case STATE_SENDING_STOP: 1988f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1989f95f3850SWill Newton &host->pending_events)) 1990f95f3850SWill Newton break; 1991f95f3850SWill Newton 199271abb133SSeungwon Jeon /* CMD error in data command */ 199331bff450SSeungwon Jeon if (mrq->cmd->error && mrq->data) 19943a33a94cSSonny Rao dw_mci_reset(host); 199571abb133SSeungwon Jeon 1996f95f3850SWill Newton host->cmd = NULL; 199771abb133SSeungwon Jeon host->data = NULL; 199890c2143aSSeungwon Jeon 1999e13c3c08SJaehoon Chung if (!mrq->sbc && mrq->stop) 2000e352c813SSeungwon Jeon dw_mci_command_complete(host, mrq->stop); 200190c2143aSSeungwon Jeon else 200290c2143aSSeungwon Jeon host->cmd_status = 0; 200390c2143aSSeungwon Jeon 2004e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 2005f95f3850SWill Newton goto unlock; 2006f95f3850SWill Newton 2007f95f3850SWill Newton case STATE_DATA_ERROR: 2008f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 2009f95f3850SWill Newton &host->pending_events)) 2010f95f3850SWill Newton break; 2011f95f3850SWill Newton 2012f95f3850SWill Newton state = STATE_DATA_BUSY; 2013f95f3850SWill Newton break; 2014f95f3850SWill Newton } 2015f95f3850SWill Newton } while (state != prev_state); 2016f95f3850SWill Newton 2017f95f3850SWill Newton host->state = state; 2018f95f3850SWill Newton unlock: 2019f95f3850SWill Newton spin_unlock(&host->lock); 2020f95f3850SWill Newton 2021f95f3850SWill Newton } 2022f95f3850SWill Newton 202334b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 202434b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 202534b664a2SJames Hogan { 202634b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 202734b664a2SJames Hogan host->part_buf_count = cnt; 202834b664a2SJames Hogan } 202934b664a2SJames Hogan 203034b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 203134b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 203234b664a2SJames Hogan { 203334b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 203434b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 203534b664a2SJames Hogan host->part_buf_count += cnt; 203634b664a2SJames Hogan return cnt; 203734b664a2SJames Hogan } 203834b664a2SJames Hogan 203934b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 204034b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 204134b664a2SJames Hogan { 20420e3a22c0SShawn Lin cnt = min_t(int, cnt, host->part_buf_count); 204334b664a2SJames Hogan if (cnt) { 204434b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 204534b664a2SJames Hogan cnt); 204634b664a2SJames Hogan host->part_buf_count -= cnt; 204734b664a2SJames Hogan host->part_buf_start += cnt; 204834b664a2SJames Hogan } 204934b664a2SJames Hogan return cnt; 205034b664a2SJames Hogan } 205134b664a2SJames Hogan 205234b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 205334b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 205434b664a2SJames Hogan { 205534b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 205634b664a2SJames Hogan host->part_buf_start = cnt; 205734b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 205834b664a2SJames Hogan } 205934b664a2SJames Hogan 2060f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 2061f95f3850SWill Newton { 2062cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2063cfbeb59cSMarkos Chandras int init_cnt = cnt; 2064cfbeb59cSMarkos Chandras 206534b664a2SJames Hogan /* try and push anything in the part_buf */ 206634b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 206734b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 20680e3a22c0SShawn Lin 206934b664a2SJames Hogan buf += len; 207034b664a2SJames Hogan cnt -= len; 2071cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 207276184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 207334b664a2SJames Hogan host->part_buf_count = 0; 207434b664a2SJames Hogan } 207534b664a2SJames Hogan } 207634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 207734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 207834b664a2SJames Hogan while (cnt >= 2) { 207934b664a2SJames Hogan u16 aligned_buf[64]; 208034b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 208134b664a2SJames Hogan int items = len >> 1; 208234b664a2SJames Hogan int i; 208334b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 208434b664a2SJames Hogan memcpy(aligned_buf, buf, len); 208534b664a2SJames Hogan buf += len; 208634b664a2SJames Hogan cnt -= len; 208734b664a2SJames Hogan /* push data from aligned buffer into fifo */ 208834b664a2SJames Hogan for (i = 0; i < items; ++i) 208976184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, aligned_buf[i]); 209034b664a2SJames Hogan } 209134b664a2SJames Hogan } else 209234b664a2SJames Hogan #endif 209334b664a2SJames Hogan { 209434b664a2SJames Hogan u16 *pdata = buf; 20950e3a22c0SShawn Lin 209634b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 209776184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, *pdata++); 209834b664a2SJames Hogan buf = pdata; 209934b664a2SJames Hogan } 210034b664a2SJames Hogan /* put anything remaining in the part_buf */ 210134b664a2SJames Hogan if (cnt) { 210234b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2103cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2104cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2105cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 210676184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 2107f95f3850SWill Newton } 2108f95f3850SWill Newton } 2109f95f3850SWill Newton 2110f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 2111f95f3850SWill Newton { 211234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 211334b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 211434b664a2SJames Hogan while (cnt >= 2) { 211534b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 211634b664a2SJames Hogan u16 aligned_buf[64]; 211734b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 211834b664a2SJames Hogan int items = len >> 1; 211934b664a2SJames Hogan int i; 21200e3a22c0SShawn Lin 212134b664a2SJames Hogan for (i = 0; i < items; ++i) 212276184ac1SBen Dooks aligned_buf[i] = mci_fifo_readw(host->fifo_reg); 212334b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 212434b664a2SJames Hogan memcpy(buf, aligned_buf, len); 212534b664a2SJames Hogan buf += len; 212634b664a2SJames Hogan cnt -= len; 212734b664a2SJames Hogan } 212834b664a2SJames Hogan } else 212934b664a2SJames Hogan #endif 213034b664a2SJames Hogan { 213134b664a2SJames Hogan u16 *pdata = buf; 21320e3a22c0SShawn Lin 213334b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 213476184ac1SBen Dooks *pdata++ = mci_fifo_readw(host->fifo_reg); 213534b664a2SJames Hogan buf = pdata; 213634b664a2SJames Hogan } 213734b664a2SJames Hogan if (cnt) { 213876184ac1SBen Dooks host->part_buf16 = mci_fifo_readw(host->fifo_reg); 213934b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 2140f95f3850SWill Newton } 2141f95f3850SWill Newton } 2142f95f3850SWill Newton 2143f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 2144f95f3850SWill Newton { 2145cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2146cfbeb59cSMarkos Chandras int init_cnt = cnt; 2147cfbeb59cSMarkos Chandras 214834b664a2SJames Hogan /* try and push anything in the part_buf */ 214934b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 215034b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 21510e3a22c0SShawn Lin 215234b664a2SJames Hogan buf += len; 215334b664a2SJames Hogan cnt -= len; 2154cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 215576184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 215634b664a2SJames Hogan host->part_buf_count = 0; 215734b664a2SJames Hogan } 215834b664a2SJames Hogan } 215934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 216034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 216134b664a2SJames Hogan while (cnt >= 4) { 216234b664a2SJames Hogan u32 aligned_buf[32]; 216334b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 216434b664a2SJames Hogan int items = len >> 2; 216534b664a2SJames Hogan int i; 216634b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 216734b664a2SJames Hogan memcpy(aligned_buf, buf, len); 216834b664a2SJames Hogan buf += len; 216934b664a2SJames Hogan cnt -= len; 217034b664a2SJames Hogan /* push data from aligned buffer into fifo */ 217134b664a2SJames Hogan for (i = 0; i < items; ++i) 217276184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, aligned_buf[i]); 217334b664a2SJames Hogan } 217434b664a2SJames Hogan } else 217534b664a2SJames Hogan #endif 217634b664a2SJames Hogan { 217734b664a2SJames Hogan u32 *pdata = buf; 21780e3a22c0SShawn Lin 217934b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 218076184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, *pdata++); 218134b664a2SJames Hogan buf = pdata; 218234b664a2SJames Hogan } 218334b664a2SJames Hogan /* put anything remaining in the part_buf */ 218434b664a2SJames Hogan if (cnt) { 218534b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2186cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2187cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2188cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 218976184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 2190f95f3850SWill Newton } 2191f95f3850SWill Newton } 2192f95f3850SWill Newton 2193f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 2194f95f3850SWill Newton { 219534b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 219634b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 219734b664a2SJames Hogan while (cnt >= 4) { 219834b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 219934b664a2SJames Hogan u32 aligned_buf[32]; 220034b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 220134b664a2SJames Hogan int items = len >> 2; 220234b664a2SJames Hogan int i; 22030e3a22c0SShawn Lin 220434b664a2SJames Hogan for (i = 0; i < items; ++i) 220576184ac1SBen Dooks aligned_buf[i] = mci_fifo_readl(host->fifo_reg); 220634b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 220734b664a2SJames Hogan memcpy(buf, aligned_buf, len); 220834b664a2SJames Hogan buf += len; 220934b664a2SJames Hogan cnt -= len; 221034b664a2SJames Hogan } 221134b664a2SJames Hogan } else 221234b664a2SJames Hogan #endif 221334b664a2SJames Hogan { 221434b664a2SJames Hogan u32 *pdata = buf; 22150e3a22c0SShawn Lin 221634b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 221776184ac1SBen Dooks *pdata++ = mci_fifo_readl(host->fifo_reg); 221834b664a2SJames Hogan buf = pdata; 221934b664a2SJames Hogan } 222034b664a2SJames Hogan if (cnt) { 222176184ac1SBen Dooks host->part_buf32 = mci_fifo_readl(host->fifo_reg); 222234b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 2223f95f3850SWill Newton } 2224f95f3850SWill Newton } 2225f95f3850SWill Newton 2226f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 2227f95f3850SWill Newton { 2228cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2229cfbeb59cSMarkos Chandras int init_cnt = cnt; 2230cfbeb59cSMarkos Chandras 223134b664a2SJames Hogan /* try and push anything in the part_buf */ 223234b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 223334b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 22340e3a22c0SShawn Lin 223534b664a2SJames Hogan buf += len; 223634b664a2SJames Hogan cnt -= len; 2237c09fbd74SSeungwon Jeon 2238cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 223976184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 224034b664a2SJames Hogan host->part_buf_count = 0; 224134b664a2SJames Hogan } 224234b664a2SJames Hogan } 224334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 224434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 224534b664a2SJames Hogan while (cnt >= 8) { 224634b664a2SJames Hogan u64 aligned_buf[16]; 224734b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 224834b664a2SJames Hogan int items = len >> 3; 224934b664a2SJames Hogan int i; 225034b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 225134b664a2SJames Hogan memcpy(aligned_buf, buf, len); 225234b664a2SJames Hogan buf += len; 225334b664a2SJames Hogan cnt -= len; 225434b664a2SJames Hogan /* push data from aligned buffer into fifo */ 225534b664a2SJames Hogan for (i = 0; i < items; ++i) 225676184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, aligned_buf[i]); 225734b664a2SJames Hogan } 225834b664a2SJames Hogan } else 225934b664a2SJames Hogan #endif 226034b664a2SJames Hogan { 226134b664a2SJames Hogan u64 *pdata = buf; 22620e3a22c0SShawn Lin 226334b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 226476184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, *pdata++); 226534b664a2SJames Hogan buf = pdata; 226634b664a2SJames Hogan } 226734b664a2SJames Hogan /* put anything remaining in the part_buf */ 226834b664a2SJames Hogan if (cnt) { 226934b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2270cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2271cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2272cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 227376184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 2274f95f3850SWill Newton } 2275f95f3850SWill Newton } 2276f95f3850SWill Newton 2277f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 2278f95f3850SWill Newton { 227934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 228034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 228134b664a2SJames Hogan while (cnt >= 8) { 228234b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 228334b664a2SJames Hogan u64 aligned_buf[16]; 228434b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 228534b664a2SJames Hogan int items = len >> 3; 228634b664a2SJames Hogan int i; 22870e3a22c0SShawn Lin 228834b664a2SJames Hogan for (i = 0; i < items; ++i) 228976184ac1SBen Dooks aligned_buf[i] = mci_fifo_readq(host->fifo_reg); 229076184ac1SBen Dooks 229134b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 229234b664a2SJames Hogan memcpy(buf, aligned_buf, len); 229334b664a2SJames Hogan buf += len; 229434b664a2SJames Hogan cnt -= len; 2295f95f3850SWill Newton } 229634b664a2SJames Hogan } else 229734b664a2SJames Hogan #endif 229834b664a2SJames Hogan { 229934b664a2SJames Hogan u64 *pdata = buf; 23000e3a22c0SShawn Lin 230134b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 230276184ac1SBen Dooks *pdata++ = mci_fifo_readq(host->fifo_reg); 230334b664a2SJames Hogan buf = pdata; 230434b664a2SJames Hogan } 230534b664a2SJames Hogan if (cnt) { 230676184ac1SBen Dooks host->part_buf = mci_fifo_readq(host->fifo_reg); 230734b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 230834b664a2SJames Hogan } 230934b664a2SJames Hogan } 231034b664a2SJames Hogan 231134b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 231234b664a2SJames Hogan { 231334b664a2SJames Hogan int len; 231434b664a2SJames Hogan 231534b664a2SJames Hogan /* get remaining partial bytes */ 231634b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 231734b664a2SJames Hogan if (unlikely(len == cnt)) 231834b664a2SJames Hogan return; 231934b664a2SJames Hogan buf += len; 232034b664a2SJames Hogan cnt -= len; 232134b664a2SJames Hogan 232234b664a2SJames Hogan /* get the rest of the data */ 232334b664a2SJames Hogan host->pull_data(host, buf, cnt); 2324f95f3850SWill Newton } 2325f95f3850SWill Newton 232687a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 2327f95f3850SWill Newton { 2328f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2329f9c2a0dcSSeungwon Jeon void *buf; 2330f9c2a0dcSSeungwon Jeon unsigned int offset; 2331f95f3850SWill Newton struct mmc_data *data = host->data; 2332f95f3850SWill Newton int shift = host->data_shift; 2333f95f3850SWill Newton u32 status; 23343e4b0d8bSMarkos Chandras unsigned int len; 2335f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2336f95f3850SWill Newton 2337f95f3850SWill Newton do { 2338f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2339f9c2a0dcSSeungwon Jeon goto done; 2340f95f3850SWill Newton 23414225fc85SImre Deak host->sg = sg_miter->piter.sg; 2342f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2343f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2344f9c2a0dcSSeungwon Jeon offset = 0; 2345f9c2a0dcSSeungwon Jeon 2346f9c2a0dcSSeungwon Jeon do { 2347f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 2348f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 2349f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2350f9c2a0dcSSeungwon Jeon if (!len) 2351f9c2a0dcSSeungwon Jeon break; 2352f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 23533e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2354f95f3850SWill Newton offset += len; 2355f9c2a0dcSSeungwon Jeon remain -= len; 2356f9c2a0dcSSeungwon Jeon } while (remain); 2357f95f3850SWill Newton 2358e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2359f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2360f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 236187a74d39SKyoungil Kim /* if the RXDR is ready read again */ 236287a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 236387a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 2364f9c2a0dcSSeungwon Jeon 2365f9c2a0dcSSeungwon Jeon if (!remain) { 2366f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2367f9c2a0dcSSeungwon Jeon goto done; 2368f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2369f9c2a0dcSSeungwon Jeon } 2370f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2371f95f3850SWill Newton return; 2372f95f3850SWill Newton 2373f95f3850SWill Newton done: 2374f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2375f9c2a0dcSSeungwon Jeon host->sg = NULL; 23760e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2377f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2378f95f3850SWill Newton } 2379f95f3850SWill Newton 2380f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 2381f95f3850SWill Newton { 2382f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2383f9c2a0dcSSeungwon Jeon void *buf; 2384f9c2a0dcSSeungwon Jeon unsigned int offset; 2385f95f3850SWill Newton struct mmc_data *data = host->data; 2386f95f3850SWill Newton int shift = host->data_shift; 2387f95f3850SWill Newton u32 status; 23883e4b0d8bSMarkos Chandras unsigned int len; 2389f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 2390f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2391f95f3850SWill Newton 2392f95f3850SWill Newton do { 2393f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2394f9c2a0dcSSeungwon Jeon goto done; 2395f95f3850SWill Newton 23964225fc85SImre Deak host->sg = sg_miter->piter.sg; 2397f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2398f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2399f9c2a0dcSSeungwon Jeon offset = 0; 2400f9c2a0dcSSeungwon Jeon 2401f9c2a0dcSSeungwon Jeon do { 2402f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 2403f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 2404f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 2405f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2406f9c2a0dcSSeungwon Jeon if (!len) 2407f9c2a0dcSSeungwon Jeon break; 2408f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 24093e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2410f95f3850SWill Newton offset += len; 2411f9c2a0dcSSeungwon Jeon remain -= len; 2412f9c2a0dcSSeungwon Jeon } while (remain); 2413f95f3850SWill Newton 2414e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2415f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2416f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2417f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 2418f9c2a0dcSSeungwon Jeon 2419f9c2a0dcSSeungwon Jeon if (!remain) { 2420f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2421f9c2a0dcSSeungwon Jeon goto done; 2422f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2423f9c2a0dcSSeungwon Jeon } 2424f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2425f95f3850SWill Newton return; 2426f95f3850SWill Newton 2427f95f3850SWill Newton done: 2428f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2429f9c2a0dcSSeungwon Jeon host->sg = NULL; 24300e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2431f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2432f95f3850SWill Newton } 2433f95f3850SWill Newton 2434f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 2435f95f3850SWill Newton { 2436f95f3850SWill Newton if (!host->cmd_status) 2437f95f3850SWill Newton host->cmd_status = status; 2438f95f3850SWill Newton 24390e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2440f95f3850SWill Newton 2441f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2442f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2443f95f3850SWill Newton } 2444f95f3850SWill Newton 24456130e7a9SDoug Anderson static void dw_mci_handle_cd(struct dw_mci *host) 24466130e7a9SDoug Anderson { 24476130e7a9SDoug Anderson int i; 24486130e7a9SDoug Anderson 24496130e7a9SDoug Anderson for (i = 0; i < host->num_slots; i++) { 24506130e7a9SDoug Anderson struct dw_mci_slot *slot = host->slot[i]; 24516130e7a9SDoug Anderson 24526130e7a9SDoug Anderson if (!slot) 24536130e7a9SDoug Anderson continue; 24546130e7a9SDoug Anderson 24556130e7a9SDoug Anderson if (slot->mmc->ops->card_event) 24566130e7a9SDoug Anderson slot->mmc->ops->card_event(slot->mmc); 24576130e7a9SDoug Anderson mmc_detect_change(slot->mmc, 24586130e7a9SDoug Anderson msecs_to_jiffies(host->pdata->detect_delay_ms)); 24596130e7a9SDoug Anderson } 24606130e7a9SDoug Anderson } 24616130e7a9SDoug Anderson 2462f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 2463f95f3850SWill Newton { 2464f95f3850SWill Newton struct dw_mci *host = dev_id; 2465182c9081SSeungwon Jeon u32 pending; 24661a5c8e1fSShashidhar Hiremath int i; 2467f95f3850SWill Newton 2468f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 2469f95f3850SWill Newton 2470476d79f1SDoug Anderson if (pending) { 247101730558SDoug Anderson /* Check volt switch first, since it can look like an error */ 247201730558SDoug Anderson if ((host->state == STATE_SENDING_CMD11) && 247301730558SDoug Anderson (pending & SDMMC_INT_VOLT_SWITCH)) { 247449ba0302SDoug Anderson unsigned long irqflags; 24755c935165SDoug Anderson 247601730558SDoug Anderson mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); 247701730558SDoug Anderson pending &= ~SDMMC_INT_VOLT_SWITCH; 247849ba0302SDoug Anderson 247949ba0302SDoug Anderson /* 248049ba0302SDoug Anderson * Hold the lock; we know cmd11_timer can't be kicked 248149ba0302SDoug Anderson * off after the lock is released, so safe to delete. 248249ba0302SDoug Anderson */ 248349ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 248401730558SDoug Anderson dw_mci_cmd_interrupt(host, pending); 248549ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 248649ba0302SDoug Anderson 248749ba0302SDoug Anderson del_timer(&host->cmd11_timer); 248801730558SDoug Anderson } 248901730558SDoug Anderson 2490f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 2491f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 2492182c9081SSeungwon Jeon host->cmd_status = pending; 24930e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2494f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2495f95f3850SWill Newton } 2496f95f3850SWill Newton 2497f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 2498f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 2499f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 2500182c9081SSeungwon Jeon host->data_status = pending; 25010e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2502f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 2503f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2504f95f3850SWill Newton } 2505f95f3850SWill Newton 2506f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 250757e10486SAddy Ke del_timer(&host->dto_timer); 250857e10486SAddy Ke 2509f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 2510f95f3850SWill Newton if (!host->data_status) 2511182c9081SSeungwon Jeon host->data_status = pending; 25120e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2513f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 2514f95f3850SWill Newton if (host->sg != NULL) 251587a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 2516f95f3850SWill Newton } 2517f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 2518f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2519f95f3850SWill Newton } 2520f95f3850SWill Newton 2521f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 2522f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 2523b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 252487a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 2525f95f3850SWill Newton } 2526f95f3850SWill Newton 2527f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 2528f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2529b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 2530f95f3850SWill Newton dw_mci_write_data_pio(host); 2531f95f3850SWill Newton } 2532f95f3850SWill Newton 2533f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 2534f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 2535182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 2536f95f3850SWill Newton } 2537f95f3850SWill Newton 2538f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 2539f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 25406130e7a9SDoug Anderson dw_mci_handle_cd(host); 2541f95f3850SWill Newton } 2542f95f3850SWill Newton 25431a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 25441a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 25451a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 2546ed2540efSDoug Anderson 2547ed2540efSDoug Anderson if (!slot) 2548ed2540efSDoug Anderson continue; 2549ed2540efSDoug Anderson 255076756234SAddy Ke if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { 255176756234SAddy Ke mci_writel(host, RINTSTS, 255276756234SAddy Ke SDMMC_INT_SDIO(slot->sdio_id)); 25531a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 25541a5c8e1fSShashidhar Hiremath } 25551a5c8e1fSShashidhar Hiremath } 25561a5c8e1fSShashidhar Hiremath 25571fb5f68aSMarkos Chandras } 2558f95f3850SWill Newton 25593fc7eaefSShawn Lin if (host->use_dma != TRANS_MODE_IDMAC) 25603fc7eaefSShawn Lin return IRQ_HANDLED; 25613fc7eaefSShawn Lin 25623fc7eaefSShawn Lin /* Handle IDMA interrupts */ 256369d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 256469d99fdcSPrabu Thangamuthu pending = mci_readl(host, IDSTS64); 256569d99fdcSPrabu Thangamuthu if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 256669d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | 256769d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 256869d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); 2569faecf411SShawn Lin if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) 25703fc7eaefSShawn Lin host->dma_ops->complete((void *)host); 257169d99fdcSPrabu Thangamuthu } 257269d99fdcSPrabu Thangamuthu } else { 2573f95f3850SWill Newton pending = mci_readl(host, IDSTS); 2574f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 257569d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | 257669d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 2577f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 2578faecf411SShawn Lin if (!test_bit(EVENT_DATA_ERROR, &host->pending_events)) 25793fc7eaefSShawn Lin host->dma_ops->complete((void *)host); 2580f95f3850SWill Newton } 258169d99fdcSPrabu Thangamuthu } 2582f95f3850SWill Newton 2583f95f3850SWill Newton return IRQ_HANDLED; 2584f95f3850SWill Newton } 2585f95f3850SWill Newton 258636c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2587f95f3850SWill Newton { 2588f95f3850SWill Newton struct mmc_host *mmc; 2589f95f3850SWill Newton struct dw_mci_slot *slot; 2590e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2591800d78bfSThomas Abraham int ctrl_id, ret; 25921f44a2a5SSeungwon Jeon u32 freq[2]; 2593f95f3850SWill Newton 25944a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2595f95f3850SWill Newton if (!mmc) 2596f95f3850SWill Newton return -ENOMEM; 2597f95f3850SWill Newton 2598f95f3850SWill Newton slot = mmc_priv(mmc); 2599f95f3850SWill Newton slot->id = id; 260076756234SAddy Ke slot->sdio_id = host->sdio_id0 + id; 2601f95f3850SWill Newton slot->mmc = mmc; 2602f95f3850SWill Newton slot->host = host; 2603c91eab4bSThomas Abraham host->slot[id] = slot; 2604f95f3850SWill Newton 2605f95f3850SWill Newton mmc->ops = &dw_mci_ops; 26061f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 26071f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 26081f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 26091f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 26101f44a2a5SSeungwon Jeon } else { 2611b023030fSJaehoon Chung dev_info(host->dev, 2612b023030fSJaehoon Chung "'clock-freq-min-max' property was deprecated.\n"); 26131f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 26141f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 26151f44a2a5SSeungwon Jeon } 2616f95f3850SWill Newton 261751da2240SYuvaraj CD /*if there are external regulators, get them*/ 261851da2240SYuvaraj CD ret = mmc_regulator_get_supply(mmc); 261951da2240SYuvaraj CD if (ret == -EPROBE_DEFER) 26203cf890fcSDoug Anderson goto err_host_allocated; 262151da2240SYuvaraj CD 262251da2240SYuvaraj CD if (!mmc->ocr_avail) 2623f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2624f95f3850SWill Newton 2625fc3d7720SJaehoon Chung if (host->pdata->caps) 2626fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2627fc3d7720SJaehoon Chung 26286024e166SJaehoon Chung /* 26296024e166SJaehoon Chung * Support MMC_CAP_ERASE by default. 26306024e166SJaehoon Chung * It needs to use trim/discard/erase commands. 26316024e166SJaehoon Chung */ 26326024e166SJaehoon Chung mmc->caps |= MMC_CAP_ERASE; 26336024e166SJaehoon Chung 2634ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2635ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2636ab269128SAbhilash Kesavan 2637800d78bfSThomas Abraham if (host->dev->of_node) { 2638800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2639800d78bfSThomas Abraham if (ctrl_id < 0) 2640800d78bfSThomas Abraham ctrl_id = 0; 2641800d78bfSThomas Abraham } else { 2642800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2643800d78bfSThomas Abraham } 2644cb27a843SJames Hogan if (drv_data && drv_data->caps) 2645cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2646800d78bfSThomas Abraham 26474f408cc6SSeungwon Jeon if (host->pdata->caps2) 26484f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 26494f408cc6SSeungwon Jeon 26503cf890fcSDoug Anderson ret = mmc_of_parse(mmc); 26513cf890fcSDoug Anderson if (ret) 26523cf890fcSDoug Anderson goto err_host_allocated; 2653f95f3850SWill Newton 2654f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 26553fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) { 2656a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2657225faf87SJaehoon Chung mmc->max_blk_size = 65535; 2658575c319dSHeiko Stuebner mmc->max_seg_size = 0x1000; 26591a25b1b4SSeungwon Jeon mmc->max_req_size = mmc->max_seg_size * host->ring_size; 26601a25b1b4SSeungwon Jeon mmc->max_blk_count = mmc->max_req_size / 512; 26613fc7eaefSShawn Lin } else if (host->use_dma == TRANS_MODE_EDMAC) { 26623fc7eaefSShawn Lin mmc->max_segs = 64; 2663225faf87SJaehoon Chung mmc->max_blk_size = 65535; 26643fc7eaefSShawn Lin mmc->max_blk_count = 65535; 26653fc7eaefSShawn Lin mmc->max_req_size = 26663fc7eaefSShawn Lin mmc->max_blk_size * mmc->max_blk_count; 26673fc7eaefSShawn Lin mmc->max_seg_size = mmc->max_req_size; 2668575c319dSHeiko Stuebner } else { 26693fc7eaefSShawn Lin /* TRANS_MODE_PIO */ 2670f95f3850SWill Newton mmc->max_segs = 64; 2671225faf87SJaehoon Chung mmc->max_blk_size = 65535; /* BLKSIZ is 16 bits */ 2672f95f3850SWill Newton mmc->max_blk_count = 512; 2673575c319dSHeiko Stuebner mmc->max_req_size = mmc->max_blk_size * 2674575c319dSHeiko Stuebner mmc->max_blk_count; 2675f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2676575c319dSHeiko Stuebner } 2677f95f3850SWill Newton 2678c0834a58SShawn Lin dw_mci_get_cd(mmc); 2679ae0eb348SJaehoon Chung 26800cea529dSJaehoon Chung ret = mmc_add_host(mmc); 26810cea529dSJaehoon Chung if (ret) 26823cf890fcSDoug Anderson goto err_host_allocated; 2683f95f3850SWill Newton 2684f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2685f95f3850SWill Newton dw_mci_init_debugfs(slot); 2686f95f3850SWill Newton #endif 2687f95f3850SWill Newton 2688f95f3850SWill Newton return 0; 2689800d78bfSThomas Abraham 26903cf890fcSDoug Anderson err_host_allocated: 2691800d78bfSThomas Abraham mmc_free_host(mmc); 269251da2240SYuvaraj CD return ret; 2693f95f3850SWill Newton } 2694f95f3850SWill Newton 2695f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2696f95f3850SWill Newton { 2697f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2698f95f3850SWill Newton mmc_remove_host(slot->mmc); 2699f95f3850SWill Newton slot->host->slot[id] = NULL; 2700f95f3850SWill Newton mmc_free_host(slot->mmc); 2701f95f3850SWill Newton } 2702f95f3850SWill Newton 2703f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2704f95f3850SWill Newton { 270569d99fdcSPrabu Thangamuthu int addr_config; 27063fc7eaefSShawn Lin struct device *dev = host->dev; 27073fc7eaefSShawn Lin struct device_node *np = dev->of_node; 27083fc7eaefSShawn Lin 27093fc7eaefSShawn Lin /* 27103fc7eaefSShawn Lin * Check tansfer mode from HCON[17:16] 27113fc7eaefSShawn Lin * Clear the ambiguous description of dw_mmc databook: 27123fc7eaefSShawn Lin * 2b'00: No DMA Interface -> Actually means using Internal DMA block 27133fc7eaefSShawn Lin * 2b'01: DesignWare DMA Interface -> Synopsys DW-DMA block 27143fc7eaefSShawn Lin * 2b'10: Generic DMA Interface -> non-Synopsys generic DMA block 27153fc7eaefSShawn Lin * 2b'11: Non DW DMA Interface -> pio only 27163fc7eaefSShawn Lin * Compared to DesignWare DMA Interface, Generic DMA Interface has a 27173fc7eaefSShawn Lin * simpler request/acknowledge handshake mechanism and both of them 27183fc7eaefSShawn Lin * are regarded as external dma master for dw_mmc. 27193fc7eaefSShawn Lin */ 27203fc7eaefSShawn Lin host->use_dma = SDMMC_GET_TRANS_MODE(mci_readl(host, HCON)); 27213fc7eaefSShawn Lin if (host->use_dma == DMA_INTERFACE_IDMA) { 27223fc7eaefSShawn Lin host->use_dma = TRANS_MODE_IDMAC; 27233fc7eaefSShawn Lin } else if (host->use_dma == DMA_INTERFACE_DWDMA || 27243fc7eaefSShawn Lin host->use_dma == DMA_INTERFACE_GDMA) { 27253fc7eaefSShawn Lin host->use_dma = TRANS_MODE_EDMAC; 27263fc7eaefSShawn Lin } else { 27273fc7eaefSShawn Lin goto no_dma; 27283fc7eaefSShawn Lin } 27293fc7eaefSShawn Lin 27303fc7eaefSShawn Lin /* Determine which DMA interface to use */ 27313fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) { 27323fc7eaefSShawn Lin /* 27333fc7eaefSShawn Lin * Check ADDR_CONFIG bit in HCON to find 27343fc7eaefSShawn Lin * IDMAC address bus width 27353fc7eaefSShawn Lin */ 273670692752SShawn Lin addr_config = SDMMC_GET_ADDR_CONFIG(mci_readl(host, HCON)); 273769d99fdcSPrabu Thangamuthu 273869d99fdcSPrabu Thangamuthu if (addr_config == 1) { 273969d99fdcSPrabu Thangamuthu /* host supports IDMAC in 64-bit address mode */ 274069d99fdcSPrabu Thangamuthu host->dma_64bit_address = 1; 27413fc7eaefSShawn Lin dev_info(host->dev, 27423fc7eaefSShawn Lin "IDMAC supports 64-bit address mode.\n"); 274369d99fdcSPrabu Thangamuthu if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) 27443fc7eaefSShawn Lin dma_set_coherent_mask(host->dev, 27453fc7eaefSShawn Lin DMA_BIT_MASK(64)); 274669d99fdcSPrabu Thangamuthu } else { 274769d99fdcSPrabu Thangamuthu /* host supports IDMAC in 32-bit address mode */ 274869d99fdcSPrabu Thangamuthu host->dma_64bit_address = 0; 27493fc7eaefSShawn Lin dev_info(host->dev, 27503fc7eaefSShawn Lin "IDMAC supports 32-bit address mode.\n"); 275169d99fdcSPrabu Thangamuthu } 275269d99fdcSPrabu Thangamuthu 2753f95f3850SWill Newton /* Alloc memory for sg translation */ 2754cc190d4cSShawn Lin host->sg_cpu = dmam_alloc_coherent(host->dev, 2755cc190d4cSShawn Lin DESC_RING_BUF_SZ, 2756f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2757f95f3850SWill Newton if (!host->sg_cpu) { 27583fc7eaefSShawn Lin dev_err(host->dev, 27593fc7eaefSShawn Lin "%s: could not alloc DMA memory\n", 2760f95f3850SWill Newton __func__); 2761f95f3850SWill Newton goto no_dma; 2762f95f3850SWill Newton } 2763f95f3850SWill Newton 2764f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 276500956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 27663fc7eaefSShawn Lin } else { 27673fc7eaefSShawn Lin /* TRANS_MODE_EDMAC: check dma bindings again */ 27683fc7eaefSShawn Lin if ((of_property_count_strings(np, "dma-names") < 0) || 27693fc7eaefSShawn Lin (!of_find_property(np, "dmas", NULL))) { 2770f95f3850SWill Newton goto no_dma; 27713fc7eaefSShawn Lin } 27723fc7eaefSShawn Lin host->dma_ops = &dw_mci_edmac_ops; 27733fc7eaefSShawn Lin dev_info(host->dev, "Using external DMA controller.\n"); 27743fc7eaefSShawn Lin } 2775f95f3850SWill Newton 2776e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2777e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2778f95f3850SWill Newton if (host->dma_ops->init(host)) { 27790e3a22c0SShawn Lin dev_err(host->dev, "%s: Unable to initialize DMA Controller.\n", 27800e3a22c0SShawn Lin __func__); 2781f95f3850SWill Newton goto no_dma; 2782f95f3850SWill Newton } 2783f95f3850SWill Newton } else { 27844a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2785f95f3850SWill Newton goto no_dma; 2786f95f3850SWill Newton } 2787f95f3850SWill Newton 2788f95f3850SWill Newton return; 2789f95f3850SWill Newton 2790f95f3850SWill Newton no_dma: 27914a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 27923fc7eaefSShawn Lin host->use_dma = TRANS_MODE_PIO; 2793f95f3850SWill Newton } 2794f95f3850SWill Newton 279531bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) 2796f95f3850SWill Newton { 2797f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 279831bff450SSeungwon Jeon u32 ctrl; 2799f95f3850SWill Newton 280031bff450SSeungwon Jeon ctrl = mci_readl(host, CTRL); 280131bff450SSeungwon Jeon ctrl |= reset; 280231bff450SSeungwon Jeon mci_writel(host, CTRL, ctrl); 2803f95f3850SWill Newton 2804f95f3850SWill Newton /* wait till resets clear */ 2805f95f3850SWill Newton do { 2806f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 280731bff450SSeungwon Jeon if (!(ctrl & reset)) 2808f95f3850SWill Newton return true; 2809f95f3850SWill Newton } while (time_before(jiffies, timeout)); 2810f95f3850SWill Newton 281131bff450SSeungwon Jeon dev_err(host->dev, 281231bff450SSeungwon Jeon "Timeout resetting block (ctrl reset %#x)\n", 281331bff450SSeungwon Jeon ctrl & reset); 2814f95f3850SWill Newton 2815f95f3850SWill Newton return false; 2816f95f3850SWill Newton } 2817f95f3850SWill Newton 28183a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host) 281931bff450SSeungwon Jeon { 28203a33a94cSSonny Rao u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; 28213a33a94cSSonny Rao bool ret = false; 28223a33a94cSSonny Rao 282331bff450SSeungwon Jeon /* 282431bff450SSeungwon Jeon * Reseting generates a block interrupt, hence setting 282531bff450SSeungwon Jeon * the scatter-gather pointer to NULL. 282631bff450SSeungwon Jeon */ 282731bff450SSeungwon Jeon if (host->sg) { 282831bff450SSeungwon Jeon sg_miter_stop(&host->sg_miter); 282931bff450SSeungwon Jeon host->sg = NULL; 283031bff450SSeungwon Jeon } 283131bff450SSeungwon Jeon 28323a33a94cSSonny Rao if (host->use_dma) 28333a33a94cSSonny Rao flags |= SDMMC_CTRL_DMA_RESET; 28343a33a94cSSonny Rao 28353a33a94cSSonny Rao if (dw_mci_ctrl_reset(host, flags)) { 28363a33a94cSSonny Rao /* 28373a33a94cSSonny Rao * In all cases we clear the RAWINTS register to clear any 28383a33a94cSSonny Rao * interrupts. 28393a33a94cSSonny Rao */ 28403a33a94cSSonny Rao mci_writel(host, RINTSTS, 0xFFFFFFFF); 28413a33a94cSSonny Rao 28423a33a94cSSonny Rao /* if using dma we wait for dma_req to clear */ 28433a33a94cSSonny Rao if (host->use_dma) { 28443a33a94cSSonny Rao unsigned long timeout = jiffies + msecs_to_jiffies(500); 28453a33a94cSSonny Rao u32 status; 28460e3a22c0SShawn Lin 28473a33a94cSSonny Rao do { 28483a33a94cSSonny Rao status = mci_readl(host, STATUS); 28493a33a94cSSonny Rao if (!(status & SDMMC_STATUS_DMA_REQ)) 28503a33a94cSSonny Rao break; 28513a33a94cSSonny Rao cpu_relax(); 28523a33a94cSSonny Rao } while (time_before(jiffies, timeout)); 28533a33a94cSSonny Rao 28543a33a94cSSonny Rao if (status & SDMMC_STATUS_DMA_REQ) { 28553a33a94cSSonny Rao dev_err(host->dev, 28560e3a22c0SShawn Lin "%s: Timeout waiting for dma_req to clear during reset\n", 28570e3a22c0SShawn Lin __func__); 28583a33a94cSSonny Rao goto ciu_out; 285931bff450SSeungwon Jeon } 286031bff450SSeungwon Jeon 28613a33a94cSSonny Rao /* when using DMA next we reset the fifo again */ 28623a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) 28633a33a94cSSonny Rao goto ciu_out; 28643a33a94cSSonny Rao } 28653a33a94cSSonny Rao } else { 28663a33a94cSSonny Rao /* if the controller reset bit did clear, then set clock regs */ 28673a33a94cSSonny Rao if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { 28680e3a22c0SShawn Lin dev_err(host->dev, 28690e3a22c0SShawn Lin "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n", 28703a33a94cSSonny Rao __func__); 28713a33a94cSSonny Rao goto ciu_out; 28723a33a94cSSonny Rao } 28733a33a94cSSonny Rao } 28743a33a94cSSonny Rao 28753fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 28763a33a94cSSonny Rao /* It is also recommended that we reset and reprogram idmac */ 28773a33a94cSSonny Rao dw_mci_idmac_reset(host); 28783a33a94cSSonny Rao 28793a33a94cSSonny Rao ret = true; 28803a33a94cSSonny Rao 28813a33a94cSSonny Rao ciu_out: 28823a33a94cSSonny Rao /* After a CTRL reset we need to have CIU set clock registers */ 28833a33a94cSSonny Rao mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); 28843a33a94cSSonny Rao 28853a33a94cSSonny Rao return ret; 288631bff450SSeungwon Jeon } 288731bff450SSeungwon Jeon 28885c935165SDoug Anderson static void dw_mci_cmd11_timer(unsigned long arg) 28895c935165SDoug Anderson { 28905c935165SDoug Anderson struct dw_mci *host = (struct dw_mci *)arg; 28915c935165SDoug Anderson 2892fd674198SDoug Anderson if (host->state != STATE_SENDING_CMD11) { 2893fd674198SDoug Anderson dev_warn(host->dev, "Unexpected CMD11 timeout\n"); 2894fd674198SDoug Anderson return; 2895fd674198SDoug Anderson } 28965c935165SDoug Anderson 28975c935165SDoug Anderson host->cmd_status = SDMMC_INT_RTO; 28985c935165SDoug Anderson set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 28995c935165SDoug Anderson tasklet_schedule(&host->tasklet); 29005c935165SDoug Anderson } 29015c935165SDoug Anderson 290257e10486SAddy Ke static void dw_mci_dto_timer(unsigned long arg) 290357e10486SAddy Ke { 290457e10486SAddy Ke struct dw_mci *host = (struct dw_mci *)arg; 290557e10486SAddy Ke 290657e10486SAddy Ke switch (host->state) { 290757e10486SAddy Ke case STATE_SENDING_DATA: 290857e10486SAddy Ke case STATE_DATA_BUSY: 290957e10486SAddy Ke /* 291057e10486SAddy Ke * If DTO interrupt does NOT come in sending data state, 291157e10486SAddy Ke * we should notify the driver to terminate current transfer 291257e10486SAddy Ke * and report a data timeout to the core. 291357e10486SAddy Ke */ 291457e10486SAddy Ke host->data_status = SDMMC_INT_DRTO; 291557e10486SAddy Ke set_bit(EVENT_DATA_ERROR, &host->pending_events); 291657e10486SAddy Ke set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 291757e10486SAddy Ke tasklet_schedule(&host->tasklet); 291857e10486SAddy Ke break; 291957e10486SAddy Ke default: 292057e10486SAddy Ke break; 292157e10486SAddy Ke } 292257e10486SAddy Ke } 292357e10486SAddy Ke 2924c91eab4bSThomas Abraham #ifdef CONFIG_OF 2925c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2926c91eab4bSThomas Abraham { 2927c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2928c91eab4bSThomas Abraham struct device *dev = host->dev; 2929c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2930e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2931e8cc37b8SShawn Lin int ret; 29323c6d89eaSDoug Anderson u32 clock_frequency; 2933c91eab4bSThomas Abraham 2934c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2935bf3707eaSBeomho Seo if (!pdata) 2936c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2937c91eab4bSThomas Abraham 2938d6786fefSGuodong Xu /* find reset controller when exist */ 29393a667e3fSJaehoon Chung pdata->rstc = devm_reset_control_get_optional(dev, "reset"); 2940d6786fefSGuodong Xu if (IS_ERR(pdata->rstc)) { 2941d6786fefSGuodong Xu if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER) 2942d6786fefSGuodong Xu return ERR_PTR(-EPROBE_DEFER); 2943d6786fefSGuodong Xu } 2944d6786fefSGuodong Xu 2945c91eab4bSThomas Abraham /* find out number of slots supported */ 29468a629d26SShawn Lin of_property_read_u32(np, "num-slots", &pdata->num_slots); 2947c91eab4bSThomas Abraham 2948c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 29490e3a22c0SShawn Lin dev_info(dev, 29500e3a22c0SShawn Lin "fifo-depth property not found, using value of FIFOTH register as default\n"); 2951c91eab4bSThomas Abraham 2952c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2953c91eab4bSThomas Abraham 29543c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 29553c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 29563c6d89eaSDoug Anderson 2957cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2958cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2959800d78bfSThomas Abraham if (ret) 2960800d78bfSThomas Abraham return ERR_PTR(ret); 2961800d78bfSThomas Abraham } 2962800d78bfSThomas Abraham 2963c91eab4bSThomas Abraham return pdata; 2964c91eab4bSThomas Abraham } 2965c91eab4bSThomas Abraham 2966c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2967c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2968c91eab4bSThomas Abraham { 2969c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2970c91eab4bSThomas Abraham } 2971c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2972c91eab4bSThomas Abraham 2973fa0c3283SDoug Anderson static void dw_mci_enable_cd(struct dw_mci *host) 2974fa0c3283SDoug Anderson { 2975fa0c3283SDoug Anderson unsigned long irqflags; 2976fa0c3283SDoug Anderson u32 temp; 2977fa0c3283SDoug Anderson int i; 2978e8cc37b8SShawn Lin struct dw_mci_slot *slot; 2979fa0c3283SDoug Anderson 2980e8cc37b8SShawn Lin /* 2981e8cc37b8SShawn Lin * No need for CD if all slots have a non-error GPIO 2982e8cc37b8SShawn Lin * as well as broken card detection is found. 2983e8cc37b8SShawn Lin */ 2984fa0c3283SDoug Anderson for (i = 0; i < host->num_slots; i++) { 2985e8cc37b8SShawn Lin slot = host->slot[i]; 2986e8cc37b8SShawn Lin if (slot->mmc->caps & MMC_CAP_NEEDS_POLL) 2987e8cc37b8SShawn Lin return; 2988fa0c3283SDoug Anderson 2989287980e4SArnd Bergmann if (mmc_gpio_get_cd(slot->mmc) < 0) 2990fa0c3283SDoug Anderson break; 2991fa0c3283SDoug Anderson } 2992fa0c3283SDoug Anderson if (i == host->num_slots) 2993fa0c3283SDoug Anderson return; 2994fa0c3283SDoug Anderson 2995fa0c3283SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 2996fa0c3283SDoug Anderson temp = mci_readl(host, INTMASK); 2997fa0c3283SDoug Anderson temp |= SDMMC_INT_CD; 2998fa0c3283SDoug Anderson mci_writel(host, INTMASK, temp); 2999fa0c3283SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 3000fa0c3283SDoug Anderson } 3001fa0c3283SDoug Anderson 300262ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 3003f95f3850SWill Newton { 3004e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 300562ca8034SShashidhar Hiremath int width, i, ret = 0; 3006f95f3850SWill Newton u32 fifo_size; 30071c2215b7SThomas Abraham int init_slots = 0; 3008f95f3850SWill Newton 3009c91eab4bSThomas Abraham if (!host->pdata) { 3010c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 3011d6786fefSGuodong Xu if (PTR_ERR(host->pdata) == -EPROBE_DEFER) { 3012d6786fefSGuodong Xu return -EPROBE_DEFER; 3013d6786fefSGuodong Xu } else if (IS_ERR(host->pdata)) { 3014c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 3015c91eab4bSThomas Abraham return -EINVAL; 3016c91eab4bSThomas Abraham } 3017f95f3850SWill Newton } 3018f95f3850SWill Newton 3019780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 3020f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 3021f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 3022f90a0612SThomas Abraham } else { 3023f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 3024f90a0612SThomas Abraham if (ret) { 3025f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 3026f90a0612SThomas Abraham return ret; 3027f90a0612SThomas Abraham } 3028f95f3850SWill Newton } 3029f95f3850SWill Newton 3030780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 3031f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 3032f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 30333c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 3034f90a0612SThomas Abraham } else { 3035f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 3036f90a0612SThomas Abraham if (ret) { 3037f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 3038f90a0612SThomas Abraham goto err_clk_biu; 3039f90a0612SThomas Abraham } 3040f90a0612SThomas Abraham 30413c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 30423c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 30433c6d89eaSDoug Anderson if (ret) 30443c6d89eaSDoug Anderson dev_warn(host->dev, 3045612de4c1SJaehoon Chung "Unable to set bus rate to %uHz\n", 30463c6d89eaSDoug Anderson host->pdata->bus_hz); 30473c6d89eaSDoug Anderson } 3048f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 30493c6d89eaSDoug Anderson } 3050f90a0612SThomas Abraham 3051612de4c1SJaehoon Chung if (!host->bus_hz) { 3052612de4c1SJaehoon Chung dev_err(host->dev, 3053612de4c1SJaehoon Chung "Platform data must supply bus speed\n"); 3054612de4c1SJaehoon Chung ret = -ENODEV; 3055612de4c1SJaehoon Chung goto err_clk_ciu; 3056612de4c1SJaehoon Chung } 3057612de4c1SJaehoon Chung 3058002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 3059002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 3060002f0d5cSYuvaraj Kumar C D if (ret) { 3061002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 3062002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 3063002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 3064002f0d5cSYuvaraj Kumar C D } 3065002f0d5cSYuvaraj Kumar C D } 3066002f0d5cSYuvaraj Kumar C D 3067d6786fefSGuodong Xu if (!IS_ERR(host->pdata->rstc)) { 3068d6786fefSGuodong Xu reset_control_assert(host->pdata->rstc); 3069d6786fefSGuodong Xu usleep_range(10, 50); 3070d6786fefSGuodong Xu reset_control_deassert(host->pdata->rstc); 3071d6786fefSGuodong Xu } 3072d6786fefSGuodong Xu 30735c935165SDoug Anderson setup_timer(&host->cmd11_timer, 30745c935165SDoug Anderson dw_mci_cmd11_timer, (unsigned long)host); 30755c935165SDoug Anderson 307657e10486SAddy Ke setup_timer(&host->dto_timer, 307757e10486SAddy Ke dw_mci_dto_timer, (unsigned long)host); 307857e10486SAddy Ke 3079f95f3850SWill Newton spin_lock_init(&host->lock); 3080f8c58c11SDoug Anderson spin_lock_init(&host->irq_lock); 3081f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 3082f95f3850SWill Newton 3083f95f3850SWill Newton /* 3084f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 3085f95f3850SWill Newton * the correct values. 3086f95f3850SWill Newton */ 308770692752SShawn Lin i = SDMMC_GET_HDATA_WIDTH(mci_readl(host, HCON)); 3088f95f3850SWill Newton if (!i) { 3089f95f3850SWill Newton host->push_data = dw_mci_push_data16; 3090f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 3091f95f3850SWill Newton width = 16; 3092f95f3850SWill Newton host->data_shift = 1; 3093f95f3850SWill Newton } else if (i == 2) { 3094f95f3850SWill Newton host->push_data = dw_mci_push_data64; 3095f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 3096f95f3850SWill Newton width = 64; 3097f95f3850SWill Newton host->data_shift = 3; 3098f95f3850SWill Newton } else { 3099f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 3100f95f3850SWill Newton WARN((i != 1), 3101f95f3850SWill Newton "HCON reports a reserved host data width!\n" 3102f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 3103f95f3850SWill Newton host->push_data = dw_mci_push_data32; 3104f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 3105f95f3850SWill Newton width = 32; 3106f95f3850SWill Newton host->data_shift = 2; 3107f95f3850SWill Newton } 3108f95f3850SWill Newton 3109f95f3850SWill Newton /* Reset all blocks */ 31103744415cSShawn Lin if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 31113744415cSShawn Lin ret = -ENODEV; 31123744415cSShawn Lin goto err_clk_ciu; 31133744415cSShawn Lin } 3114141a712aSSeungwon Jeon 3115141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 3116141a712aSSeungwon Jeon dw_mci_init_dma(host); 3117f95f3850SWill Newton 3118f95f3850SWill Newton /* Clear the interrupts for the host controller */ 3119f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 3120f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 3121f95f3850SWill Newton 3122f95f3850SWill Newton /* Put in max timeout */ 3123f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 3124f95f3850SWill Newton 3125f95f3850SWill Newton /* 3126f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 3127f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 3128f95f3850SWill Newton */ 3129b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 3130b86d8253SJames Hogan /* 3131b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 3132b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 3133b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 3134b86d8253SJames Hogan * should put it in the platform data. 3135b86d8253SJames Hogan */ 3136f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 31378234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 3138b86d8253SJames Hogan } else { 3139b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 3140b86d8253SJames Hogan } 3141b86d8253SJames Hogan host->fifo_depth = fifo_size; 314252426899SSeungwon Jeon host->fifoth_val = 314352426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 3144e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 3145f95f3850SWill Newton 3146f95f3850SWill Newton /* disable clock to CIU */ 3147f95f3850SWill Newton mci_writel(host, CLKENA, 0); 3148f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 3149f95f3850SWill Newton 315063008768SJames Hogan /* 315163008768SJames Hogan * In 2.40a spec, Data offset is changed. 315263008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 315363008768SJames Hogan */ 315463008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 315563008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 315663008768SJames Hogan 315763008768SJames Hogan if (host->verid < DW_MMC_240A) 315876184ac1SBen Dooks host->fifo_reg = host->regs + DATA_OFFSET; 315963008768SJames Hogan else 316076184ac1SBen Dooks host->fifo_reg = host->regs + DATA_240A_OFFSET; 316163008768SJames Hogan 3162f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 3163780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 3164780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 3165f95f3850SWill Newton if (ret) 31666130e7a9SDoug Anderson goto err_dmaunmap; 3167f95f3850SWill Newton 3168f95f3850SWill Newton if (host->pdata->num_slots) 3169f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 3170f95f3850SWill Newton else 31718a629d26SShawn Lin host->num_slots = 1; 31728a629d26SShawn Lin 31738a629d26SShawn Lin if (host->num_slots < 1 || 31748a629d26SShawn Lin host->num_slots > SDMMC_GET_SLOT_NUM(mci_readl(host, HCON))) { 31758a629d26SShawn Lin dev_err(host->dev, 31768a629d26SShawn Lin "Platform data must supply correct num_slots.\n"); 31778a629d26SShawn Lin ret = -ENODEV; 31788a629d26SShawn Lin goto err_clk_ciu; 31798a629d26SShawn Lin } 3180f95f3850SWill Newton 31812da1d7f2SYuvaraj CD /* 3182fa0c3283SDoug Anderson * Enable interrupts for command done, data over, data empty, 31832da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 31842da1d7f2SYuvaraj CD */ 31852da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 31862da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 3187fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 31880e3a22c0SShawn Lin /* Enable mci interrupt */ 31890e3a22c0SShawn Lin mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 31902da1d7f2SYuvaraj CD 31910e3a22c0SShawn Lin dev_info(host->dev, 31920e3a22c0SShawn Lin "DW MMC controller at irq %d,%d bit host data width,%u deep fifo\n", 31932da1d7f2SYuvaraj CD host->irq, width, fifo_size); 31942da1d7f2SYuvaraj CD 3195f95f3850SWill Newton /* We need at least one slot to succeed */ 3196f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 3197f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 31981c2215b7SThomas Abraham if (ret) 31991c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 32001c2215b7SThomas Abraham else 32011c2215b7SThomas Abraham init_slots++; 3202f95f3850SWill Newton } 32031c2215b7SThomas Abraham 32041c2215b7SThomas Abraham if (init_slots) { 32051c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 32061c2215b7SThomas Abraham } else { 32070e3a22c0SShawn Lin dev_dbg(host->dev, 32080e3a22c0SShawn Lin "attempted to initialize %d slots, but failed on all\n", 32090e3a22c0SShawn Lin host->num_slots); 32106130e7a9SDoug Anderson goto err_dmaunmap; 3211f95f3850SWill Newton } 3212f95f3850SWill Newton 3213b793f658SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3214b793f658SDoug Anderson dw_mci_enable_cd(host); 3215b793f658SDoug Anderson 3216f95f3850SWill Newton return 0; 3217f95f3850SWill Newton 3218f95f3850SWill Newton err_dmaunmap: 3219f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3220f95f3850SWill Newton host->dma_ops->exit(host); 3221f90a0612SThomas Abraham 3222d6786fefSGuodong Xu if (!IS_ERR(host->pdata->rstc)) 3223d6786fefSGuodong Xu reset_control_assert(host->pdata->rstc); 3224d6786fefSGuodong Xu 3225f90a0612SThomas Abraham err_clk_ciu: 3226f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3227780f22afSSeungwon Jeon 3228f90a0612SThomas Abraham err_clk_biu: 3229f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3230780f22afSSeungwon Jeon 3231f95f3850SWill Newton return ret; 3232f95f3850SWill Newton } 323362ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 3234f95f3850SWill Newton 323562ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 3236f95f3850SWill Newton { 3237f95f3850SWill Newton int i; 3238f95f3850SWill Newton 3239f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 32404a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 3241f95f3850SWill Newton if (host->slot[i]) 3242f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 3243f95f3850SWill Newton } 3244f95f3850SWill Newton 3245048fd7e6SPrabu Thangamuthu mci_writel(host, RINTSTS, 0xFFFFFFFF); 3246048fd7e6SPrabu Thangamuthu mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 3247048fd7e6SPrabu Thangamuthu 3248f95f3850SWill Newton /* disable clock to CIU */ 3249f95f3850SWill Newton mci_writel(host, CLKENA, 0); 3250f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 3251f95f3850SWill Newton 3252f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3253f95f3850SWill Newton host->dma_ops->exit(host); 3254f95f3850SWill Newton 3255d6786fefSGuodong Xu if (!IS_ERR(host->pdata->rstc)) 3256d6786fefSGuodong Xu reset_control_assert(host->pdata->rstc); 3257d6786fefSGuodong Xu 3258f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3259f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3260f95f3850SWill Newton } 326162ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 326262ca8034SShashidhar Hiremath 326362ca8034SShashidhar Hiremath 3264f95f3850SWill Newton 3265e9ed8835SShawn Lin #ifdef CONFIG_PM 3266ed24e1ffSShawn Lin int dw_mci_runtime_suspend(struct device *dev) 3267f95f3850SWill Newton { 3268ed24e1ffSShawn Lin struct dw_mci *host = dev_get_drvdata(dev); 3269ed24e1ffSShawn Lin 32703fc7eaefSShawn Lin if (host->use_dma && host->dma_ops->exit) 32713fc7eaefSShawn Lin host->dma_ops->exit(host); 32723fc7eaefSShawn Lin 3273ed24e1ffSShawn Lin clk_disable_unprepare(host->ciu_clk); 3274ed24e1ffSShawn Lin 3275ed24e1ffSShawn Lin if (host->cur_slot && 3276ed24e1ffSShawn Lin (mmc_can_gpio_cd(host->cur_slot->mmc) || 3277ed24e1ffSShawn Lin !mmc_card_is_removable(host->cur_slot->mmc))) 3278ed24e1ffSShawn Lin clk_disable_unprepare(host->biu_clk); 3279ed24e1ffSShawn Lin 3280f95f3850SWill Newton return 0; 3281f95f3850SWill Newton } 3282ed24e1ffSShawn Lin EXPORT_SYMBOL(dw_mci_runtime_suspend); 3283f95f3850SWill Newton 3284ed24e1ffSShawn Lin int dw_mci_runtime_resume(struct device *dev) 3285f95f3850SWill Newton { 3286ed24e1ffSShawn Lin int i, ret = 0; 3287ed24e1ffSShawn Lin struct dw_mci *host = dev_get_drvdata(dev); 3288f95f3850SWill Newton 3289ed24e1ffSShawn Lin if (host->cur_slot && 3290ed24e1ffSShawn Lin (mmc_can_gpio_cd(host->cur_slot->mmc) || 3291ed24e1ffSShawn Lin !mmc_card_is_removable(host->cur_slot->mmc))) { 3292ed24e1ffSShawn Lin ret = clk_prepare_enable(host->biu_clk); 3293ed24e1ffSShawn Lin if (ret) 3294e61cf118SJaehoon Chung return ret; 3295e61cf118SJaehoon Chung } 3296e61cf118SJaehoon Chung 3297ed24e1ffSShawn Lin ret = clk_prepare_enable(host->ciu_clk); 3298ed24e1ffSShawn Lin if (ret) 3299*df9bcc2bSJoonyoung Shim goto err; 3300*df9bcc2bSJoonyoung Shim 3301*df9bcc2bSJoonyoung Shim if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 3302*df9bcc2bSJoonyoung Shim clk_disable_unprepare(host->ciu_clk); 3303*df9bcc2bSJoonyoung Shim ret = -ENODEV; 3304*df9bcc2bSJoonyoung Shim goto err; 3305*df9bcc2bSJoonyoung Shim } 3306ed24e1ffSShawn Lin 33073bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 3308141a712aSSeungwon Jeon host->dma_ops->init(host); 3309141a712aSSeungwon Jeon 331052426899SSeungwon Jeon /* 331152426899SSeungwon Jeon * Restore the initial value at FIFOTH register 331252426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 331352426899SSeungwon Jeon */ 3314e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 331552426899SSeungwon Jeon host->prev_blksz = 0; 3316e61cf118SJaehoon Chung 33172eb2944fSDoug Anderson /* Put in max timeout */ 33182eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 33192eb2944fSDoug Anderson 3320e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 3321e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 3322e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 3323fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 3324e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 3325e61cf118SJaehoon Chung 3326f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 3327f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 33280e3a22c0SShawn Lin 3329f95f3850SWill Newton if (!slot) 3330f95f3850SWill Newton continue; 3331ab269128SAbhilash Kesavan if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { 3332ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 3333ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 3334ab269128SAbhilash Kesavan } 3335f95f3850SWill Newton } 3336fa0c3283SDoug Anderson 3337fa0c3283SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3338fa0c3283SDoug Anderson dw_mci_enable_cd(host); 3339fa0c3283SDoug Anderson 3340*df9bcc2bSJoonyoung Shim return 0; 3341*df9bcc2bSJoonyoung Shim 3342*df9bcc2bSJoonyoung Shim err: 3343*df9bcc2bSJoonyoung Shim if (host->cur_slot && 3344*df9bcc2bSJoonyoung Shim (mmc_can_gpio_cd(host->cur_slot->mmc) || 3345*df9bcc2bSJoonyoung Shim !mmc_card_is_removable(host->cur_slot->mmc))) 3346*df9bcc2bSJoonyoung Shim clk_disable_unprepare(host->biu_clk); 3347*df9bcc2bSJoonyoung Shim 33481f5c51d7SShawn Lin return ret; 33491f5c51d7SShawn Lin } 3350e9ed8835SShawn Lin EXPORT_SYMBOL(dw_mci_runtime_resume); 3351e9ed8835SShawn Lin #endif /* CONFIG_PM */ 33526fe8890dSJaehoon Chung 3353f95f3850SWill Newton static int __init dw_mci_init(void) 3354f95f3850SWill Newton { 33558e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 335662ca8034SShashidhar Hiremath return 0; 3357f95f3850SWill Newton } 3358f95f3850SWill Newton 3359f95f3850SWill Newton static void __exit dw_mci_exit(void) 3360f95f3850SWill Newton { 3361f95f3850SWill Newton } 3362f95f3850SWill Newton 3363f95f3850SWill Newton module_init(dw_mci_init); 3364f95f3850SWill Newton module_exit(dw_mci_exit); 3365f95f3850SWill Newton 3366f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 3367f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 3368f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 3369f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 3370