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 59f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 60fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ 61fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ 62fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ 63fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_TI) 64fc79a4d6SJoonyoung Shim 6569d99fdcSPrabu Thangamuthu struct idmac_desc_64addr { 6669d99fdcSPrabu Thangamuthu u32 des0; /* Control Descriptor */ 6769d99fdcSPrabu Thangamuthu 6869d99fdcSPrabu Thangamuthu u32 des1; /* Reserved */ 6969d99fdcSPrabu Thangamuthu 7069d99fdcSPrabu Thangamuthu u32 des2; /*Buffer sizes */ 7169d99fdcSPrabu Thangamuthu #define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ 726687c42fSBen Dooks ((d)->des2 = ((d)->des2 & cpu_to_le32(0x03ffe000)) | \ 736687c42fSBen Dooks ((cpu_to_le32(s)) & cpu_to_le32(0x1fff))) 7469d99fdcSPrabu Thangamuthu 7569d99fdcSPrabu Thangamuthu u32 des3; /* Reserved */ 7669d99fdcSPrabu Thangamuthu 7769d99fdcSPrabu Thangamuthu u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/ 7869d99fdcSPrabu Thangamuthu u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/ 7969d99fdcSPrabu Thangamuthu 8069d99fdcSPrabu Thangamuthu u32 des6; /* Lower 32-bits of Next Descriptor Address */ 8169d99fdcSPrabu Thangamuthu u32 des7; /* Upper 32-bits of Next Descriptor Address */ 8269d99fdcSPrabu Thangamuthu }; 8369d99fdcSPrabu Thangamuthu 84f95f3850SWill Newton struct idmac_desc { 856687c42fSBen Dooks __le32 des0; /* Control Descriptor */ 86f95f3850SWill Newton #define IDMAC_DES0_DIC BIT(1) 87f95f3850SWill Newton #define IDMAC_DES0_LD BIT(2) 88f95f3850SWill Newton #define IDMAC_DES0_FD BIT(3) 89f95f3850SWill Newton #define IDMAC_DES0_CH BIT(4) 90f95f3850SWill Newton #define IDMAC_DES0_ER BIT(5) 91f95f3850SWill Newton #define IDMAC_DES0_CES BIT(30) 92f95f3850SWill Newton #define IDMAC_DES0_OWN BIT(31) 93f95f3850SWill Newton 946687c42fSBen Dooks __le32 des1; /* Buffer sizes */ 95f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \ 969b7bbe10SShashidhar Hiremath ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) 97f95f3850SWill Newton 986687c42fSBen Dooks __le32 des2; /* buffer 1 physical address */ 99f95f3850SWill Newton 1006687c42fSBen Dooks __le32 des3; /* buffer 2 physical address */ 101f95f3850SWill Newton }; 1025959b32eSAlexey Brodkin 1035959b32eSAlexey Brodkin /* Each descriptor can transfer up to 4KB of data in chained mode */ 1045959b32eSAlexey Brodkin #define DW_MCI_DESC_DATA_LENGTH 0x1000 105f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 106f95f3850SWill Newton 1073a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host); 108536f6b91SSonny Rao static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); 1090bdbd0e8SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc); 11031bff450SSeungwon Jeon 111f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 112f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 113f95f3850SWill Newton { 114f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 115f95f3850SWill Newton struct mmc_request *mrq; 116f95f3850SWill Newton struct mmc_command *cmd; 117f95f3850SWill Newton struct mmc_command *stop; 118f95f3850SWill Newton struct mmc_data *data; 119f95f3850SWill Newton 120f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 121f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 122f95f3850SWill Newton mrq = slot->mrq; 123f95f3850SWill Newton 124f95f3850SWill Newton if (mrq) { 125f95f3850SWill Newton cmd = mrq->cmd; 126f95f3850SWill Newton data = mrq->data; 127f95f3850SWill Newton stop = mrq->stop; 128f95f3850SWill Newton 129f95f3850SWill Newton if (cmd) 130f95f3850SWill Newton seq_printf(s, 131f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 132f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 133f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 134f95f3850SWill Newton cmd->resp[2], cmd->error); 135f95f3850SWill Newton if (data) 136f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 137f95f3850SWill Newton data->bytes_xfered, data->blocks, 138f95f3850SWill Newton data->blksz, data->flags, data->error); 139f95f3850SWill Newton if (stop) 140f95f3850SWill Newton seq_printf(s, 141f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 142f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 143f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 144f95f3850SWill Newton stop->resp[2], stop->error); 145f95f3850SWill Newton } 146f95f3850SWill Newton 147f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 148f95f3850SWill Newton 149f95f3850SWill Newton return 0; 150f95f3850SWill Newton } 151f95f3850SWill Newton 152f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 153f95f3850SWill Newton { 154f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 155f95f3850SWill Newton } 156f95f3850SWill Newton 157f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 158f95f3850SWill Newton .owner = THIS_MODULE, 159f95f3850SWill Newton .open = dw_mci_req_open, 160f95f3850SWill Newton .read = seq_read, 161f95f3850SWill Newton .llseek = seq_lseek, 162f95f3850SWill Newton .release = single_release, 163f95f3850SWill Newton }; 164f95f3850SWill Newton 165f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 166f95f3850SWill Newton { 167f95f3850SWill Newton seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); 168f95f3850SWill Newton seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); 169f95f3850SWill Newton seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); 170f95f3850SWill Newton seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); 171f95f3850SWill Newton seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); 172f95f3850SWill Newton seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); 173f95f3850SWill Newton 174f95f3850SWill Newton return 0; 175f95f3850SWill Newton } 176f95f3850SWill Newton 177f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 178f95f3850SWill Newton { 179f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 180f95f3850SWill Newton } 181f95f3850SWill Newton 182f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 183f95f3850SWill Newton .owner = THIS_MODULE, 184f95f3850SWill Newton .open = dw_mci_regs_open, 185f95f3850SWill Newton .read = seq_read, 186f95f3850SWill Newton .llseek = seq_lseek, 187f95f3850SWill Newton .release = single_release, 188f95f3850SWill Newton }; 189f95f3850SWill Newton 190f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 191f95f3850SWill Newton { 192f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 193f95f3850SWill Newton struct dw_mci *host = slot->host; 194f95f3850SWill Newton struct dentry *root; 195f95f3850SWill Newton struct dentry *node; 196f95f3850SWill Newton 197f95f3850SWill Newton root = mmc->debugfs_root; 198f95f3850SWill Newton if (!root) 199f95f3850SWill Newton return; 200f95f3850SWill Newton 201f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 202f95f3850SWill Newton &dw_mci_regs_fops); 203f95f3850SWill Newton if (!node) 204f95f3850SWill Newton goto err; 205f95f3850SWill Newton 206f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 207f95f3850SWill Newton &dw_mci_req_fops); 208f95f3850SWill Newton if (!node) 209f95f3850SWill Newton goto err; 210f95f3850SWill Newton 211f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 212f95f3850SWill Newton if (!node) 213f95f3850SWill Newton goto err; 214f95f3850SWill Newton 215f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 216f95f3850SWill Newton (u32 *)&host->pending_events); 217f95f3850SWill Newton if (!node) 218f95f3850SWill Newton goto err; 219f95f3850SWill Newton 220f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 221f95f3850SWill Newton (u32 *)&host->completed_events); 222f95f3850SWill Newton if (!node) 223f95f3850SWill Newton goto err; 224f95f3850SWill Newton 225f95f3850SWill Newton return; 226f95f3850SWill Newton 227f95f3850SWill Newton err: 228f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 229f95f3850SWill Newton } 230f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 231f95f3850SWill Newton 23201730558SDoug Anderson static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg); 23301730558SDoug Anderson 234f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 235f95f3850SWill Newton { 236f95f3850SWill Newton struct mmc_data *data; 237800d78bfSThomas Abraham struct dw_mci_slot *slot = mmc_priv(mmc); 23801730558SDoug Anderson struct dw_mci *host = slot->host; 239e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 240f95f3850SWill Newton u32 cmdr; 241f95f3850SWill Newton 2420e3a22c0SShawn Lin cmd->error = -EINPROGRESS; 243f95f3850SWill Newton cmdr = cmd->opcode; 244f95f3850SWill Newton 24590c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 24690c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 24790c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 24890c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 24990c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 250f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 2514a1b27adSJaehoon Chung else if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 252f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 253f95f3850SWill Newton 25401730558SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 25501730558SDoug Anderson u32 clk_en_a; 25601730558SDoug Anderson 25701730558SDoug Anderson /* Special bit makes CMD11 not die */ 25801730558SDoug Anderson cmdr |= SDMMC_CMD_VOLT_SWITCH; 25901730558SDoug Anderson 26001730558SDoug Anderson /* Change state to continue to handle CMD11 weirdness */ 26101730558SDoug Anderson WARN_ON(slot->host->state != STATE_SENDING_CMD); 26201730558SDoug Anderson slot->host->state = STATE_SENDING_CMD11; 26301730558SDoug Anderson 26401730558SDoug Anderson /* 26501730558SDoug Anderson * We need to disable low power mode (automatic clock stop) 26601730558SDoug Anderson * while doing voltage switch so we don't confuse the card, 26701730558SDoug Anderson * since stopping the clock is a specific part of the UHS 26801730558SDoug Anderson * voltage change dance. 26901730558SDoug Anderson * 27001730558SDoug Anderson * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be 27101730558SDoug Anderson * unconditionally turned back on in dw_mci_setup_bus() if it's 27201730558SDoug Anderson * ever called with a non-zero clock. That shouldn't happen 27301730558SDoug Anderson * until the voltage change is all done. 27401730558SDoug Anderson */ 27501730558SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 27601730558SDoug Anderson clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id); 27701730558SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 27801730558SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 27901730558SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 28001730558SDoug Anderson } 28101730558SDoug Anderson 282f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 283f95f3850SWill Newton /* We expect a response, so set this bit */ 284f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 285f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 286f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 287f95f3850SWill Newton } 288f95f3850SWill Newton 289f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 290f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 291f95f3850SWill Newton 292f95f3850SWill Newton data = cmd->data; 293f95f3850SWill Newton if (data) { 294f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 295f95f3850SWill Newton if (data->flags & MMC_DATA_STREAM) 296f95f3850SWill Newton cmdr |= SDMMC_CMD_STRM_MODE; 297f95f3850SWill Newton if (data->flags & MMC_DATA_WRITE) 298f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 299f95f3850SWill Newton } 300f95f3850SWill Newton 301cb27a843SJames Hogan if (drv_data && drv_data->prepare_command) 302cb27a843SJames Hogan drv_data->prepare_command(slot->host, &cmdr); 303800d78bfSThomas Abraham 304f95f3850SWill Newton return cmdr; 305f95f3850SWill Newton } 306f95f3850SWill Newton 30790c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) 30890c2143aSSeungwon Jeon { 30990c2143aSSeungwon Jeon struct mmc_command *stop; 31090c2143aSSeungwon Jeon u32 cmdr; 31190c2143aSSeungwon Jeon 31290c2143aSSeungwon Jeon if (!cmd->data) 31390c2143aSSeungwon Jeon return 0; 31490c2143aSSeungwon Jeon 31590c2143aSSeungwon Jeon stop = &host->stop_abort; 31690c2143aSSeungwon Jeon cmdr = cmd->opcode; 31790c2143aSSeungwon Jeon memset(stop, 0, sizeof(struct mmc_command)); 31890c2143aSSeungwon Jeon 31990c2143aSSeungwon Jeon if (cmdr == MMC_READ_SINGLE_BLOCK || 32090c2143aSSeungwon Jeon cmdr == MMC_READ_MULTIPLE_BLOCK || 32190c2143aSSeungwon Jeon cmdr == MMC_WRITE_BLOCK || 3226c2c6506SUlf Hansson cmdr == MMC_WRITE_MULTIPLE_BLOCK || 3236c2c6506SUlf Hansson cmdr == MMC_SEND_TUNING_BLOCK || 3246c2c6506SUlf Hansson cmdr == MMC_SEND_TUNING_BLOCK_HS200) { 32590c2143aSSeungwon Jeon stop->opcode = MMC_STOP_TRANSMISSION; 32690c2143aSSeungwon Jeon stop->arg = 0; 32790c2143aSSeungwon Jeon stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 32890c2143aSSeungwon Jeon } else if (cmdr == SD_IO_RW_EXTENDED) { 32990c2143aSSeungwon Jeon stop->opcode = SD_IO_RW_DIRECT; 33090c2143aSSeungwon Jeon stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | 33190c2143aSSeungwon Jeon ((cmd->arg >> 28) & 0x7); 33290c2143aSSeungwon Jeon stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; 33390c2143aSSeungwon Jeon } else { 33490c2143aSSeungwon Jeon return 0; 33590c2143aSSeungwon Jeon } 33690c2143aSSeungwon Jeon 33790c2143aSSeungwon Jeon cmdr = stop->opcode | SDMMC_CMD_STOP | 33890c2143aSSeungwon Jeon SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; 33990c2143aSSeungwon Jeon 34090c2143aSSeungwon Jeon return cmdr; 34190c2143aSSeungwon Jeon } 34290c2143aSSeungwon Jeon 3430bdbd0e8SDoug Anderson static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) 3440bdbd0e8SDoug Anderson { 3450bdbd0e8SDoug Anderson unsigned long timeout = jiffies + msecs_to_jiffies(500); 3460bdbd0e8SDoug Anderson 3470bdbd0e8SDoug Anderson /* 3480bdbd0e8SDoug Anderson * Databook says that before issuing a new data transfer command 3490bdbd0e8SDoug Anderson * we need to check to see if the card is busy. Data transfer commands 3500bdbd0e8SDoug Anderson * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that. 3510bdbd0e8SDoug Anderson * 3520bdbd0e8SDoug Anderson * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is 3530bdbd0e8SDoug Anderson * expected. 3540bdbd0e8SDoug Anderson */ 3550bdbd0e8SDoug Anderson if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) && 3560bdbd0e8SDoug Anderson !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) { 3570bdbd0e8SDoug Anderson while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) { 3580bdbd0e8SDoug Anderson if (time_after(jiffies, timeout)) { 3590bdbd0e8SDoug Anderson /* Command will fail; we'll pass error then */ 3600bdbd0e8SDoug Anderson dev_err(host->dev, "Busy; trying anyway\n"); 3610bdbd0e8SDoug Anderson break; 3620bdbd0e8SDoug Anderson } 3630bdbd0e8SDoug Anderson udelay(10); 3640bdbd0e8SDoug Anderson } 3650bdbd0e8SDoug Anderson } 3660bdbd0e8SDoug Anderson } 3670bdbd0e8SDoug Anderson 368f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 369f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 370f95f3850SWill Newton { 371f95f3850SWill Newton host->cmd = cmd; 3724a90920cSThomas Abraham dev_vdbg(host->dev, 373f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 374f95f3850SWill Newton cmd->arg, cmd_flags); 375f95f3850SWill Newton 376f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 3770e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 3780bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd_flags); 379f95f3850SWill Newton 380f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 381f95f3850SWill Newton } 382f95f3850SWill Newton 38390c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 384f95f3850SWill Newton { 38590c2143aSSeungwon Jeon struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; 3860e3a22c0SShawn Lin 38790c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 388f95f3850SWill Newton } 389f95f3850SWill Newton 390f95f3850SWill Newton /* DMA interface functions */ 391f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 392f95f3850SWill Newton { 39303e8cb53SJames Hogan if (host->using_dma) { 394f95f3850SWill Newton host->dma_ops->stop(host); 395f95f3850SWill Newton host->dma_ops->cleanup(host); 396aa50f259SSeungwon Jeon } 397aa50f259SSeungwon Jeon 398f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 399f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 400f95f3850SWill Newton } 401f95f3850SWill Newton 4029aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 4039aa51408SSeungwon Jeon { 4049aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 4059aa51408SSeungwon Jeon return DMA_TO_DEVICE; 4069aa51408SSeungwon Jeon else 4079aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 4089aa51408SSeungwon Jeon } 4099aa51408SSeungwon Jeon 4109beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 411f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 412f95f3850SWill Newton { 413f95f3850SWill Newton struct mmc_data *data = host->data; 414f95f3850SWill Newton 415f95f3850SWill Newton if (data) 4169aa51408SSeungwon Jeon if (!data->host_cookie) 4174a90920cSThomas Abraham dma_unmap_sg(host->dev, 4189aa51408SSeungwon Jeon data->sg, 4199aa51408SSeungwon Jeon data->sg_len, 4209aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 421f95f3850SWill Newton } 422f95f3850SWill Newton 4235ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host) 4245ce9d961SSeungwon Jeon { 4255ce9d961SSeungwon Jeon u32 bmod = mci_readl(host, BMOD); 4265ce9d961SSeungwon Jeon /* Software reset of DMA */ 4275ce9d961SSeungwon Jeon bmod |= SDMMC_IDMAC_SWRESET; 4285ce9d961SSeungwon Jeon mci_writel(host, BMOD, bmod); 4295ce9d961SSeungwon Jeon } 4305ce9d961SSeungwon Jeon 431f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 432f95f3850SWill Newton { 433f95f3850SWill Newton u32 temp; 434f95f3850SWill Newton 435f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 436f95f3850SWill Newton temp = mci_readl(host, CTRL); 437f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 438f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 439f95f3850SWill Newton mci_writel(host, CTRL, temp); 440f95f3850SWill Newton 441f95f3850SWill Newton /* Stop the IDMAC running */ 442f95f3850SWill Newton temp = mci_readl(host, BMOD); 443a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 4445ce9d961SSeungwon Jeon temp |= SDMMC_IDMAC_SWRESET; 445f95f3850SWill Newton mci_writel(host, BMOD, temp); 446f95f3850SWill Newton } 447f95f3850SWill Newton 448f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host) 449f95f3850SWill Newton { 450f95f3850SWill Newton struct mmc_data *data = host->data; 451f95f3850SWill Newton 4524a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 453f95f3850SWill Newton 454f95f3850SWill Newton host->dma_ops->cleanup(host); 455f95f3850SWill Newton 456f95f3850SWill Newton /* 457f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 458f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 459f95f3850SWill Newton */ 460f95f3850SWill Newton if (data) { 461f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 462f95f3850SWill Newton tasklet_schedule(&host->tasklet); 463f95f3850SWill Newton } 464f95f3850SWill Newton } 465f95f3850SWill Newton 466f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, 467f95f3850SWill Newton unsigned int sg_len) 468f95f3850SWill Newton { 4695959b32eSAlexey Brodkin unsigned int desc_len; 470f95f3850SWill Newton int i; 4710e3a22c0SShawn Lin 47269d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 4735959b32eSAlexey Brodkin struct idmac_desc_64addr *desc_first, *desc_last, *desc; 47469d99fdcSPrabu Thangamuthu 4755959b32eSAlexey Brodkin desc_first = desc_last = desc = host->sg_cpu; 4765959b32eSAlexey Brodkin 4775959b32eSAlexey Brodkin for (i = 0; i < sg_len; i++) { 47869d99fdcSPrabu Thangamuthu unsigned int length = sg_dma_len(&data->sg[i]); 4790e3a22c0SShawn Lin 48069d99fdcSPrabu Thangamuthu u64 mem_addr = sg_dma_address(&data->sg[i]); 48169d99fdcSPrabu Thangamuthu 4825959b32eSAlexey Brodkin for ( ; length ; desc++) { 4835959b32eSAlexey Brodkin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 4845959b32eSAlexey Brodkin length : DW_MCI_DESC_DATA_LENGTH; 4855959b32eSAlexey Brodkin 4865959b32eSAlexey Brodkin length -= desc_len; 4875959b32eSAlexey Brodkin 48869d99fdcSPrabu Thangamuthu /* 4895959b32eSAlexey Brodkin * Set the OWN bit and disable interrupts 4905959b32eSAlexey Brodkin * for this descriptor 49169d99fdcSPrabu Thangamuthu */ 49269d99fdcSPrabu Thangamuthu desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | 49369d99fdcSPrabu Thangamuthu IDMAC_DES0_CH; 4945959b32eSAlexey Brodkin 49569d99fdcSPrabu Thangamuthu /* Buffer length */ 4965959b32eSAlexey Brodkin IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len); 49769d99fdcSPrabu Thangamuthu 49869d99fdcSPrabu Thangamuthu /* Physical address to DMA to/from */ 49969d99fdcSPrabu Thangamuthu desc->des4 = mem_addr & 0xffffffff; 50069d99fdcSPrabu Thangamuthu desc->des5 = mem_addr >> 32; 5015959b32eSAlexey Brodkin 5025959b32eSAlexey Brodkin /* Update physical address for the next desc */ 5035959b32eSAlexey Brodkin mem_addr += desc_len; 5045959b32eSAlexey Brodkin 5055959b32eSAlexey Brodkin /* Save pointer to the last descriptor */ 5065959b32eSAlexey Brodkin desc_last = desc; 5075959b32eSAlexey Brodkin } 50869d99fdcSPrabu Thangamuthu } 50969d99fdcSPrabu Thangamuthu 51069d99fdcSPrabu Thangamuthu /* Set first descriptor */ 5115959b32eSAlexey Brodkin desc_first->des0 |= IDMAC_DES0_FD; 51269d99fdcSPrabu Thangamuthu 51369d99fdcSPrabu Thangamuthu /* Set last descriptor */ 5145959b32eSAlexey Brodkin desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 5155959b32eSAlexey Brodkin desc_last->des0 |= IDMAC_DES0_LD; 51669d99fdcSPrabu Thangamuthu 51769d99fdcSPrabu Thangamuthu } else { 5185959b32eSAlexey Brodkin struct idmac_desc *desc_first, *desc_last, *desc; 519f95f3850SWill Newton 5205959b32eSAlexey Brodkin desc_first = desc_last = desc = host->sg_cpu; 5215959b32eSAlexey Brodkin 5225959b32eSAlexey Brodkin for (i = 0; i < sg_len; i++) { 523f95f3850SWill Newton unsigned int length = sg_dma_len(&data->sg[i]); 5240e3a22c0SShawn Lin 525f95f3850SWill Newton u32 mem_addr = sg_dma_address(&data->sg[i]); 526f95f3850SWill Newton 5275959b32eSAlexey Brodkin for ( ; length ; desc++) { 5285959b32eSAlexey Brodkin desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ? 5295959b32eSAlexey Brodkin length : DW_MCI_DESC_DATA_LENGTH; 5305959b32eSAlexey Brodkin 5315959b32eSAlexey Brodkin length -= desc_len; 5325959b32eSAlexey Brodkin 53369d99fdcSPrabu Thangamuthu /* 5345959b32eSAlexey Brodkin * Set the OWN bit and disable interrupts 5355959b32eSAlexey Brodkin * for this descriptor 53669d99fdcSPrabu Thangamuthu */ 5376687c42fSBen Dooks desc->des0 = cpu_to_le32(IDMAC_DES0_OWN | 5385959b32eSAlexey Brodkin IDMAC_DES0_DIC | 5395959b32eSAlexey Brodkin IDMAC_DES0_CH); 5405959b32eSAlexey Brodkin 541f95f3850SWill Newton /* Buffer length */ 5425959b32eSAlexey Brodkin IDMAC_SET_BUFFER1_SIZE(desc, desc_len); 543f95f3850SWill Newton 544f95f3850SWill Newton /* Physical address to DMA to/from */ 5456687c42fSBen Dooks desc->des2 = cpu_to_le32(mem_addr); 5465959b32eSAlexey Brodkin 5475959b32eSAlexey Brodkin /* Update physical address for the next desc */ 5485959b32eSAlexey Brodkin mem_addr += desc_len; 5495959b32eSAlexey Brodkin 5505959b32eSAlexey Brodkin /* Save pointer to the last descriptor */ 5515959b32eSAlexey Brodkin desc_last = desc; 5525959b32eSAlexey Brodkin } 553f95f3850SWill Newton } 554f95f3850SWill Newton 555f95f3850SWill Newton /* Set first descriptor */ 5565959b32eSAlexey Brodkin desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD); 557f95f3850SWill Newton 558f95f3850SWill Newton /* Set last descriptor */ 5595959b32eSAlexey Brodkin desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | 5605959b32eSAlexey Brodkin IDMAC_DES0_DIC)); 5615959b32eSAlexey Brodkin desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD); 56269d99fdcSPrabu Thangamuthu } 563f95f3850SWill Newton 5640e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 565f95f3850SWill Newton } 566f95f3850SWill Newton 567f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 568f95f3850SWill Newton { 569f95f3850SWill Newton u32 temp; 570f95f3850SWill Newton 571f95f3850SWill Newton dw_mci_translate_sglist(host, host->data, sg_len); 572f95f3850SWill Newton 573536f6b91SSonny Rao /* Make sure to reset DMA in case we did PIO before this */ 574536f6b91SSonny Rao dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET); 575536f6b91SSonny Rao dw_mci_idmac_reset(host); 576536f6b91SSonny Rao 577f95f3850SWill Newton /* Select IDMAC interface */ 578f95f3850SWill Newton temp = mci_readl(host, CTRL); 579f95f3850SWill Newton temp |= SDMMC_CTRL_USE_IDMAC; 580f95f3850SWill Newton mci_writel(host, CTRL, temp); 581f95f3850SWill Newton 5820e3a22c0SShawn Lin /* drain writebuffer */ 583f95f3850SWill Newton wmb(); 584f95f3850SWill Newton 585f95f3850SWill Newton /* Enable the IDMAC */ 586f95f3850SWill Newton temp = mci_readl(host, BMOD); 587a5289a43SJaehoon Chung temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 588f95f3850SWill Newton mci_writel(host, BMOD, temp); 589f95f3850SWill Newton 590f95f3850SWill Newton /* Start it running */ 591f95f3850SWill Newton mci_writel(host, PLDMND, 1); 592f95f3850SWill Newton } 593f95f3850SWill Newton 594f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 595f95f3850SWill Newton { 596897b69e7SSeungwon Jeon int i; 597f95f3850SWill Newton 59869d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 59969d99fdcSPrabu Thangamuthu struct idmac_desc_64addr *p; 60069d99fdcSPrabu Thangamuthu /* Number of descriptors in the ring buffer */ 60169d99fdcSPrabu Thangamuthu host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr); 60269d99fdcSPrabu Thangamuthu 60369d99fdcSPrabu Thangamuthu /* Forward link the descriptor list */ 60469d99fdcSPrabu Thangamuthu for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; 60569d99fdcSPrabu Thangamuthu i++, p++) { 60669d99fdcSPrabu Thangamuthu p->des6 = (host->sg_dma + 60769d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 60869d99fdcSPrabu Thangamuthu (i + 1))) & 0xffffffff; 60969d99fdcSPrabu Thangamuthu 61069d99fdcSPrabu Thangamuthu p->des7 = (u64)(host->sg_dma + 61169d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 61269d99fdcSPrabu Thangamuthu (i + 1))) >> 32; 61369d99fdcSPrabu Thangamuthu /* Initialize reserved and buffer size fields to "0" */ 61469d99fdcSPrabu Thangamuthu p->des1 = 0; 61569d99fdcSPrabu Thangamuthu p->des2 = 0; 61669d99fdcSPrabu Thangamuthu p->des3 = 0; 61769d99fdcSPrabu Thangamuthu } 61869d99fdcSPrabu Thangamuthu 61969d99fdcSPrabu Thangamuthu /* Set the last descriptor as the end-of-ring descriptor */ 62069d99fdcSPrabu Thangamuthu p->des6 = host->sg_dma & 0xffffffff; 62169d99fdcSPrabu Thangamuthu p->des7 = (u64)host->sg_dma >> 32; 62269d99fdcSPrabu Thangamuthu p->des0 = IDMAC_DES0_ER; 62369d99fdcSPrabu Thangamuthu 62469d99fdcSPrabu Thangamuthu } else { 62569d99fdcSPrabu Thangamuthu struct idmac_desc *p; 626f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 627f95f3850SWill Newton host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 628f95f3850SWill Newton 629f95f3850SWill Newton /* Forward link the descriptor list */ 6300e3a22c0SShawn Lin for (i = 0, p = host->sg_cpu; 6310e3a22c0SShawn Lin i < host->ring_size - 1; 6320e3a22c0SShawn Lin i++, p++) { 6336687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma + 6346687c42fSBen Dooks (sizeof(struct idmac_desc) * (i + 1))); 6354b244724SZhangfei Gao p->des1 = 0; 6364b244724SZhangfei Gao } 637f95f3850SWill Newton 638f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 6396687c42fSBen Dooks p->des3 = cpu_to_le32(host->sg_dma); 6406687c42fSBen Dooks p->des0 = cpu_to_le32(IDMAC_DES0_ER); 64169d99fdcSPrabu Thangamuthu } 642f95f3850SWill Newton 6435ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 644141a712aSSeungwon Jeon 64569d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 64669d99fdcSPrabu Thangamuthu /* Mask out interrupts - get Tx & Rx complete only */ 64769d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, IDMAC_INT_CLR); 64869d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI | 64969d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 65069d99fdcSPrabu Thangamuthu 65169d99fdcSPrabu Thangamuthu /* Set the descriptor base address */ 65269d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff); 65369d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32); 65469d99fdcSPrabu Thangamuthu 65569d99fdcSPrabu Thangamuthu } else { 656f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 657fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 65869d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | 65969d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 660f95f3850SWill Newton 661f95f3850SWill Newton /* Set the descriptor base address */ 662f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 66369d99fdcSPrabu Thangamuthu } 66469d99fdcSPrabu Thangamuthu 665f95f3850SWill Newton return 0; 666f95f3850SWill Newton } 667f95f3850SWill Newton 6688e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 669885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 670885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 671885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 672885c3e80SSeungwon Jeon .complete = dw_mci_idmac_complete_dma, 673885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 674885c3e80SSeungwon Jeon }; 675885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */ 676885c3e80SSeungwon Jeon 6779aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 6789aa51408SSeungwon Jeon struct mmc_data *data, 6799aa51408SSeungwon Jeon bool next) 680f95f3850SWill Newton { 681f95f3850SWill Newton struct scatterlist *sg; 6829aa51408SSeungwon Jeon unsigned int i, sg_len; 683f95f3850SWill Newton 6849aa51408SSeungwon Jeon if (!next && data->host_cookie) 6859aa51408SSeungwon Jeon return data->host_cookie; 686f95f3850SWill Newton 687f95f3850SWill Newton /* 688f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 689f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 690f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 691f95f3850SWill Newton */ 692f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 693f95f3850SWill Newton return -EINVAL; 6949aa51408SSeungwon Jeon 695f95f3850SWill Newton if (data->blksz & 3) 696f95f3850SWill Newton return -EINVAL; 697f95f3850SWill Newton 698f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 699f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 700f95f3850SWill Newton return -EINVAL; 701f95f3850SWill Newton } 702f95f3850SWill Newton 7034a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 7049aa51408SSeungwon Jeon data->sg, 7059aa51408SSeungwon Jeon data->sg_len, 7069aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 7079aa51408SSeungwon Jeon if (sg_len == 0) 7089aa51408SSeungwon Jeon return -EINVAL; 7099aa51408SSeungwon Jeon 7109aa51408SSeungwon Jeon if (next) 7119aa51408SSeungwon Jeon data->host_cookie = sg_len; 7129aa51408SSeungwon Jeon 7139aa51408SSeungwon Jeon return sg_len; 7149aa51408SSeungwon Jeon } 7159aa51408SSeungwon Jeon 7169aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 7179aa51408SSeungwon Jeon struct mmc_request *mrq, 7189aa51408SSeungwon Jeon bool is_first_req) 7199aa51408SSeungwon Jeon { 7209aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 7219aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 7229aa51408SSeungwon Jeon 7239aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 7249aa51408SSeungwon Jeon return; 7259aa51408SSeungwon Jeon 7269aa51408SSeungwon Jeon if (data->host_cookie) { 7279aa51408SSeungwon Jeon data->host_cookie = 0; 7289aa51408SSeungwon Jeon return; 7299aa51408SSeungwon Jeon } 7309aa51408SSeungwon Jeon 7319aa51408SSeungwon Jeon if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) 7329aa51408SSeungwon Jeon data->host_cookie = 0; 7339aa51408SSeungwon Jeon } 7349aa51408SSeungwon Jeon 7359aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 7369aa51408SSeungwon Jeon struct mmc_request *mrq, 7379aa51408SSeungwon Jeon int err) 7389aa51408SSeungwon Jeon { 7399aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 7409aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 7419aa51408SSeungwon Jeon 7429aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 7439aa51408SSeungwon Jeon return; 7449aa51408SSeungwon Jeon 7459aa51408SSeungwon Jeon if (data->host_cookie) 7464a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 7479aa51408SSeungwon Jeon data->sg, 7489aa51408SSeungwon Jeon data->sg_len, 7499aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 7509aa51408SSeungwon Jeon data->host_cookie = 0; 7519aa51408SSeungwon Jeon } 7529aa51408SSeungwon Jeon 75352426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 75452426899SSeungwon Jeon { 75552426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC 75652426899SSeungwon Jeon unsigned int blksz = data->blksz; 75752426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 75852426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 75952426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 76052426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 7610e3a22c0SShawn Lin int idx = ARRAY_SIZE(mszs) - 1; 76252426899SSeungwon Jeon 76352426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 76452426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 76552426899SSeungwon Jeon 76652426899SSeungwon Jeon /* 76752426899SSeungwon Jeon * MSIZE is '1', 76852426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 76952426899SSeungwon Jeon */ 77052426899SSeungwon Jeon if (blksz % fifo_width) { 77152426899SSeungwon Jeon msize = 0; 77252426899SSeungwon Jeon rx_wmark = 1; 77352426899SSeungwon Jeon goto done; 77452426899SSeungwon Jeon } 77552426899SSeungwon Jeon 77652426899SSeungwon Jeon do { 77752426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 77852426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 77952426899SSeungwon Jeon msize = idx; 78052426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 78152426899SSeungwon Jeon break; 78252426899SSeungwon Jeon } 78352426899SSeungwon Jeon } while (--idx > 0); 78452426899SSeungwon Jeon /* 78552426899SSeungwon Jeon * If idx is '0', it won't be tried 78652426899SSeungwon Jeon * Thus, initial values are uesed 78752426899SSeungwon Jeon */ 78852426899SSeungwon Jeon done: 78952426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 79052426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 79152426899SSeungwon Jeon #endif 79252426899SSeungwon Jeon } 79352426899SSeungwon Jeon 794f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) 795f1d2736cSSeungwon Jeon { 796f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 797f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 798f1d2736cSSeungwon Jeon u16 thld_size; 799f1d2736cSSeungwon Jeon 800f1d2736cSSeungwon Jeon WARN_ON(!(data->flags & MMC_DATA_READ)); 801f1d2736cSSeungwon Jeon 80266dfd101SJames Hogan /* 80366dfd101SJames Hogan * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is 80466dfd101SJames Hogan * in the FIFO region, so we really shouldn't access it). 80566dfd101SJames Hogan */ 80666dfd101SJames Hogan if (host->verid < DW_MMC_240A) 80766dfd101SJames Hogan return; 80866dfd101SJames Hogan 809f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 810488b8d63SJaehoon Chung host->timing != MMC_TIMING_MMC_HS400 && 811f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 812f1d2736cSSeungwon Jeon goto disable; 813f1d2736cSSeungwon Jeon 814f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 815f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 816f1d2736cSSeungwon Jeon 817f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 818f1d2736cSSeungwon Jeon goto disable; 819f1d2736cSSeungwon Jeon 820f1d2736cSSeungwon Jeon /* 821f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 822f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 823f1d2736cSSeungwon Jeon * Currently just choose blksz. 824f1d2736cSSeungwon Jeon */ 825f1d2736cSSeungwon Jeon thld_size = blksz; 826f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1)); 827f1d2736cSSeungwon Jeon return; 828f1d2736cSSeungwon Jeon 829f1d2736cSSeungwon Jeon disable: 830f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0)); 831f1d2736cSSeungwon Jeon } 832f1d2736cSSeungwon Jeon 8339aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 8349aa51408SSeungwon Jeon { 835f8c58c11SDoug Anderson unsigned long irqflags; 8369aa51408SSeungwon Jeon int sg_len; 8379aa51408SSeungwon Jeon u32 temp; 8389aa51408SSeungwon Jeon 8399aa51408SSeungwon Jeon host->using_dma = 0; 8409aa51408SSeungwon Jeon 8419aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 8429aa51408SSeungwon Jeon if (!host->use_dma) 8439aa51408SSeungwon Jeon return -ENODEV; 8449aa51408SSeungwon Jeon 8459aa51408SSeungwon Jeon sg_len = dw_mci_pre_dma_transfer(host, data, 0); 846a99aa9b9SSeungwon Jeon if (sg_len < 0) { 847a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 8489aa51408SSeungwon Jeon return sg_len; 849a99aa9b9SSeungwon Jeon } 8509aa51408SSeungwon Jeon 85103e8cb53SJames Hogan host->using_dma = 1; 85203e8cb53SJames Hogan 8534a90920cSThomas Abraham dev_vdbg(host->dev, 854f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 855f95f3850SWill Newton (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, 856f95f3850SWill Newton sg_len); 857f95f3850SWill Newton 85852426899SSeungwon Jeon /* 85952426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 86052426899SSeungwon Jeon * If current block size is same with previous size, 86152426899SSeungwon Jeon * no need to update fifoth. 86252426899SSeungwon Jeon */ 86352426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 86452426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 86552426899SSeungwon Jeon 866f95f3850SWill Newton /* Enable the DMA interface */ 867f95f3850SWill Newton temp = mci_readl(host, CTRL); 868f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 869f95f3850SWill Newton mci_writel(host, CTRL, temp); 870f95f3850SWill Newton 871f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 872f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 873f95f3850SWill Newton temp = mci_readl(host, INTMASK); 874f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 875f95f3850SWill Newton mci_writel(host, INTMASK, temp); 876f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 877f95f3850SWill Newton 878f95f3850SWill Newton host->dma_ops->start(host, sg_len); 879f95f3850SWill Newton 880f95f3850SWill Newton return 0; 881f95f3850SWill Newton } 882f95f3850SWill Newton 883f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 884f95f3850SWill Newton { 885f8c58c11SDoug Anderson unsigned long irqflags; 8860e3a22c0SShawn Lin int flags = SG_MITER_ATOMIC; 887f95f3850SWill Newton u32 temp; 888f95f3850SWill Newton 889f95f3850SWill Newton data->error = -EINPROGRESS; 890f95f3850SWill Newton 891f95f3850SWill Newton WARN_ON(host->data); 892f95f3850SWill Newton host->sg = NULL; 893f95f3850SWill Newton host->data = data; 894f95f3850SWill Newton 895f1d2736cSSeungwon Jeon if (data->flags & MMC_DATA_READ) { 89655c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 897f1d2736cSSeungwon Jeon dw_mci_ctrl_rd_thld(host, data); 898f1d2736cSSeungwon Jeon } else { 89955c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 900f1d2736cSSeungwon Jeon } 90155c5efbcSJames Hogan 902f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 903f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 904f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 905f9c2a0dcSSeungwon Jeon else 906f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 907f9c2a0dcSSeungwon Jeon 908f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 909f95f3850SWill Newton host->sg = data->sg; 91034b664a2SJames Hogan host->part_buf_start = 0; 91134b664a2SJames Hogan host->part_buf_count = 0; 912f95f3850SWill Newton 913b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 914f8c58c11SDoug Anderson 915f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 916f95f3850SWill Newton temp = mci_readl(host, INTMASK); 917f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 918f95f3850SWill Newton mci_writel(host, INTMASK, temp); 919f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 920f95f3850SWill Newton 921f95f3850SWill Newton temp = mci_readl(host, CTRL); 922f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 923f95f3850SWill Newton mci_writel(host, CTRL, temp); 92452426899SSeungwon Jeon 92552426899SSeungwon Jeon /* 92652426899SSeungwon Jeon * Use the initial fifoth_val for PIO mode. 92752426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 92852426899SSeungwon Jeon * prev_blksz should be invalidated. 92952426899SSeungwon Jeon */ 93052426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 93152426899SSeungwon Jeon host->prev_blksz = 0; 93252426899SSeungwon Jeon } else { 93352426899SSeungwon Jeon /* 93452426899SSeungwon Jeon * Keep the current block size. 93552426899SSeungwon Jeon * It will be used to decide whether to update 93652426899SSeungwon Jeon * fifoth register next time. 93752426899SSeungwon Jeon */ 93852426899SSeungwon Jeon host->prev_blksz = data->blksz; 939f95f3850SWill Newton } 940f95f3850SWill Newton } 941f95f3850SWill Newton 942f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 943f95f3850SWill Newton { 944f95f3850SWill Newton struct dw_mci *host = slot->host; 945f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 946f95f3850SWill Newton unsigned int cmd_status = 0; 947f95f3850SWill Newton 948f95f3850SWill Newton mci_writel(host, CMDARG, arg); 9490e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 9500bdbd0e8SDoug Anderson dw_mci_wait_while_busy(host, cmd); 951f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 952f95f3850SWill Newton 953f95f3850SWill Newton while (time_before(jiffies, timeout)) { 954f95f3850SWill Newton cmd_status = mci_readl(host, CMD); 955f95f3850SWill Newton if (!(cmd_status & SDMMC_CMD_START)) 956f95f3850SWill Newton return; 957f95f3850SWill Newton } 958f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 959f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 960f95f3850SWill Newton cmd, arg, cmd_status); 961f95f3850SWill Newton } 962f95f3850SWill Newton 963ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 964f95f3850SWill Newton { 965f95f3850SWill Newton struct dw_mci *host = slot->host; 966fdf492a1SDoug Anderson unsigned int clock = slot->clock; 967f95f3850SWill Newton u32 div; 9689623b5b9SDoug Anderson u32 clk_en_a; 96901730558SDoug Anderson u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT; 97001730558SDoug Anderson 97101730558SDoug Anderson /* We must continue to set bit 28 in CMD until the change is complete */ 97201730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) 97301730558SDoug Anderson sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; 974f95f3850SWill Newton 975fdf492a1SDoug Anderson if (!clock) { 976fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 97701730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 978fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 979fdf492a1SDoug Anderson div = host->bus_hz / clock; 980fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 981f95f3850SWill Newton /* 982f95f3850SWill Newton * move the + 1 after the divide to prevent 983f95f3850SWill Newton * over-clocking the card. 984f95f3850SWill Newton */ 985e419990bSSeungwon Jeon div += 1; 986e419990bSSeungwon Jeon 987fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 988f95f3850SWill Newton 989fdf492a1SDoug Anderson if ((clock << div) != slot->__clk_old || force_clkinit) 990f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 991fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 992fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 993fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 994fdf492a1SDoug Anderson host->bus_hz, div); 995f95f3850SWill Newton 996f95f3850SWill Newton /* disable clock */ 997f95f3850SWill Newton mci_writel(host, CLKENA, 0); 998f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 999f95f3850SWill Newton 1000f95f3850SWill Newton /* inform CIU */ 100101730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1002f95f3850SWill Newton 1003f95f3850SWill Newton /* set clock to desired speed */ 1004f95f3850SWill Newton mci_writel(host, CLKDIV, div); 1005f95f3850SWill Newton 1006f95f3850SWill Newton /* inform CIU */ 100701730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1008f95f3850SWill Newton 10099623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 10109623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 1011b24c8b26SDoug Anderson if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) 10129623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 10139623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 1014f95f3850SWill Newton 1015f95f3850SWill Newton /* inform CIU */ 101601730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 1017f95f3850SWill Newton 1018fdf492a1SDoug Anderson /* keep the clock with reflecting clock dividor */ 1019fdf492a1SDoug Anderson slot->__clk_old = clock << div; 1020f95f3850SWill Newton } 1021f95f3850SWill Newton 1022fdf492a1SDoug Anderson host->current_speed = clock; 1023fdf492a1SDoug Anderson 1024f95f3850SWill Newton /* Set the current slot bus width */ 10251d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 1026f95f3850SWill Newton } 1027f95f3850SWill Newton 1028053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 1029053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 1030053b3ce6SSeungwon Jeon struct mmc_command *cmd) 1031f95f3850SWill Newton { 1032f95f3850SWill Newton struct mmc_request *mrq; 1033f95f3850SWill Newton struct mmc_data *data; 1034f95f3850SWill Newton u32 cmdflags; 1035f95f3850SWill Newton 1036f95f3850SWill Newton mrq = slot->mrq; 1037f95f3850SWill Newton 1038f95f3850SWill Newton host->cur_slot = slot; 1039f95f3850SWill Newton host->mrq = mrq; 1040f95f3850SWill Newton 1041f95f3850SWill Newton host->pending_events = 0; 1042f95f3850SWill Newton host->completed_events = 0; 1043e352c813SSeungwon Jeon host->cmd_status = 0; 1044f95f3850SWill Newton host->data_status = 0; 1045e352c813SSeungwon Jeon host->dir_status = 0; 1046f95f3850SWill Newton 1047053b3ce6SSeungwon Jeon data = cmd->data; 1048f95f3850SWill Newton if (data) { 1049f16afa88SJaehoon Chung mci_writel(host, TMOUT, 0xFFFFFFFF); 1050f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 1051f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 1052f95f3850SWill Newton } 1053f95f3850SWill Newton 1054f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 1055f95f3850SWill Newton 1056f95f3850SWill Newton /* this is the first command, send the initialization clock */ 1057f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 1058f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 1059f95f3850SWill Newton 1060f95f3850SWill Newton if (data) { 1061f95f3850SWill Newton dw_mci_submit_data(host, data); 10620e3a22c0SShawn Lin wmb(); /* drain writebuffer */ 1063f95f3850SWill Newton } 1064f95f3850SWill Newton 1065f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 1066f95f3850SWill Newton 10675c935165SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 106849ba0302SDoug Anderson unsigned long irqflags; 106949ba0302SDoug Anderson 10705c935165SDoug Anderson /* 10718886a6fdSDoug Anderson * Databook says to fail after 2ms w/ no response, but evidence 10728886a6fdSDoug Anderson * shows that sometimes the cmd11 interrupt takes over 130ms. 10738886a6fdSDoug Anderson * We'll set to 500ms, plus an extra jiffy just in case jiffies 10748886a6fdSDoug Anderson * is just about to roll over. 107549ba0302SDoug Anderson * 107649ba0302SDoug Anderson * We do this whole thing under spinlock and only if the 107749ba0302SDoug Anderson * command hasn't already completed (indicating the the irq 107849ba0302SDoug Anderson * already ran so we don't want the timeout). 10795c935165SDoug Anderson */ 108049ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 108149ba0302SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) 10825c935165SDoug Anderson mod_timer(&host->cmd11_timer, 10838886a6fdSDoug Anderson jiffies + msecs_to_jiffies(500) + 1); 108449ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 10855c935165SDoug Anderson } 10865c935165SDoug Anderson 1087f95f3850SWill Newton if (mrq->stop) 1088f95f3850SWill Newton host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 108990c2143aSSeungwon Jeon else 109090c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 1091f95f3850SWill Newton } 1092f95f3850SWill Newton 1093053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 1094053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 1095053b3ce6SSeungwon Jeon { 1096053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 1097053b3ce6SSeungwon Jeon struct mmc_command *cmd; 1098053b3ce6SSeungwon Jeon 1099053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 1100053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 1101053b3ce6SSeungwon Jeon } 1102053b3ce6SSeungwon Jeon 11037456caaeSJames Hogan /* must be called with host->lock held */ 1104f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 1105f95f3850SWill Newton struct mmc_request *mrq) 1106f95f3850SWill Newton { 1107f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 1108f95f3850SWill Newton host->state); 1109f95f3850SWill Newton 1110f95f3850SWill Newton slot->mrq = mrq; 1111f95f3850SWill Newton 111201730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) { 111301730558SDoug Anderson dev_warn(&slot->mmc->class_dev, 111401730558SDoug Anderson "Voltage change didn't complete\n"); 111501730558SDoug Anderson /* 111601730558SDoug Anderson * this case isn't expected to happen, so we can 111701730558SDoug Anderson * either crash here or just try to continue on 111801730558SDoug Anderson * in the closest possible state 111901730558SDoug Anderson */ 112001730558SDoug Anderson host->state = STATE_IDLE; 112101730558SDoug Anderson } 112201730558SDoug Anderson 1123f95f3850SWill Newton if (host->state == STATE_IDLE) { 1124f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1125f95f3850SWill Newton dw_mci_start_request(host, slot); 1126f95f3850SWill Newton } else { 1127f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 1128f95f3850SWill Newton } 1129f95f3850SWill Newton } 1130f95f3850SWill Newton 1131f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1132f95f3850SWill Newton { 1133f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1134f95f3850SWill Newton struct dw_mci *host = slot->host; 1135f95f3850SWill Newton 1136f95f3850SWill Newton WARN_ON(slot->mrq); 1137f95f3850SWill Newton 11387456caaeSJames Hogan /* 11397456caaeSJames Hogan * The check for card presence and queueing of the request must be 11407456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 11417456caaeSJames Hogan * request wouldn't fail until another card was inserted. 11427456caaeSJames Hogan */ 11437456caaeSJames Hogan spin_lock_bh(&host->lock); 11447456caaeSJames Hogan 1145f95f3850SWill Newton if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { 11467456caaeSJames Hogan spin_unlock_bh(&host->lock); 1147f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1148f95f3850SWill Newton mmc_request_done(mmc, mrq); 1149f95f3850SWill Newton return; 1150f95f3850SWill Newton } 1151f95f3850SWill Newton 1152f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 11537456caaeSJames Hogan 11547456caaeSJames Hogan spin_unlock_bh(&host->lock); 1155f95f3850SWill Newton } 1156f95f3850SWill Newton 1157f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1158f95f3850SWill Newton { 1159f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1160e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 116141babf75SJaehoon Chung u32 regs; 116251da2240SYuvaraj CD int ret; 1163f95f3850SWill Newton 1164f95f3850SWill Newton switch (ios->bus_width) { 1165f95f3850SWill Newton case MMC_BUS_WIDTH_4: 1166f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 1167f95f3850SWill Newton break; 1168c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 1169c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 1170c9b2a06fSJaehoon Chung break; 1171b2f7cb45SJaehoon Chung default: 1172b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 1173b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 1174f95f3850SWill Newton } 1175f95f3850SWill Newton 117641babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 11773f514291SSeungwon Jeon 11783f514291SSeungwon Jeon /* DDR mode set */ 117980113132SSeungwon Jeon if (ios->timing == MMC_TIMING_MMC_DDR52 || 118080113132SSeungwon Jeon ios->timing == MMC_TIMING_MMC_HS400) 1181c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 11823f514291SSeungwon Jeon else 1183c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 11843f514291SSeungwon Jeon 118541babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 1186f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 118741babf75SJaehoon Chung 1188f95f3850SWill Newton /* 1189f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 1190f95f3850SWill Newton * core ios update when finding the minimum. 1191f95f3850SWill Newton */ 1192f95f3850SWill Newton slot->clock = ios->clock; 1193f95f3850SWill Newton 1194cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 1195cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 1196800d78bfSThomas Abraham 1197f95f3850SWill Newton switch (ios->power_mode) { 1198f95f3850SWill Newton case MMC_POWER_UP: 119951da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) { 120051da2240SYuvaraj CD ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 120151da2240SYuvaraj CD ios->vdd); 120251da2240SYuvaraj CD if (ret) { 120351da2240SYuvaraj CD dev_err(slot->host->dev, 120451da2240SYuvaraj CD "failed to enable vmmc regulator\n"); 120551da2240SYuvaraj CD /*return, if failed turn on vmmc*/ 120651da2240SYuvaraj CD return; 120751da2240SYuvaraj CD } 120851da2240SYuvaraj CD } 120929d0d161SDoug Anderson set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 121029d0d161SDoug Anderson regs = mci_readl(slot->host, PWREN); 121129d0d161SDoug Anderson regs |= (1 << slot->id); 121229d0d161SDoug Anderson mci_writel(slot->host, PWREN, regs); 121329d0d161SDoug Anderson break; 121429d0d161SDoug Anderson case MMC_POWER_ON: 1215d1f1dd86SDoug Anderson if (!slot->host->vqmmc_enabled) { 1216d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 121751da2240SYuvaraj CD ret = regulator_enable(mmc->supply.vqmmc); 121851da2240SYuvaraj CD if (ret < 0) 121951da2240SYuvaraj CD dev_err(slot->host->dev, 1220d1f1dd86SDoug Anderson "failed to enable vqmmc\n"); 122151da2240SYuvaraj CD else 122251da2240SYuvaraj CD slot->host->vqmmc_enabled = true; 1223d1f1dd86SDoug Anderson 1224d1f1dd86SDoug Anderson } else { 1225d1f1dd86SDoug Anderson /* Keep track so we don't reset again */ 1226d1f1dd86SDoug Anderson slot->host->vqmmc_enabled = true; 1227d1f1dd86SDoug Anderson } 1228d1f1dd86SDoug Anderson 1229d1f1dd86SDoug Anderson /* Reset our state machine after powering on */ 1230d1f1dd86SDoug Anderson dw_mci_ctrl_reset(slot->host, 1231d1f1dd86SDoug Anderson SDMMC_CTRL_ALL_RESET_FLAGS); 123251da2240SYuvaraj CD } 1233655babbdSDoug Anderson 1234655babbdSDoug Anderson /* Adjust clock / bus width after power is up */ 1235655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1236655babbdSDoug Anderson 1237e6f34e2fSJames Hogan break; 1238e6f34e2fSJames Hogan case MMC_POWER_OFF: 1239655babbdSDoug Anderson /* Turn clock off before power goes down */ 1240655babbdSDoug Anderson dw_mci_setup_bus(slot, false); 1241655babbdSDoug Anderson 124251da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) 124351da2240SYuvaraj CD mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 124451da2240SYuvaraj CD 1245d1f1dd86SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) 124651da2240SYuvaraj CD regulator_disable(mmc->supply.vqmmc); 124751da2240SYuvaraj CD slot->host->vqmmc_enabled = false; 124851da2240SYuvaraj CD 12494366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 12504366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 12514366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1252f95f3850SWill Newton break; 1253f95f3850SWill Newton default: 1254f95f3850SWill Newton break; 1255f95f3850SWill Newton } 1256655babbdSDoug Anderson 1257655babbdSDoug Anderson if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) 1258655babbdSDoug Anderson slot->host->state = STATE_IDLE; 1259f95f3850SWill Newton } 1260f95f3850SWill Newton 126101730558SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc) 126201730558SDoug Anderson { 126301730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 126401730558SDoug Anderson u32 status; 126501730558SDoug Anderson 126601730558SDoug Anderson /* 126701730558SDoug Anderson * Check the busy bit which is low when DAT[3:0] 126801730558SDoug Anderson * (the data lines) are 0000 126901730558SDoug Anderson */ 127001730558SDoug Anderson status = mci_readl(slot->host, STATUS); 127101730558SDoug Anderson 127201730558SDoug Anderson return !!(status & SDMMC_STATUS_BUSY); 127301730558SDoug Anderson } 127401730558SDoug Anderson 127501730558SDoug Anderson static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) 127601730558SDoug Anderson { 127701730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 127801730558SDoug Anderson struct dw_mci *host = slot->host; 12798f7849c4SZhangfei Gao const struct dw_mci_drv_data *drv_data = host->drv_data; 128001730558SDoug Anderson u32 uhs; 128101730558SDoug Anderson u32 v18 = SDMMC_UHS_18V << slot->id; 128201730558SDoug Anderson int ret; 128301730558SDoug Anderson 12848f7849c4SZhangfei Gao if (drv_data && drv_data->switch_voltage) 12858f7849c4SZhangfei Gao return drv_data->switch_voltage(mmc, ios); 12868f7849c4SZhangfei Gao 128701730558SDoug Anderson /* 128801730558SDoug Anderson * Program the voltage. Note that some instances of dw_mmc may use 128901730558SDoug Anderson * the UHS_REG for this. For other instances (like exynos) the UHS_REG 129001730558SDoug Anderson * does no harm but you need to set the regulator directly. Try both. 129101730558SDoug Anderson */ 129201730558SDoug Anderson uhs = mci_readl(host, UHS_REG); 1293*e0848f5dSDouglas Anderson if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) 129401730558SDoug Anderson uhs &= ~v18; 1295*e0848f5dSDouglas Anderson else 129601730558SDoug Anderson uhs |= v18; 1297*e0848f5dSDouglas Anderson 129801730558SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 1299*e0848f5dSDouglas Anderson ret = mmc_regulator_set_vqmmc(mmc, ios); 130001730558SDoug Anderson 130101730558SDoug Anderson if (ret) { 1302b19caf37SDoug Anderson dev_dbg(&mmc->class_dev, 1303*e0848f5dSDouglas Anderson "Regulator set error %d - %s V\n", 1304*e0848f5dSDouglas Anderson ret, uhs & v18 ? "1.8" : "3.3"); 130501730558SDoug Anderson return ret; 130601730558SDoug Anderson } 130701730558SDoug Anderson } 130801730558SDoug Anderson mci_writel(host, UHS_REG, uhs); 130901730558SDoug Anderson 131001730558SDoug Anderson return 0; 131101730558SDoug Anderson } 131201730558SDoug Anderson 1313f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 1314f95f3850SWill Newton { 1315f95f3850SWill Newton int read_only; 1316f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 13179795a846SJaehoon Chung int gpio_ro = mmc_gpio_get_ro(mmc); 1318f95f3850SWill Newton 1319f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 1320eff8f2f5SLars-Peter Clausen if (!IS_ERR_VALUE(gpio_ro)) 13219795a846SJaehoon Chung read_only = gpio_ro; 1322f95f3850SWill Newton else 1323f95f3850SWill Newton read_only = 1324f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1325f95f3850SWill Newton 1326f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1327f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1328f95f3850SWill Newton 1329f95f3850SWill Newton return read_only; 1330f95f3850SWill Newton } 1331f95f3850SWill Newton 1332f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1333f95f3850SWill Newton { 1334f95f3850SWill Newton int present; 1335f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1336f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 13377cf347bdSZhangfei Gao struct dw_mci *host = slot->host; 13387cf347bdSZhangfei Gao int gpio_cd = mmc_gpio_get_cd(mmc); 1339f95f3850SWill Newton 1340f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 13414de3bf66SZhangfei Gao if ((brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) || 13424de3bf66SZhangfei Gao (mmc->caps & MMC_CAP_NONREMOVABLE)) 1343fc3d7720SJaehoon Chung present = 1; 1344bf626e55SZhangfei Gao else if (!IS_ERR_VALUE(gpio_cd)) 13457cf347bdSZhangfei Gao present = gpio_cd; 1346f95f3850SWill Newton else 1347f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1348f95f3850SWill Newton == 0 ? 1 : 0; 1349f95f3850SWill Newton 13507cf347bdSZhangfei Gao spin_lock_bh(&host->lock); 1351bf626e55SZhangfei Gao if (present) { 1352bf626e55SZhangfei Gao set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1353f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 1354bf626e55SZhangfei Gao } else { 1355bf626e55SZhangfei Gao clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1356f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 1357bf626e55SZhangfei Gao } 13587cf347bdSZhangfei Gao spin_unlock_bh(&host->lock); 1359f95f3850SWill Newton 1360f95f3850SWill Newton return present; 1361f95f3850SWill Newton } 1362f95f3850SWill Newton 1363b24c8b26SDoug Anderson static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) 1364b24c8b26SDoug Anderson { 1365b24c8b26SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 1366b24c8b26SDoug Anderson struct dw_mci *host = slot->host; 1367b24c8b26SDoug Anderson 13689623b5b9SDoug Anderson /* 13699623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 13709623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 13719623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 13729623b5b9SDoug Anderson */ 1373b24c8b26SDoug Anderson if (mmc->caps & MMC_CAP_SDIO_IRQ) { 13749623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 1375b24c8b26SDoug Anderson u32 clk_en_a_old; 1376b24c8b26SDoug Anderson u32 clk_en_a; 13779623b5b9SDoug Anderson 1378b24c8b26SDoug Anderson clk_en_a_old = mci_readl(host, CLKENA); 13799623b5b9SDoug Anderson 1380b24c8b26SDoug Anderson if (card->type == MMC_TYPE_SDIO || 1381b24c8b26SDoug Anderson card->type == MMC_TYPE_SD_COMBO) { 1382b24c8b26SDoug Anderson set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1383b24c8b26SDoug Anderson clk_en_a = clk_en_a_old & ~clken_low_pwr; 1384b24c8b26SDoug Anderson } else { 1385b24c8b26SDoug Anderson clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); 1386b24c8b26SDoug Anderson clk_en_a = clk_en_a_old | clken_low_pwr; 1387b24c8b26SDoug Anderson } 1388b24c8b26SDoug Anderson 1389b24c8b26SDoug Anderson if (clk_en_a != clk_en_a_old) { 1390b24c8b26SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 13919623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 13929623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 13939623b5b9SDoug Anderson } 13949623b5b9SDoug Anderson } 1395b24c8b26SDoug Anderson } 13969623b5b9SDoug Anderson 13971a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 13981a5c8e1fSShashidhar Hiremath { 13991a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 14001a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 1401f8c58c11SDoug Anderson unsigned long irqflags; 14021a5c8e1fSShashidhar Hiremath u32 int_mask; 14031a5c8e1fSShashidhar Hiremath 1404f8c58c11SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 1405f8c58c11SDoug Anderson 14061a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 14071a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 1408b24c8b26SDoug Anderson if (enb) 1409b24c8b26SDoug Anderson int_mask |= SDMMC_INT_SDIO(slot->sdio_id); 1410b24c8b26SDoug Anderson else 1411b24c8b26SDoug Anderson int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id); 1412b24c8b26SDoug Anderson mci_writel(host, INTMASK, int_mask); 1413f8c58c11SDoug Anderson 1414f8c58c11SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 14151a5c8e1fSShashidhar Hiremath } 14161a5c8e1fSShashidhar Hiremath 14170976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 14180976f16dSSeungwon Jeon { 14190976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 14200976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 14210976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 14220e3a22c0SShawn Lin int err = -EINVAL; 14230976f16dSSeungwon Jeon 14240976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 14256c2c6506SUlf Hansson err = drv_data->execute_tuning(slot); 14260976f16dSSeungwon Jeon return err; 14270976f16dSSeungwon Jeon } 14280976f16dSSeungwon Jeon 14290e3a22c0SShawn Lin static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, 14300e3a22c0SShawn Lin struct mmc_ios *ios) 143180113132SSeungwon Jeon { 143280113132SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 143380113132SSeungwon Jeon struct dw_mci *host = slot->host; 143480113132SSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 143580113132SSeungwon Jeon 143680113132SSeungwon Jeon if (drv_data && drv_data->prepare_hs400_tuning) 143780113132SSeungwon Jeon return drv_data->prepare_hs400_tuning(host, ios); 143880113132SSeungwon Jeon 143980113132SSeungwon Jeon return 0; 144080113132SSeungwon Jeon } 144180113132SSeungwon Jeon 1442f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1443f95f3850SWill Newton .request = dw_mci_request, 14449aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 14459aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1446f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1447f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1448f95f3850SWill Newton .get_cd = dw_mci_get_cd, 14491a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 14500976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 145101730558SDoug Anderson .card_busy = dw_mci_card_busy, 145201730558SDoug Anderson .start_signal_voltage_switch = dw_mci_switch_voltage, 1453b24c8b26SDoug Anderson .init_card = dw_mci_init_card, 145480113132SSeungwon Jeon .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, 1455f95f3850SWill Newton }; 1456f95f3850SWill Newton 1457f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1458f95f3850SWill Newton __releases(&host->lock) 1459f95f3850SWill Newton __acquires(&host->lock) 1460f95f3850SWill Newton { 1461f95f3850SWill Newton struct dw_mci_slot *slot; 1462f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1463f95f3850SWill Newton 1464f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1465f95f3850SWill Newton 1466f95f3850SWill Newton host->cur_slot->mrq = NULL; 1467f95f3850SWill Newton host->mrq = NULL; 1468f95f3850SWill Newton if (!list_empty(&host->queue)) { 1469f95f3850SWill Newton slot = list_entry(host->queue.next, 1470f95f3850SWill Newton struct dw_mci_slot, queue_node); 1471f95f3850SWill Newton list_del(&slot->queue_node); 14724a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1473f95f3850SWill Newton mmc_hostname(slot->mmc)); 1474f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1475f95f3850SWill Newton dw_mci_start_request(host, slot); 1476f95f3850SWill Newton } else { 14774a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 147801730558SDoug Anderson 147901730558SDoug Anderson if (host->state == STATE_SENDING_CMD11) 148001730558SDoug Anderson host->state = STATE_WAITING_CMD11_DONE; 148101730558SDoug Anderson else 1482f95f3850SWill Newton host->state = STATE_IDLE; 1483f95f3850SWill Newton } 1484f95f3850SWill Newton 1485f95f3850SWill Newton spin_unlock(&host->lock); 1486f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1487f95f3850SWill Newton spin_lock(&host->lock); 1488f95f3850SWill Newton } 1489f95f3850SWill Newton 1490e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1491f95f3850SWill Newton { 1492f95f3850SWill Newton u32 status = host->cmd_status; 1493f95f3850SWill Newton 1494f95f3850SWill Newton host->cmd_status = 0; 1495f95f3850SWill Newton 1496f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1497f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1498f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1499f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1500f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1501f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1502f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1503f95f3850SWill Newton } else { 1504f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1505f95f3850SWill Newton cmd->resp[1] = 0; 1506f95f3850SWill Newton cmd->resp[2] = 0; 1507f95f3850SWill Newton cmd->resp[3] = 0; 1508f95f3850SWill Newton } 1509f95f3850SWill Newton } 1510f95f3850SWill Newton 1511f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1512f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1513f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1514f95f3850SWill Newton cmd->error = -EILSEQ; 1515f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1516f95f3850SWill Newton cmd->error = -EIO; 1517f95f3850SWill Newton else 1518f95f3850SWill Newton cmd->error = 0; 1519f95f3850SWill Newton 1520f95f3850SWill Newton if (cmd->error) { 1521f95f3850SWill Newton /* newer ip versions need a delay between retries */ 1522f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) 1523f95f3850SWill Newton mdelay(20); 1524f95f3850SWill Newton } 1525e352c813SSeungwon Jeon 1526e352c813SSeungwon Jeon return cmd->error; 1527e352c813SSeungwon Jeon } 1528e352c813SSeungwon Jeon 1529e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) 1530e352c813SSeungwon Jeon { 153131bff450SSeungwon Jeon u32 status = host->data_status; 1532e352c813SSeungwon Jeon 1533e352c813SSeungwon Jeon if (status & DW_MCI_DATA_ERROR_FLAGS) { 1534e352c813SSeungwon Jeon if (status & SDMMC_INT_DRTO) { 1535e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1536e352c813SSeungwon Jeon } else if (status & SDMMC_INT_DCRC) { 1537e352c813SSeungwon Jeon data->error = -EILSEQ; 1538e352c813SSeungwon Jeon } else if (status & SDMMC_INT_EBE) { 1539e352c813SSeungwon Jeon if (host->dir_status == 1540e352c813SSeungwon Jeon DW_MCI_SEND_STATUS) { 1541e352c813SSeungwon Jeon /* 1542e352c813SSeungwon Jeon * No data CRC status was returned. 1543e352c813SSeungwon Jeon * The number of bytes transferred 1544e352c813SSeungwon Jeon * will be exaggerated in PIO mode. 1545e352c813SSeungwon Jeon */ 1546e352c813SSeungwon Jeon data->bytes_xfered = 0; 1547e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1548e352c813SSeungwon Jeon } else if (host->dir_status == 1549e352c813SSeungwon Jeon DW_MCI_RECV_STATUS) { 1550e352c813SSeungwon Jeon data->error = -EIO; 1551e352c813SSeungwon Jeon } 1552e352c813SSeungwon Jeon } else { 1553e352c813SSeungwon Jeon /* SDMMC_INT_SBE is included */ 1554e352c813SSeungwon Jeon data->error = -EIO; 1555e352c813SSeungwon Jeon } 1556e352c813SSeungwon Jeon 1557e6cc0123SDoug Anderson dev_dbg(host->dev, "data error, status 0x%08x\n", status); 1558e352c813SSeungwon Jeon 1559e352c813SSeungwon Jeon /* 1560e352c813SSeungwon Jeon * After an error, there may be data lingering 156131bff450SSeungwon Jeon * in the FIFO 1562e352c813SSeungwon Jeon */ 15633a33a94cSSonny Rao dw_mci_reset(host); 1564e352c813SSeungwon Jeon } else { 1565e352c813SSeungwon Jeon data->bytes_xfered = data->blocks * data->blksz; 1566e352c813SSeungwon Jeon data->error = 0; 1567e352c813SSeungwon Jeon } 1568e352c813SSeungwon Jeon 1569e352c813SSeungwon Jeon return data->error; 1570f95f3850SWill Newton } 1571f95f3850SWill Newton 157257e10486SAddy Ke static void dw_mci_set_drto(struct dw_mci *host) 157357e10486SAddy Ke { 157457e10486SAddy Ke unsigned int drto_clks; 157557e10486SAddy Ke unsigned int drto_ms; 157657e10486SAddy Ke 157757e10486SAddy Ke drto_clks = mci_readl(host, TMOUT) >> 8; 157857e10486SAddy Ke drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000); 157957e10486SAddy Ke 158057e10486SAddy Ke /* add a bit spare time */ 158157e10486SAddy Ke drto_ms += 10; 158257e10486SAddy Ke 158357e10486SAddy Ke mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms)); 158457e10486SAddy Ke } 158557e10486SAddy Ke 1586f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1587f95f3850SWill Newton { 1588f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1589f95f3850SWill Newton struct mmc_data *data; 1590f95f3850SWill Newton struct mmc_command *cmd; 1591e352c813SSeungwon Jeon struct mmc_request *mrq; 1592f95f3850SWill Newton enum dw_mci_state state; 1593f95f3850SWill Newton enum dw_mci_state prev_state; 1594e352c813SSeungwon Jeon unsigned int err; 1595f95f3850SWill Newton 1596f95f3850SWill Newton spin_lock(&host->lock); 1597f95f3850SWill Newton 1598f95f3850SWill Newton state = host->state; 1599f95f3850SWill Newton data = host->data; 1600e352c813SSeungwon Jeon mrq = host->mrq; 1601f95f3850SWill Newton 1602f95f3850SWill Newton do { 1603f95f3850SWill Newton prev_state = state; 1604f95f3850SWill Newton 1605f95f3850SWill Newton switch (state) { 1606f95f3850SWill Newton case STATE_IDLE: 160701730558SDoug Anderson case STATE_WAITING_CMD11_DONE: 1608f95f3850SWill Newton break; 1609f95f3850SWill Newton 161001730558SDoug Anderson case STATE_SENDING_CMD11: 1611f95f3850SWill Newton case STATE_SENDING_CMD: 1612f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1613f95f3850SWill Newton &host->pending_events)) 1614f95f3850SWill Newton break; 1615f95f3850SWill Newton 1616f95f3850SWill Newton cmd = host->cmd; 1617f95f3850SWill Newton host->cmd = NULL; 1618f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1619e352c813SSeungwon Jeon err = dw_mci_command_complete(host, cmd); 1620e352c813SSeungwon Jeon if (cmd == mrq->sbc && !err) { 1621053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1622053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1623e352c813SSeungwon Jeon mrq->cmd); 1624053b3ce6SSeungwon Jeon goto unlock; 1625053b3ce6SSeungwon Jeon } 1626053b3ce6SSeungwon Jeon 1627e352c813SSeungwon Jeon if (cmd->data && err) { 162871abb133SSeungwon Jeon dw_mci_stop_dma(host); 162990c2143aSSeungwon Jeon send_stop_abort(host, data); 163071abb133SSeungwon Jeon state = STATE_SENDING_STOP; 163171abb133SSeungwon Jeon break; 163271abb133SSeungwon Jeon } 163371abb133SSeungwon Jeon 1634e352c813SSeungwon Jeon if (!cmd->data || err) { 1635e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1636f95f3850SWill Newton goto unlock; 1637f95f3850SWill Newton } 1638f95f3850SWill Newton 1639f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1640f95f3850SWill Newton /* fall through */ 1641f95f3850SWill Newton 1642f95f3850SWill Newton case STATE_SENDING_DATA: 16432aa35465SDoug Anderson /* 16442aa35465SDoug Anderson * We could get a data error and never a transfer 16452aa35465SDoug Anderson * complete so we'd better check for it here. 16462aa35465SDoug Anderson * 16472aa35465SDoug Anderson * Note that we don't really care if we also got a 16482aa35465SDoug Anderson * transfer complete; stopping the DMA and sending an 16492aa35465SDoug Anderson * abort won't hurt. 16502aa35465SDoug Anderson */ 1651f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1652f95f3850SWill Newton &host->pending_events)) { 1653f95f3850SWill Newton dw_mci_stop_dma(host); 1654bdb9a90bSaddy ke if (data->stop || 1655bdb9a90bSaddy ke !(host->data_status & (SDMMC_INT_DRTO | 1656bdb9a90bSaddy ke SDMMC_INT_EBE))) 165790c2143aSSeungwon Jeon send_stop_abort(host, data); 1658f95f3850SWill Newton state = STATE_DATA_ERROR; 1659f95f3850SWill Newton break; 1660f95f3850SWill Newton } 1661f95f3850SWill Newton 1662f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 166357e10486SAddy Ke &host->pending_events)) { 166457e10486SAddy Ke /* 166557e10486SAddy Ke * If all data-related interrupts don't come 166657e10486SAddy Ke * within the given time in reading data state. 166757e10486SAddy Ke */ 166857e10486SAddy Ke if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && 166957e10486SAddy Ke (host->dir_status == DW_MCI_RECV_STATUS)) 167057e10486SAddy Ke dw_mci_set_drto(host); 1671f95f3850SWill Newton break; 167257e10486SAddy Ke } 1673f95f3850SWill Newton 1674f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 16752aa35465SDoug Anderson 16762aa35465SDoug Anderson /* 16772aa35465SDoug Anderson * Handle an EVENT_DATA_ERROR that might have shown up 16782aa35465SDoug Anderson * before the transfer completed. This might not have 16792aa35465SDoug Anderson * been caught by the check above because the interrupt 16802aa35465SDoug Anderson * could have gone off between the previous check and 16812aa35465SDoug Anderson * the check for transfer complete. 16822aa35465SDoug Anderson * 16832aa35465SDoug Anderson * Technically this ought not be needed assuming we 16842aa35465SDoug Anderson * get a DATA_COMPLETE eventually (we'll notice the 16852aa35465SDoug Anderson * error and end the request), but it shouldn't hurt. 16862aa35465SDoug Anderson * 16872aa35465SDoug Anderson * This has the advantage of sending the stop command. 16882aa35465SDoug Anderson */ 16892aa35465SDoug Anderson if (test_and_clear_bit(EVENT_DATA_ERROR, 16902aa35465SDoug Anderson &host->pending_events)) { 16912aa35465SDoug Anderson dw_mci_stop_dma(host); 1692bdb9a90bSaddy ke if (data->stop || 1693bdb9a90bSaddy ke !(host->data_status & (SDMMC_INT_DRTO | 1694bdb9a90bSaddy ke SDMMC_INT_EBE))) 16952aa35465SDoug Anderson send_stop_abort(host, data); 16962aa35465SDoug Anderson state = STATE_DATA_ERROR; 16972aa35465SDoug Anderson break; 16982aa35465SDoug Anderson } 1699f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 17002aa35465SDoug Anderson 1701f95f3850SWill Newton /* fall through */ 1702f95f3850SWill Newton 1703f95f3850SWill Newton case STATE_DATA_BUSY: 1704f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 170557e10486SAddy Ke &host->pending_events)) { 170657e10486SAddy Ke /* 170757e10486SAddy Ke * If data error interrupt comes but data over 170857e10486SAddy Ke * interrupt doesn't come within the given time. 170957e10486SAddy Ke * in reading data state. 171057e10486SAddy Ke */ 171157e10486SAddy Ke if ((host->quirks & DW_MCI_QUIRK_BROKEN_DTO) && 171257e10486SAddy Ke (host->dir_status == DW_MCI_RECV_STATUS)) 171357e10486SAddy Ke dw_mci_set_drto(host); 1714f95f3850SWill Newton break; 171557e10486SAddy Ke } 1716f95f3850SWill Newton 1717f95f3850SWill Newton host->data = NULL; 1718f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 1719e352c813SSeungwon Jeon err = dw_mci_data_complete(host, data); 1720f95f3850SWill Newton 1721e352c813SSeungwon Jeon if (!err) { 1722e352c813SSeungwon Jeon if (!data->stop || mrq->sbc) { 172317c8bc85SSachin Kamat if (mrq->sbc && data->stop) 1724053b3ce6SSeungwon Jeon data->stop->error = 0; 1725e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1726053b3ce6SSeungwon Jeon goto unlock; 1727053b3ce6SSeungwon Jeon } 1728053b3ce6SSeungwon Jeon 172990c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 1730e352c813SSeungwon Jeon if (data->stop) 173190c2143aSSeungwon Jeon send_stop_abort(host, data); 17322aa35465SDoug Anderson } else { 17332aa35465SDoug Anderson /* 17342aa35465SDoug Anderson * If we don't have a command complete now we'll 17352aa35465SDoug Anderson * never get one since we just reset everything; 17362aa35465SDoug Anderson * better end the request. 17372aa35465SDoug Anderson * 17382aa35465SDoug Anderson * If we do have a command complete we'll fall 17392aa35465SDoug Anderson * through to the SENDING_STOP command and 17402aa35465SDoug Anderson * everything will be peachy keen. 17412aa35465SDoug Anderson */ 17422aa35465SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, 17432aa35465SDoug Anderson &host->pending_events)) { 17442aa35465SDoug Anderson host->cmd = NULL; 17452aa35465SDoug Anderson dw_mci_request_end(host, mrq); 17462aa35465SDoug Anderson goto unlock; 17472aa35465SDoug Anderson } 174890c2143aSSeungwon Jeon } 1749e352c813SSeungwon Jeon 1750e352c813SSeungwon Jeon /* 1751e352c813SSeungwon Jeon * If err has non-zero, 1752e352c813SSeungwon Jeon * stop-abort command has been already issued. 1753e352c813SSeungwon Jeon */ 1754e352c813SSeungwon Jeon prev_state = state = STATE_SENDING_STOP; 1755e352c813SSeungwon Jeon 1756f95f3850SWill Newton /* fall through */ 1757f95f3850SWill Newton 1758f95f3850SWill Newton case STATE_SENDING_STOP: 1759f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1760f95f3850SWill Newton &host->pending_events)) 1761f95f3850SWill Newton break; 1762f95f3850SWill Newton 176371abb133SSeungwon Jeon /* CMD error in data command */ 176431bff450SSeungwon Jeon if (mrq->cmd->error && mrq->data) 17653a33a94cSSonny Rao dw_mci_reset(host); 176671abb133SSeungwon Jeon 1767f95f3850SWill Newton host->cmd = NULL; 176871abb133SSeungwon Jeon host->data = NULL; 176990c2143aSSeungwon Jeon 1770e352c813SSeungwon Jeon if (mrq->stop) 1771e352c813SSeungwon Jeon dw_mci_command_complete(host, mrq->stop); 177290c2143aSSeungwon Jeon else 177390c2143aSSeungwon Jeon host->cmd_status = 0; 177490c2143aSSeungwon Jeon 1775e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1776f95f3850SWill Newton goto unlock; 1777f95f3850SWill Newton 1778f95f3850SWill Newton case STATE_DATA_ERROR: 1779f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1780f95f3850SWill Newton &host->pending_events)) 1781f95f3850SWill Newton break; 1782f95f3850SWill Newton 1783f95f3850SWill Newton state = STATE_DATA_BUSY; 1784f95f3850SWill Newton break; 1785f95f3850SWill Newton } 1786f95f3850SWill Newton } while (state != prev_state); 1787f95f3850SWill Newton 1788f95f3850SWill Newton host->state = state; 1789f95f3850SWill Newton unlock: 1790f95f3850SWill Newton spin_unlock(&host->lock); 1791f95f3850SWill Newton 1792f95f3850SWill Newton } 1793f95f3850SWill Newton 179434b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 179534b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 179634b664a2SJames Hogan { 179734b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 179834b664a2SJames Hogan host->part_buf_count = cnt; 179934b664a2SJames Hogan } 180034b664a2SJames Hogan 180134b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 180234b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 180334b664a2SJames Hogan { 180434b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 180534b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 180634b664a2SJames Hogan host->part_buf_count += cnt; 180734b664a2SJames Hogan return cnt; 180834b664a2SJames Hogan } 180934b664a2SJames Hogan 181034b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 181134b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 181234b664a2SJames Hogan { 18130e3a22c0SShawn Lin cnt = min_t(int, cnt, host->part_buf_count); 181434b664a2SJames Hogan if (cnt) { 181534b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 181634b664a2SJames Hogan cnt); 181734b664a2SJames Hogan host->part_buf_count -= cnt; 181834b664a2SJames Hogan host->part_buf_start += cnt; 181934b664a2SJames Hogan } 182034b664a2SJames Hogan return cnt; 182134b664a2SJames Hogan } 182234b664a2SJames Hogan 182334b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 182434b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 182534b664a2SJames Hogan { 182634b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 182734b664a2SJames Hogan host->part_buf_start = cnt; 182834b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 182934b664a2SJames Hogan } 183034b664a2SJames Hogan 1831f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 1832f95f3850SWill Newton { 1833cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1834cfbeb59cSMarkos Chandras int init_cnt = cnt; 1835cfbeb59cSMarkos Chandras 183634b664a2SJames Hogan /* try and push anything in the part_buf */ 183734b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 183834b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 18390e3a22c0SShawn Lin 184034b664a2SJames Hogan buf += len; 184134b664a2SJames Hogan cnt -= len; 1842cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 184376184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 184434b664a2SJames Hogan host->part_buf_count = 0; 184534b664a2SJames Hogan } 184634b664a2SJames Hogan } 184734b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 184834b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 184934b664a2SJames Hogan while (cnt >= 2) { 185034b664a2SJames Hogan u16 aligned_buf[64]; 185134b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 185234b664a2SJames Hogan int items = len >> 1; 185334b664a2SJames Hogan int i; 185434b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 185534b664a2SJames Hogan memcpy(aligned_buf, buf, len); 185634b664a2SJames Hogan buf += len; 185734b664a2SJames Hogan cnt -= len; 185834b664a2SJames Hogan /* push data from aligned buffer into fifo */ 185934b664a2SJames Hogan for (i = 0; i < items; ++i) 186076184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, aligned_buf[i]); 186134b664a2SJames Hogan } 186234b664a2SJames Hogan } else 186334b664a2SJames Hogan #endif 186434b664a2SJames Hogan { 186534b664a2SJames Hogan u16 *pdata = buf; 18660e3a22c0SShawn Lin 186734b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 186876184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, *pdata++); 186934b664a2SJames Hogan buf = pdata; 187034b664a2SJames Hogan } 187134b664a2SJames Hogan /* put anything remaining in the part_buf */ 187234b664a2SJames Hogan if (cnt) { 187334b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1874cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1875cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1876cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 187776184ac1SBen Dooks mci_fifo_writew(host->fifo_reg, host->part_buf16); 1878f95f3850SWill Newton } 1879f95f3850SWill Newton } 1880f95f3850SWill Newton 1881f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 1882f95f3850SWill Newton { 188334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 188434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 188534b664a2SJames Hogan while (cnt >= 2) { 188634b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 188734b664a2SJames Hogan u16 aligned_buf[64]; 188834b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 188934b664a2SJames Hogan int items = len >> 1; 189034b664a2SJames Hogan int i; 18910e3a22c0SShawn Lin 189234b664a2SJames Hogan for (i = 0; i < items; ++i) 189376184ac1SBen Dooks aligned_buf[i] = mci_fifo_readw(host->fifo_reg); 189434b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 189534b664a2SJames Hogan memcpy(buf, aligned_buf, len); 189634b664a2SJames Hogan buf += len; 189734b664a2SJames Hogan cnt -= len; 189834b664a2SJames Hogan } 189934b664a2SJames Hogan } else 190034b664a2SJames Hogan #endif 190134b664a2SJames Hogan { 190234b664a2SJames Hogan u16 *pdata = buf; 19030e3a22c0SShawn Lin 190434b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 190576184ac1SBen Dooks *pdata++ = mci_fifo_readw(host->fifo_reg); 190634b664a2SJames Hogan buf = pdata; 190734b664a2SJames Hogan } 190834b664a2SJames Hogan if (cnt) { 190976184ac1SBen Dooks host->part_buf16 = mci_fifo_readw(host->fifo_reg); 191034b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1911f95f3850SWill Newton } 1912f95f3850SWill Newton } 1913f95f3850SWill Newton 1914f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 1915f95f3850SWill Newton { 1916cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1917cfbeb59cSMarkos Chandras int init_cnt = cnt; 1918cfbeb59cSMarkos Chandras 191934b664a2SJames Hogan /* try and push anything in the part_buf */ 192034b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 192134b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 19220e3a22c0SShawn Lin 192334b664a2SJames Hogan buf += len; 192434b664a2SJames Hogan cnt -= len; 1925cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 192676184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 192734b664a2SJames Hogan host->part_buf_count = 0; 192834b664a2SJames Hogan } 192934b664a2SJames Hogan } 193034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 193134b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 193234b664a2SJames Hogan while (cnt >= 4) { 193334b664a2SJames Hogan u32 aligned_buf[32]; 193434b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 193534b664a2SJames Hogan int items = len >> 2; 193634b664a2SJames Hogan int i; 193734b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 193834b664a2SJames Hogan memcpy(aligned_buf, buf, len); 193934b664a2SJames Hogan buf += len; 194034b664a2SJames Hogan cnt -= len; 194134b664a2SJames Hogan /* push data from aligned buffer into fifo */ 194234b664a2SJames Hogan for (i = 0; i < items; ++i) 194376184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, aligned_buf[i]); 194434b664a2SJames Hogan } 194534b664a2SJames Hogan } else 194634b664a2SJames Hogan #endif 194734b664a2SJames Hogan { 194834b664a2SJames Hogan u32 *pdata = buf; 19490e3a22c0SShawn Lin 195034b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 195176184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, *pdata++); 195234b664a2SJames Hogan buf = pdata; 195334b664a2SJames Hogan } 195434b664a2SJames Hogan /* put anything remaining in the part_buf */ 195534b664a2SJames Hogan if (cnt) { 195634b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1957cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1958cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1959cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 196076184ac1SBen Dooks mci_fifo_writel(host->fifo_reg, host->part_buf32); 1961f95f3850SWill Newton } 1962f95f3850SWill Newton } 1963f95f3850SWill Newton 1964f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 1965f95f3850SWill Newton { 196634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 196734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 196834b664a2SJames Hogan while (cnt >= 4) { 196934b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 197034b664a2SJames Hogan u32 aligned_buf[32]; 197134b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 197234b664a2SJames Hogan int items = len >> 2; 197334b664a2SJames Hogan int i; 19740e3a22c0SShawn Lin 197534b664a2SJames Hogan for (i = 0; i < items; ++i) 197676184ac1SBen Dooks aligned_buf[i] = mci_fifo_readl(host->fifo_reg); 197734b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 197834b664a2SJames Hogan memcpy(buf, aligned_buf, len); 197934b664a2SJames Hogan buf += len; 198034b664a2SJames Hogan cnt -= len; 198134b664a2SJames Hogan } 198234b664a2SJames Hogan } else 198334b664a2SJames Hogan #endif 198434b664a2SJames Hogan { 198534b664a2SJames Hogan u32 *pdata = buf; 19860e3a22c0SShawn Lin 198734b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 198876184ac1SBen Dooks *pdata++ = mci_fifo_readl(host->fifo_reg); 198934b664a2SJames Hogan buf = pdata; 199034b664a2SJames Hogan } 199134b664a2SJames Hogan if (cnt) { 199276184ac1SBen Dooks host->part_buf32 = mci_fifo_readl(host->fifo_reg); 199334b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1994f95f3850SWill Newton } 1995f95f3850SWill Newton } 1996f95f3850SWill Newton 1997f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 1998f95f3850SWill Newton { 1999cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 2000cfbeb59cSMarkos Chandras int init_cnt = cnt; 2001cfbeb59cSMarkos Chandras 200234b664a2SJames Hogan /* try and push anything in the part_buf */ 200334b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 200434b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 20050e3a22c0SShawn Lin 200634b664a2SJames Hogan buf += len; 200734b664a2SJames Hogan cnt -= len; 2008c09fbd74SSeungwon Jeon 2009cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 201076184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 201134b664a2SJames Hogan host->part_buf_count = 0; 201234b664a2SJames Hogan } 201334b664a2SJames Hogan } 201434b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 201534b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 201634b664a2SJames Hogan while (cnt >= 8) { 201734b664a2SJames Hogan u64 aligned_buf[16]; 201834b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 201934b664a2SJames Hogan int items = len >> 3; 202034b664a2SJames Hogan int i; 202134b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 202234b664a2SJames Hogan memcpy(aligned_buf, buf, len); 202334b664a2SJames Hogan buf += len; 202434b664a2SJames Hogan cnt -= len; 202534b664a2SJames Hogan /* push data from aligned buffer into fifo */ 202634b664a2SJames Hogan for (i = 0; i < items; ++i) 202776184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, aligned_buf[i]); 202834b664a2SJames Hogan } 202934b664a2SJames Hogan } else 203034b664a2SJames Hogan #endif 203134b664a2SJames Hogan { 203234b664a2SJames Hogan u64 *pdata = buf; 20330e3a22c0SShawn Lin 203434b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 203576184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, *pdata++); 203634b664a2SJames Hogan buf = pdata; 203734b664a2SJames Hogan } 203834b664a2SJames Hogan /* put anything remaining in the part_buf */ 203934b664a2SJames Hogan if (cnt) { 204034b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 2041cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 2042cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 2043cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 204476184ac1SBen Dooks mci_fifo_writeq(host->fifo_reg, host->part_buf); 2045f95f3850SWill Newton } 2046f95f3850SWill Newton } 2047f95f3850SWill Newton 2048f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 2049f95f3850SWill Newton { 205034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 205134b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 205234b664a2SJames Hogan while (cnt >= 8) { 205334b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 205434b664a2SJames Hogan u64 aligned_buf[16]; 205534b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 205634b664a2SJames Hogan int items = len >> 3; 205734b664a2SJames Hogan int i; 20580e3a22c0SShawn Lin 205934b664a2SJames Hogan for (i = 0; i < items; ++i) 206076184ac1SBen Dooks aligned_buf[i] = mci_fifo_readq(host->fifo_reg); 206176184ac1SBen Dooks 206234b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 206334b664a2SJames Hogan memcpy(buf, aligned_buf, len); 206434b664a2SJames Hogan buf += len; 206534b664a2SJames Hogan cnt -= len; 2066f95f3850SWill Newton } 206734b664a2SJames Hogan } else 206834b664a2SJames Hogan #endif 206934b664a2SJames Hogan { 207034b664a2SJames Hogan u64 *pdata = buf; 20710e3a22c0SShawn Lin 207234b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 207376184ac1SBen Dooks *pdata++ = mci_fifo_readq(host->fifo_reg); 207434b664a2SJames Hogan buf = pdata; 207534b664a2SJames Hogan } 207634b664a2SJames Hogan if (cnt) { 207776184ac1SBen Dooks host->part_buf = mci_fifo_readq(host->fifo_reg); 207834b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 207934b664a2SJames Hogan } 208034b664a2SJames Hogan } 208134b664a2SJames Hogan 208234b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 208334b664a2SJames Hogan { 208434b664a2SJames Hogan int len; 208534b664a2SJames Hogan 208634b664a2SJames Hogan /* get remaining partial bytes */ 208734b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 208834b664a2SJames Hogan if (unlikely(len == cnt)) 208934b664a2SJames Hogan return; 209034b664a2SJames Hogan buf += len; 209134b664a2SJames Hogan cnt -= len; 209234b664a2SJames Hogan 209334b664a2SJames Hogan /* get the rest of the data */ 209434b664a2SJames Hogan host->pull_data(host, buf, cnt); 2095f95f3850SWill Newton } 2096f95f3850SWill Newton 209787a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 2098f95f3850SWill Newton { 2099f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2100f9c2a0dcSSeungwon Jeon void *buf; 2101f9c2a0dcSSeungwon Jeon unsigned int offset; 2102f95f3850SWill Newton struct mmc_data *data = host->data; 2103f95f3850SWill Newton int shift = host->data_shift; 2104f95f3850SWill Newton u32 status; 21053e4b0d8bSMarkos Chandras unsigned int len; 2106f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2107f95f3850SWill Newton 2108f95f3850SWill Newton do { 2109f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2110f9c2a0dcSSeungwon Jeon goto done; 2111f95f3850SWill Newton 21124225fc85SImre Deak host->sg = sg_miter->piter.sg; 2113f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2114f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2115f9c2a0dcSSeungwon Jeon offset = 0; 2116f9c2a0dcSSeungwon Jeon 2117f9c2a0dcSSeungwon Jeon do { 2118f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 2119f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 2120f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2121f9c2a0dcSSeungwon Jeon if (!len) 2122f9c2a0dcSSeungwon Jeon break; 2123f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 21243e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2125f95f3850SWill Newton offset += len; 2126f9c2a0dcSSeungwon Jeon remain -= len; 2127f9c2a0dcSSeungwon Jeon } while (remain); 2128f95f3850SWill Newton 2129e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2130f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2131f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 213287a74d39SKyoungil Kim /* if the RXDR is ready read again */ 213387a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 213487a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 2135f9c2a0dcSSeungwon Jeon 2136f9c2a0dcSSeungwon Jeon if (!remain) { 2137f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2138f9c2a0dcSSeungwon Jeon goto done; 2139f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2140f9c2a0dcSSeungwon Jeon } 2141f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2142f95f3850SWill Newton return; 2143f95f3850SWill Newton 2144f95f3850SWill Newton done: 2145f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2146f9c2a0dcSSeungwon Jeon host->sg = NULL; 21470e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2148f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2149f95f3850SWill Newton } 2150f95f3850SWill Newton 2151f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 2152f95f3850SWill Newton { 2153f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 2154f9c2a0dcSSeungwon Jeon void *buf; 2155f9c2a0dcSSeungwon Jeon unsigned int offset; 2156f95f3850SWill Newton struct mmc_data *data = host->data; 2157f95f3850SWill Newton int shift = host->data_shift; 2158f95f3850SWill Newton u32 status; 21593e4b0d8bSMarkos Chandras unsigned int len; 2160f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 2161f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2162f95f3850SWill Newton 2163f95f3850SWill Newton do { 2164f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2165f9c2a0dcSSeungwon Jeon goto done; 2166f95f3850SWill Newton 21674225fc85SImre Deak host->sg = sg_miter->piter.sg; 2168f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2169f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2170f9c2a0dcSSeungwon Jeon offset = 0; 2171f9c2a0dcSSeungwon Jeon 2172f9c2a0dcSSeungwon Jeon do { 2173f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 2174f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 2175f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 2176f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2177f9c2a0dcSSeungwon Jeon if (!len) 2178f9c2a0dcSSeungwon Jeon break; 2179f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 21803e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2181f95f3850SWill Newton offset += len; 2182f9c2a0dcSSeungwon Jeon remain -= len; 2183f9c2a0dcSSeungwon Jeon } while (remain); 2184f95f3850SWill Newton 2185e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2186f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2187f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2188f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 2189f9c2a0dcSSeungwon Jeon 2190f9c2a0dcSSeungwon Jeon if (!remain) { 2191f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2192f9c2a0dcSSeungwon Jeon goto done; 2193f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2194f9c2a0dcSSeungwon Jeon } 2195f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2196f95f3850SWill Newton return; 2197f95f3850SWill Newton 2198f95f3850SWill Newton done: 2199f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2200f9c2a0dcSSeungwon Jeon host->sg = NULL; 22010e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2202f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2203f95f3850SWill Newton } 2204f95f3850SWill Newton 2205f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 2206f95f3850SWill Newton { 2207f95f3850SWill Newton if (!host->cmd_status) 2208f95f3850SWill Newton host->cmd_status = status; 2209f95f3850SWill Newton 22100e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2211f95f3850SWill Newton 2212f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2213f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2214f95f3850SWill Newton } 2215f95f3850SWill Newton 22166130e7a9SDoug Anderson static void dw_mci_handle_cd(struct dw_mci *host) 22176130e7a9SDoug Anderson { 22186130e7a9SDoug Anderson int i; 22196130e7a9SDoug Anderson 22206130e7a9SDoug Anderson for (i = 0; i < host->num_slots; i++) { 22216130e7a9SDoug Anderson struct dw_mci_slot *slot = host->slot[i]; 22226130e7a9SDoug Anderson 22236130e7a9SDoug Anderson if (!slot) 22246130e7a9SDoug Anderson continue; 22256130e7a9SDoug Anderson 22266130e7a9SDoug Anderson if (slot->mmc->ops->card_event) 22276130e7a9SDoug Anderson slot->mmc->ops->card_event(slot->mmc); 22286130e7a9SDoug Anderson mmc_detect_change(slot->mmc, 22296130e7a9SDoug Anderson msecs_to_jiffies(host->pdata->detect_delay_ms)); 22306130e7a9SDoug Anderson } 22316130e7a9SDoug Anderson } 22326130e7a9SDoug Anderson 2233f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 2234f95f3850SWill Newton { 2235f95f3850SWill Newton struct dw_mci *host = dev_id; 2236182c9081SSeungwon Jeon u32 pending; 22371a5c8e1fSShashidhar Hiremath int i; 2238f95f3850SWill Newton 2239f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 2240f95f3850SWill Newton 2241f95f3850SWill Newton /* 2242f95f3850SWill Newton * DTO fix - version 2.10a and below, and only if internal DMA 2243f95f3850SWill Newton * is configured. 2244f95f3850SWill Newton */ 2245f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { 2246f95f3850SWill Newton if (!pending && 2247f95f3850SWill Newton ((mci_readl(host, STATUS) >> 17) & 0x1fff)) 2248f95f3850SWill Newton pending |= SDMMC_INT_DATA_OVER; 2249f95f3850SWill Newton } 2250f95f3850SWill Newton 2251476d79f1SDoug Anderson if (pending) { 225201730558SDoug Anderson /* Check volt switch first, since it can look like an error */ 225301730558SDoug Anderson if ((host->state == STATE_SENDING_CMD11) && 225401730558SDoug Anderson (pending & SDMMC_INT_VOLT_SWITCH)) { 225549ba0302SDoug Anderson unsigned long irqflags; 22565c935165SDoug Anderson 225701730558SDoug Anderson mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); 225801730558SDoug Anderson pending &= ~SDMMC_INT_VOLT_SWITCH; 225949ba0302SDoug Anderson 226049ba0302SDoug Anderson /* 226149ba0302SDoug Anderson * Hold the lock; we know cmd11_timer can't be kicked 226249ba0302SDoug Anderson * off after the lock is released, so safe to delete. 226349ba0302SDoug Anderson */ 226449ba0302SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 226501730558SDoug Anderson dw_mci_cmd_interrupt(host, pending); 226649ba0302SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 226749ba0302SDoug Anderson 226849ba0302SDoug Anderson del_timer(&host->cmd11_timer); 226901730558SDoug Anderson } 227001730558SDoug Anderson 2271f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 2272f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 2273182c9081SSeungwon Jeon host->cmd_status = pending; 22740e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2275f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2276f95f3850SWill Newton } 2277f95f3850SWill Newton 2278f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 2279f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 2280f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 2281182c9081SSeungwon Jeon host->data_status = pending; 22820e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2283f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 2284f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2285f95f3850SWill Newton } 2286f95f3850SWill Newton 2287f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 228857e10486SAddy Ke if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) 228957e10486SAddy Ke del_timer(&host->dto_timer); 229057e10486SAddy Ke 2291f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 2292f95f3850SWill Newton if (!host->data_status) 2293182c9081SSeungwon Jeon host->data_status = pending; 22940e3a22c0SShawn Lin smp_wmb(); /* drain writebuffer */ 2295f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 2296f95f3850SWill Newton if (host->sg != NULL) 229787a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 2298f95f3850SWill Newton } 2299f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 2300f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2301f95f3850SWill Newton } 2302f95f3850SWill Newton 2303f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 2304f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 2305b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 230687a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 2307f95f3850SWill Newton } 2308f95f3850SWill Newton 2309f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 2310f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2311b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 2312f95f3850SWill Newton dw_mci_write_data_pio(host); 2313f95f3850SWill Newton } 2314f95f3850SWill Newton 2315f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 2316f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 2317182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 2318f95f3850SWill Newton } 2319f95f3850SWill Newton 2320f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 2321f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 23226130e7a9SDoug Anderson dw_mci_handle_cd(host); 2323f95f3850SWill Newton } 2324f95f3850SWill Newton 23251a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 23261a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 23271a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 2328ed2540efSDoug Anderson 2329ed2540efSDoug Anderson if (!slot) 2330ed2540efSDoug Anderson continue; 2331ed2540efSDoug Anderson 233276756234SAddy Ke if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { 233376756234SAddy Ke mci_writel(host, RINTSTS, 233476756234SAddy Ke SDMMC_INT_SDIO(slot->sdio_id)); 23351a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 23361a5c8e1fSShashidhar Hiremath } 23371a5c8e1fSShashidhar Hiremath } 23381a5c8e1fSShashidhar Hiremath 23391fb5f68aSMarkos Chandras } 2340f95f3850SWill Newton 2341f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2342f95f3850SWill Newton /* Handle DMA interrupts */ 234369d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 234469d99fdcSPrabu Thangamuthu pending = mci_readl(host, IDSTS64); 234569d99fdcSPrabu Thangamuthu if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 234669d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | 234769d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 234869d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); 234969d99fdcSPrabu Thangamuthu host->dma_ops->complete(host); 235069d99fdcSPrabu Thangamuthu } 235169d99fdcSPrabu Thangamuthu } else { 2352f95f3850SWill Newton pending = mci_readl(host, IDSTS); 2353f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 235469d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | 235569d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 2356f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 2357f95f3850SWill Newton host->dma_ops->complete(host); 2358f95f3850SWill Newton } 235969d99fdcSPrabu Thangamuthu } 2360f95f3850SWill Newton #endif 2361f95f3850SWill Newton 2362f95f3850SWill Newton return IRQ_HANDLED; 2363f95f3850SWill Newton } 2364f95f3850SWill Newton 2365c91eab4bSThomas Abraham #ifdef CONFIG_OF 2366eff8f2f5SLars-Peter Clausen /* given a slot, find out the device node representing that slot */ 2367eff8f2f5SLars-Peter Clausen static struct device_node *dw_mci_of_find_slot_node(struct dw_mci_slot *slot) 2368c91eab4bSThomas Abraham { 2369eff8f2f5SLars-Peter Clausen struct device *dev = slot->mmc->parent; 2370c91eab4bSThomas Abraham struct device_node *np; 2371c91eab4bSThomas Abraham const __be32 *addr; 2372c91eab4bSThomas Abraham int len; 2373c91eab4bSThomas Abraham 2374c91eab4bSThomas Abraham if (!dev || !dev->of_node) 2375c91eab4bSThomas Abraham return NULL; 2376c91eab4bSThomas Abraham 2377c91eab4bSThomas Abraham for_each_child_of_node(dev->of_node, np) { 2378c91eab4bSThomas Abraham addr = of_get_property(np, "reg", &len); 2379c91eab4bSThomas Abraham if (!addr || (len < sizeof(int))) 2380c91eab4bSThomas Abraham continue; 2381eff8f2f5SLars-Peter Clausen if (be32_to_cpup(addr) == slot->id) 2382c91eab4bSThomas Abraham return np; 2383c91eab4bSThomas Abraham } 2384c91eab4bSThomas Abraham return NULL; 2385c91eab4bSThomas Abraham } 2386c91eab4bSThomas Abraham 2387eff8f2f5SLars-Peter Clausen static void dw_mci_slot_of_parse(struct dw_mci_slot *slot) 2388a70aaa64SDoug Anderson { 2389eff8f2f5SLars-Peter Clausen struct device_node *np = dw_mci_of_find_slot_node(slot); 2390a70aaa64SDoug Anderson 2391eff8f2f5SLars-Peter Clausen if (!np) 2392eff8f2f5SLars-Peter Clausen return; 2393a70aaa64SDoug Anderson 2394eff8f2f5SLars-Peter Clausen if (of_property_read_bool(np, "disable-wp")) { 2395eff8f2f5SLars-Peter Clausen slot->mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; 2396eff8f2f5SLars-Peter Clausen dev_warn(slot->mmc->parent, 2397eff8f2f5SLars-Peter Clausen "Slot quirk 'disable-wp' is deprecated\n"); 239826375b5cSJaehoon Chung } 2399a70aaa64SDoug Anderson } 2400c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2401eff8f2f5SLars-Peter Clausen static void dw_mci_slot_of_parse(struct dw_mci_slot *slot) 2402a70aaa64SDoug Anderson { 2403a70aaa64SDoug Anderson } 2404c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2405c91eab4bSThomas Abraham 240636c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2407f95f3850SWill Newton { 2408f95f3850SWill Newton struct mmc_host *mmc; 2409f95f3850SWill Newton struct dw_mci_slot *slot; 2410e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2411800d78bfSThomas Abraham int ctrl_id, ret; 24121f44a2a5SSeungwon Jeon u32 freq[2]; 2413f95f3850SWill Newton 24144a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2415f95f3850SWill Newton if (!mmc) 2416f95f3850SWill Newton return -ENOMEM; 2417f95f3850SWill Newton 2418f95f3850SWill Newton slot = mmc_priv(mmc); 2419f95f3850SWill Newton slot->id = id; 242076756234SAddy Ke slot->sdio_id = host->sdio_id0 + id; 2421f95f3850SWill Newton slot->mmc = mmc; 2422f95f3850SWill Newton slot->host = host; 2423c91eab4bSThomas Abraham host->slot[id] = slot; 2424f95f3850SWill Newton 2425f95f3850SWill Newton mmc->ops = &dw_mci_ops; 24261f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 24271f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 24281f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 24291f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 24301f44a2a5SSeungwon Jeon } else { 24311f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 24321f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 24331f44a2a5SSeungwon Jeon } 2434f95f3850SWill Newton 243551da2240SYuvaraj CD /*if there are external regulators, get them*/ 243651da2240SYuvaraj CD ret = mmc_regulator_get_supply(mmc); 243751da2240SYuvaraj CD if (ret == -EPROBE_DEFER) 24383cf890fcSDoug Anderson goto err_host_allocated; 243951da2240SYuvaraj CD 244051da2240SYuvaraj CD if (!mmc->ocr_avail) 2441f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2442f95f3850SWill Newton 2443fc3d7720SJaehoon Chung if (host->pdata->caps) 2444fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2445fc3d7720SJaehoon Chung 2446ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2447ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2448ab269128SAbhilash Kesavan 2449800d78bfSThomas Abraham if (host->dev->of_node) { 2450800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2451800d78bfSThomas Abraham if (ctrl_id < 0) 2452800d78bfSThomas Abraham ctrl_id = 0; 2453800d78bfSThomas Abraham } else { 2454800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2455800d78bfSThomas Abraham } 2456cb27a843SJames Hogan if (drv_data && drv_data->caps) 2457cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2458800d78bfSThomas Abraham 24594f408cc6SSeungwon Jeon if (host->pdata->caps2) 24604f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 24614f408cc6SSeungwon Jeon 2462eff8f2f5SLars-Peter Clausen dw_mci_slot_of_parse(slot); 2463eff8f2f5SLars-Peter Clausen 24643cf890fcSDoug Anderson ret = mmc_of_parse(mmc); 24653cf890fcSDoug Anderson if (ret) 24663cf890fcSDoug Anderson goto err_host_allocated; 2467f95f3850SWill Newton 2468f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 2469575c319dSHeiko Stuebner if (host->use_dma) { 2470a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2471a39e5746SJaehoon Chung mmc->max_blk_size = 65536; 2472575c319dSHeiko Stuebner mmc->max_seg_size = 0x1000; 24731a25b1b4SSeungwon Jeon mmc->max_req_size = mmc->max_seg_size * host->ring_size; 24741a25b1b4SSeungwon Jeon mmc->max_blk_count = mmc->max_req_size / 512; 2475575c319dSHeiko Stuebner } else { 2476f95f3850SWill Newton mmc->max_segs = 64; 2477f95f3850SWill Newton mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ 2478f95f3850SWill Newton mmc->max_blk_count = 512; 2479575c319dSHeiko Stuebner mmc->max_req_size = mmc->max_blk_size * 2480575c319dSHeiko Stuebner mmc->max_blk_count; 2481f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2482575c319dSHeiko Stuebner } 2483f95f3850SWill Newton 2484ae0eb348SJaehoon Chung if (dw_mci_get_cd(mmc)) 2485ae0eb348SJaehoon Chung set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2486ae0eb348SJaehoon Chung else 2487ae0eb348SJaehoon Chung clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2488ae0eb348SJaehoon Chung 24890cea529dSJaehoon Chung ret = mmc_add_host(mmc); 24900cea529dSJaehoon Chung if (ret) 24913cf890fcSDoug Anderson goto err_host_allocated; 2492f95f3850SWill Newton 2493f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2494f95f3850SWill Newton dw_mci_init_debugfs(slot); 2495f95f3850SWill Newton #endif 2496f95f3850SWill Newton 2497f95f3850SWill Newton return 0; 2498800d78bfSThomas Abraham 24993cf890fcSDoug Anderson err_host_allocated: 2500800d78bfSThomas Abraham mmc_free_host(mmc); 250151da2240SYuvaraj CD return ret; 2502f95f3850SWill Newton } 2503f95f3850SWill Newton 2504f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2505f95f3850SWill Newton { 2506f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2507f95f3850SWill Newton mmc_remove_host(slot->mmc); 2508f95f3850SWill Newton slot->host->slot[id] = NULL; 2509f95f3850SWill Newton mmc_free_host(slot->mmc); 2510f95f3850SWill Newton } 2511f95f3850SWill Newton 2512f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2513f95f3850SWill Newton { 251469d99fdcSPrabu Thangamuthu int addr_config; 251569d99fdcSPrabu Thangamuthu /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ 251669d99fdcSPrabu Thangamuthu addr_config = (mci_readl(host, HCON) >> 27) & 0x01; 251769d99fdcSPrabu Thangamuthu 251869d99fdcSPrabu Thangamuthu if (addr_config == 1) { 251969d99fdcSPrabu Thangamuthu /* host supports IDMAC in 64-bit address mode */ 252069d99fdcSPrabu Thangamuthu host->dma_64bit_address = 1; 252169d99fdcSPrabu Thangamuthu dev_info(host->dev, "IDMAC supports 64-bit address mode.\n"); 252269d99fdcSPrabu Thangamuthu if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) 252369d99fdcSPrabu Thangamuthu dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64)); 252469d99fdcSPrabu Thangamuthu } else { 252569d99fdcSPrabu Thangamuthu /* host supports IDMAC in 32-bit address mode */ 252669d99fdcSPrabu Thangamuthu host->dma_64bit_address = 0; 252769d99fdcSPrabu Thangamuthu dev_info(host->dev, "IDMAC supports 32-bit address mode.\n"); 252869d99fdcSPrabu Thangamuthu } 252969d99fdcSPrabu Thangamuthu 2530f95f3850SWill Newton /* Alloc memory for sg translation */ 2531780f22afSSeungwon Jeon host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, 2532f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2533f95f3850SWill Newton if (!host->sg_cpu) { 25344a90920cSThomas Abraham dev_err(host->dev, "%s: could not alloc DMA memory\n", 2535f95f3850SWill Newton __func__); 2536f95f3850SWill Newton goto no_dma; 2537f95f3850SWill Newton } 2538f95f3850SWill Newton 2539f95f3850SWill Newton /* Determine which DMA interface to use */ 2540f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2541f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 254200956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 2543f95f3850SWill Newton #endif 2544f95f3850SWill Newton 2545f95f3850SWill Newton if (!host->dma_ops) 2546f95f3850SWill Newton goto no_dma; 2547f95f3850SWill Newton 2548e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2549e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2550f95f3850SWill Newton if (host->dma_ops->init(host)) { 25510e3a22c0SShawn Lin dev_err(host->dev, "%s: Unable to initialize DMA Controller.\n", 25520e3a22c0SShawn Lin __func__); 2553f95f3850SWill Newton goto no_dma; 2554f95f3850SWill Newton } 2555f95f3850SWill Newton } else { 25564a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2557f95f3850SWill Newton goto no_dma; 2558f95f3850SWill Newton } 2559f95f3850SWill Newton 2560f95f3850SWill Newton host->use_dma = 1; 2561f95f3850SWill Newton return; 2562f95f3850SWill Newton 2563f95f3850SWill Newton no_dma: 25644a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 2565f95f3850SWill Newton host->use_dma = 0; 2566f95f3850SWill Newton } 2567f95f3850SWill Newton 256831bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) 2569f95f3850SWill Newton { 2570f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 257131bff450SSeungwon Jeon u32 ctrl; 2572f95f3850SWill Newton 257331bff450SSeungwon Jeon ctrl = mci_readl(host, CTRL); 257431bff450SSeungwon Jeon ctrl |= reset; 257531bff450SSeungwon Jeon mci_writel(host, CTRL, ctrl); 2576f95f3850SWill Newton 2577f95f3850SWill Newton /* wait till resets clear */ 2578f95f3850SWill Newton do { 2579f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 258031bff450SSeungwon Jeon if (!(ctrl & reset)) 2581f95f3850SWill Newton return true; 2582f95f3850SWill Newton } while (time_before(jiffies, timeout)); 2583f95f3850SWill Newton 258431bff450SSeungwon Jeon dev_err(host->dev, 258531bff450SSeungwon Jeon "Timeout resetting block (ctrl reset %#x)\n", 258631bff450SSeungwon Jeon ctrl & reset); 2587f95f3850SWill Newton 2588f95f3850SWill Newton return false; 2589f95f3850SWill Newton } 2590f95f3850SWill Newton 25913a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host) 259231bff450SSeungwon Jeon { 25933a33a94cSSonny Rao u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; 25943a33a94cSSonny Rao bool ret = false; 25953a33a94cSSonny Rao 259631bff450SSeungwon Jeon /* 259731bff450SSeungwon Jeon * Reseting generates a block interrupt, hence setting 259831bff450SSeungwon Jeon * the scatter-gather pointer to NULL. 259931bff450SSeungwon Jeon */ 260031bff450SSeungwon Jeon if (host->sg) { 260131bff450SSeungwon Jeon sg_miter_stop(&host->sg_miter); 260231bff450SSeungwon Jeon host->sg = NULL; 260331bff450SSeungwon Jeon } 260431bff450SSeungwon Jeon 26053a33a94cSSonny Rao if (host->use_dma) 26063a33a94cSSonny Rao flags |= SDMMC_CTRL_DMA_RESET; 26073a33a94cSSonny Rao 26083a33a94cSSonny Rao if (dw_mci_ctrl_reset(host, flags)) { 26093a33a94cSSonny Rao /* 26103a33a94cSSonny Rao * In all cases we clear the RAWINTS register to clear any 26113a33a94cSSonny Rao * interrupts. 26123a33a94cSSonny Rao */ 26133a33a94cSSonny Rao mci_writel(host, RINTSTS, 0xFFFFFFFF); 26143a33a94cSSonny Rao 26153a33a94cSSonny Rao /* if using dma we wait for dma_req to clear */ 26163a33a94cSSonny Rao if (host->use_dma) { 26173a33a94cSSonny Rao unsigned long timeout = jiffies + msecs_to_jiffies(500); 26183a33a94cSSonny Rao u32 status; 26190e3a22c0SShawn Lin 26203a33a94cSSonny Rao do { 26213a33a94cSSonny Rao status = mci_readl(host, STATUS); 26223a33a94cSSonny Rao if (!(status & SDMMC_STATUS_DMA_REQ)) 26233a33a94cSSonny Rao break; 26243a33a94cSSonny Rao cpu_relax(); 26253a33a94cSSonny Rao } while (time_before(jiffies, timeout)); 26263a33a94cSSonny Rao 26273a33a94cSSonny Rao if (status & SDMMC_STATUS_DMA_REQ) { 26283a33a94cSSonny Rao dev_err(host->dev, 26290e3a22c0SShawn Lin "%s: Timeout waiting for dma_req to clear during reset\n", 26300e3a22c0SShawn Lin __func__); 26313a33a94cSSonny Rao goto ciu_out; 263231bff450SSeungwon Jeon } 263331bff450SSeungwon Jeon 26343a33a94cSSonny Rao /* when using DMA next we reset the fifo again */ 26353a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) 26363a33a94cSSonny Rao goto ciu_out; 26373a33a94cSSonny Rao } 26383a33a94cSSonny Rao } else { 26393a33a94cSSonny Rao /* if the controller reset bit did clear, then set clock regs */ 26403a33a94cSSonny Rao if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { 26410e3a22c0SShawn Lin dev_err(host->dev, 26420e3a22c0SShawn Lin "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n", 26433a33a94cSSonny Rao __func__); 26443a33a94cSSonny Rao goto ciu_out; 26453a33a94cSSonny Rao } 26463a33a94cSSonny Rao } 26473a33a94cSSonny Rao 26483a33a94cSSonny Rao #if IS_ENABLED(CONFIG_MMC_DW_IDMAC) 26493a33a94cSSonny Rao /* It is also recommended that we reset and reprogram idmac */ 26503a33a94cSSonny Rao dw_mci_idmac_reset(host); 26513a33a94cSSonny Rao #endif 26523a33a94cSSonny Rao 26533a33a94cSSonny Rao ret = true; 26543a33a94cSSonny Rao 26553a33a94cSSonny Rao ciu_out: 26563a33a94cSSonny Rao /* After a CTRL reset we need to have CIU set clock registers */ 26573a33a94cSSonny Rao mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); 26583a33a94cSSonny Rao 26593a33a94cSSonny Rao return ret; 266031bff450SSeungwon Jeon } 266131bff450SSeungwon Jeon 26625c935165SDoug Anderson static void dw_mci_cmd11_timer(unsigned long arg) 26635c935165SDoug Anderson { 26645c935165SDoug Anderson struct dw_mci *host = (struct dw_mci *)arg; 26655c935165SDoug Anderson 2666fd674198SDoug Anderson if (host->state != STATE_SENDING_CMD11) { 2667fd674198SDoug Anderson dev_warn(host->dev, "Unexpected CMD11 timeout\n"); 2668fd674198SDoug Anderson return; 2669fd674198SDoug Anderson } 26705c935165SDoug Anderson 26715c935165SDoug Anderson host->cmd_status = SDMMC_INT_RTO; 26725c935165SDoug Anderson set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 26735c935165SDoug Anderson tasklet_schedule(&host->tasklet); 26745c935165SDoug Anderson } 26755c935165SDoug Anderson 267657e10486SAddy Ke static void dw_mci_dto_timer(unsigned long arg) 267757e10486SAddy Ke { 267857e10486SAddy Ke struct dw_mci *host = (struct dw_mci *)arg; 267957e10486SAddy Ke 268057e10486SAddy Ke switch (host->state) { 268157e10486SAddy Ke case STATE_SENDING_DATA: 268257e10486SAddy Ke case STATE_DATA_BUSY: 268357e10486SAddy Ke /* 268457e10486SAddy Ke * If DTO interrupt does NOT come in sending data state, 268557e10486SAddy Ke * we should notify the driver to terminate current transfer 268657e10486SAddy Ke * and report a data timeout to the core. 268757e10486SAddy Ke */ 268857e10486SAddy Ke host->data_status = SDMMC_INT_DRTO; 268957e10486SAddy Ke set_bit(EVENT_DATA_ERROR, &host->pending_events); 269057e10486SAddy Ke set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 269157e10486SAddy Ke tasklet_schedule(&host->tasklet); 269257e10486SAddy Ke break; 269357e10486SAddy Ke default: 269457e10486SAddy Ke break; 269557e10486SAddy Ke } 269657e10486SAddy Ke } 269757e10486SAddy Ke 2698c91eab4bSThomas Abraham #ifdef CONFIG_OF 2699c91eab4bSThomas Abraham static struct dw_mci_of_quirks { 2700c91eab4bSThomas Abraham char *quirk; 2701c91eab4bSThomas Abraham int id; 2702c91eab4bSThomas Abraham } of_quirks[] = { 2703c91eab4bSThomas Abraham { 2704c91eab4bSThomas Abraham .quirk = "broken-cd", 2705c91eab4bSThomas Abraham .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, 2706c91eab4bSThomas Abraham }, 2707c91eab4bSThomas Abraham }; 2708c91eab4bSThomas Abraham 2709c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2710c91eab4bSThomas Abraham { 2711c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2712c91eab4bSThomas Abraham struct device *dev = host->dev; 2713c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2714e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2715800d78bfSThomas Abraham int idx, ret; 27163c6d89eaSDoug Anderson u32 clock_frequency; 2717c91eab4bSThomas Abraham 2718c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2719bf3707eaSBeomho Seo if (!pdata) 2720c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2721c91eab4bSThomas Abraham 2722c91eab4bSThomas Abraham /* find out number of slots supported */ 2723c91eab4bSThomas Abraham if (of_property_read_u32(dev->of_node, "num-slots", 2724c91eab4bSThomas Abraham &pdata->num_slots)) { 27250e3a22c0SShawn Lin dev_info(dev, 27260e3a22c0SShawn Lin "num-slots property not found, assuming 1 slot is available\n"); 2727c91eab4bSThomas Abraham pdata->num_slots = 1; 2728c91eab4bSThomas Abraham } 2729c91eab4bSThomas Abraham 2730c91eab4bSThomas Abraham /* get quirks */ 2731c91eab4bSThomas Abraham for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) 2732c91eab4bSThomas Abraham if (of_get_property(np, of_quirks[idx].quirk, NULL)) 2733c91eab4bSThomas Abraham pdata->quirks |= of_quirks[idx].id; 2734c91eab4bSThomas Abraham 2735c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 27360e3a22c0SShawn Lin dev_info(dev, 27370e3a22c0SShawn Lin "fifo-depth property not found, using value of FIFOTH register as default\n"); 2738c91eab4bSThomas Abraham 2739c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2740c91eab4bSThomas Abraham 27413c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 27423c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 27433c6d89eaSDoug Anderson 2744cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2745cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2746800d78bfSThomas Abraham if (ret) 2747800d78bfSThomas Abraham return ERR_PTR(ret); 2748800d78bfSThomas Abraham } 2749800d78bfSThomas Abraham 275040a7a463SJaehoon Chung if (of_find_property(np, "supports-highspeed", NULL)) { 275140a7a463SJaehoon Chung dev_info(dev, "supports-highspeed property is deprecated.\n"); 275210b49841SSeungwon Jeon pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; 275340a7a463SJaehoon Chung } 275410b49841SSeungwon Jeon 2755c91eab4bSThomas Abraham return pdata; 2756c91eab4bSThomas Abraham } 2757c91eab4bSThomas Abraham 2758c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2759c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2760c91eab4bSThomas Abraham { 2761c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2762c91eab4bSThomas Abraham } 2763c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2764c91eab4bSThomas Abraham 2765fa0c3283SDoug Anderson static void dw_mci_enable_cd(struct dw_mci *host) 2766fa0c3283SDoug Anderson { 2767fa0c3283SDoug Anderson struct dw_mci_board *brd = host->pdata; 2768fa0c3283SDoug Anderson unsigned long irqflags; 2769fa0c3283SDoug Anderson u32 temp; 2770fa0c3283SDoug Anderson int i; 2771fa0c3283SDoug Anderson 2772fa0c3283SDoug Anderson /* No need for CD if broken card detection */ 2773fa0c3283SDoug Anderson if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) 2774fa0c3283SDoug Anderson return; 2775fa0c3283SDoug Anderson 2776fa0c3283SDoug Anderson /* No need for CD if all slots have a non-error GPIO */ 2777fa0c3283SDoug Anderson for (i = 0; i < host->num_slots; i++) { 2778fa0c3283SDoug Anderson struct dw_mci_slot *slot = host->slot[i]; 2779fa0c3283SDoug Anderson 2780fa0c3283SDoug Anderson if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc))) 2781fa0c3283SDoug Anderson break; 2782fa0c3283SDoug Anderson } 2783fa0c3283SDoug Anderson if (i == host->num_slots) 2784fa0c3283SDoug Anderson return; 2785fa0c3283SDoug Anderson 2786fa0c3283SDoug Anderson spin_lock_irqsave(&host->irq_lock, irqflags); 2787fa0c3283SDoug Anderson temp = mci_readl(host, INTMASK); 2788fa0c3283SDoug Anderson temp |= SDMMC_INT_CD; 2789fa0c3283SDoug Anderson mci_writel(host, INTMASK, temp); 2790fa0c3283SDoug Anderson spin_unlock_irqrestore(&host->irq_lock, irqflags); 2791fa0c3283SDoug Anderson } 2792fa0c3283SDoug Anderson 279362ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 2794f95f3850SWill Newton { 2795e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 279662ca8034SShashidhar Hiremath int width, i, ret = 0; 2797f95f3850SWill Newton u32 fifo_size; 27981c2215b7SThomas Abraham int init_slots = 0; 2799f95f3850SWill Newton 2800c91eab4bSThomas Abraham if (!host->pdata) { 2801c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 2802c91eab4bSThomas Abraham if (IS_ERR(host->pdata)) { 2803c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 2804c91eab4bSThomas Abraham return -EINVAL; 2805c91eab4bSThomas Abraham } 2806f95f3850SWill Newton } 2807f95f3850SWill Newton 28089e747b7eSJaehoon Chung if (host->pdata->num_slots < 1) { 28094a90920cSThomas Abraham dev_err(host->dev, 2810907abd51SJaehoon Chung "Platform data must supply num_slots.\n"); 281162ca8034SShashidhar Hiremath return -ENODEV; 2812f95f3850SWill Newton } 2813f95f3850SWill Newton 2814780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 2815f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 2816f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 2817f90a0612SThomas Abraham } else { 2818f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 2819f90a0612SThomas Abraham if (ret) { 2820f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 2821f90a0612SThomas Abraham return ret; 2822f90a0612SThomas Abraham } 2823f95f3850SWill Newton } 2824f95f3850SWill Newton 2825780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 2826f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 2827f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 28283c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 2829f90a0612SThomas Abraham } else { 2830f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 2831f90a0612SThomas Abraham if (ret) { 2832f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 2833f90a0612SThomas Abraham goto err_clk_biu; 2834f90a0612SThomas Abraham } 2835f90a0612SThomas Abraham 28363c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 28373c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 28383c6d89eaSDoug Anderson if (ret) 28393c6d89eaSDoug Anderson dev_warn(host->dev, 2840612de4c1SJaehoon Chung "Unable to set bus rate to %uHz\n", 28413c6d89eaSDoug Anderson host->pdata->bus_hz); 28423c6d89eaSDoug Anderson } 2843f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 28443c6d89eaSDoug Anderson } 2845f90a0612SThomas Abraham 2846612de4c1SJaehoon Chung if (!host->bus_hz) { 2847612de4c1SJaehoon Chung dev_err(host->dev, 2848612de4c1SJaehoon Chung "Platform data must supply bus speed\n"); 2849612de4c1SJaehoon Chung ret = -ENODEV; 2850612de4c1SJaehoon Chung goto err_clk_ciu; 2851612de4c1SJaehoon Chung } 2852612de4c1SJaehoon Chung 2853002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 2854002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 2855002f0d5cSYuvaraj Kumar C D if (ret) { 2856002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 2857002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 2858002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 2859002f0d5cSYuvaraj Kumar C D } 2860002f0d5cSYuvaraj Kumar C D } 2861002f0d5cSYuvaraj Kumar C D 2862cb27a843SJames Hogan if (drv_data && drv_data->setup_clock) { 2863cb27a843SJames Hogan ret = drv_data->setup_clock(host); 2864800d78bfSThomas Abraham if (ret) { 2865800d78bfSThomas Abraham dev_err(host->dev, 2866800d78bfSThomas Abraham "implementation specific clock setup failed\n"); 2867800d78bfSThomas Abraham goto err_clk_ciu; 2868800d78bfSThomas Abraham } 2869800d78bfSThomas Abraham } 2870800d78bfSThomas Abraham 28715c935165SDoug Anderson setup_timer(&host->cmd11_timer, 28725c935165SDoug Anderson dw_mci_cmd11_timer, (unsigned long)host); 28735c935165SDoug Anderson 287462ca8034SShashidhar Hiremath host->quirks = host->pdata->quirks; 2875f95f3850SWill Newton 287657e10486SAddy Ke if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO) 287757e10486SAddy Ke setup_timer(&host->dto_timer, 287857e10486SAddy Ke dw_mci_dto_timer, (unsigned long)host); 287957e10486SAddy Ke 2880f95f3850SWill Newton spin_lock_init(&host->lock); 2881f8c58c11SDoug Anderson spin_lock_init(&host->irq_lock); 2882f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 2883f95f3850SWill Newton 2884f95f3850SWill Newton /* 2885f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 2886f95f3850SWill Newton * the correct values. 2887f95f3850SWill Newton */ 2888f95f3850SWill Newton i = (mci_readl(host, HCON) >> 7) & 0x7; 2889f95f3850SWill Newton if (!i) { 2890f95f3850SWill Newton host->push_data = dw_mci_push_data16; 2891f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 2892f95f3850SWill Newton width = 16; 2893f95f3850SWill Newton host->data_shift = 1; 2894f95f3850SWill Newton } else if (i == 2) { 2895f95f3850SWill Newton host->push_data = dw_mci_push_data64; 2896f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 2897f95f3850SWill Newton width = 64; 2898f95f3850SWill Newton host->data_shift = 3; 2899f95f3850SWill Newton } else { 2900f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 2901f95f3850SWill Newton WARN((i != 1), 2902f95f3850SWill Newton "HCON reports a reserved host data width!\n" 2903f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 2904f95f3850SWill Newton host->push_data = dw_mci_push_data32; 2905f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 2906f95f3850SWill Newton width = 32; 2907f95f3850SWill Newton host->data_shift = 2; 2908f95f3850SWill Newton } 2909f95f3850SWill Newton 2910f95f3850SWill Newton /* Reset all blocks */ 29113a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) 2912141a712aSSeungwon Jeon return -ENODEV; 2913141a712aSSeungwon Jeon 2914141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 2915141a712aSSeungwon Jeon dw_mci_init_dma(host); 2916f95f3850SWill Newton 2917f95f3850SWill Newton /* Clear the interrupts for the host controller */ 2918f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2919f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2920f95f3850SWill Newton 2921f95f3850SWill Newton /* Put in max timeout */ 2922f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 2923f95f3850SWill Newton 2924f95f3850SWill Newton /* 2925f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 2926f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 2927f95f3850SWill Newton */ 2928b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 2929b86d8253SJames Hogan /* 2930b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 2931b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 2932b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 2933b86d8253SJames Hogan * should put it in the platform data. 2934b86d8253SJames Hogan */ 2935f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 29368234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 2937b86d8253SJames Hogan } else { 2938b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 2939b86d8253SJames Hogan } 2940b86d8253SJames Hogan host->fifo_depth = fifo_size; 294152426899SSeungwon Jeon host->fifoth_val = 294252426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 2943e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 2944f95f3850SWill Newton 2945f95f3850SWill Newton /* disable clock to CIU */ 2946f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2947f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2948f95f3850SWill Newton 294963008768SJames Hogan /* 295063008768SJames Hogan * In 2.40a spec, Data offset is changed. 295163008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 295263008768SJames Hogan */ 295363008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 295463008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 295563008768SJames Hogan 295663008768SJames Hogan if (host->verid < DW_MMC_240A) 295776184ac1SBen Dooks host->fifo_reg = host->regs + DATA_OFFSET; 295863008768SJames Hogan else 295976184ac1SBen Dooks host->fifo_reg = host->regs + DATA_240A_OFFSET; 296063008768SJames Hogan 2961f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 2962780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 2963780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 2964f95f3850SWill Newton if (ret) 29656130e7a9SDoug Anderson goto err_dmaunmap; 2966f95f3850SWill Newton 2967f95f3850SWill Newton if (host->pdata->num_slots) 2968f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 2969f95f3850SWill Newton else 2970f95f3850SWill Newton host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; 2971f95f3850SWill Newton 29722da1d7f2SYuvaraj CD /* 2973fa0c3283SDoug Anderson * Enable interrupts for command done, data over, data empty, 29742da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 29752da1d7f2SYuvaraj CD */ 29762da1d7f2SYuvaraj CD mci_writel(host, RINTSTS, 0xFFFFFFFF); 29772da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 29782da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 2979fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 29800e3a22c0SShawn Lin /* Enable mci interrupt */ 29810e3a22c0SShawn Lin mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 29822da1d7f2SYuvaraj CD 29830e3a22c0SShawn Lin dev_info(host->dev, 29840e3a22c0SShawn Lin "DW MMC controller at irq %d,%d bit host data width,%u deep fifo\n", 29852da1d7f2SYuvaraj CD host->irq, width, fifo_size); 29862da1d7f2SYuvaraj CD 2987f95f3850SWill Newton /* We need at least one slot to succeed */ 2988f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2989f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 29901c2215b7SThomas Abraham if (ret) 29911c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 29921c2215b7SThomas Abraham else 29931c2215b7SThomas Abraham init_slots++; 2994f95f3850SWill Newton } 29951c2215b7SThomas Abraham 29961c2215b7SThomas Abraham if (init_slots) { 29971c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 29981c2215b7SThomas Abraham } else { 29990e3a22c0SShawn Lin dev_dbg(host->dev, 30000e3a22c0SShawn Lin "attempted to initialize %d slots, but failed on all\n", 30010e3a22c0SShawn Lin host->num_slots); 30026130e7a9SDoug Anderson goto err_dmaunmap; 3003f95f3850SWill Newton } 3004f95f3850SWill Newton 3005b793f658SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3006b793f658SDoug Anderson dw_mci_enable_cd(host); 3007b793f658SDoug Anderson 3008f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) 30094a90920cSThomas Abraham dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); 3010f95f3850SWill Newton 3011f95f3850SWill Newton return 0; 3012f95f3850SWill Newton 3013f95f3850SWill Newton err_dmaunmap: 3014f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3015f95f3850SWill Newton host->dma_ops->exit(host); 3016f90a0612SThomas Abraham 3017f90a0612SThomas Abraham err_clk_ciu: 3018780f22afSSeungwon Jeon if (!IS_ERR(host->ciu_clk)) 3019f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3020780f22afSSeungwon Jeon 3021f90a0612SThomas Abraham err_clk_biu: 3022780f22afSSeungwon Jeon if (!IS_ERR(host->biu_clk)) 3023f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3024780f22afSSeungwon Jeon 3025f95f3850SWill Newton return ret; 3026f95f3850SWill Newton } 302762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 3028f95f3850SWill Newton 302962ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 3030f95f3850SWill Newton { 3031f95f3850SWill Newton int i; 3032f95f3850SWill Newton 3033f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 30344a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 3035f95f3850SWill Newton if (host->slot[i]) 3036f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 3037f95f3850SWill Newton } 3038f95f3850SWill Newton 3039048fd7e6SPrabu Thangamuthu mci_writel(host, RINTSTS, 0xFFFFFFFF); 3040048fd7e6SPrabu Thangamuthu mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 3041048fd7e6SPrabu Thangamuthu 3042f95f3850SWill Newton /* disable clock to CIU */ 3043f95f3850SWill Newton mci_writel(host, CLKENA, 0); 3044f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 3045f95f3850SWill Newton 3046f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 3047f95f3850SWill Newton host->dma_ops->exit(host); 3048f95f3850SWill Newton 3049f90a0612SThomas Abraham if (!IS_ERR(host->ciu_clk)) 3050f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 3051780f22afSSeungwon Jeon 3052f90a0612SThomas Abraham if (!IS_ERR(host->biu_clk)) 3053f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 3054f95f3850SWill Newton } 305562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 305662ca8034SShashidhar Hiremath 305762ca8034SShashidhar Hiremath 3058f95f3850SWill Newton 30596fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP 3060f95f3850SWill Newton /* 3061f95f3850SWill Newton * TODO: we should probably disable the clock to the card in the suspend path. 3062f95f3850SWill Newton */ 306362ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host) 3064f95f3850SWill Newton { 3065f95f3850SWill Newton return 0; 3066f95f3850SWill Newton } 306762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend); 3068f95f3850SWill Newton 306962ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host) 3070f95f3850SWill Newton { 3071f95f3850SWill Newton int i, ret; 3072f95f3850SWill Newton 30733a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 3074e61cf118SJaehoon Chung ret = -ENODEV; 3075e61cf118SJaehoon Chung return ret; 3076e61cf118SJaehoon Chung } 3077e61cf118SJaehoon Chung 30783bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 3079141a712aSSeungwon Jeon host->dma_ops->init(host); 3080141a712aSSeungwon Jeon 308152426899SSeungwon Jeon /* 308252426899SSeungwon Jeon * Restore the initial value at FIFOTH register 308352426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 308452426899SSeungwon Jeon */ 3085e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 308652426899SSeungwon Jeon host->prev_blksz = 0; 3087e61cf118SJaehoon Chung 30882eb2944fSDoug Anderson /* Put in max timeout */ 30892eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 30902eb2944fSDoug Anderson 3091e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 3092e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 3093e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 3094fa0c3283SDoug Anderson DW_MCI_ERROR_FLAGS); 3095e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 3096e61cf118SJaehoon Chung 3097f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 3098f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 30990e3a22c0SShawn Lin 3100f95f3850SWill Newton if (!slot) 3101f95f3850SWill Newton continue; 3102ab269128SAbhilash Kesavan if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { 3103ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 3104ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 3105ab269128SAbhilash Kesavan } 3106f95f3850SWill Newton } 3107fa0c3283SDoug Anderson 3108fa0c3283SDoug Anderson /* Now that slots are all setup, we can enable card detect */ 3109fa0c3283SDoug Anderson dw_mci_enable_cd(host); 3110fa0c3283SDoug Anderson 3111f95f3850SWill Newton return 0; 3112f95f3850SWill Newton } 311362ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume); 31146fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */ 31156fe8890dSJaehoon Chung 3116f95f3850SWill Newton static int __init dw_mci_init(void) 3117f95f3850SWill Newton { 31188e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 311962ca8034SShashidhar Hiremath return 0; 3120f95f3850SWill Newton } 3121f95f3850SWill Newton 3122f95f3850SWill Newton static void __exit dw_mci_exit(void) 3123f95f3850SWill Newton { 3124f95f3850SWill Newton } 3125f95f3850SWill Newton 3126f95f3850SWill Newton module_init(dw_mci_init); 3127f95f3850SWill Newton module_exit(dw_mci_exit); 3128f95f3850SWill Newton 3129f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 3130f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 3131f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 3132f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 3133