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 | \ 47f95f3850SWill Newton SDMMC_INT_EBE) 48f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ 49f95f3850SWill Newton SDMMC_INT_RESP_ERR) 50f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ 51f95f3850SWill Newton DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE) 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 */ 571f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN 400000 /* 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 6469d99fdcSPrabu Thangamuthu struct idmac_desc_64addr { 6569d99fdcSPrabu Thangamuthu u32 des0; /* Control Descriptor */ 6669d99fdcSPrabu Thangamuthu 6769d99fdcSPrabu Thangamuthu u32 des1; /* Reserved */ 6869d99fdcSPrabu Thangamuthu 6969d99fdcSPrabu Thangamuthu u32 des2; /*Buffer sizes */ 7069d99fdcSPrabu Thangamuthu #define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ 716687c42fSBen Dooks ((d)->des2 = ((d)->des2 & cpu_to_le32(0x03ffe000)) | \ 726687c42fSBen Dooks ((cpu_to_le32(s)) & cpu_to_le32(0x1fff))) 7369d99fdcSPrabu Thangamuthu 7469d99fdcSPrabu Thangamuthu u32 des3; /* Reserved */ 7569d99fdcSPrabu Thangamuthu 7669d99fdcSPrabu Thangamuthu u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/ 7769d99fdcSPrabu Thangamuthu u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/ 7869d99fdcSPrabu Thangamuthu 7969d99fdcSPrabu Thangamuthu u32 des6; /* Lower 32-bits of Next Descriptor Address */ 8069d99fdcSPrabu Thangamuthu u32 des7; /* Upper 32-bits of Next Descriptor Address */ 8169d99fdcSPrabu Thangamuthu }; 8269d99fdcSPrabu Thangamuthu 83f95f3850SWill Newton struct idmac_desc { 846687c42fSBen Dooks __le32 des0; /* Control Descriptor */ 85f95f3850SWill Newton #define IDMAC_DES0_DIC BIT(1) 86f95f3850SWill Newton #define IDMAC_DES0_LD BIT(2) 87f95f3850SWill Newton #define IDMAC_DES0_FD BIT(3) 88f95f3850SWill Newton #define IDMAC_DES0_CH BIT(4) 89f95f3850SWill Newton #define IDMAC_DES0_ER BIT(5) 90f95f3850SWill Newton #define IDMAC_DES0_CES BIT(30) 91f95f3850SWill Newton #define IDMAC_DES0_OWN BIT(31) 92f95f3850SWill Newton 936687c42fSBen Dooks __le32 des1; /* Buffer sizes */ 94f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \ 959b7bbe10SShashidhar Hiremath ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) 96f95f3850SWill Newton 976687c42fSBen Dooks __le32 des2; /* buffer 1 physical address */ 98f95f3850SWill Newton 996687c42fSBen Dooks __le32 des3; /* buffer 2 physical address */ 100f95f3850SWill Newton }; 1015959b32eSAlexey Brodkin 1025959b32eSAlexey Brodkin /* Each descriptor can transfer up to 4KB of data in chained mode */ 1035959b32eSAlexey Brodkin #define DW_MCI_DESC_DATA_LENGTH 0x1000 104f95f3850SWill Newton 1053a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host); 106536f6b91SSonny Rao static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); 1070bdbd0e8SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc); 10831bff450SSeungwon Jeon 109f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 110f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 111f95f3850SWill Newton { 112f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 113f95f3850SWill Newton struct mmc_request *mrq; 114f95f3850SWill Newton struct mmc_command *cmd; 115f95f3850SWill Newton struct mmc_command *stop; 116f95f3850SWill Newton struct mmc_data *data; 117f95f3850SWill Newton 118f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 119f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 120f95f3850SWill Newton mrq = slot->mrq; 121f95f3850SWill Newton 122f95f3850SWill Newton if (mrq) { 123f95f3850SWill Newton cmd = mrq->cmd; 124f95f3850SWill Newton data = mrq->data; 125f95f3850SWill Newton stop = mrq->stop; 126f95f3850SWill Newton 127f95f3850SWill Newton if (cmd) 128f95f3850SWill Newton seq_printf(s, 129f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 130f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 131f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 132f95f3850SWill Newton cmd->resp[2], cmd->error); 133f95f3850SWill Newton if (data) 134f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 135f95f3850SWill Newton data->bytes_xfered, data->blocks, 136f95f3850SWill Newton data->blksz, data->flags, data->error); 137f95f3850SWill Newton if (stop) 138f95f3850SWill Newton seq_printf(s, 139f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 140f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 141f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 142f95f3850SWill Newton stop->resp[2], stop->error); 143f95f3850SWill Newton } 144f95f3850SWill Newton 145f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 146f95f3850SWill Newton 147f95f3850SWill Newton return 0; 148f95f3850SWill Newton } 149f95f3850SWill Newton 150f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 151f95f3850SWill Newton { 152f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 153f95f3850SWill Newton } 154f95f3850SWill Newton 155f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 156f95f3850SWill Newton .owner = THIS_MODULE, 157f95f3850SWill Newton .open = dw_mci_req_open, 158f95f3850SWill Newton .read = seq_read, 159f95f3850SWill Newton .llseek = seq_lseek, 160f95f3850SWill Newton .release = single_release, 161f95f3850SWill Newton }; 162f95f3850SWill Newton 163f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 164f95f3850SWill Newton { 165f95f3850SWill Newton seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); 166f95f3850SWill Newton seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); 167f95f3850SWill Newton seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); 168f95f3850SWill Newton seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); 169f95f3850SWill Newton seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); 170f95f3850SWill Newton seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); 171f95f3850SWill Newton 172f95f3850SWill Newton return 0; 173f95f3850SWill Newton } 174f95f3850SWill Newton 175f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 176f95f3850SWill Newton { 177f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 178f95f3850SWill Newton } 179f95f3850SWill Newton 180f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 181f95f3850SWill Newton .owner = THIS_MODULE, 182f95f3850SWill Newton .open = dw_mci_regs_open, 183f95f3850SWill Newton .read = seq_read, 184f95f3850SWill Newton .llseek = seq_lseek, 185f95f3850SWill Newton .release = single_release, 186f95f3850SWill Newton }; 187f95f3850SWill Newton 188f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 189f95f3850SWill Newton { 190f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 191f95f3850SWill Newton struct dw_mci *host = slot->host; 192f95f3850SWill Newton struct dentry *root; 193f95f3850SWill Newton struct dentry *node; 194f95f3850SWill Newton 195f95f3850SWill Newton root = mmc->debugfs_root; 196f95f3850SWill Newton if (!root) 197f95f3850SWill Newton return; 198f95f3850SWill Newton 199f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 200f95f3850SWill Newton &dw_mci_regs_fops); 201f95f3850SWill Newton if (!node) 202f95f3850SWill Newton goto err; 203f95f3850SWill Newton 204f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 205f95f3850SWill Newton &dw_mci_req_fops); 206f95f3850SWill Newton if (!node) 207f95f3850SWill Newton goto err; 208f95f3850SWill Newton 209f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 210f95f3850SWill Newton if (!node) 211f95f3850SWill Newton goto err; 212f95f3850SWill Newton 213f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 214f95f3850SWill Newton (u32 *)&host->pending_events); 215f95f3850SWill Newton if (!node) 216f95f3850SWill Newton goto err; 217f95f3850SWill Newton 218f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 219f95f3850SWill Newton (u32 *)&host->completed_events); 220f95f3850SWill Newton if (!node) 221f95f3850SWill Newton goto err; 222f95f3850SWill Newton 223f95f3850SWill Newton return; 224f95f3850SWill Newton 225f95f3850SWill Newton err: 226f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 227f95f3850SWill Newton } 228f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 229f95f3850SWill Newton 23001730558SDoug Anderson static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg); 23101730558SDoug Anderson 232f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 233f95f3850SWill Newton { 234f95f3850SWill Newton struct mmc_data *data; 235800d78bfSThomas Abraham struct dw_mci_slot *slot = mmc_priv(mmc); 23601730558SDoug Anderson struct dw_mci *host = slot->host; 237e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 238f95f3850SWill Newton u32 cmdr; 239f95f3850SWill Newton 2400e3a22c0SShawn Lin cmd->error = -EINPROGRESS; 241f95f3850SWill Newton cmdr = cmd->opcode; 242f95f3850SWill Newton 24390c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 24490c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 24590c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 24690c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 24790c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 248f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 2494a1b27adSJaehoon Chung else if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 250f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 251f95f3850SWill Newton 25201730558SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 25301730558SDoug Anderson u32 clk_en_a; 25401730558SDoug Anderson 25501730558SDoug Anderson /* Special bit makes CMD11 not die */ 25601730558SDoug Anderson cmdr |= SDMMC_CMD_VOLT_SWITCH; 25701730558SDoug Anderson 25801730558SDoug Anderson /* Change state to continue to handle CMD11 weirdness */ 25901730558SDoug Anderson WARN_ON(slot->host->state != STATE_SENDING_CMD); 26001730558SDoug Anderson slot->host->state = STATE_SENDING_CMD11; 26101730558SDoug Anderson 26201730558SDoug Anderson /* 26301730558SDoug Anderson * We need to disable low power mode (automatic clock stop) 26401730558SDoug Anderson * while doing voltage switch so we don't confuse the card, 26501730558SDoug Anderson * since stopping the clock is a specific part of the UHS 26601730558SDoug Anderson * voltage change dance. 26701730558SDoug Anderson * 26801730558SDoug Anderson * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be 26901730558SDoug Anderson * unconditionally turned back on in dw_mci_setup_bus() if it's 27001730558SDoug Anderson * ever called with a non-zero clock. That shouldn't happen 27101730558SDoug Anderson * until the voltage change is all done. 27201730558SDoug Anderson */ 27301730558SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 27401730558SDoug Anderson clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id); 27501730558SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 27601730558SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 27701730558SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 27801730558SDoug Anderson } 27901730558SDoug Anderson 280f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 281f95f3850SWill Newton /* We expect a response, so set this bit */ 282f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 283f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 284f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 285f95f3850SWill Newton } 286f95f3850SWill Newton 287f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 288f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 289f95f3850SWill Newton 290f95f3850SWill Newton data = cmd->data; 291f95f3850SWill Newton if (data) { 292f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 293f95f3850SWill Newton if (data->flags & MMC_DATA_STREAM) 294f95f3850SWill Newton cmdr |= SDMMC_CMD_STRM_MODE; 295f95f3850SWill Newton if (data->flags & MMC_DATA_WRITE) 296f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 297f95f3850SWill Newton } 298f95f3850SWill Newton 299cb27a843SJames Hogan if (drv_data && drv_data->prepare_command) 300cb27a843SJames Hogan drv_data->prepare_command(slot->host, &cmdr); 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 33890c2143aSSeungwon Jeon return cmdr; 33990c2143aSSeungwon Jeon } 34090c2143aSSeungwon Jeon 3410bdbd0e8SDoug Anderson static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) 3420bdbd0e8SDoug Anderson { 3430bdbd0e8SDoug Anderson unsigned long timeout = jiffies + msecs_to_jiffies(500); 3440bdbd0e8SDoug Anderson 3450bdbd0e8SDoug Anderson /* 3460bdbd0e8SDoug Anderson * Databook says that before issuing a new data transfer command 3470bdbd0e8SDoug Anderson * we need to check to see if the card is busy. Data transfer commands 3480bdbd0e8SDoug Anderson * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that. 3490bdbd0e8SDoug Anderson * 3500bdbd0e8SDoug Anderson * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is 3510bdbd0e8SDoug Anderson * expected. 3520bdbd0e8SDoug Anderson */ 3530bdbd0e8SDoug Anderson if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) && 3540bdbd0e8SDoug Anderson !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) { 3550bdbd0e8SDoug Anderson while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) { 3560bdbd0e8SDoug Anderson if (time_after(jiffies, timeout)) { 3570bdbd0e8SDoug Anderson /* Command will fail; we'll pass error then */ 3580bdbd0e8SDoug Anderson dev_err(host->dev, "Busy; trying anyway\n"); 3590bdbd0e8SDoug Anderson break; 3600bdbd0e8SDoug Anderson } 3610bdbd0e8SDoug Anderson udelay(10); 3620bdbd0e8SDoug Anderson } 3630bdbd0e8SDoug Anderson } 3640bdbd0e8SDoug Anderson } 3650bdbd0e8SDoug Anderson 366f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 367f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 368f95f3850SWill Newton { 369f95f3850SWill Newton host->cmd = cmd; 3704a90920cSThomas Abraham dev_vdbg(host->dev, 371f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 372f95f3850SWill Newton cmd->arg, cmd_flags); 373f95f3850SWill Newton 374f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 3750e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 3760bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd_flags); 377f95f3850SWill Newton 378f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 379f95f3850SWill Newton } 380f95f3850SWill Newton 38190c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 382f95f3850SWill Newton { 38390c2143aSSeungwon Jeon struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; 3840e3a22c0SShawn Lin 38590c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 386f95f3850SWill Newton } 387f95f3850SWill Newton 388f95f3850SWill Newton /* DMA interface functions */ 389f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 390f95f3850SWill Newton { 39103e8cb53SJames Hogan if (host->using_dma) { 392f95f3850SWill Newton host->dma_ops->stop(host); 393f95f3850SWill Newton host->dma_ops->cleanup(host); 394aa50f259SSeungwon Jeon } 395aa50f259SSeungwon Jeon 396f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 397f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 398f95f3850SWill Newton } 399f95f3850SWill Newton 4009aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 4019aa51408SSeungwon Jeon { 4029aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 4039aa51408SSeungwon Jeon return DMA_TO_DEVICE; 4049aa51408SSeungwon Jeon else 4059aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 4069aa51408SSeungwon Jeon } 4079aa51408SSeungwon Jeon 408f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 409f95f3850SWill Newton { 410f95f3850SWill Newton struct mmc_data *data = host->data; 411f95f3850SWill Newton 412f95f3850SWill Newton if (data) 4139aa51408SSeungwon Jeon if (!data->host_cookie) 4144a90920cSThomas Abraham dma_unmap_sg(host->dev, 4159aa51408SSeungwon Jeon data->sg, 4169aa51408SSeungwon Jeon data->sg_len, 4179aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 418f95f3850SWill Newton } 419f95f3850SWill Newton 4205ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host) 4215ce9d961SSeungwon Jeon { 4225ce9d961SSeungwon Jeon u32 bmod = mci_readl(host, BMOD); 4235ce9d961SSeungwon Jeon /* Software reset of DMA */ 4245ce9d961SSeungwon Jeon bmod |= SDMMC_IDMAC_SWRESET; 4255ce9d961SSeungwon Jeon mci_writel(host, BMOD, bmod); 4265ce9d961SSeungwon Jeon } 4275ce9d961SSeungwon Jeon 428f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 429f95f3850SWill Newton { 430f95f3850SWill Newton u32 temp; 431f95f3850SWill Newton 432f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 433f95f3850SWill Newton temp = mci_readl(host, CTRL); 434f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 435f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 436f95f3850SWill Newton mci_writel(host, CTRL, temp); 437f95f3850SWill Newton 438f95f3850SWill Newton /* Stop the IDMAC running */ 439f95f3850SWill Newton temp = mci_readl(host, BMOD); 440a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 4415ce9d961SSeungwon Jeon temp |= SDMMC_IDMAC_SWRESET; 442f95f3850SWill Newton mci_writel(host, BMOD, temp); 443f95f3850SWill Newton } 444f95f3850SWill Newton 445*3fc7eaefSShawn Lin static void dw_mci_dmac_complete_dma(void *arg) 446f95f3850SWill Newton { 447*3fc7eaefSShawn Lin struct dw_mci *host = arg; 448f95f3850SWill Newton struct mmc_data *data = host->data; 449f95f3850SWill Newton 4504a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 451f95f3850SWill Newton 452*3fc7eaefSShawn Lin if ((host->use_dma == TRANS_MODE_EDMAC) && 453*3fc7eaefSShawn Lin data && (data->flags & MMC_DATA_READ)) 454*3fc7eaefSShawn Lin /* Invalidate cache after read */ 455*3fc7eaefSShawn Lin dma_sync_sg_for_cpu(mmc_dev(host->cur_slot->mmc), 456*3fc7eaefSShawn Lin data->sg, 457*3fc7eaefSShawn Lin data->sg_len, 458*3fc7eaefSShawn Lin DMA_FROM_DEVICE); 459*3fc7eaefSShawn Lin 460f95f3850SWill Newton host->dma_ops->cleanup(host); 461f95f3850SWill Newton 462f95f3850SWill Newton /* 463f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 464f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 465f95f3850SWill Newton */ 466f95f3850SWill Newton if (data) { 467f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 468f95f3850SWill Newton tasklet_schedule(&host->tasklet); 469f95f3850SWill Newton } 470f95f3850SWill Newton } 471f95f3850SWill Newton 472f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, 473f95f3850SWill Newton unsigned int sg_len) 474f95f3850SWill Newton { 4755959b32eSAlexey Brodkin unsigned int desc_len; 476f95f3850SWill Newton int i; 4770e3a22c0SShawn Lin 47869d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 4795959b32eSAlexey Brodkin struct idmac_desc_64addr *desc_first, *desc_last, *desc; 48069d99fdcSPrabu Thangamuthu 4815959b32eSAlexey Brodkin desc_first = desc_last = desc = host->sg_cpu; 4825959b32eSAlexey Brodkin 4835959b32eSAlexey Brodkin for (i = 0; i < sg_len; i++) { 48469d99fdcSPrabu Thangamuthu unsigned int length = sg_dma_len(&data->sg[i]); 4850e3a22c0SShawn Lin 48669d99fdcSPrabu Thangamuthu u64 mem_addr = sg_dma_address(&data->sg[i]); 48769d99fdcSPrabu Thangamuthu 4885959b32eSAlexey Brodkin for ( ; length ; desc++) { 4895959b32eSAlexey Brodkin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 4905959b32eSAlexey Brodkin length : DW_MCI_DESC_DATA_LENGTH; 4915959b32eSAlexey Brodkin 4925959b32eSAlexey Brodkin length -= desc_len; 4935959b32eSAlexey Brodkin 49469d99fdcSPrabu Thangamuthu /* 4955959b32eSAlexey Brodkin * Set the OWN bit and disable interrupts 4965959b32eSAlexey Brodkin * for this descriptor 49769d99fdcSPrabu Thangamuthu */ 49869d99fdcSPrabu Thangamuthu desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | 49969d99fdcSPrabu Thangamuthu IDMAC_DES0_CH; 5005959b32eSAlexey Brodkin 50169d99fdcSPrabu Thangamuthu /* Buffer length */ 5025959b32eSAlexey Brodkin IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len); 50369d99fdcSPrabu Thangamuthu 50469d99fdcSPrabu Thangamuthu /* Physical address to DMA to/from */ 50569d99fdcSPrabu Thangamuthu desc->des4 = mem_addr & 0xffffffff; 50669d99fdcSPrabu Thangamuthu desc->des5 = mem_addr >> 32; 5075959b32eSAlexey Brodkin 5085959b32eSAlexey Brodkin /* Update physical address for the next desc */ 5095959b32eSAlexey Brodkin mem_addr += desc_len; 5105959b32eSAlexey Brodkin 5115959b32eSAlexey Brodkin /* Save pointer to the last descriptor */ 5125959b32eSAlexey Brodkin desc_last = desc; 5135959b32eSAlexey Brodkin } 51469d99fdcSPrabu Thangamuthu } 51569d99fdcSPrabu Thangamuthu 51669d99fdcSPrabu Thangamuthu /* Set first descriptor */ 5175959b32eSAlexey Brodkin desc_first->des0 |= IDMAC_DES0_FD; 51869d99fdcSPrabu Thangamuthu 51969d99fdcSPrabu Thangamuthu /* Set last descriptor */ 5205959b32eSAlexey Brodkin desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 5215959b32eSAlexey Brodkin desc_last->des0 |= IDMAC_DES0_LD; 52269d99fdcSPrabu Thangamuthu 52369d99fdcSPrabu Thangamuthu } else { 5245959b32eSAlexey Brodkin struct idmac_desc *desc_first, *desc_last, *desc; 525f95f3850SWill Newton 5265959b32eSAlexey Brodkin desc_first = desc_last = desc = host->sg_cpu; 5275959b32eSAlexey Brodkin 5285959b32eSAlexey Brodkin for (i = 0; i < sg_len; i++) { 529f95f3850SWill Newton unsigned int length = sg_dma_len(&data->sg[i]); 5300e3a22c0SShawn Lin 531f95f3850SWill Newton u32 mem_addr = sg_dma_address(&data->sg[i]); 532f95f3850SWill Newton 5335959b32eSAlexey Brodkin for ( ; length ; desc++) { 5345959b32eSAlexey Brodkin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 5355959b32eSAlexey Brodkin length : DW_MCI_DESC_DATA_LENGTH; 5365959b32eSAlexey Brodkin 5375959b32eSAlexey Brodkin length -= desc_len; 5385959b32eSAlexey Brodkin 53969d99fdcSPrabu Thangamuthu /* 5405959b32eSAlexey Brodkin * Set the OWN bit and disable interrupts 5415959b32eSAlexey Brodkin * for this descriptor 54269d99fdcSPrabu Thangamuthu */ 5436687c42fSBen Dooks desc->des0 = cpu_to_le32(IDMAC_DES0_OWN | 5445959b32eSAlexey Brodkin IDMAC_DES0_DIC | 5455959b32eSAlexey Brodkin IDMAC_DES0_CH); 5465959b32eSAlexey Brodkin 547f95f3850SWill Newton /* Buffer length */ 5485959b32eSAlexey Brodkin IDMAC_SET_BUFFER1_SIZE(desc, desc_len); 549f95f3850SWill Newton 550f95f3850SWill Newton /* Physical address to DMA to/from */ 5516687c42fSBen Dooks desc->des2 = cpu_to_le32(mem_addr); 5525959b32eSAlexey Brodkin 5535959b32eSAlexey Brodkin /* Update physical address for the next desc */ 5545959b32eSAlexey Brodkin mem_addr += desc_len; 5555959b32eSAlexey Brodkin 5565959b32eSAlexey Brodkin /* Save pointer to the last descriptor */ 5575959b32eSAlexey Brodkin desc_last = desc; 5585959b32eSAlexey Brodkin } 559f95f3850SWill Newton } 560f95f3850SWill Newton 561f95f3850SWill Newton /* Set first descriptor */ 5625959b32eSAlexey Brodkin desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD); 563f95f3850SWill Newton 564f95f3850SWill Newton /* Set last descriptor */ 5655959b32eSAlexey Brodkin desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | 5665959b32eSAlexey Brodkin IDMAC_DES0_DIC)); 5675959b32eSAlexey Brodkin desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD); 56869d99fdcSPrabu Thangamuthu } 569f95f3850SWill Newton 5700e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 571f95f3850SWill Newton } 572f95f3850SWill Newton 573*3fc7eaefSShawn Lin static int dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 574f95f3850SWill Newton { 575f95f3850SWill Newton u32 temp; 576f95f3850SWill Newton 577f95f3850SWill Newton dw_mci_translate_sglist(host, host->data, sg_len); 578f95f3850SWill Newton 579536f6b91SSonny Rao /* Make sure to reset DMA in case we did PIO before this */ 580536f6b91SSonny Rao dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET); 581536f6b91SSonny Rao dw_mci_idmac_reset(host); 582536f6b91SSonny Rao 583f95f3850SWill Newton /* Select IDMAC interface */ 584f95f3850SWill Newton temp = mci_readl(host, CTRL); 585f95f3850SWill Newton temp |= SDMMC_CTRL_USE_IDMAC; 586f95f3850SWill Newton mci_writel(host, CTRL, temp); 587f95f3850SWill Newton 5880e3a22c0SShawn Lin /* drain writebuffer */ 589f95f3850SWill Newton wmb(); 590f95f3850SWill Newton 591f95f3850SWill Newton /* Enable the IDMAC */ 592f95f3850SWill Newton temp = mci_readl(host, BMOD); 593a5289a43SJaehoon Chung temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 594f95f3850SWill Newton mci_writel(host, BMOD, temp); 595f95f3850SWill Newton 596f95f3850SWill Newton /* Start it running */ 597f95f3850SWill Newton mci_writel(host, PLDMND, 1); 598*3fc7eaefSShawn Lin 599*3fc7eaefSShawn Lin return 0; 600f95f3850SWill Newton } 601f95f3850SWill Newton 602f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 603f95f3850SWill Newton { 604897b69e7SSeungwon Jeon int i; 605f95f3850SWill Newton 60669d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 60769d99fdcSPrabu Thangamuthu struct idmac_desc_64addr *p; 60869d99fdcSPrabu Thangamuthu /* Number of descriptors in the ring buffer */ 60969d99fdcSPrabu Thangamuthu host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr); 61069d99fdcSPrabu Thangamuthu 61169d99fdcSPrabu Thangamuthu /* Forward link the descriptor list */ 61269d99fdcSPrabu Thangamuthu for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; 61369d99fdcSPrabu Thangamuthu i++, p++) { 61469d99fdcSPrabu Thangamuthu p->des6 = (host->sg_dma + 61569d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 61669d99fdcSPrabu Thangamuthu (i + 1))) & 0xffffffff; 61769d99fdcSPrabu Thangamuthu 61869d99fdcSPrabu Thangamuthu p->des7 = (u64)(host->sg_dma + 61969d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 62069d99fdcSPrabu Thangamuthu (i + 1))) >> 32; 62169d99fdcSPrabu Thangamuthu /* Initialize reserved and buffer size fields to "0" */ 62269d99fdcSPrabu Thangamuthu p->des1 = 0; 62369d99fdcSPrabu Thangamuthu p->des2 = 0; 62469d99fdcSPrabu Thangamuthu p->des3 = 0; 62569d99fdcSPrabu Thangamuthu } 62669d99fdcSPrabu Thangamuthu 62769d99fdcSPrabu Thangamuthu /* Set the last descriptor as the end-of-ring descriptor */ 62869d99fdcSPrabu Thangamuthu p->des6 = host->sg_dma & 0xffffffff; 62969d99fdcSPrabu Thangamuthu p->des7 = (u64)host->sg_dma >> 32; 63069d99fdcSPrabu Thangamuthu p->des0 = IDMAC_DES0_ER; 63169d99fdcSPrabu Thangamuthu 63269d99fdcSPrabu Thangamuthu } else { 63369d99fdcSPrabu Thangamuthu struct idmac_desc *p; 634f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 635f95f3850SWill Newton host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 636f95f3850SWill Newton 637f95f3850SWill Newton /* Forward link the descriptor list */ 6380e3a22c0SShawn Lin for (i = 0, p = host->sg_cpu; 6390e3a22c0SShawn Lin i < host->ring_size - 1; 6400e3a22c0SShawn Lin i++, p++) { 6416687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma + 6426687c42fSBen Dooks (sizeof(struct idmac_desc) * (i + 1))); 6434b244724SZhangfei Gao p->des1 = 0; 6444b244724SZhangfei Gao } 645f95f3850SWill Newton 646f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 6476687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma); 6486687c42fSBen Dooks p->des0 = cpu_to_le32(IDMAC_DES0_ER); 64969d99fdcSPrabu Thangamuthu } 650f95f3850SWill Newton 6515ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 652141a712aSSeungwon Jeon 65369d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 65469d99fdcSPrabu Thangamuthu /* Mask out interrupts - get Tx & Rx complete only */ 65569d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, IDMAC_INT_CLR); 65669d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI | 65769d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 65869d99fdcSPrabu Thangamuthu 65969d99fdcSPrabu Thangamuthu /* Set the descriptor base address */ 66069d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff); 66169d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32); 66269d99fdcSPrabu Thangamuthu 66369d99fdcSPrabu Thangamuthu } else { 664f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 665fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 66669d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | 66769d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 668f95f3850SWill Newton 669f95f3850SWill Newton /* Set the descriptor base address */ 670f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 67169d99fdcSPrabu Thangamuthu } 67269d99fdcSPrabu Thangamuthu 673f95f3850SWill Newton return 0; 674f95f3850SWill Newton } 675f95f3850SWill Newton 6768e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 677885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 678885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 679885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 680*3fc7eaefSShawn Lin .complete = dw_mci_dmac_complete_dma, 681885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 682885c3e80SSeungwon Jeon }; 683*3fc7eaefSShawn Lin 684*3fc7eaefSShawn Lin static void dw_mci_edmac_stop_dma(struct dw_mci *host) 685*3fc7eaefSShawn Lin { 686*3fc7eaefSShawn Lin dmaengine_terminate_all(host->dms->ch); 687*3fc7eaefSShawn Lin } 688*3fc7eaefSShawn Lin 689*3fc7eaefSShawn Lin static int dw_mci_edmac_start_dma(struct dw_mci *host, 690*3fc7eaefSShawn Lin unsigned int sg_len) 691*3fc7eaefSShawn Lin { 692*3fc7eaefSShawn Lin struct dma_slave_config cfg; 693*3fc7eaefSShawn Lin struct dma_async_tx_descriptor *desc = NULL; 694*3fc7eaefSShawn Lin struct scatterlist *sgl = host->data->sg; 695*3fc7eaefSShawn Lin const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 696*3fc7eaefSShawn Lin u32 sg_elems = host->data->sg_len; 697*3fc7eaefSShawn Lin u32 fifoth_val; 698*3fc7eaefSShawn Lin u32 fifo_offset = host->fifo_reg - host->regs; 699*3fc7eaefSShawn Lin int ret = 0; 700*3fc7eaefSShawn Lin 701*3fc7eaefSShawn Lin /* Set external dma config: burst size, burst width */ 702*3fc7eaefSShawn Lin cfg.dst_addr = (dma_addr_t)(host->phy_regs + fifo_offset); 703*3fc7eaefSShawn Lin cfg.src_addr = cfg.dst_addr; 704*3fc7eaefSShawn Lin cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 705*3fc7eaefSShawn Lin cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 706*3fc7eaefSShawn Lin 707*3fc7eaefSShawn Lin /* Match burst msize with external dma config */ 708*3fc7eaefSShawn Lin fifoth_val = mci_readl(host, FIFOTH); 709*3fc7eaefSShawn Lin cfg.dst_maxburst = mszs[(fifoth_val >> 28) & 0x7]; 710*3fc7eaefSShawn Lin cfg.src_maxburst = cfg.dst_maxburst; 711*3fc7eaefSShawn Lin 712*3fc7eaefSShawn Lin if (host->data->flags & MMC_DATA_WRITE) 713*3fc7eaefSShawn Lin cfg.direction = DMA_MEM_TO_DEV; 714*3fc7eaefSShawn Lin else 715*3fc7eaefSShawn Lin cfg.direction = DMA_DEV_TO_MEM; 716*3fc7eaefSShawn Lin 717*3fc7eaefSShawn Lin ret = dmaengine_slave_config(host->dms->ch, &cfg); 718*3fc7eaefSShawn Lin if (ret) { 719*3fc7eaefSShawn Lin dev_err(host->dev, "Failed to config edmac.\n"); 720*3fc7eaefSShawn Lin return -EBUSY; 721*3fc7eaefSShawn Lin } 722*3fc7eaefSShawn Lin 723*3fc7eaefSShawn Lin desc = dmaengine_prep_slave_sg(host->dms->ch, sgl, 724*3fc7eaefSShawn Lin sg_len, cfg.direction, 725*3fc7eaefSShawn Lin DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 726*3fc7eaefSShawn Lin if (!desc) { 727*3fc7eaefSShawn Lin dev_err(host->dev, "Can't prepare slave sg.\n"); 728*3fc7eaefSShawn Lin return -EBUSY; 729*3fc7eaefSShawn Lin } 730*3fc7eaefSShawn Lin 731*3fc7eaefSShawn Lin /* Set dw_mci_dmac_complete_dma as callback */ 732*3fc7eaefSShawn Lin desc->callback = dw_mci_dmac_complete_dma; 733*3fc7eaefSShawn Lin desc->callback_param = (void *)host; 734*3fc7eaefSShawn Lin dmaengine_submit(desc); 735*3fc7eaefSShawn Lin 736*3fc7eaefSShawn Lin /* Flush cache before write */ 737*3fc7eaefSShawn Lin if (host->data->flags & MMC_DATA_WRITE) 738*3fc7eaefSShawn Lin dma_sync_sg_for_device(mmc_dev(host->cur_slot->mmc), sgl, 739*3fc7eaefSShawn Lin sg_elems, DMA_TO_DEVICE); 740*3fc7eaefSShawn Lin 741*3fc7eaefSShawn Lin dma_async_issue_pending(host->dms->ch); 742*3fc7eaefSShawn Lin 743*3fc7eaefSShawn Lin return 0; 744*3fc7eaefSShawn Lin } 745*3fc7eaefSShawn Lin 746*3fc7eaefSShawn Lin static int dw_mci_edmac_init(struct dw_mci *host) 747*3fc7eaefSShawn Lin { 748*3fc7eaefSShawn Lin /* Request external dma channel */ 749*3fc7eaefSShawn Lin host->dms = kzalloc(sizeof(struct dw_mci_dma_slave), GFP_KERNEL); 750*3fc7eaefSShawn Lin if (!host->dms) 751*3fc7eaefSShawn Lin return -ENOMEM; 752*3fc7eaefSShawn Lin 753*3fc7eaefSShawn Lin host->dms->ch = dma_request_slave_channel(host->dev, "rx-tx"); 754*3fc7eaefSShawn Lin if (!host->dms->ch) { 755*3fc7eaefSShawn Lin dev_err(host->dev, 756*3fc7eaefSShawn Lin "Failed to get external DMA channel %d\n", 757*3fc7eaefSShawn Lin host->dms->ch->chan_id); 758*3fc7eaefSShawn Lin kfree(host->dms); 759*3fc7eaefSShawn Lin host->dms = NULL; 760*3fc7eaefSShawn Lin return -ENXIO; 761*3fc7eaefSShawn Lin } 762*3fc7eaefSShawn Lin 763*3fc7eaefSShawn Lin return 0; 764*3fc7eaefSShawn Lin } 765*3fc7eaefSShawn Lin 766*3fc7eaefSShawn Lin static void dw_mci_edmac_exit(struct dw_mci *host) 767*3fc7eaefSShawn Lin { 768*3fc7eaefSShawn Lin if (host->dms) { 769*3fc7eaefSShawn Lin if (host->dms->ch) { 770*3fc7eaefSShawn Lin dma_release_channel(host->dms->ch); 771*3fc7eaefSShawn Lin host->dms->ch = NULL; 772*3fc7eaefSShawn Lin } 773*3fc7eaefSShawn Lin kfree(host->dms); 774*3fc7eaefSShawn Lin host->dms = NULL; 775*3fc7eaefSShawn Lin } 776*3fc7eaefSShawn Lin } 777*3fc7eaefSShawn Lin 778*3fc7eaefSShawn Lin static const struct dw_mci_dma_ops dw_mci_edmac_ops = { 779*3fc7eaefSShawn Lin .init = dw_mci_edmac_init, 780*3fc7eaefSShawn Lin .exit = dw_mci_edmac_exit, 781*3fc7eaefSShawn Lin .start = dw_mci_edmac_start_dma, 782*3fc7eaefSShawn Lin .stop = dw_mci_edmac_stop_dma, 783*3fc7eaefSShawn Lin .complete = dw_mci_dmac_complete_dma, 784*3fc7eaefSShawn Lin .cleanup = dw_mci_dma_cleanup, 785*3fc7eaefSShawn Lin }; 786885c3e80SSeungwon Jeon 7879aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 7889aa51408SSeungwon Jeon struct mmc_data *data, 7899aa51408SSeungwon Jeon bool next) 790f95f3850SWill Newton { 791f95f3850SWill Newton struct scatterlist *sg; 7929aa51408SSeungwon Jeon unsigned int i, sg_len; 793f95f3850SWill Newton 7949aa51408SSeungwon Jeon if (!next && data->host_cookie) 7959aa51408SSeungwon Jeon return data->host_cookie; 796f95f3850SWill Newton 797f95f3850SWill Newton /* 798f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 799f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 800f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 801f95f3850SWill Newton */ 802f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 803f95f3850SWill Newton return -EINVAL; 8049aa51408SSeungwon Jeon 805f95f3850SWill Newton if (data->blksz & 3) 806f95f3850SWill Newton return -EINVAL; 807f95f3850SWill Newton 808f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 809f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 810f95f3850SWill Newton return -EINVAL; 811f95f3850SWill Newton } 812f95f3850SWill Newton 8134a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 8149aa51408SSeungwon Jeon data->sg, 8159aa51408SSeungwon Jeon data->sg_len, 8169aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 8179aa51408SSeungwon Jeon if (sg_len == 0) 8189aa51408SSeungwon Jeon return -EINVAL; 8199aa51408SSeungwon Jeon 8209aa51408SSeungwon Jeon if (next) 8219aa51408SSeungwon Jeon data->host_cookie = sg_len; 8229aa51408SSeungwon Jeon 8239aa51408SSeungwon Jeon return sg_len; 8249aa51408SSeungwon Jeon } 8259aa51408SSeungwon Jeon 8269aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 8279aa51408SSeungwon Jeon struct mmc_request *mrq, 8289aa51408SSeungwon Jeon bool is_first_req) 8299aa51408SSeungwon Jeon { 8309aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 8319aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 8329aa51408SSeungwon Jeon 8339aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 8349aa51408SSeungwon Jeon return; 8359aa51408SSeungwon Jeon 8369aa51408SSeungwon Jeon if (data->host_cookie) { 8379aa51408SSeungwon Jeon data->host_cookie = 0; 8389aa51408SSeungwon Jeon return; 8399aa51408SSeungwon Jeon } 8409aa51408SSeungwon Jeon 8419aa51408SSeungwon Jeon if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) 8429aa51408SSeungwon Jeon data->host_cookie = 0; 8439aa51408SSeungwon Jeon } 8449aa51408SSeungwon Jeon 8459aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 8469aa51408SSeungwon Jeon struct mmc_request *mrq, 8479aa51408SSeungwon Jeon int err) 8489aa51408SSeungwon Jeon { 8499aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 8509aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 8519aa51408SSeungwon Jeon 8529aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 8539aa51408SSeungwon Jeon return; 8549aa51408SSeungwon Jeon 8559aa51408SSeungwon Jeon if (data->host_cookie) 8564a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 8579aa51408SSeungwon Jeon data->sg, 8589aa51408SSeungwon Jeon data->sg_len, 8599aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 8609aa51408SSeungwon Jeon data->host_cookie = 0; 8619aa51408SSeungwon Jeon } 8629aa51408SSeungwon Jeon 86352426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 86452426899SSeungwon Jeon { 86552426899SSeungwon Jeon unsigned int blksz = data->blksz; 86652426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 86752426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 86852426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 86952426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 8700e3a22c0SShawn Lin int idx = ARRAY_SIZE(mszs) - 1; 87152426899SSeungwon Jeon 872*3fc7eaefSShawn Lin /* pio should ship this scenario */ 873*3fc7eaefSShawn Lin if (!host->use_dma) 874*3fc7eaefSShawn Lin return; 875*3fc7eaefSShawn Lin 87652426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 87752426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 87852426899SSeungwon Jeon 87952426899SSeungwon Jeon /* 88052426899SSeungwon Jeon * MSIZE is '1', 88152426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 88252426899SSeungwon Jeon */ 88352426899SSeungwon Jeon if (blksz % fifo_width) { 88452426899SSeungwon Jeon msize = 0; 88552426899SSeungwon Jeon rx_wmark = 1; 88652426899SSeungwon Jeon goto done; 88752426899SSeungwon Jeon } 88852426899SSeungwon Jeon 88952426899SSeungwon Jeon do { 89052426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 89152426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 89252426899SSeungwon Jeon msize = idx; 89352426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 89452426899SSeungwon Jeon break; 89552426899SSeungwon Jeon } 89652426899SSeungwon Jeon } while (--idx > 0); 89752426899SSeungwon Jeon /* 89852426899SSeungwon Jeon * If idx is '0', it won't be tried 89952426899SSeungwon Jeon * Thus, initial values are uesed 90052426899SSeungwon Jeon */ 90152426899SSeungwon Jeon done: 90252426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 90352426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 90452426899SSeungwon Jeon } 90552426899SSeungwon Jeon 906f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) 907f1d2736cSSeungwon Jeon { 908f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 909f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 910f1d2736cSSeungwon Jeon u16 thld_size; 911f1d2736cSSeungwon Jeon 912f1d2736cSSeungwon Jeon WARN_ON(!(data->flags & MMC_DATA_READ)); 913f1d2736cSSeungwon Jeon 91466dfd101SJames Hogan /* 91566dfd101SJames Hogan * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is 91666dfd101SJames Hogan * in the FIFO region, so we really shouldn't access it). 91766dfd101SJames Hogan */ 91866dfd101SJames Hogan if (host->verid < DW_MMC_240A) 91966dfd101SJames Hogan return; 92066dfd101SJames Hogan 921f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 922488b8d63SJaehoon Chung host->timing != MMC_TIMING_MMC_HS400 && 923f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 924f1d2736cSSeungwon Jeon goto disable; 925f1d2736cSSeungwon Jeon 926f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 927f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 928f1d2736cSSeungwon Jeon 929f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 930f1d2736cSSeungwon Jeon goto disable; 931f1d2736cSSeungwon Jeon 932f1d2736cSSeungwon Jeon /* 933f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 934f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 935f1d2736cSSeungwon Jeon * Currently just choose blksz. 936f1d2736cSSeungwon Jeon */ 937f1d2736cSSeungwon Jeon thld_size = blksz; 938f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1)); 939f1d2736cSSeungwon Jeon return; 940f1d2736cSSeungwon Jeon 941f1d2736cSSeungwon Jeon disable: 942f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0)); 943f1d2736cSSeungwon Jeon } 944f1d2736cSSeungwon Jeon 9459aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 9469aa51408SSeungwon Jeon { 947f8c58c11SDoug Anderson unsigned long irqflags; 9489aa51408SSeungwon Jeon int sg_len; 9499aa51408SSeungwon Jeon u32 temp; 9509aa51408SSeungwon Jeon 9519aa51408SSeungwon Jeon host->using_dma = 0; 9529aa51408SSeungwon Jeon 9539aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 9549aa51408SSeungwon Jeon if (!host->use_dma) 9559aa51408SSeungwon Jeon return -ENODEV; 9569aa51408SSeungwon Jeon 9579aa51408SSeungwon Jeon sg_len = dw_mci_pre_dma_transfer(host, data, 0); 958a99aa9b9SSeungwon Jeon if (sg_len < 0) { 959a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 9609aa51408SSeungwon Jeon return sg_len; 961a99aa9b9SSeungwon Jeon } 9629aa51408SSeungwon Jeon 96303e8cb53SJames Hogan host->using_dma = 1; 96403e8cb53SJames Hogan 965*3fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 9664a90920cSThomas Abraham dev_vdbg(host->dev, 967f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 968*3fc7eaefSShawn Lin (unsigned long)host->sg_cpu, 969*3fc7eaefSShawn Lin (unsigned long)host->sg_dma, 970f95f3850SWill Newton sg_len); 971f95f3850SWill Newton 97252426899SSeungwon Jeon /* 97352426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 97452426899SSeungwon Jeon * If current block size is same with previous size, 97552426899SSeungwon Jeon * no need to update fifoth. 97652426899SSeungwon Jeon */ 97752426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 97852426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 97952426899SSeungwon Jeon 980f95f3850SWill Newton /* Enable the DMA interface */ 981f95f3850SWill Newton temp = mci_readl(host, CTRL); 982f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 983f95f3850SWill Newton mci_writel(host, CTRL, temp); 984f95f3850SWill Newton 985f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 986f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 987f95f3850SWill Newton temp = mci_readl(host, INTMASK); 988f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 989f95f3850SWill Newton mci_writel(host, INTMASK, temp); 990f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 991f95f3850SWill Newton 992*3fc7eaefSShawn Lin if (host->dma_ops->start(host, sg_len)) { 993*3fc7eaefSShawn Lin /* We can't do DMA */ 994*3fc7eaefSShawn Lin dev_err(host->dev, "%s: failed to start DMA.\n", __func__); 995*3fc7eaefSShawn Lin return -ENODEV; 996*3fc7eaefSShawn Lin } 997f95f3850SWill Newton 998f95f3850SWill Newton return 0; 999f95f3850SWill Newton } 1000f95f3850SWill Newton 1001f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 1002f95f3850SWill Newton { 1003f8c58c11SDoug Anderson unsigned long irqflags; 10040e3a22c0SShawn Lin int flags = SG_MITER_ATOMIC; 1005f95f3850SWill Newton u32 temp; 1006f95f3850SWill Newton 1007f95f3850SWill Newton data->error = -EINPROGRESS; 1008f95f3850SWill Newton 1009f95f3850SWill Newton WARN_ON(host->data); 1010f95f3850SWill Newton host->sg = NULL; 1011f95f3850SWill Newton host->data = data; 1012f95f3850SWill Newton 1013f1d2736cSSeungwon Jeon if (data->flags & MMC_DATA_READ) { 101455c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 1015f1d2736cSSeungwon Jeon dw_mci_ctrl_rd_thld(host, data); 1016f1d2736cSSeungwon Jeon } else { 101755c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 1018f1d2736cSSeungwon Jeon } 101955c5efbcSJames Hogan 1020f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 1021f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 1022f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 1023f9c2a0dcSSeungwon Jeon else 1024f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 1025f9c2a0dcSSeungwon Jeon 1026f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 1027f95f3850SWill Newton host->sg = data->sg; 102834b664a2SJames Hogan host->part_buf_start = 0; 102934b664a2SJames Hogan host->part_buf_count = 0; 1030f95f3850SWill Newton 1031b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 1032f8c58c11SDoug Anderson 1033f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1034f95f3850SWill Newton temp = mci_readl(host, INTMASK); 1035f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 1036f95f3850SWill Newton mci_writel(host, INTMASK, temp); 1037f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 1038f95f3850SWill Newton 1039f95f3850SWill Newton temp = mci_readl(host, CTRL); 1040f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 1041f95f3850SWill Newton mci_writel(host, CTRL, temp); 104252426899SSeungwon Jeon 104352426899SSeungwon Jeon /* 104452426899SSeungwon Jeon * Use the initial fifoth_val for PIO mode. 104552426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 104652426899SSeungwon Jeon * prev_blksz should be invalidated. 104752426899SSeungwon Jeon */ 104852426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 104952426899SSeungwon Jeon host->prev_blksz = 0; 105052426899SSeungwon Jeon } else { 105152426899SSeungwon Jeon /* 105252426899SSeungwon Jeon * Keep the current block size. 105352426899SSeungwon Jeon * It will be used to decide whether to update 105452426899SSeungwon Jeon * fifoth register next time. 105552426899SSeungwon Jeon */ 105652426899SSeungwon Jeon host->prev_blksz = data->blksz; 1057f95f3850SWill Newton } 1058f95f3850SWill Newton } 1059f95f3850SWill Newton 1060f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 1061f95f3850SWill Newton { 1062f95f3850SWill Newton struct dw_mci *host = slot->host; 1063f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 1064f95f3850SWill Newton unsigned int cmd_status = 0; 1065f95f3850SWill Newton 1066f95f3850SWill Newton mci_writel(host, CMDARG, arg); 10670e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 10680bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd); 1069f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 1070f95f3850SWill Newton 1071f95f3850SWill Newton while (time_before(jiffies, timeout)) { 1072f95f3850SWill Newton cmd_status = mci_readl(host, CMD); 1073f95f3850SWill Newton if (!(cmd_status & SDMMC_CMD_START)) 1074f95f3850SWill Newton return; 1075f95f3850SWill Newton } 1076f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 1077f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 1078f95f3850SWill Newton cmd, arg, cmd_status); 1079f95f3850SWill Newton } 1080f95f3850SWill Newton 1081ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 1082f95f3850SWill Newton { 1083f95f3850SWill Newton struct dw_mci *host = slot->host; 1084fdf492a1SDoug Anderson unsigned int clock = slot->clock; 1085f95f3850SWill Newton u32 div; 10869623b5b9SDoug Anderson u32 clk_en_a; 108701730558SDoug Anderson u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT; 108801730558SDoug Anderson 108901730558SDoug Anderson /* We must continue to set bit 28 in CMD until the change is complete */ 109001730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) 109101730558SDoug Anderson sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; 1092f95f3850SWill Newton 1093fdf492a1SDoug Anderson if (!clock) { 1094fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 109501730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1096fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 1097fdf492a1SDoug Anderson div = host->bus_hz / clock; 1098fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 1099f95f3850SWill Newton /* 1100f95f3850SWill Newton * move the + 1 after the divide to prevent 1101f95f3850SWill Newton * over-clocking the card. 1102f95f3850SWill Newton */ 1103e419990bSSeungwon Jeon div += 1; 1104e419990bSSeungwon Jeon 1105fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 1106f95f3850SWill Newton 1107fdf492a1SDoug Anderson if ((clock << div) != slot->__clk_old || force_clkinit) 1108f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 1109fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 1110fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 1111fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 1112fdf492a1SDoug Anderson host->bus_hz, div); 1113f95f3850SWill Newton 1114f95f3850SWill Newton /* disable clock */ 1115f95f3850SWill Newton mci_writel(host, CLKENA, 0); 1116f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 1117f95f3850SWill Newton 1118f95f3850SWill Newton /* inform CIU */ 111901730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1120f95f3850SWill Newton 1121f95f3850SWill Newton /* set clock to desired speed */ 1122f95f3850SWill Newton mci_writel(host, CLKDIV, div); 1123f95f3850SWill Newton 1124f95f3850SWill Newton /* inform CIU */ 112501730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1126f95f3850SWill Newton 11279623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 11289623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 1129b24c8b26SDoug Anderson if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) 11309623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 11319623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 1132f95f3850SWill Newton 1133f95f3850SWill Newton /* inform CIU */ 113401730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1135f95f3850SWill Newton 1136fdf492a1SDoug Anderson /* keep the clock with reflecting clock dividor */ 1137fdf492a1SDoug Anderson slot->__clk_old = clock << div; 1138f95f3850SWill Newton } 1139f95f3850SWill Newton 1140fdf492a1SDoug Anderson host->current_speed = clock; 1141fdf492a1SDoug Anderson 1142f95f3850SWill Newton /* Set the current slot bus width */ 11431d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 1144f95f3850SWill Newton } 1145f95f3850SWill Newton 1146053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 1147053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 1148053b3ce6SSeungwon Jeon struct mmc_command *cmd) 1149f95f3850SWill Newton { 1150f95f3850SWill Newton struct mmc_request *mrq; 1151f95f3850SWill Newton struct mmc_data *data; 1152f95f3850SWill Newton u32 cmdflags; 1153f95f3850SWill Newton 1154f95f3850SWill Newton mrq = slot->mrq; 1155f95f3850SWill Newton 1156f95f3850SWill Newton host->cur_slot = slot; 1157f95f3850SWill Newton host->mrq = mrq; 1158f95f3850SWill Newton 1159f95f3850SWill Newton host->pending_events = 0; 1160f95f3850SWill Newton host->completed_events = 0; 1161e352c813SSeungwon Jeon host->cmd_status = 0; 1162f95f3850SWill Newton host->data_status = 0; 1163e352c813SSeungwon Jeon host->dir_status = 0; 1164f95f3850SWill Newton 1165053b3ce6SSeungwon Jeon data = cmd->data; 1166f95f3850SWill Newton if (data) { 1167f16afa88SJaehoon Chung mci_writel(host, TMOUT, 0xFFFFFFFF); 1168f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 1169f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 1170f95f3850SWill Newton } 1171f95f3850SWill Newton 1172f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 1173f95f3850SWill Newton 1174f95f3850SWill Newton /* this is the first command, send the initialization clock */ 1175f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 1176f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 1177f95f3850SWill Newton 1178f95f3850SWill Newton if (data) { 1179f95f3850SWill Newton dw_mci_submit_data(host, data); 11800e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 1181f95f3850SWill Newton } 1182f95f3850SWill Newton 1183f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 1184f95f3850SWill Newton 11855c935165SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 118649ba0302SDoug Anderson unsigned long irqflags; 118749ba0302SDoug Anderson 11885c935165SDoug Anderson /* 11898886a6fdSDoug Anderson * Databook says to fail after 2ms w/ no response, but evidence 11908886a6fdSDoug Anderson * shows that sometimes the cmd11 interrupt takes over 130ms. 11918886a6fdSDoug Anderson * We'll set to 500ms, plus an extra jiffy just in case jiffies 11928886a6fdSDoug Anderson * is just about to roll over. 119349ba0302SDoug Anderson * 119449ba0302SDoug Anderson * We do this whole thing under spinlock and only if the 119549ba0302SDoug Anderson * command hasn't already completed (indicating the the irq 119649ba0302SDoug Anderson * already ran so we don't want the timeout). 11975c935165SDoug Anderson */ 119849ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 119949ba0302SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) 12005c935165SDoug Anderson mod_timer(&host->cmd11_timer, 12018886a6fdSDoug Anderson jiffies + msecs_to_jiffies(500) + 1); 120249ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 12035c935165SDoug Anderson } 12045c935165SDoug Anderson 1205f95f3850SWill Newton if (mrq->stop) 1206f95f3850SWill Newton host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 120790c2143aSSeungwon Jeon else 120890c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 1209f95f3850SWill Newton } 1210f95f3850SWill Newton 1211053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 1212053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 1213053b3ce6SSeungwon Jeon { 1214053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 1215053b3ce6SSeungwon Jeon struct mmc_command *cmd; 1216053b3ce6SSeungwon Jeon 1217053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 1218053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 1219053b3ce6SSeungwon Jeon } 1220053b3ce6SSeungwon Jeon 12217456caaeSJames Hogan /* must be called with host->lock held */ 1222f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 1223f95f3850SWill Newton struct mmc_request *mrq) 1224f95f3850SWill Newton { 1225f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 1226f95f3850SWill Newton host->state); 1227f95f3850SWill Newton 1228f95f3850SWill Newton slot->mrq = mrq; 1229f95f3850SWill Newton 123001730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) { 123101730558SDoug Anderson dev_warn(&slot->mmc->class_dev, 123201730558SDoug Anderson "Voltage change didn't complete\n"); 123301730558SDoug Anderson /* 123401730558SDoug Anderson * this case isn't expected to happen, so we can 123501730558SDoug Anderson * either crash here or just try to continue on 123601730558SDoug Anderson * in the closest possible state 123701730558SDoug Anderson */ 123801730558SDoug Anderson host->state = STATE_IDLE; 123901730558SDoug Anderson } 124001730558SDoug Anderson 1241f95f3850SWill Newton if (host->state == STATE_IDLE) { 1242f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1243f95f3850SWill Newton dw_mci_start_request(host, slot); 1244f95f3850SWill Newton } else { 1245f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 1246f95f3850SWill Newton } 1247f95f3850SWill Newton } 1248f95f3850SWill Newton 1249f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1250f95f3850SWill Newton { 1251f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1252f95f3850SWill Newton struct dw_mci *host = slot->host; 1253f95f3850SWill Newton 1254f95f3850SWill Newton WARN_ON(slot->mrq); 1255f95f3850SWill Newton 12567456caaeSJames Hogan /* 12577456caaeSJames Hogan * The check for card presence and queueing of the request must be 12587456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 12597456caaeSJames Hogan * request wouldn't fail until another card was inserted. 12607456caaeSJames Hogan */ 12617456caaeSJames Hogan spin_lock_bh(&host->lock); 12627456caaeSJames Hogan 1263f95f3850SWill Newton if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { 12647456caaeSJames Hogan spin_unlock_bh(&host->lock); 1265f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1266f95f3850SWill Newton mmc_request_done(mmc, mrq); 1267f95f3850SWill Newton return; 1268f95f3850SWill Newton } 1269f95f3850SWill Newton 1270f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 12717456caaeSJames Hogan 12727456caaeSJames Hogan spin_unlock_bh(&host->lock); 1273f95f3850SWill Newton } 1274f95f3850SWill Newton 1275f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1276f95f3850SWill Newton { 1277f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1278e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 127941babf75SJaehoon Chung u32 regs; 128051da2240SYuvaraj CD int ret; 1281f95f3850SWill Newton 1282f95f3850SWill Newton switch (ios->bus_width) { 1283f95f3850SWill Newton case MMC_BUS_WIDTH_4: 1284f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 1285f95f3850SWill Newton break; 1286c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 1287c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 1288c9b2a06fSJaehoon Chung break; 1289b2f7cb45SJaehoon Chung default: 1290b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 1291b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 1292f95f3850SWill Newton } 1293f95f3850SWill Newton 129441babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 12953f514291SSeungwon Jeon 12963f514291SSeungwon Jeon /* DDR mode set */ 129780113132SSeungwon Jeon if (ios->timing == MMC_TIMING_MMC_DDR52 || 129880113132SSeungwon Jeon ios->timing == MMC_TIMING_MMC_HS400) 1299c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 13003f514291SSeungwon Jeon else 1301c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 13023f514291SSeungwon Jeon 130341babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 1304f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 130541babf75SJaehoon Chung 1306f95f3850SWill Newton /* 1307f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 1308f95f3850SWill Newton * core ios update when finding the minimum. 1309f95f3850SWill Newton */ 1310f95f3850SWill Newton slot->clock = ios->clock; 1311f95f3850SWill Newton 1312cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 1313cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 1314800d78bfSThomas Abraham 1315f95f3850SWill Newton switch (ios->power_mode) { 1316f95f3850SWill Newton case MMC_POWER_UP: 131751da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) { 131851da2240SYuvaraj CD ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 131951da2240SYuvaraj CD ios->vdd); 132051da2240SYuvaraj CD if (ret) { 132151da2240SYuvaraj CD dev_err(slot->host->dev, 132251da2240SYuvaraj CD "failed to enable vmmc regulator\n"); 132351da2240SYuvaraj CD /*return, if failed turn on vmmc*/ 132451da2240SYuvaraj CD return; 132551da2240SYuvaraj CD } 132651da2240SYuvaraj CD } 132729d0d161SDoug Anderson set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 132829d0d161SDoug Anderson regs = mci_readl(slot->host, PWREN); 132929d0d161SDoug Anderson regs |= (1 << slot->id); 133029d0d161SDoug Anderson mci_writel(slot->host, PWREN, regs); 133129d0d161SDoug Anderson break; 133229d0d161SDoug Anderson case MMC_POWER_ON: 1333d1f1dd86SDoug Anderson if (!slot->host->vqmmc_enabled) { 1334d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 133551da2240SYuvaraj CD ret = regulator_enable(mmc->supply.vqmmc); 133651da2240SYuvaraj CD if (ret < 0) 133751da2240SYuvaraj CD dev_err(slot->host->dev, 1338d1f1dd86SDoug Anderson "failed to enable vqmmc\n"); 133951da2240SYuvaraj CD else 134051da2240SYuvaraj CD slot->host->vqmmc_enabled = true; 1341d1f1dd86SDoug Anderson 1342d1f1dd86SDoug Anderson } else { 1343d1f1dd86SDoug Anderson /* Keep track so we don't reset again */ 1344d1f1dd86SDoug Anderson slot->host->vqmmc_enabled = true; 1345d1f1dd86SDoug Anderson } 1346d1f1dd86SDoug Anderson 1347d1f1dd86SDoug Anderson /* Reset our state machine after powering on */ 1348d1f1dd86SDoug Anderson dw_mci_ctrl_reset(slot->host, 1349d1f1dd86SDoug Anderson SDMMC_CTRL_ALL_RESET_FLAGS); 135051da2240SYuvaraj CD } 1351655babbdSDoug Anderson 1352655babbdSDoug Anderson /* Adjust clock / bus width after power is up */ 1353655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1354655babbdSDoug Anderson 1355e6f34e2fSJames Hogan break; 1356e6f34e2fSJames Hogan case MMC_POWER_OFF: 1357655babbdSDoug Anderson /* Turn clock off before power goes down */ 1358655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1359655babbdSDoug Anderson 136051da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) 136151da2240SYuvaraj CD mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 136251da2240SYuvaraj CD 1363d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) 136451da2240SYuvaraj CD regulator_disable(mmc->supply.vqmmc); 136551da2240SYuvaraj CD slot->host->vqmmc_enabled = false; 136651da2240SYuvaraj CD 13674366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 13684366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 13694366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1370f95f3850SWill Newton break; 1371f95f3850SWill Newton default: 1372f95f3850SWill Newton break; 1373f95f3850SWill Newton } 1374655babbdSDoug Anderson 1375655babbdSDoug Anderson if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) 1376655babbdSDoug Anderson slot->host->state = STATE_IDLE; 1377f95f3850SWill Newton } 1378f95f3850SWill Newton 137901730558SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc) 138001730558SDoug Anderson { 138101730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 138201730558SDoug Anderson u32 status; 138301730558SDoug Anderson 138401730558SDoug Anderson /* 138501730558SDoug Anderson * Check the busy bit which is low when DAT[3:0] 138601730558SDoug Anderson * (the data lines) are 0000 138701730558SDoug Anderson */ 138801730558SDoug Anderson status = mci_readl(slot->host, STATUS); 138901730558SDoug Anderson 139001730558SDoug Anderson return !!(status & SDMMC_STATUS_BUSY); 139101730558SDoug Anderson } 139201730558SDoug Anderson 139301730558SDoug Anderson static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) 139401730558SDoug Anderson { 139501730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 139601730558SDoug Anderson struct dw_mci *host = slot->host; 13978f7849c4SZhangfei Gao const struct dw_mci_drv_data *drv_data = host->drv_data; 139801730558SDoug Anderson u32 uhs; 139901730558SDoug Anderson u32 v18 = SDMMC_UHS_18V << slot->id; 140001730558SDoug Anderson int ret; 140101730558SDoug Anderson 14028f7849c4SZhangfei Gao if (drv_data && drv_data->switch_voltage) 14038f7849c4SZhangfei Gao return drv_data->switch_voltage(mmc, ios); 14048f7849c4SZhangfei Gao 140501730558SDoug Anderson /* 140601730558SDoug Anderson * Program the voltage. Note that some instances of dw_mmc may use 140701730558SDoug Anderson * the UHS_REG for this. For other instances (like exynos) the UHS_REG 140801730558SDoug Anderson * does no harm but you need to set the regulator directly. Try both. 140901730558SDoug Anderson */ 141001730558SDoug Anderson uhs = mci_readl(host, UHS_REG); 1411e0848f5dSDouglas Anderson if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) 141201730558SDoug Anderson uhs &= ~v18; 1413e0848f5dSDouglas Anderson else 141401730558SDoug Anderson uhs |= v18; 1415e0848f5dSDouglas Anderson 141601730558SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 1417e0848f5dSDouglas Anderson ret = mmc_regulator_set_vqmmc(mmc, ios); 141801730558SDoug Anderson 141901730558SDoug Anderson if (ret) { 1420b19caf37SDoug Anderson dev_dbg(&mmc->class_dev, 1421e0848f5dSDouglas Anderson "Regulator set error %d - %s V\n", 1422e0848f5dSDouglas Anderson ret, uhs & v18 ? "1.8" : "3.3"); 142301730558SDoug Anderson return ret; 142401730558SDoug Anderson } 142501730558SDoug Anderson } 142601730558SDoug Anderson mci_writel(host, UHS_REG, uhs); 142701730558SDoug Anderson 142801730558SDoug Anderson return 0; 142901730558SDoug Anderson } 143001730558SDoug Anderson 1431f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 1432f95f3850SWill Newton { 1433f95f3850SWill Newton int read_only; 1434f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 14359795a846SJaehoon Chung int gpio_ro = mmc_gpio_get_ro(mmc); 1436f95f3850SWill Newton 1437f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 1438eff8f2f5SLars-Peter Clausen if (!IS_ERR_VALUE(gpio_ro)) 14399795a846SJaehoon Chung read_only = gpio_ro; 1440f95f3850SWill Newton else 1441f95f3850SWill Newton read_only = 1442f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1443f95f3850SWill Newton 1444f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1445f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1446f95f3850SWill Newton 1447f95f3850SWill Newton return read_only; 1448f95f3850SWill Newton } 1449f95f3850SWill Newton 1450f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1451f95f3850SWill Newton { 1452f95f3850SWill Newton int present; 1453f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1454f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 14557cf347bdSZhangfei Gao struct dw_mci *host = slot->host; 14567cf347bdSZhangfei Gao int gpio_cd = mmc_gpio_get_cd(mmc); 1457f95f3850SWill Newton 1458f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 14594de3bf66SZhangfei Gao if ((brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) || 14604de3bf66SZhangfei Gao (mmc->caps & MMC_CAP_NONREMOVABLE)) 1461fc3d7720SJaehoon Chung present = 1; 1462bf626e55SZhangfei Gao else if (!IS_ERR_VALUE(gpio_cd)) 14637cf347bdSZhangfei Gao present = gpio_cd; 1464f95f3850SWill Newton else 1465f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1466f95f3850SWill Newton == 0 ? 1 : 0; 1467f95f3850SWill Newton 14687cf347bdSZhangfei Gao spin_lock_bh(&host->lock); 1469bf626e55SZhangfei Gao if (present) { 1470bf626e55SZhangfei Gao set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1471f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 1472bf626e55SZhangfei Gao } else { 1473bf626e55SZhangfei Gao clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1474f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 1475bf626e55SZhangfei Gao } 14767cf347bdSZhangfei Gao spin_unlock_bh(&host->lock); 1477f95f3850SWill Newton 1478f95f3850SWill Newton return present; 1479f95f3850SWill Newton } 1480f95f3850SWill Newton 1481b24c8b26SDoug Anderson static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) 1482b24c8b26SDoug Anderson { 1483b24c8b26SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 1484b24c8b26SDoug Anderson struct dw_mci *host = slot->host; 1485b24c8b26SDoug Anderson 14869623b5b9SDoug Anderson /* 14879623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 14889623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 14899623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 14909623b5b9SDoug Anderson */ 1491b24c8b26SDoug Anderson if (mmc->caps & MMC_CAP_SDIO_IRQ) { 14929623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 1493b24c8b26SDoug Anderson u32 clk_en_a_old; 1494b24c8b26SDoug Anderson u32 clk_en_a; 14959623b5b9SDoug Anderson 1496b24c8b26SDoug Anderson clk_en_a_old = mci_readl(host, CLKENA); 14979623b5b9SDoug Anderson 1498b24c8b26SDoug Anderson if (card->type == MMC_TYPE_SDIO || 1499b24c8b26SDoug Anderson card->type == MMC_TYPE_SD_COMBO) { 1500b24c8b26SDoug Anderson set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1501b24c8b26SDoug Anderson clk_en_a = clk_en_a_old & ~clken_low_pwr; 1502b24c8b26SDoug Anderson } else { 1503b24c8b26SDoug Anderson clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1504b24c8b26SDoug Anderson clk_en_a = clk_en_a_old | clken_low_pwr; 1505b24c8b26SDoug Anderson } 1506b24c8b26SDoug Anderson 1507b24c8b26SDoug Anderson if (clk_en_a != clk_en_a_old) { 1508b24c8b26SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 15099623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 15109623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 15119623b5b9SDoug Anderson } 15129623b5b9SDoug Anderson } 1513b24c8b26SDoug Anderson } 15149623b5b9SDoug Anderson 15151a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 15161a5c8e1fSShashidhar Hiremath { 15171a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 15181a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 1519f8c58c11SDoug Anderson unsigned long irqflags; 15201a5c8e1fSShashidhar Hiremath u32 int_mask; 15211a5c8e1fSShashidhar Hiremath 1522f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1523f8c58c11SDoug Anderson 15241a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 15251a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 1526b24c8b26SDoug Anderson if (enb) 1527b24c8b26SDoug Anderson int_mask |= SDMMC_INT_SDIO(slot->sdio_id); 1528b24c8b26SDoug Anderson else 1529b24c8b26SDoug Anderson int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id); 1530b24c8b26SDoug Anderson mci_writel(host, INTMASK, int_mask); 1531f8c58c11SDoug Anderson 1532f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 15331a5c8e1fSShashidhar Hiremath } 15341a5c8e1fSShashidhar Hiremath 15350976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 15360976f16dSSeungwon Jeon { 15370976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 15380976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 15390976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 15400e3a22c0SShawn Lin int err = -EINVAL; 15410976f16dSSeungwon Jeon 15420976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 15436c2c6506SUlf Hansson err = drv_data->execute_tuning(slot); 15440976f16dSSeungwon Jeon return err; 15450976f16dSSeungwon Jeon } 15460976f16dSSeungwon Jeon 15470e3a22c0SShawn Lin static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, 15480e3a22c0SShawn Lin struct mmc_ios *ios) 154980113132SSeungwon Jeon { 155080113132SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 155180113132SSeungwon Jeon struct dw_mci *host = slot->host; 155280113132SSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 155380113132SSeungwon Jeon 155480113132SSeungwon Jeon if (drv_data && drv_data->prepare_hs400_tuning) 155580113132SSeungwon Jeon return drv_data->prepare_hs400_tuning(host, ios); 155680113132SSeungwon Jeon 155780113132SSeungwon Jeon return 0; 155880113132SSeungwon Jeon } 155980113132SSeungwon Jeon 1560f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1561f95f3850SWill Newton .request = dw_mci_request, 15629aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 15639aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1564f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1565f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1566f95f3850SWill Newton .get_cd = dw_mci_get_cd, 15671a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 15680976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 156901730558SDoug Anderson .card_busy = dw_mci_card_busy, 157001730558SDoug Anderson .start_signal_voltage_switch = dw_mci_switch_voltage, 1571b24c8b26SDoug Anderson .init_card = dw_mci_init_card, 157280113132SSeungwon Jeon .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, 1573f95f3850SWill Newton }; 1574f95f3850SWill Newton 1575f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1576f95f3850SWill Newton __releases(&host->lock) 1577f95f3850SWill Newton __acquires(&host->lock) 1578f95f3850SWill Newton { 1579f95f3850SWill Newton struct dw_mci_slot *slot; 1580f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1581f95f3850SWill Newton 1582f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1583f95f3850SWill Newton 1584f95f3850SWill Newton host->cur_slot->mrq = NULL; 1585f95f3850SWill Newton host->mrq = NULL; 1586f95f3850SWill Newton if (!list_empty(&host->queue)) { 1587f95f3850SWill Newton slot = list_entry(host->queue.next, 1588f95f3850SWill Newton struct dw_mci_slot, queue_node); 1589f95f3850SWill Newton list_del(&slot->queue_node); 15904a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1591f95f3850SWill Newton mmc_hostname(slot->mmc)); 1592f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1593f95f3850SWill Newton dw_mci_start_request(host, slot); 1594f95f3850SWill Newton } else { 15954a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 159601730558SDoug Anderson 159701730558SDoug Anderson if (host->state == STATE_SENDING_CMD11) 159801730558SDoug Anderson host->state = STATE_WAITING_CMD11_DONE; 159901730558SDoug Anderson else 1600f95f3850SWill Newton host->state = STATE_IDLE; 1601f95f3850SWill Newton } 1602f95f3850SWill Newton 1603f95f3850SWill Newton spin_unlock(&host->lock); 1604f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1605f95f3850SWill Newton spin_lock(&host->lock); 1606f95f3850SWill Newton } 1607f95f3850SWill Newton 1608e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1609f95f3850SWill Newton { 1610f95f3850SWill Newton u32 status = host->cmd_status; 1611f95f3850SWill Newton 1612f95f3850SWill Newton host->cmd_status = 0; 1613f95f3850SWill Newton 1614f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1615f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1616f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1617f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1618f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1619f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1620f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1621f95f3850SWill Newton } else { 1622f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1623f95f3850SWill Newton cmd->resp[1] = 0; 1624f95f3850SWill Newton cmd->resp[2] = 0; 1625f95f3850SWill Newton cmd->resp[3] = 0; 1626f95f3850SWill Newton } 1627f95f3850SWill Newton } 1628f95f3850SWill Newton 1629f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1630f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1631f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1632f95f3850SWill Newton cmd->error = -EILSEQ; 1633f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1634f95f3850SWill Newton cmd->error = -EIO; 1635f95f3850SWill Newton else 1636f95f3850SWill Newton cmd->error = 0; 1637f95f3850SWill Newton 1638f95f3850SWill Newton if (cmd->error) { 1639f95f3850SWill Newton /* newer ip versions need a delay between retries */ 1640f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) 1641f95f3850SWill Newton mdelay(20); 1642f95f3850SWill Newton } 1643e352c813SSeungwon Jeon 1644e352c813SSeungwon Jeon return cmd->error; 1645e352c813SSeungwon Jeon } 1646e352c813SSeungwon Jeon 1647e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) 1648e352c813SSeungwon Jeon { 164931bff450SSeungwon Jeon u32 status = host->data_status; 1650e352c813SSeungwon Jeon 1651e352c813SSeungwon Jeon if (status & DW_MCI_DATA_ERROR_FLAGS) { 1652e352c813SSeungwon Jeon if (status & SDMMC_INT_DRTO) { 1653e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1654e352c813SSeungwon Jeon } else if (status & SDMMC_INT_DCRC) { 1655e352c813SSeungwon Jeon data->error = -EILSEQ; 1656e352c813SSeungwon Jeon } else if (status & SDMMC_INT_EBE) { 1657e352c813SSeungwon Jeon if (host->dir_status == 1658e352c813SSeungwon Jeon DW_MCI_SEND_STATUS) { 1659e352c813SSeungwon Jeon /* 1660e352c813SSeungwon Jeon * No data CRC status was returned. 1661e352c813SSeungwon Jeon * The number of bytes transferred 1662e352c813SSeungwon Jeon * will be exaggerated in PIO mode. 1663e352c813SSeungwon Jeon */ 1664e352c813SSeungwon Jeon data->bytes_xfered = 0; 1665e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1666e352c813SSeungwon Jeon } else if (host->dir_status == 1667e352c813SSeungwon Jeon DW_MCI_RECV_STATUS) { 1668e352c813SSeungwon Jeon data->error = -EIO; 1669e352c813SSeungwon Jeon } 1670e352c813SSeungwon Jeon } else { 1671e352c813SSeungwon Jeon /* SDMMC_INT_SBE is included */ 1672e352c813SSeungwon Jeon data->error = -EIO; 1673e352c813SSeungwon Jeon } 1674e352c813SSeungwon Jeon 1675e6cc0123SDoug Anderson dev_dbg(host->dev, "data error, status 0x%08x\n", status); 1676e352c813SSeungwon Jeon 1677e352c813SSeungwon Jeon /* 1678e352c813SSeungwon Jeon * After an error, there may be data lingering 167931bff450SSeungwon Jeon * in the FIFO 1680e352c813SSeungwon Jeon */ 16813a33a94cSSonny Rao dw_mci_reset(host); 1682e352c813SSeungwon Jeon } else { 1683e352c813SSeungwon Jeon data->bytes_xfered = data->blocks * data->blksz; 1684e352c813SSeungwon Jeon data->error = 0; 1685e352c813SSeungwon Jeon } 1686e352c813SSeungwon Jeon 1687e352c813SSeungwon Jeon return data->error; 1688f95f3850SWill Newton } 1689f95f3850SWill Newton 169057e10486SAddy Ke static void dw_mci_set_drto(struct dw_mci *host) 169157e10486SAddy Ke { 169257e10486SAddy Ke unsigned int drto_clks; 169357e10486SAddy Ke unsigned int drto_ms; 169457e10486SAddy Ke 169557e10486SAddy Ke drto_clks = mci_readl(host, TMOUT) >> 8; 169657e10486SAddy Ke drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000); 169757e10486SAddy Ke 169857e10486SAddy Ke /* add a bit spare time */ 169957e10486SAddy Ke drto_ms += 10; 170057e10486SAddy Ke 170157e10486SAddy Ke mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms)); 170257e10486SAddy Ke } 170357e10486SAddy Ke 1704f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1705f95f3850SWill Newton { 1706f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1707f95f3850SWill Newton struct mmc_data *data; 1708f95f3850SWill Newton struct mmc_command *cmd; 1709e352c813SSeungwon Jeon struct mmc_request *mrq; 1710f95f3850SWill Newton enum dw_mci_state state; 1711f95f3850SWill Newton enum dw_mci_state prev_state; 1712e352c813SSeungwon Jeon unsigned int err; 1713f95f3850SWill Newton 1714f95f3850SWill Newton spin_lock(&host->lock); 1715f95f3850SWill Newton 1716f95f3850SWill Newton state = host->state; 1717f95f3850SWill Newton data = host->data; 1718e352c813SSeungwon Jeon mrq = host->mrq; 1719f95f3850SWill Newton 1720f95f3850SWill Newton do { 1721f95f3850SWill Newton prev_state = state; 1722f95f3850SWill Newton 1723f95f3850SWill Newton switch (state) { 1724f95f3850SWill Newton case STATE_IDLE: 172501730558SDoug Anderson case STATE_WAITING_CMD11_DONE: 1726f95f3850SWill Newton break; 1727f95f3850SWill Newton 172801730558SDoug Anderson case STATE_SENDING_CMD11: 1729f95f3850SWill Newton case STATE_SENDING_CMD: 1730f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1731f95f3850SWill Newton &host->pending_events)) 1732f95f3850SWill Newton break; 1733f95f3850SWill Newton 1734f95f3850SWill Newton cmd = host->cmd; 1735f95f3850SWill Newton host->cmd = NULL; 1736f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1737e352c813SSeungwon Jeon err = dw_mci_command_complete(host, cmd); 1738e352c813SSeungwon Jeon if (cmd == mrq->sbc && !err) { 1739053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1740053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1741e352c813SSeungwon Jeon mrq->cmd); 1742053b3ce6SSeungwon Jeon goto unlock; 1743053b3ce6SSeungwon Jeon } 1744053b3ce6SSeungwon Jeon 1745e352c813SSeungwon Jeon if (cmd->data && err) { 174671abb133SSeungwon Jeon dw_mci_stop_dma(host); 174790c2143aSSeungwon Jeon send_stop_abort(host, data); 174871abb133SSeungwon Jeon state = STATE_SENDING_STOP; 174971abb133SSeungwon Jeon break; 175071abb133SSeungwon Jeon } 175171abb133SSeungwon Jeon 1752e352c813SSeungwon Jeon if (!cmd->data || err) { 1753e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1754f95f3850SWill Newton goto unlock; 1755f95f3850SWill Newton } 1756f95f3850SWill Newton 1757f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1758f95f3850SWill Newton /* fall through */ 1759f95f3850SWill Newton 1760f95f3850SWill Newton case STATE_SENDING_DATA: 17612aa35465SDoug Anderson /* 17622aa35465SDoug Anderson * We could get a data error and never a transfer 17632aa35465SDoug Anderson * complete so we'd better check for it here. 17642aa35465SDoug Anderson * 17652aa35465SDoug Anderson * Note that we don't really care if we also got a 17662aa35465SDoug Anderson * transfer complete; stopping the DMA and sending an 17672aa35465SDoug Anderson * abort won't hurt. 17682aa35465SDoug Anderson */ 1769f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1770f95f3850SWill Newton &host->pending_events)) { 1771f95f3850SWill Newton dw_mci_stop_dma(host); 1772bdb9a90bSaddy ke if (data->stop || 1773bdb9a90bSaddy ke !(host->data_status & (SDMMC_INT_DRTO | 1774bdb9a90bSaddy ke SDMMC_INT_EBE))) 177590c2143aSSeungwon Jeon send_stop_abort(host, data); 1776f95f3850SWill Newton state = STATE_DATA_ERROR; 1777f95f3850SWill Newton break; 1778f95f3850SWill Newton } 1779f95f3850SWill Newton 1780f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 178157e10486SAddy Ke &host->pending_events)) { 178257e10486SAddy Ke /* 178357e10486SAddy Ke * If all data-related interrupts don't come 178457e10486SAddy Ke * within the given time in reading data state. 178557e10486SAddy Ke */ 178657e10486SAddy Ke if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && 178757e10486SAddy Ke (host->dir_status == DW_MCI_RECV_STATUS)) 178857e10486SAddy Ke dw_mci_set_drto(host); 1789f95f3850SWill Newton break; 179057e10486SAddy Ke } 1791f95f3850SWill Newton 1792f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 17932aa35465SDoug Anderson 17942aa35465SDoug Anderson /* 17952aa35465SDoug Anderson * Handle an EVENT_DATA_ERROR that might have shown up 17962aa35465SDoug Anderson * before the transfer completed. This might not have 17972aa35465SDoug Anderson * been caught by the check above because the interrupt 17982aa35465SDoug Anderson * could have gone off between the previous check and 17992aa35465SDoug Anderson * the check for transfer complete. 18002aa35465SDoug Anderson * 18012aa35465SDoug Anderson * Technically this ought not be needed assuming we 18022aa35465SDoug Anderson * get a DATA_COMPLETE eventually (we'll notice the 18032aa35465SDoug Anderson * error and end the request), but it shouldn't hurt. 18042aa35465SDoug Anderson * 18052aa35465SDoug Anderson * This has the advantage of sending the stop command. 18062aa35465SDoug Anderson */ 18072aa35465SDoug Anderson if (test_and_clear_bit(EVENT_DATA_ERROR, 18082aa35465SDoug Anderson &host->pending_events)) { 18092aa35465SDoug Anderson dw_mci_stop_dma(host); 1810bdb9a90bSaddy ke if (data->stop || 1811bdb9a90bSaddy ke !(host->data_status & (SDMMC_INT_DRTO | 1812bdb9a90bSaddy ke SDMMC_INT_EBE))) 18132aa35465SDoug Anderson send_stop_abort(host, data); 18142aa35465SDoug Anderson state = STATE_DATA_ERROR; 18152aa35465SDoug Anderson break; 18162aa35465SDoug Anderson } 1817f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 18182aa35465SDoug Anderson 1819f95f3850SWill Newton /* fall through */ 1820f95f3850SWill Newton 1821f95f3850SWill Newton case STATE_DATA_BUSY: 1822f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 182357e10486SAddy Ke &host->pending_events)) { 182457e10486SAddy Ke /* 182557e10486SAddy Ke * If data error interrupt comes but data over 182657e10486SAddy Ke * interrupt doesn't come within the given time. 182757e10486SAddy Ke * in reading data state. 182857e10486SAddy Ke */ 182957e10486SAddy Ke if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && 183057e10486SAddy Ke (host->dir_status == DW_MCI_RECV_STATUS)) 183157e10486SAddy Ke dw_mci_set_drto(host); 1832f95f3850SWill Newton break; 183357e10486SAddy Ke } 1834f95f3850SWill Newton 1835f95f3850SWill Newton host->data = NULL; 1836f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 1837e352c813SSeungwon Jeon err = dw_mci_data_complete(host, data); 1838f95f3850SWill Newton 1839e352c813SSeungwon Jeon if (!err) { 1840e352c813SSeungwon Jeon if (!data->stop || mrq->sbc) { 184117c8bc85SSachin Kamat if (mrq->sbc && data->stop) 1842053b3ce6SSeungwon Jeon data->stop->error = 0; 1843e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1844053b3ce6SSeungwon Jeon goto unlock; 1845053b3ce6SSeungwon Jeon } 1846053b3ce6SSeungwon Jeon 184790c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 1848e352c813SSeungwon Jeon if (data->stop) 184990c2143aSSeungwon Jeon send_stop_abort(host, data); 18502aa35465SDoug Anderson } else { 18512aa35465SDoug Anderson /* 18522aa35465SDoug Anderson * If we don't have a command complete now we'll 18532aa35465SDoug Anderson * never get one since we just reset everything; 18542aa35465SDoug Anderson * better end the request. 18552aa35465SDoug Anderson * 18562aa35465SDoug Anderson * If we do have a command complete we'll fall 18572aa35465SDoug Anderson * through to the SENDING_STOP command and 18582aa35465SDoug Anderson * everything will be peachy keen. 18592aa35465SDoug Anderson */ 18602aa35465SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, 18612aa35465SDoug Anderson &host->pending_events)) { 18622aa35465SDoug Anderson host->cmd = NULL; 18632aa35465SDoug Anderson dw_mci_request_end(host, mrq); 18642aa35465SDoug Anderson goto unlock; 18652aa35465SDoug Anderson } 186690c2143aSSeungwon Jeon } 1867e352c813SSeungwon Jeon 1868e352c813SSeungwon Jeon /* 1869e352c813SSeungwon Jeon * If err has non-zero, 1870e352c813SSeungwon Jeon * stop-abort command has been already issued. 1871e352c813SSeungwon Jeon */ 1872e352c813SSeungwon Jeon prev_state = state = STATE_SENDING_STOP; 1873e352c813SSeungwon Jeon 1874f95f3850SWill Newton /* fall through */ 1875f95f3850SWill Newton 1876f95f3850SWill Newton case STATE_SENDING_STOP: 1877f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1878f95f3850SWill Newton &host->pending_events)) 1879f95f3850SWill Newton break; 1880f95f3850SWill Newton 188171abb133SSeungwon Jeon /* CMD error in data command */ 188231bff450SSeungwon Jeon if (mrq->cmd->error && mrq->data) 18833a33a94cSSonny Rao dw_mci_reset(host); 188471abb133SSeungwon Jeon 1885f95f3850SWill Newton host->cmd = NULL; 188671abb133SSeungwon Jeon host->data = NULL; 188790c2143aSSeungwon Jeon 1888e352c813SSeungwon Jeon if (mrq->stop) 1889e352c813SSeungwon Jeon dw_mci_command_complete(host, mrq->stop); 189090c2143aSSeungwon Jeon else 189190c2143aSSeungwon Jeon host->cmd_status = 0; 189290c2143aSSeungwon Jeon 1893e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1894f95f3850SWill Newton goto unlock; 1895f95f3850SWill Newton 1896f95f3850SWill Newton case STATE_DATA_ERROR: 1897f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1898f95f3850SWill Newton &host->pending_events)) 1899f95f3850SWill Newton break; 1900f95f3850SWill Newton 1901f95f3850SWill Newton state = STATE_DATA_BUSY; 1902f95f3850SWill Newton break; 1903f95f3850SWill Newton } 1904f95f3850SWill Newton } while (state != prev_state); 1905f95f3850SWill Newton 1906f95f3850SWill Newton host->state = state; 1907f95f3850SWill Newton unlock: 1908f95f3850SWill Newton spin_unlock(&host->lock); 1909f95f3850SWill Newton 1910f95f3850SWill Newton } 1911f95f3850SWill Newton 191234b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 191334b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 191434b664a2SJames Hogan { 191534b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 191634b664a2SJames Hogan host->part_buf_count = cnt; 191734b664a2SJames Hogan } 191834b664a2SJames Hogan 191934b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 192034b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 192134b664a2SJames Hogan { 192234b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 192334b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 192434b664a2SJames Hogan host->part_buf_count += cnt; 192534b664a2SJames Hogan return cnt; 192634b664a2SJames Hogan } 192734b664a2SJames Hogan 192834b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 192934b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 193034b664a2SJames Hogan { 19310e3a22c0SShawn Lin cnt = min_t(int, cnt, host->part_buf_count); 193234b664a2SJames Hogan if (cnt) { 193334b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 193434b664a2SJames Hogan cnt); 193534b664a2SJames Hogan host->part_buf_count -= cnt; 193634b664a2SJames Hogan host->part_buf_start += cnt; 193734b664a2SJames Hogan } 193834b664a2SJames Hogan return cnt; 193934b664a2SJames Hogan } 194034b664a2SJames Hogan 194134b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 194234b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 194334b664a2SJames Hogan { 194434b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 194534b664a2SJames Hogan host->part_buf_start = cnt; 194634b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 194734b664a2SJames Hogan } 194834b664a2SJames Hogan 1949f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 1950f95f3850SWill Newton { 1951cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1952cfbeb59cSMarkos Chandras int init_cnt = cnt; 1953cfbeb59cSMarkos Chandras 195434b664a2SJames Hogan /* try and push anything in the part_buf */ 195534b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 195634b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 19570e3a22c0SShawn Lin 195834b664a2SJames Hogan buf += len; 195934b664a2SJames Hogan cnt -= len; 1960cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 196176184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 196234b664a2SJames Hogan host->part_buf_count = 0; 196334b664a2SJames Hogan } 196434b664a2SJames Hogan } 196534b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 196634b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 196734b664a2SJames Hogan while (cnt >= 2) { 196834b664a2SJames Hogan u16 aligned_buf[64]; 196934b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 197034b664a2SJames Hogan int items = len >> 1; 197134b664a2SJames Hogan int i; 197234b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 197334b664a2SJames Hogan memcpy(aligned_buf, buf, len); 197434b664a2SJames Hogan buf += len; 197534b664a2SJames Hogan cnt -= len; 197634b664a2SJames Hogan /* push data from aligned buffer into fifo */ 197734b664a2SJames Hogan for (i = 0; i < items; ++i) 197876184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, aligned_buf[i]); 197934b664a2SJames Hogan } 198034b664a2SJames Hogan } else 198134b664a2SJames Hogan #endif 198234b664a2SJames Hogan { 198334b664a2SJames Hogan u16 *pdata = buf; 19840e3a22c0SShawn Lin 198534b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 198676184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, *pdata++); 198734b664a2SJames Hogan buf = pdata; 198834b664a2SJames Hogan } 198934b664a2SJames Hogan /* put anything remaining in the part_buf */ 199034b664a2SJames Hogan if (cnt) { 199134b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1992cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1993cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1994cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 199576184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 1996f95f3850SWill Newton } 1997f95f3850SWill Newton } 1998f95f3850SWill Newton 1999f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 2000f95f3850SWill Newton { 200134b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 200234b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 200334b664a2SJames Hogan while (cnt >= 2) { 200434b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 200534b664a2SJames Hogan u16 aligned_buf[64]; 200634b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 200734b664a2SJames Hogan int items = len >> 1; 200834b664a2SJames Hogan int i; 20090e3a22c0SShawn Lin 201034b664a2SJames Hogan for (i = 0; i < items; ++i) 201176184ac1SBen Dooks aligned_buf[i] = mci_fifo_readw(host->fifo_reg); 201234b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 201334b664a2SJames Hogan memcpy(buf, aligned_buf, len); 201434b664a2SJames Hogan buf += len; 201534b664a2SJames Hogan cnt -= len; 201634b664a2SJames Hogan } 201734b664a2SJames Hogan } else 201834b664a2SJames Hogan #endif 201934b664a2SJames Hogan { 202034b664a2SJames Hogan u16 *pdata = buf; 20210e3a22c0SShawn Lin 202234b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 202376184ac1SBen Dooks *pdata++ = mci_fifo_readw(host->fifo_reg); 202434b664a2SJames Hogan buf = pdata; 202534b664a2SJames Hogan } 202634b664a2SJames Hogan if (cnt) { 202776184ac1SBen Dooks host->part_buf16 = mci_fifo_readw(host->fifo_reg); 202834b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 2029f95f3850SWill Newton } 2030f95f3850SWill Newton } 2031f95f3850SWill Newton 2032f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 2033f95f3850SWill Newton { 2034cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2035cfbeb59cSMarkos Chandras int init_cnt = cnt; 2036cfbeb59cSMarkos Chandras 203734b664a2SJames Hogan /* try and push anything in the part_buf */ 203834b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 203934b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 20400e3a22c0SShawn Lin 204134b664a2SJames Hogan buf += len; 204234b664a2SJames Hogan cnt -= len; 2043cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 204476184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 204534b664a2SJames Hogan host->part_buf_count = 0; 204634b664a2SJames Hogan } 204734b664a2SJames Hogan } 204834b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 204934b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 205034b664a2SJames Hogan while (cnt >= 4) { 205134b664a2SJames Hogan u32 aligned_buf[32]; 205234b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 205334b664a2SJames Hogan int items = len >> 2; 205434b664a2SJames Hogan int i; 205534b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 205634b664a2SJames Hogan memcpy(aligned_buf, buf, len); 205734b664a2SJames Hogan buf += len; 205834b664a2SJames Hogan cnt -= len; 205934b664a2SJames Hogan /* push data from aligned buffer into fifo */ 206034b664a2SJames Hogan for (i = 0; i < items; ++i) 206176184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, aligned_buf[i]); 206234b664a2SJames Hogan } 206334b664a2SJames Hogan } else 206434b664a2SJames Hogan #endif 206534b664a2SJames Hogan { 206634b664a2SJames Hogan u32 *pdata = buf; 20670e3a22c0SShawn Lin 206834b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 206976184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, *pdata++); 207034b664a2SJames Hogan buf = pdata; 207134b664a2SJames Hogan } 207234b664a2SJames Hogan /* put anything remaining in the part_buf */ 207334b664a2SJames Hogan if (cnt) { 207434b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2075cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2076cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2077cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 207876184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 2079f95f3850SWill Newton } 2080f95f3850SWill Newton } 2081f95f3850SWill Newton 2082f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 2083f95f3850SWill Newton { 208434b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 208534b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 208634b664a2SJames Hogan while (cnt >= 4) { 208734b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 208834b664a2SJames Hogan u32 aligned_buf[32]; 208934b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 209034b664a2SJames Hogan int items = len >> 2; 209134b664a2SJames Hogan int i; 20920e3a22c0SShawn Lin 209334b664a2SJames Hogan for (i = 0; i < items; ++i) 209476184ac1SBen Dooks aligned_buf[i] = mci_fifo_readl(host->fifo_reg); 209534b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 209634b664a2SJames Hogan memcpy(buf, aligned_buf, len); 209734b664a2SJames Hogan buf += len; 209834b664a2SJames Hogan cnt -= len; 209934b664a2SJames Hogan } 210034b664a2SJames Hogan } else 210134b664a2SJames Hogan #endif 210234b664a2SJames Hogan { 210334b664a2SJames Hogan u32 *pdata = buf; 21040e3a22c0SShawn Lin 210534b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 210676184ac1SBen Dooks *pdata++ = mci_fifo_readl(host->fifo_reg); 210734b664a2SJames Hogan buf = pdata; 210834b664a2SJames Hogan } 210934b664a2SJames Hogan if (cnt) { 211076184ac1SBen Dooks host->part_buf32 = mci_fifo_readl(host->fifo_reg); 211134b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 2112f95f3850SWill Newton } 2113f95f3850SWill Newton } 2114f95f3850SWill Newton 2115f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 2116f95f3850SWill Newton { 2117cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2118cfbeb59cSMarkos Chandras int init_cnt = cnt; 2119cfbeb59cSMarkos Chandras 212034b664a2SJames Hogan /* try and push anything in the part_buf */ 212134b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 212234b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 21230e3a22c0SShawn Lin 212434b664a2SJames Hogan buf += len; 212534b664a2SJames Hogan cnt -= len; 2126c09fbd74SSeungwon Jeon 2127cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 212876184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 212934b664a2SJames Hogan host->part_buf_count = 0; 213034b664a2SJames Hogan } 213134b664a2SJames Hogan } 213234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 213334b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 213434b664a2SJames Hogan while (cnt >= 8) { 213534b664a2SJames Hogan u64 aligned_buf[16]; 213634b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 213734b664a2SJames Hogan int items = len >> 3; 213834b664a2SJames Hogan int i; 213934b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 214034b664a2SJames Hogan memcpy(aligned_buf, buf, len); 214134b664a2SJames Hogan buf += len; 214234b664a2SJames Hogan cnt -= len; 214334b664a2SJames Hogan /* push data from aligned buffer into fifo */ 214434b664a2SJames Hogan for (i = 0; i < items; ++i) 214576184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, aligned_buf[i]); 214634b664a2SJames Hogan } 214734b664a2SJames Hogan } else 214834b664a2SJames Hogan #endif 214934b664a2SJames Hogan { 215034b664a2SJames Hogan u64 *pdata = buf; 21510e3a22c0SShawn Lin 215234b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 215376184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, *pdata++); 215434b664a2SJames Hogan buf = pdata; 215534b664a2SJames Hogan } 215634b664a2SJames Hogan /* put anything remaining in the part_buf */ 215734b664a2SJames Hogan if (cnt) { 215834b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2159cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2160cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2161cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 216276184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 2163f95f3850SWill Newton } 2164f95f3850SWill Newton } 2165f95f3850SWill Newton 2166f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 2167f95f3850SWill Newton { 216834b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 216934b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 217034b664a2SJames Hogan while (cnt >= 8) { 217134b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 217234b664a2SJames Hogan u64 aligned_buf[16]; 217334b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 217434b664a2SJames Hogan int items = len >> 3; 217534b664a2SJames Hogan int i; 21760e3a22c0SShawn Lin 217734b664a2SJames Hogan for (i = 0; i < items; ++i) 217876184ac1SBen Dooks aligned_buf[i] = mci_fifo_readq(host->fifo_reg); 217976184ac1SBen Dooks 218034b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 218134b664a2SJames Hogan memcpy(buf, aligned_buf, len); 218234b664a2SJames Hogan buf += len; 218334b664a2SJames Hogan cnt -= len; 2184f95f3850SWill Newton } 218534b664a2SJames Hogan } else 218634b664a2SJames Hogan #endif 218734b664a2SJames Hogan { 218834b664a2SJames Hogan u64 *pdata = buf; 21890e3a22c0SShawn Lin 219034b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 219176184ac1SBen Dooks *pdata++ = mci_fifo_readq(host->fifo_reg); 219234b664a2SJames Hogan buf = pdata; 219334b664a2SJames Hogan } 219434b664a2SJames Hogan if (cnt) { 219576184ac1SBen Dooks host->part_buf = mci_fifo_readq(host->fifo_reg); 219634b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 219734b664a2SJames Hogan } 219834b664a2SJames Hogan } 219934b664a2SJames Hogan 220034b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 220134b664a2SJames Hogan { 220234b664a2SJames Hogan int len; 220334b664a2SJames Hogan 220434b664a2SJames Hogan /* get remaining partial bytes */ 220534b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 220634b664a2SJames Hogan if (unlikely(len == cnt)) 220734b664a2SJames Hogan return; 220834b664a2SJames Hogan buf += len; 220934b664a2SJames Hogan cnt -= len; 221034b664a2SJames Hogan 221134b664a2SJames Hogan /* get the rest of the data */ 221234b664a2SJames Hogan host->pull_data(host, buf, cnt); 2213f95f3850SWill Newton } 2214f95f3850SWill Newton 221587a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 2216f95f3850SWill Newton { 2217f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2218f9c2a0dcSSeungwon Jeon void *buf; 2219f9c2a0dcSSeungwon Jeon unsigned int offset; 2220f95f3850SWill Newton struct mmc_data *data = host->data; 2221f95f3850SWill Newton int shift = host->data_shift; 2222f95f3850SWill Newton u32 status; 22233e4b0d8bSMarkos Chandras unsigned int len; 2224f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2225f95f3850SWill Newton 2226f95f3850SWill Newton do { 2227f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2228f9c2a0dcSSeungwon Jeon goto done; 2229f95f3850SWill Newton 22304225fc85SImre Deak host->sg = sg_miter->piter.sg; 2231f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2232f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2233f9c2a0dcSSeungwon Jeon offset = 0; 2234f9c2a0dcSSeungwon Jeon 2235f9c2a0dcSSeungwon Jeon do { 2236f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 2237f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 2238f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2239f9c2a0dcSSeungwon Jeon if (!len) 2240f9c2a0dcSSeungwon Jeon break; 2241f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 22423e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2243f95f3850SWill Newton offset += len; 2244f9c2a0dcSSeungwon Jeon remain -= len; 2245f9c2a0dcSSeungwon Jeon } while (remain); 2246f95f3850SWill Newton 2247e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2248f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2249f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 225087a74d39SKyoungil Kim /* if the RXDR is ready read again */ 225187a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 225287a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 2253f9c2a0dcSSeungwon Jeon 2254f9c2a0dcSSeungwon Jeon if (!remain) { 2255f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2256f9c2a0dcSSeungwon Jeon goto done; 2257f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2258f9c2a0dcSSeungwon Jeon } 2259f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2260f95f3850SWill Newton return; 2261f95f3850SWill Newton 2262f95f3850SWill Newton done: 2263f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2264f9c2a0dcSSeungwon Jeon host->sg = NULL; 22650e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2266f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2267f95f3850SWill Newton } 2268f95f3850SWill Newton 2269f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 2270f95f3850SWill Newton { 2271f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2272f9c2a0dcSSeungwon Jeon void *buf; 2273f9c2a0dcSSeungwon Jeon unsigned int offset; 2274f95f3850SWill Newton struct mmc_data *data = host->data; 2275f95f3850SWill Newton int shift = host->data_shift; 2276f95f3850SWill Newton u32 status; 22773e4b0d8bSMarkos Chandras unsigned int len; 2278f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 2279f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2280f95f3850SWill Newton 2281f95f3850SWill Newton do { 2282f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2283f9c2a0dcSSeungwon Jeon goto done; 2284f95f3850SWill Newton 22854225fc85SImre Deak host->sg = sg_miter->piter.sg; 2286f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2287f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2288f9c2a0dcSSeungwon Jeon offset = 0; 2289f9c2a0dcSSeungwon Jeon 2290f9c2a0dcSSeungwon Jeon do { 2291f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 2292f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 2293f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 2294f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2295f9c2a0dcSSeungwon Jeon if (!len) 2296f9c2a0dcSSeungwon Jeon break; 2297f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 22983e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2299f95f3850SWill Newton offset += len; 2300f9c2a0dcSSeungwon Jeon remain -= len; 2301f9c2a0dcSSeungwon Jeon } while (remain); 2302f95f3850SWill Newton 2303e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2304f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2305f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2306f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 2307f9c2a0dcSSeungwon Jeon 2308f9c2a0dcSSeungwon Jeon if (!remain) { 2309f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2310f9c2a0dcSSeungwon Jeon goto done; 2311f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2312f9c2a0dcSSeungwon Jeon } 2313f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2314f95f3850SWill Newton return; 2315f95f3850SWill Newton 2316f95f3850SWill Newton done: 2317f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2318f9c2a0dcSSeungwon Jeon host->sg = NULL; 23190e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2320f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2321f95f3850SWill Newton } 2322f95f3850SWill Newton 2323f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 2324f95f3850SWill Newton { 2325f95f3850SWill Newton if (!host->cmd_status) 2326f95f3850SWill Newton host->cmd_status = status; 2327f95f3850SWill Newton 23280e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2329f95f3850SWill Newton 2330f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2331f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2332f95f3850SWill Newton } 2333f95f3850SWill Newton 23346130e7a9SDoug Anderson static void dw_mci_handle_cd(struct dw_mci *host) 23356130e7a9SDoug Anderson { 23366130e7a9SDoug Anderson int i; 23376130e7a9SDoug Anderson 23386130e7a9SDoug Anderson for (i = 0; i < host->num_slots; i++) { 23396130e7a9SDoug Anderson struct dw_mci_slot *slot = host->slot[i]; 23406130e7a9SDoug Anderson 23416130e7a9SDoug Anderson if (!slot) 23426130e7a9SDoug Anderson continue; 23436130e7a9SDoug Anderson 23446130e7a9SDoug Anderson if (slot->mmc->ops->card_event) 23456130e7a9SDoug Anderson slot->mmc->ops->card_event(slot->mmc); 23466130e7a9SDoug Anderson mmc_detect_change(slot->mmc, 23476130e7a9SDoug Anderson msecs_to_jiffies(host->pdata->detect_delay_ms)); 23486130e7a9SDoug Anderson } 23496130e7a9SDoug Anderson } 23506130e7a9SDoug Anderson 2351f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 2352f95f3850SWill Newton { 2353f95f3850SWill Newton struct dw_mci *host = dev_id; 2354182c9081SSeungwon Jeon u32 pending; 23551a5c8e1fSShashidhar Hiremath int i; 2356f95f3850SWill Newton 2357f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 2358f95f3850SWill Newton 2359f95f3850SWill Newton /* 2360f95f3850SWill Newton * DTO fix - version 2.10a and below, and only if internal DMA 2361f95f3850SWill Newton * is configured. 2362f95f3850SWill Newton */ 2363f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { 2364f95f3850SWill Newton if (!pending && 2365f95f3850SWill Newton ((mci_readl(host, STATUS) >> 17) & 0x1fff)) 2366f95f3850SWill Newton pending |= SDMMC_INT_DATA_OVER; 2367f95f3850SWill Newton } 2368f95f3850SWill Newton 2369476d79f1SDoug Anderson if (pending) { 237001730558SDoug Anderson /* Check volt switch first, since it can look like an error */ 237101730558SDoug Anderson if ((host->state == STATE_SENDING_CMD11) && 237201730558SDoug Anderson (pending & SDMMC_INT_VOLT_SWITCH)) { 237349ba0302SDoug Anderson unsigned long irqflags; 23745c935165SDoug Anderson 237501730558SDoug Anderson mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); 237601730558SDoug Anderson pending &= ~SDMMC_INT_VOLT_SWITCH; 237749ba0302SDoug Anderson 237849ba0302SDoug Anderson /* 237949ba0302SDoug Anderson * Hold the lock; we know cmd11_timer can't be kicked 238049ba0302SDoug Anderson * off after the lock is released, so safe to delete. 238149ba0302SDoug Anderson */ 238249ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 238301730558SDoug Anderson dw_mci_cmd_interrupt(host, pending); 238449ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 238549ba0302SDoug Anderson 238649ba0302SDoug Anderson del_timer(&host->cmd11_timer); 238701730558SDoug Anderson } 238801730558SDoug Anderson 2389f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 2390f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 2391182c9081SSeungwon Jeon host->cmd_status = pending; 23920e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2393f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2394f95f3850SWill Newton } 2395f95f3850SWill Newton 2396f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 2397f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 2398f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 2399182c9081SSeungwon Jeon host->data_status = pending; 24000e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2401f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 2402f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2403f95f3850SWill Newton } 2404f95f3850SWill Newton 2405f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 240657e10486SAddy Ke if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) 240757e10486SAddy Ke del_timer(&host->dto_timer); 240857e10486SAddy Ke 2409f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 2410f95f3850SWill Newton if (!host->data_status) 2411182c9081SSeungwon Jeon host->data_status = pending; 24120e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2413f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 2414f95f3850SWill Newton if (host->sg != NULL) 241587a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 2416f95f3850SWill Newton } 2417f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 2418f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2419f95f3850SWill Newton } 2420f95f3850SWill Newton 2421f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 2422f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 2423b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 242487a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 2425f95f3850SWill Newton } 2426f95f3850SWill Newton 2427f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 2428f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2429b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 2430f95f3850SWill Newton dw_mci_write_data_pio(host); 2431f95f3850SWill Newton } 2432f95f3850SWill Newton 2433f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 2434f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 2435182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 2436f95f3850SWill Newton } 2437f95f3850SWill Newton 2438f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 2439f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 24406130e7a9SDoug Anderson dw_mci_handle_cd(host); 2441f95f3850SWill Newton } 2442f95f3850SWill Newton 24431a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 24441a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 24451a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 2446ed2540efSDoug Anderson 2447ed2540efSDoug Anderson if (!slot) 2448ed2540efSDoug Anderson continue; 2449ed2540efSDoug Anderson 245076756234SAddy Ke if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { 245176756234SAddy Ke mci_writel(host, RINTSTS, 245276756234SAddy Ke SDMMC_INT_SDIO(slot->sdio_id)); 24531a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 24541a5c8e1fSShashidhar Hiremath } 24551a5c8e1fSShashidhar Hiremath } 24561a5c8e1fSShashidhar Hiremath 24571fb5f68aSMarkos Chandras } 2458f95f3850SWill Newton 2459*3fc7eaefSShawn Lin if (host->use_dma != TRANS_MODE_IDMAC) 2460*3fc7eaefSShawn Lin return IRQ_HANDLED; 2461*3fc7eaefSShawn Lin 2462*3fc7eaefSShawn Lin /* Handle IDMA interrupts */ 246369d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 246469d99fdcSPrabu Thangamuthu pending = mci_readl(host, IDSTS64); 246569d99fdcSPrabu Thangamuthu if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 246669d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | 246769d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 246869d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); 2469*3fc7eaefSShawn Lin host->dma_ops->complete((void *)host); 247069d99fdcSPrabu Thangamuthu } 247169d99fdcSPrabu Thangamuthu } else { 2472f95f3850SWill Newton pending = mci_readl(host, IDSTS); 2473f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 247469d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | 247569d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 2476f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 2477*3fc7eaefSShawn Lin host->dma_ops->complete((void *)host); 2478f95f3850SWill Newton } 247969d99fdcSPrabu Thangamuthu } 2480f95f3850SWill Newton 2481f95f3850SWill Newton return IRQ_HANDLED; 2482f95f3850SWill Newton } 2483f95f3850SWill Newton 2484c91eab4bSThomas Abraham #ifdef CONFIG_OF 2485eff8f2f5SLars-Peter Clausen /* given a slot, find out the device node representing that slot */ 2486eff8f2f5SLars-Peter Clausen static struct device_node *dw_mci_of_find_slot_node(struct dw_mci_slot *slot) 2487c91eab4bSThomas Abraham { 2488eff8f2f5SLars-Peter Clausen struct device *dev = slot->mmc->parent; 2489c91eab4bSThomas Abraham struct device_node *np; 2490c91eab4bSThomas Abraham const __be32 *addr; 2491c91eab4bSThomas Abraham int len; 2492c91eab4bSThomas Abraham 2493c91eab4bSThomas Abraham if (!dev || !dev->of_node) 2494c91eab4bSThomas Abraham return NULL; 2495c91eab4bSThomas Abraham 2496c91eab4bSThomas Abraham for_each_child_of_node(dev->of_node, np) { 2497c91eab4bSThomas Abraham addr = of_get_property(np, "reg", &len); 2498c91eab4bSThomas Abraham if (!addr || (len < sizeof(int))) 2499c91eab4bSThomas Abraham continue; 2500eff8f2f5SLars-Peter Clausen if (be32_to_cpup(addr) == slot->id) 2501c91eab4bSThomas Abraham return np; 2502c91eab4bSThomas Abraham } 2503c91eab4bSThomas Abraham return NULL; 2504c91eab4bSThomas Abraham } 2505c91eab4bSThomas Abraham 2506eff8f2f5SLars-Peter Clausen static void dw_mci_slot_of_parse(struct dw_mci_slot *slot) 2507a70aaa64SDoug Anderson { 2508eff8f2f5SLars-Peter Clausen struct device_node *np = dw_mci_of_find_slot_node(slot); 2509a70aaa64SDoug Anderson 2510eff8f2f5SLars-Peter Clausen if (!np) 2511eff8f2f5SLars-Peter Clausen return; 2512a70aaa64SDoug Anderson 2513eff8f2f5SLars-Peter Clausen if (of_property_read_bool(np, "disable-wp")) { 2514eff8f2f5SLars-Peter Clausen slot->mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; 2515eff8f2f5SLars-Peter Clausen dev_warn(slot->mmc->parent, 2516eff8f2f5SLars-Peter Clausen "Slot quirk 'disable-wp' is deprecated\n"); 251726375b5cSJaehoon Chung } 2518a70aaa64SDoug Anderson } 2519c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2520eff8f2f5SLars-Peter Clausen static void dw_mci_slot_of_parse(struct dw_mci_slot *slot) 2521a70aaa64SDoug Anderson { 2522a70aaa64SDoug Anderson } 2523c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2524c91eab4bSThomas Abraham 252536c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2526f95f3850SWill Newton { 2527f95f3850SWill Newton struct mmc_host *mmc; 2528f95f3850SWill Newton struct dw_mci_slot *slot; 2529e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2530800d78bfSThomas Abraham int ctrl_id, ret; 25311f44a2a5SSeungwon Jeon u32 freq[2]; 2532f95f3850SWill Newton 25334a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2534f95f3850SWill Newton if (!mmc) 2535f95f3850SWill Newton return -ENOMEM; 2536f95f3850SWill Newton 2537f95f3850SWill Newton slot = mmc_priv(mmc); 2538f95f3850SWill Newton slot->id = id; 253976756234SAddy Ke slot->sdio_id = host->sdio_id0 + id; 2540f95f3850SWill Newton slot->mmc = mmc; 2541f95f3850SWill Newton slot->host = host; 2542c91eab4bSThomas Abraham host->slot[id] = slot; 2543f95f3850SWill Newton 2544f95f3850SWill Newton mmc->ops = &dw_mci_ops; 25451f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 25461f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 25471f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 25481f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 25491f44a2a5SSeungwon Jeon } else { 25501f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 25511f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 25521f44a2a5SSeungwon Jeon } 2553f95f3850SWill Newton 255451da2240SYuvaraj CD /*if there are external regulators, get them*/ 255551da2240SYuvaraj CD ret = mmc_regulator_get_supply(mmc); 255651da2240SYuvaraj CD if (ret == -EPROBE_DEFER) 25573cf890fcSDoug Anderson goto err_host_allocated; 255851da2240SYuvaraj CD 255951da2240SYuvaraj CD if (!mmc->ocr_avail) 2560f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2561f95f3850SWill Newton 2562fc3d7720SJaehoon Chung if (host->pdata->caps) 2563fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2564fc3d7720SJaehoon Chung 2565ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2566ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2567ab269128SAbhilash Kesavan 2568800d78bfSThomas Abraham if (host->dev->of_node) { 2569800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2570800d78bfSThomas Abraham if (ctrl_id < 0) 2571800d78bfSThomas Abraham ctrl_id = 0; 2572800d78bfSThomas Abraham } else { 2573800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2574800d78bfSThomas Abraham } 2575cb27a843SJames Hogan if (drv_data && drv_data->caps) 2576cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2577800d78bfSThomas Abraham 25784f408cc6SSeungwon Jeon if (host->pdata->caps2) 25794f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 25804f408cc6SSeungwon Jeon 2581eff8f2f5SLars-Peter Clausen dw_mci_slot_of_parse(slot); 2582eff8f2f5SLars-Peter Clausen 25833cf890fcSDoug Anderson ret = mmc_of_parse(mmc); 25843cf890fcSDoug Anderson if (ret) 25853cf890fcSDoug Anderson goto err_host_allocated; 2586f95f3850SWill Newton 2587f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 2588*3fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) { 2589a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2590a39e5746SJaehoon Chung mmc->max_blk_size = 65536; 2591575c319dSHeiko Stuebner mmc->max_seg_size = 0x1000; 25921a25b1b4SSeungwon Jeon mmc->max_req_size = mmc->max_seg_size * host->ring_size; 25931a25b1b4SSeungwon Jeon mmc->max_blk_count = mmc->max_req_size / 512; 2594*3fc7eaefSShawn Lin } else if (host->use_dma == TRANS_MODE_EDMAC) { 2595*3fc7eaefSShawn Lin mmc->max_segs = 64; 2596*3fc7eaefSShawn Lin mmc->max_blk_size = 65536; 2597*3fc7eaefSShawn Lin mmc->max_blk_count = 65535; 2598*3fc7eaefSShawn Lin mmc->max_req_size = 2599*3fc7eaefSShawn Lin mmc->max_blk_size * mmc->max_blk_count; 2600*3fc7eaefSShawn Lin mmc->max_seg_size = mmc->max_req_size; 2601575c319dSHeiko Stuebner } else { 2602*3fc7eaefSShawn Lin /* TRANS_MODE_PIO */ 2603f95f3850SWill Newton mmc->max_segs = 64; 2604f95f3850SWill Newton mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ 2605f95f3850SWill Newton mmc->max_blk_count = 512; 2606575c319dSHeiko Stuebner mmc->max_req_size = mmc->max_blk_size * 2607575c319dSHeiko Stuebner mmc->max_blk_count; 2608f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2609575c319dSHeiko Stuebner } 2610f95f3850SWill Newton 2611ae0eb348SJaehoon Chung if (dw_mci_get_cd(mmc)) 2612ae0eb348SJaehoon Chung set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2613ae0eb348SJaehoon Chung else 2614ae0eb348SJaehoon Chung clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2615ae0eb348SJaehoon Chung 26160cea529dSJaehoon Chung ret = mmc_add_host(mmc); 26170cea529dSJaehoon Chung if (ret) 26183cf890fcSDoug Anderson goto err_host_allocated; 2619f95f3850SWill Newton 2620f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2621f95f3850SWill Newton dw_mci_init_debugfs(slot); 2622f95f3850SWill Newton #endif 2623f95f3850SWill Newton 2624f95f3850SWill Newton return 0; 2625800d78bfSThomas Abraham 26263cf890fcSDoug Anderson err_host_allocated: 2627800d78bfSThomas Abraham mmc_free_host(mmc); 262851da2240SYuvaraj CD return ret; 2629f95f3850SWill Newton } 2630f95f3850SWill Newton 2631f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2632f95f3850SWill Newton { 2633f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2634f95f3850SWill Newton mmc_remove_host(slot->mmc); 2635f95f3850SWill Newton slot->host->slot[id] = NULL; 2636f95f3850SWill Newton mmc_free_host(slot->mmc); 2637f95f3850SWill Newton } 2638f95f3850SWill Newton 2639f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2640f95f3850SWill Newton { 264169d99fdcSPrabu Thangamuthu int addr_config; 2642*3fc7eaefSShawn Lin struct device *dev = host->dev; 2643*3fc7eaefSShawn Lin struct device_node *np = dev->of_node; 2644*3fc7eaefSShawn Lin 2645*3fc7eaefSShawn Lin /* 2646*3fc7eaefSShawn Lin * Check tansfer mode from HCON[17:16] 2647*3fc7eaefSShawn Lin * Clear the ambiguous description of dw_mmc databook: 2648*3fc7eaefSShawn Lin * 2b'00: No DMA Interface -> Actually means using Internal DMA block 2649*3fc7eaefSShawn Lin * 2b'01: DesignWare DMA Interface -> Synopsys DW-DMA block 2650*3fc7eaefSShawn Lin * 2b'10: Generic DMA Interface -> non-Synopsys generic DMA block 2651*3fc7eaefSShawn Lin * 2b'11: Non DW DMA Interface -> pio only 2652*3fc7eaefSShawn Lin * Compared to DesignWare DMA Interface, Generic DMA Interface has a 2653*3fc7eaefSShawn Lin * simpler request/acknowledge handshake mechanism and both of them 2654*3fc7eaefSShawn Lin * are regarded as external dma master for dw_mmc. 2655*3fc7eaefSShawn Lin */ 2656*3fc7eaefSShawn Lin host->use_dma = SDMMC_GET_TRANS_MODE(mci_readl(host, HCON)); 2657*3fc7eaefSShawn Lin if (host->use_dma == DMA_INTERFACE_IDMA) { 2658*3fc7eaefSShawn Lin host->use_dma = TRANS_MODE_IDMAC; 2659*3fc7eaefSShawn Lin } else if (host->use_dma == DMA_INTERFACE_DWDMA || 2660*3fc7eaefSShawn Lin host->use_dma == DMA_INTERFACE_GDMA) { 2661*3fc7eaefSShawn Lin host->use_dma = TRANS_MODE_EDMAC; 2662*3fc7eaefSShawn Lin } else { 2663*3fc7eaefSShawn Lin goto no_dma; 2664*3fc7eaefSShawn Lin } 2665*3fc7eaefSShawn Lin 2666*3fc7eaefSShawn Lin /* Determine which DMA interface to use */ 2667*3fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) { 2668*3fc7eaefSShawn Lin /* 2669*3fc7eaefSShawn Lin * Check ADDR_CONFIG bit in HCON to find 2670*3fc7eaefSShawn Lin * IDMAC address bus width 2671*3fc7eaefSShawn Lin */ 267269d99fdcSPrabu Thangamuthu addr_config = (mci_readl(host, HCON) >> 27) & 0x01; 267369d99fdcSPrabu Thangamuthu 267469d99fdcSPrabu Thangamuthu if (addr_config == 1) { 267569d99fdcSPrabu Thangamuthu /* host supports IDMAC in 64-bit address mode */ 267669d99fdcSPrabu Thangamuthu host->dma_64bit_address = 1; 2677*3fc7eaefSShawn Lin dev_info(host->dev, 2678*3fc7eaefSShawn Lin "IDMAC supports 64-bit address mode.\n"); 267969d99fdcSPrabu Thangamuthu if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) 2680*3fc7eaefSShawn Lin dma_set_coherent_mask(host->dev, 2681*3fc7eaefSShawn Lin DMA_BIT_MASK(64)); 268269d99fdcSPrabu Thangamuthu } else { 268369d99fdcSPrabu Thangamuthu /* host supports IDMAC in 32-bit address mode */ 268469d99fdcSPrabu Thangamuthu host->dma_64bit_address = 0; 2685*3fc7eaefSShawn Lin dev_info(host->dev, 2686*3fc7eaefSShawn Lin "IDMAC supports 32-bit address mode.\n"); 268769d99fdcSPrabu Thangamuthu } 268869d99fdcSPrabu Thangamuthu 2689f95f3850SWill Newton /* Alloc memory for sg translation */ 2690780f22afSSeungwon Jeon host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, 2691f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2692f95f3850SWill Newton if (!host->sg_cpu) { 2693*3fc7eaefSShawn Lin dev_err(host->dev, 2694*3fc7eaefSShawn Lin "%s: could not alloc DMA memory\n", 2695f95f3850SWill Newton __func__); 2696f95f3850SWill Newton goto no_dma; 2697f95f3850SWill Newton } 2698f95f3850SWill Newton 2699f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 270000956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 2701*3fc7eaefSShawn Lin } else { 2702*3fc7eaefSShawn Lin /* TRANS_MODE_EDMAC: check dma bindings again */ 2703*3fc7eaefSShawn Lin if ((of_property_count_strings(np, "dma-names") < 0) || 2704*3fc7eaefSShawn Lin (!of_find_property(np, "dmas", NULL))) { 2705f95f3850SWill Newton goto no_dma; 2706*3fc7eaefSShawn Lin } 2707*3fc7eaefSShawn Lin host->dma_ops = &dw_mci_edmac_ops; 2708*3fc7eaefSShawn Lin dev_info(host->dev, "Using external DMA controller.\n"); 2709*3fc7eaefSShawn Lin } 2710f95f3850SWill Newton 2711e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2712e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2713f95f3850SWill Newton if (host->dma_ops->init(host)) { 27140e3a22c0SShawn Lin dev_err(host->dev, "%s: Unable to initialize DMA Controller.\n", 27150e3a22c0SShawn Lin __func__); 2716f95f3850SWill Newton goto no_dma; 2717f95f3850SWill Newton } 2718f95f3850SWill Newton } else { 27194a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2720f95f3850SWill Newton goto no_dma; 2721f95f3850SWill Newton } 2722f95f3850SWill Newton 2723f95f3850SWill Newton return; 2724f95f3850SWill Newton 2725f95f3850SWill Newton no_dma: 27264a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 2727*3fc7eaefSShawn Lin host->use_dma = TRANS_MODE_PIO; 2728f95f3850SWill Newton } 2729f95f3850SWill Newton 273031bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) 2731f95f3850SWill Newton { 2732f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 273331bff450SSeungwon Jeon u32 ctrl; 2734f95f3850SWill Newton 273531bff450SSeungwon Jeon ctrl = mci_readl(host, CTRL); 273631bff450SSeungwon Jeon ctrl |= reset; 273731bff450SSeungwon Jeon mci_writel(host, CTRL, ctrl); 2738f95f3850SWill Newton 2739f95f3850SWill Newton /* wait till resets clear */ 2740f95f3850SWill Newton do { 2741f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 274231bff450SSeungwon Jeon if (!(ctrl & reset)) 2743f95f3850SWill Newton return true; 2744f95f3850SWill Newton } while (time_before(jiffies, timeout)); 2745f95f3850SWill Newton 274631bff450SSeungwon Jeon dev_err(host->dev, 274731bff450SSeungwon Jeon "Timeout resetting block (ctrl reset %#x)\n", 274831bff450SSeungwon Jeon ctrl & reset); 2749f95f3850SWill Newton 2750f95f3850SWill Newton return false; 2751f95f3850SWill Newton } 2752f95f3850SWill Newton 27533a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host) 275431bff450SSeungwon Jeon { 27553a33a94cSSonny Rao u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; 27563a33a94cSSonny Rao bool ret = false; 27573a33a94cSSonny Rao 275831bff450SSeungwon Jeon /* 275931bff450SSeungwon Jeon * Reseting generates a block interrupt, hence setting 276031bff450SSeungwon Jeon * the scatter-gather pointer to NULL. 276131bff450SSeungwon Jeon */ 276231bff450SSeungwon Jeon if (host->sg) { 276331bff450SSeungwon Jeon sg_miter_stop(&host->sg_miter); 276431bff450SSeungwon Jeon host->sg = NULL; 276531bff450SSeungwon Jeon } 276631bff450SSeungwon Jeon 27673a33a94cSSonny Rao if (host->use_dma) 27683a33a94cSSonny Rao flags |= SDMMC_CTRL_DMA_RESET; 27693a33a94cSSonny Rao 27703a33a94cSSonny Rao if (dw_mci_ctrl_reset(host, flags)) { 27713a33a94cSSonny Rao /* 27723a33a94cSSonny Rao * In all cases we clear the RAWINTS register to clear any 27733a33a94cSSonny Rao * interrupts. 27743a33a94cSSonny Rao */ 27753a33a94cSSonny Rao mci_writel(host, RINTSTS, 0xFFFFFFFF); 27763a33a94cSSonny Rao 27773a33a94cSSonny Rao /* if using dma we wait for dma_req to clear */ 27783a33a94cSSonny Rao if (host->use_dma) { 27793a33a94cSSonny Rao unsigned long timeout = jiffies + msecs_to_jiffies(500); 27803a33a94cSSonny Rao u32 status; 27810e3a22c0SShawn Lin 27823a33a94cSSonny Rao do { 27833a33a94cSSonny Rao status = mci_readl(host, STATUS); 27843a33a94cSSonny Rao if (!(status & SDMMC_STATUS_DMA_REQ)) 27853a33a94cSSonny Rao break; 27863a33a94cSSonny Rao cpu_relax(); 27873a33a94cSSonny Rao } while (time_before(jiffies, timeout)); 27883a33a94cSSonny Rao 27893a33a94cSSonny Rao if (status & SDMMC_STATUS_DMA_REQ) { 27903a33a94cSSonny Rao dev_err(host->dev, 27910e3a22c0SShawn Lin "%s: Timeout waiting for dma_req to clear during reset\n", 27920e3a22c0SShawn Lin __func__); 27933a33a94cSSonny Rao goto ciu_out; 279431bff450SSeungwon Jeon } 279531bff450SSeungwon Jeon 27963a33a94cSSonny Rao /* when using DMA next we reset the fifo again */ 27973a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) 27983a33a94cSSonny Rao goto ciu_out; 27993a33a94cSSonny Rao } 28003a33a94cSSonny Rao } else { 28013a33a94cSSonny Rao /* if the controller reset bit did clear, then set clock regs */ 28023a33a94cSSonny Rao if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { 28030e3a22c0SShawn Lin dev_err(host->dev, 28040e3a22c0SShawn Lin "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n", 28053a33a94cSSonny Rao __func__); 28063a33a94cSSonny Rao goto ciu_out; 28073a33a94cSSonny Rao } 28083a33a94cSSonny Rao } 28093a33a94cSSonny Rao 2810*3fc7eaefSShawn Lin if (host->use_dma == TRANS_MODE_IDMAC) 28113a33a94cSSonny Rao /* It is also recommended that we reset and reprogram idmac */ 28123a33a94cSSonny Rao dw_mci_idmac_reset(host); 28133a33a94cSSonny Rao 28143a33a94cSSonny Rao ret = true; 28153a33a94cSSonny Rao 28163a33a94cSSonny Rao ciu_out: 28173a33a94cSSonny Rao /* After a CTRL reset we need to have CIU set clock registers */ 28183a33a94cSSonny Rao mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); 28193a33a94cSSonny Rao 28203a33a94cSSonny Rao return ret; 282131bff450SSeungwon Jeon } 282231bff450SSeungwon Jeon 28235c935165SDoug Anderson static void dw_mci_cmd11_timer(unsigned long arg) 28245c935165SDoug Anderson { 28255c935165SDoug Anderson struct dw_mci *host = (struct dw_mci *)arg; 28265c935165SDoug Anderson 2827fd674198SDoug Anderson if (host->state != STATE_SENDING_CMD11) { 2828fd674198SDoug Anderson dev_warn(host->dev, "Unexpected CMD11 timeout\n"); 2829fd674198SDoug Anderson return; 2830fd674198SDoug Anderson } 28315c935165SDoug Anderson 28325c935165SDoug Anderson host->cmd_status = SDMMC_INT_RTO; 28335c935165SDoug Anderson set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 28345c935165SDoug Anderson tasklet_schedule(&host->tasklet); 28355c935165SDoug Anderson } 28365c935165SDoug Anderson 283757e10486SAddy Ke static void dw_mci_dto_timer(unsigned long arg) 283857e10486SAddy Ke { 283957e10486SAddy Ke struct dw_mci *host = (struct dw_mci *)arg; 284057e10486SAddy Ke 284157e10486SAddy Ke switch (host->state) { 284257e10486SAddy Ke case STATE_SENDING_DATA: 284357e10486SAddy Ke case STATE_DATA_BUSY: 284457e10486SAddy Ke /* 284557e10486SAddy Ke * If DTO interrupt does NOT come in sending data state, 284657e10486SAddy Ke * we should notify the driver to terminate current transfer 284757e10486SAddy Ke * and report a data timeout to the core. 284857e10486SAddy Ke */ 284957e10486SAddy Ke host->data_status = SDMMC_INT_DRTO; 285057e10486SAddy Ke set_bit(EVENT_DATA_ERROR, &host->pending_events); 285157e10486SAddy Ke set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 285257e10486SAddy Ke tasklet_schedule(&host->tasklet); 285357e10486SAddy Ke break; 285457e10486SAddy Ke default: 285557e10486SAddy Ke break; 285657e10486SAddy Ke } 285757e10486SAddy Ke } 285857e10486SAddy Ke 2859c91eab4bSThomas Abraham #ifdef CONFIG_OF 2860c91eab4bSThomas Abraham static struct dw_mci_of_quirks { 2861c91eab4bSThomas Abraham char *quirk; 2862c91eab4bSThomas Abraham int id; 2863c91eab4bSThomas Abraham } of_quirks[] = { 2864c91eab4bSThomas Abraham { 2865c91eab4bSThomas Abraham .quirk = "broken-cd", 2866c91eab4bSThomas Abraham .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, 2867c91eab4bSThomas Abraham }, 2868c91eab4bSThomas Abraham }; 2869c91eab4bSThomas Abraham 2870c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2871c91eab4bSThomas Abraham { 2872c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2873c91eab4bSThomas Abraham struct device *dev = host->dev; 2874c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2875e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2876800d78bfSThomas Abraham int idx, ret; 28773c6d89eaSDoug Anderson u32 clock_frequency; 2878c91eab4bSThomas Abraham 2879c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2880bf3707eaSBeomho Seo if (!pdata) 2881c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2882c91eab4bSThomas Abraham 2883c91eab4bSThomas Abraham /* find out number of slots supported */ 2884c91eab4bSThomas Abraham if (of_property_read_u32(dev->of_node, "num-slots", 2885c91eab4bSThomas Abraham &pdata->num_slots)) { 28860e3a22c0SShawn Lin dev_info(dev, 28870e3a22c0SShawn Lin "num-slots property not found, assuming 1 slot is available\n"); 2888c91eab4bSThomas Abraham pdata->num_slots = 1; 2889c91eab4bSThomas Abraham } 2890c91eab4bSThomas Abraham 2891c91eab4bSThomas Abraham /* get quirks */ 2892c91eab4bSThomas Abraham for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) 2893c91eab4bSThomas Abraham if (of_get_property(np, of_quirks[idx].quirk, NULL)) 2894c91eab4bSThomas Abraham pdata->quirks |= of_quirks[idx].id; 2895c91eab4bSThomas Abraham 2896c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 28970e3a22c0SShawn Lin dev_info(dev, 28980e3a22c0SShawn Lin "fifo-depth property not found, using value of FIFOTH register as default\n"); 2899c91eab4bSThomas Abraham 2900c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2901c91eab4bSThomas Abraham 29023c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 29033c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 29043c6d89eaSDoug Anderson 2905cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2906cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2907800d78bfSThomas Abraham if (ret) 2908800d78bfSThomas Abraham return ERR_PTR(ret); 2909800d78bfSThomas Abraham } 2910800d78bfSThomas Abraham 291140a7a463SJaehoon Chung if (of_find_property(np, "supports-highspeed", NULL)) { 291240a7a463SJaehoon Chung dev_info(dev, "supports-highspeed property is deprecated.\n"); 291310b49841SSeungwon Jeon pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; 291440a7a463SJaehoon Chung } 291510b49841SSeungwon Jeon 2916c91eab4bSThomas Abraham return pdata; 2917c91eab4bSThomas Abraham } 2918c91eab4bSThomas Abraham 2919c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2920c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2921c91eab4bSThomas Abraham { 2922c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2923c91eab4bSThomas Abraham } 2924c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2925c91eab4bSThomas Abraham 2926fa0c3283SDoug Anderson static void dw_mci_enable_cd(struct dw_mci *host) 2927fa0c3283SDoug Anderson { 2928fa0c3283SDoug Anderson struct dw_mci_board *brd = host->pdata; 2929fa0c3283SDoug Anderson unsigned long irqflags; 2930fa0c3283SDoug Anderson u32 temp; 2931fa0c3283SDoug Anderson int i; 2932fa0c3283SDoug Anderson 2933fa0c3283SDoug Anderson /* No need for CD if broken card detection */ 2934fa0c3283SDoug Anderson if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) 2935fa0c3283SDoug Anderson return; 2936fa0c3283SDoug Anderson 2937fa0c3283SDoug Anderson /* No need for CD if all slots have a non-error GPIO */ 2938fa0c3283SDoug Anderson for (i = 0; i < host->num_slots; i++) { 2939fa0c3283SDoug Anderson struct dw_mci_slot *slot = host->slot[i]; 2940fa0c3283SDoug Anderson 2941fa0c3283SDoug Anderson if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc))) 2942fa0c3283SDoug Anderson break; 2943fa0c3283SDoug Anderson } 2944fa0c3283SDoug Anderson if (i == host->num_slots) 2945fa0c3283SDoug Anderson return; 2946fa0c3283SDoug Anderson 2947fa0c3283SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 2948fa0c3283SDoug Anderson temp = mci_readl(host, INTMASK); 2949fa0c3283SDoug Anderson temp |= SDMMC_INT_CD; 2950fa0c3283SDoug Anderson mci_writel(host, INTMASK, temp); 2951fa0c3283SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 2952fa0c3283SDoug Anderson } 2953fa0c3283SDoug Anderson 295462ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 2955f95f3850SWill Newton { 2956e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 295762ca8034SShashidhar Hiremath int width, i, ret = 0; 2958f95f3850SWill Newton u32 fifo_size; 29591c2215b7SThomas Abraham int init_slots = 0; 2960f95f3850SWill Newton 2961c91eab4bSThomas Abraham if (!host->pdata) { 2962c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 2963c91eab4bSThomas Abraham if (IS_ERR(host->pdata)) { 2964c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 2965c91eab4bSThomas Abraham return -EINVAL; 2966c91eab4bSThomas Abraham } 2967f95f3850SWill Newton } 2968f95f3850SWill Newton 29699e747b7eSJaehoon Chung if (host->pdata->num_slots < 1) { 29704a90920cSThomas Abraham dev_err(host->dev, 2971907abd51SJaehoon Chung "Platform data must supply num_slots.\n"); 297262ca8034SShashidhar Hiremath return -ENODEV; 2973f95f3850SWill Newton } 2974f95f3850SWill Newton 2975780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 2976f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 2977f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 2978f90a0612SThomas Abraham } else { 2979f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 2980f90a0612SThomas Abraham if (ret) { 2981f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 2982f90a0612SThomas Abraham return ret; 2983f90a0612SThomas Abraham } 2984f95f3850SWill Newton } 2985f95f3850SWill Newton 2986780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 2987f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 2988f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 29893c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 2990f90a0612SThomas Abraham } else { 2991f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 2992f90a0612SThomas Abraham if (ret) { 2993f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 2994f90a0612SThomas Abraham goto err_clk_biu; 2995f90a0612SThomas Abraham } 2996f90a0612SThomas Abraham 29973c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 29983c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 29993c6d89eaSDoug Anderson if (ret) 30003c6d89eaSDoug Anderson dev_warn(host->dev, 3001612de4c1SJaehoon Chung "Unable to set bus rate to %uHz\n", 30023c6d89eaSDoug Anderson host->pdata->bus_hz); 30033c6d89eaSDoug Anderson } 3004f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 30053c6d89eaSDoug Anderson } 3006f90a0612SThomas Abraham 3007612de4c1SJaehoon Chung if (!host->bus_hz) { 3008612de4c1SJaehoon Chung dev_err(host->dev, 3009612de4c1SJaehoon Chung "Platform data must supply bus speed\n"); 3010612de4c1SJaehoon Chung ret = -ENODEV; 3011612de4c1SJaehoon Chung goto err_clk_ciu; 3012612de4c1SJaehoon Chung } 3013612de4c1SJaehoon Chung 3014002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 3015002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 3016002f0d5cSYuvaraj Kumar C D if (ret) { 3017002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 3018002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 3019002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 3020002f0d5cSYuvaraj Kumar C D } 3021002f0d5cSYuvaraj Kumar C D } 3022002f0d5cSYuvaraj Kumar C D 3023cb27a843SJames Hogan if (drv_data && drv_data->setup_clock) { 3024cb27a843SJames Hogan ret = drv_data->setup_clock(host); 3025800d78bfSThomas Abraham if (ret) { 3026800d78bfSThomas Abraham dev_err(host->dev, 3027800d78bfSThomas Abraham "implementation specific clock setup failed\n"); 3028800d78bfSThomas Abraham goto err_clk_ciu; 3029800d78bfSThomas Abraham } 3030800d78bfSThomas Abraham } 3031800d78bfSThomas Abraham 30325c935165SDoug Anderson setup_timer(&host->cmd11_timer, 30335c935165SDoug Anderson dw_mci_cmd11_timer, (unsigned long)host); 30345c935165SDoug Anderson 303562ca8034SShashidhar Hiremath host->quirks = host->pdata->quirks; 3036f95f3850SWill Newton 303757e10486SAddy Ke if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) 303857e10486SAddy Ke setup_timer(&host->dto_timer, 303957e10486SAddy Ke dw_mci_dto_timer, (unsigned long)host); 304057e10486SAddy Ke 3041f95f3850SWill Newton spin_lock_init(&host->lock); 3042f8c58c11SDoug Anderson spin_lock_init(&host->irq_lock); 3043f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 3044f95f3850SWill Newton 3045f95f3850SWill Newton /* 3046f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 3047f95f3850SWill Newton * the correct values. 3048f95f3850SWill Newton */ 3049f95f3850SWill Newton i = (mci_readl(host, HCON) >> 7) & 0x7; 3050f95f3850SWill Newton if (!i) { 3051f95f3850SWill Newton host->push_data = dw_mci_push_data16; 3052f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 3053f95f3850SWill Newton width = 16; 3054f95f3850SWill Newton host->data_shift = 1; 3055f95f3850SWill Newton } else if (i == 2) { 3056f95f3850SWill Newton host->push_data = dw_mci_push_data64; 3057f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 3058f95f3850SWill Newton width = 64; 3059f95f3850SWill Newton host->data_shift = 3; 3060f95f3850SWill Newton } else { 3061f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 3062f95f3850SWill Newton WARN((i != 1), 3063f95f3850SWill Newton "HCON reports a reserved host data width!\n" 3064f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 3065f95f3850SWill Newton host->push_data = dw_mci_push_data32; 3066f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 3067f95f3850SWill Newton width = 32; 3068f95f3850SWill Newton host->data_shift = 2; 3069f95f3850SWill Newton } 3070f95f3850SWill Newton 3071f95f3850SWill Newton /* Reset all blocks */ 30723a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) 3073141a712aSSeungwon Jeon return -ENODEV; 3074141a712aSSeungwon Jeon 3075141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 3076141a712aSSeungwon Jeon dw_mci_init_dma(host); 3077f95f3850SWill Newton 3078f95f3850SWill Newton /* Clear the interrupts for the host controller */ 3079f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 3080f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 3081f95f3850SWill Newton 3082f95f3850SWill Newton /* Put in max timeout */ 3083f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 3084f95f3850SWill Newton 3085f95f3850SWill Newton /* 3086f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 3087f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 3088f95f3850SWill Newton */ 3089b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 3090b86d8253SJames Hogan /* 3091b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 3092b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 3093b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 3094b86d8253SJames Hogan * should put it in the platform data. 3095b86d8253SJames Hogan */ 3096f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 30978234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 3098b86d8253SJames Hogan } else { 3099b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 3100b86d8253SJames Hogan } 3101b86d8253SJames Hogan host->fifo_depth = fifo_size; 310252426899SSeungwon Jeon host->fifoth_val = 310352426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 3104e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 3105f95f3850SWill Newton 3106f95f3850SWill Newton /* disable clock to CIU */ 3107f95f3850SWill Newton mci_writel(host, CLKENA, 0); 3108f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 3109f95f3850SWill Newton 311063008768SJames Hogan /* 311163008768SJames Hogan * In 2.40a spec, Data offset is changed. 311263008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 311363008768SJames Hogan */ 311463008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 311563008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 311663008768SJames Hogan 311763008768SJames Hogan if (host->verid < DW_MMC_240A) 311876184ac1SBen Dooks host->fifo_reg = host->regs + DATA_OFFSET; 311963008768SJames Hogan else 312076184ac1SBen Dooks host->fifo_reg = host->regs + DATA_240A_OFFSET; 312163008768SJames Hogan 3122f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 3123780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 3124780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 3125f95f3850SWill Newton if (ret) 31266130e7a9SDoug Anderson goto err_dmaunmap; 3127f95f3850SWill Newton 3128f95f3850SWill Newton if (host->pdata->num_slots) 3129f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 3130f95f3850SWill Newton else 3131f95f3850SWill Newton host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; 3132f95f3850SWill Newton 31332da1d7f2SYuvaraj CD /* 3134fa0c3283SDoug Anderson * Enable interrupts for command done, data over, data empty, 31352da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 31362da1d7f2SYuvaraj CD */ 31372da1d7f2SYuvaraj CD mci_writel(host, RINTSTS, 0xFFFFFFFF); 31382da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 31392da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 3140fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 31410e3a22c0SShawn Lin /* Enable mci interrupt */ 31420e3a22c0SShawn Lin mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 31432da1d7f2SYuvaraj CD 31440e3a22c0SShawn Lin dev_info(host->dev, 31450e3a22c0SShawn Lin "DW MMC controller at irq %d,%d bit host data width,%u deep fifo\n", 31462da1d7f2SYuvaraj CD host->irq, width, fifo_size); 31472da1d7f2SYuvaraj CD 3148f95f3850SWill Newton /* We need at least one slot to succeed */ 3149f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 3150f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 31511c2215b7SThomas Abraham if (ret) 31521c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 31531c2215b7SThomas Abraham else 31541c2215b7SThomas Abraham init_slots++; 3155f95f3850SWill Newton } 31561c2215b7SThomas Abraham 31571c2215b7SThomas Abraham if (init_slots) { 31581c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 31591c2215b7SThomas Abraham } else { 31600e3a22c0SShawn Lin dev_dbg(host->dev, 31610e3a22c0SShawn Lin "attempted to initialize %d slots, but failed on all\n", 31620e3a22c0SShawn Lin host->num_slots); 31636130e7a9SDoug Anderson goto err_dmaunmap; 3164f95f3850SWill Newton } 3165f95f3850SWill Newton 3166b793f658SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3167b793f658SDoug Anderson dw_mci_enable_cd(host); 3168b793f658SDoug Anderson 3169f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) 31704a90920cSThomas Abraham dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); 3171f95f3850SWill Newton 3172f95f3850SWill Newton return 0; 3173f95f3850SWill Newton 3174f95f3850SWill Newton err_dmaunmap: 3175f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3176f95f3850SWill Newton host->dma_ops->exit(host); 3177f90a0612SThomas Abraham 3178f90a0612SThomas Abraham err_clk_ciu: 3179780f22afSSeungwon Jeon if (!IS_ERR(host->ciu_clk)) 3180f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3181780f22afSSeungwon Jeon 3182f90a0612SThomas Abraham err_clk_biu: 3183780f22afSSeungwon Jeon if (!IS_ERR(host->biu_clk)) 3184f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3185780f22afSSeungwon Jeon 3186f95f3850SWill Newton return ret; 3187f95f3850SWill Newton } 318862ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 3189f95f3850SWill Newton 319062ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 3191f95f3850SWill Newton { 3192f95f3850SWill Newton int i; 3193f95f3850SWill Newton 3194f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 31954a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 3196f95f3850SWill Newton if (host->slot[i]) 3197f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 3198f95f3850SWill Newton } 3199f95f3850SWill Newton 3200048fd7e6SPrabu Thangamuthu mci_writel(host, RINTSTS, 0xFFFFFFFF); 3201048fd7e6SPrabu Thangamuthu mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 3202048fd7e6SPrabu Thangamuthu 3203f95f3850SWill Newton /* disable clock to CIU */ 3204f95f3850SWill Newton mci_writel(host, CLKENA, 0); 3205f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 3206f95f3850SWill Newton 3207f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3208f95f3850SWill Newton host->dma_ops->exit(host); 3209f95f3850SWill Newton 3210f90a0612SThomas Abraham if (!IS_ERR(host->ciu_clk)) 3211f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3212780f22afSSeungwon Jeon 3213f90a0612SThomas Abraham if (!IS_ERR(host->biu_clk)) 3214f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3215f95f3850SWill Newton } 321662ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 321762ca8034SShashidhar Hiremath 321862ca8034SShashidhar Hiremath 3219f95f3850SWill Newton 32206fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP 3221f95f3850SWill Newton /* 3222f95f3850SWill Newton * TODO: we should probably disable the clock to the card in the suspend path. 3223f95f3850SWill Newton */ 322462ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host) 3225f95f3850SWill Newton { 3226*3fc7eaefSShawn Lin if (host->use_dma && host->dma_ops->exit) 3227*3fc7eaefSShawn Lin host->dma_ops->exit(host); 3228*3fc7eaefSShawn Lin 3229f95f3850SWill Newton return 0; 3230f95f3850SWill Newton } 323162ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend); 3232f95f3850SWill Newton 323362ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host) 3234f95f3850SWill Newton { 3235f95f3850SWill Newton int i, ret; 3236f95f3850SWill Newton 32373a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 3238e61cf118SJaehoon Chung ret = -ENODEV; 3239e61cf118SJaehoon Chung return ret; 3240e61cf118SJaehoon Chung } 3241e61cf118SJaehoon Chung 32423bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 3243141a712aSSeungwon Jeon host->dma_ops->init(host); 3244141a712aSSeungwon Jeon 324552426899SSeungwon Jeon /* 324652426899SSeungwon Jeon * Restore the initial value at FIFOTH register 324752426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 324852426899SSeungwon Jeon */ 3249e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 325052426899SSeungwon Jeon host->prev_blksz = 0; 3251e61cf118SJaehoon Chung 32522eb2944fSDoug Anderson /* Put in max timeout */ 32532eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 32542eb2944fSDoug Anderson 3255e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 3256e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 3257e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 3258fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 3259e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 3260e61cf118SJaehoon Chung 3261f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 3262f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 32630e3a22c0SShawn Lin 3264f95f3850SWill Newton if (!slot) 3265f95f3850SWill Newton continue; 3266ab269128SAbhilash Kesavan if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { 3267ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 3268ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 3269ab269128SAbhilash Kesavan } 3270f95f3850SWill Newton } 3271fa0c3283SDoug Anderson 3272fa0c3283SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3273fa0c3283SDoug Anderson dw_mci_enable_cd(host); 3274fa0c3283SDoug Anderson 3275f95f3850SWill Newton return 0; 3276f95f3850SWill Newton } 327762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume); 32786fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */ 32796fe8890dSJaehoon Chung 3280f95f3850SWill Newton static int __init dw_mci_init(void) 3281f95f3850SWill Newton { 32828e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 328362ca8034SShashidhar Hiremath return 0; 3284f95f3850SWill Newton } 3285f95f3850SWill Newton 3286f95f3850SWill Newton static void __exit dw_mci_exit(void) 3287f95f3850SWill Newton { 3288f95f3850SWill Newton } 3289f95f3850SWill Newton 3290f95f3850SWill Newton module_init(dw_mci_init); 3291f95f3850SWill Newton module_exit(dw_mci_exit); 3292f95f3850SWill Newton 3293f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 3294f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 3295f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 3296f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 3297