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> 30f95f3850SWill Newton #include <linux/mmc/host.h> 31f95f3850SWill Newton #include <linux/mmc/mmc.h> 3201730558SDoug Anderson #include <linux/mmc/sd.h> 3390c2143aSSeungwon Jeon #include <linux/mmc/sdio.h> 34f95f3850SWill Newton #include <linux/mmc/dw_mmc.h> 35f95f3850SWill Newton #include <linux/bitops.h> 36c07946a3SJaehoon Chung #include <linux/regulator/consumer.h> 37c91eab4bSThomas Abraham #include <linux/of.h> 3855a6ceb2SDoug Anderson #include <linux/of_gpio.h> 39bf626e55SZhangfei Gao #include <linux/mmc/slot-gpio.h> 40f95f3850SWill Newton 41f95f3850SWill Newton #include "dw_mmc.h" 42f95f3850SWill Newton 43f95f3850SWill Newton /* Common flag combinations */ 443f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ 45f95f3850SWill Newton SDMMC_INT_HTO | SDMMC_INT_SBE | \ 46f95f3850SWill Newton SDMMC_INT_EBE) 47f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ 48f95f3850SWill Newton SDMMC_INT_RESP_ERR) 49f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ 50f95f3850SWill Newton DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE) 51f95f3850SWill Newton #define DW_MCI_SEND_STATUS 1 52f95f3850SWill Newton #define DW_MCI_RECV_STATUS 2 53f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD 16 54f95f3850SWill Newton 551f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */ 561f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN 400000 /* unit: HZ */ 571f44a2a5SSeungwon Jeon 58f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 59fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ 60fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ 61fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ 62fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_TI) 63fc79a4d6SJoonyoung Shim 6469d99fdcSPrabu Thangamuthu struct idmac_desc_64addr { 6569d99fdcSPrabu Thangamuthu u32 des0; /* Control Descriptor */ 6669d99fdcSPrabu Thangamuthu 6769d99fdcSPrabu Thangamuthu u32 des1; /* Reserved */ 6869d99fdcSPrabu Thangamuthu 6969d99fdcSPrabu Thangamuthu u32 des2; /*Buffer sizes */ 7069d99fdcSPrabu Thangamuthu #define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ 7169d99fdcSPrabu Thangamuthu ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff)) 7269d99fdcSPrabu Thangamuthu 7369d99fdcSPrabu Thangamuthu u32 des3; /* Reserved */ 7469d99fdcSPrabu Thangamuthu 7569d99fdcSPrabu Thangamuthu u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/ 7669d99fdcSPrabu Thangamuthu u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/ 7769d99fdcSPrabu Thangamuthu 7869d99fdcSPrabu Thangamuthu u32 des6; /* Lower 32-bits of Next Descriptor Address */ 7969d99fdcSPrabu Thangamuthu u32 des7; /* Upper 32-bits of Next Descriptor Address */ 8069d99fdcSPrabu Thangamuthu }; 8169d99fdcSPrabu Thangamuthu 82f95f3850SWill Newton struct idmac_desc { 83f95f3850SWill Newton u32 des0; /* Control Descriptor */ 84f95f3850SWill Newton #define IDMAC_DES0_DIC BIT(1) 85f95f3850SWill Newton #define IDMAC_DES0_LD BIT(2) 86f95f3850SWill Newton #define IDMAC_DES0_FD BIT(3) 87f95f3850SWill Newton #define IDMAC_DES0_CH BIT(4) 88f95f3850SWill Newton #define IDMAC_DES0_ER BIT(5) 89f95f3850SWill Newton #define IDMAC_DES0_CES BIT(30) 90f95f3850SWill Newton #define IDMAC_DES0_OWN BIT(31) 91f95f3850SWill Newton 92f95f3850SWill Newton u32 des1; /* Buffer sizes */ 93f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \ 949b7bbe10SShashidhar Hiremath ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) 95f95f3850SWill Newton 96f95f3850SWill Newton u32 des2; /* buffer 1 physical address */ 97f95f3850SWill Newton 98f95f3850SWill Newton u32 des3; /* buffer 2 physical address */ 99f95f3850SWill Newton }; 100f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 101f95f3850SWill Newton 1023a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host); 103536f6b91SSonny Rao static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); 10431bff450SSeungwon Jeon 105f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 106f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 107f95f3850SWill Newton { 108f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 109f95f3850SWill Newton struct mmc_request *mrq; 110f95f3850SWill Newton struct mmc_command *cmd; 111f95f3850SWill Newton struct mmc_command *stop; 112f95f3850SWill Newton struct mmc_data *data; 113f95f3850SWill Newton 114f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 115f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 116f95f3850SWill Newton mrq = slot->mrq; 117f95f3850SWill Newton 118f95f3850SWill Newton if (mrq) { 119f95f3850SWill Newton cmd = mrq->cmd; 120f95f3850SWill Newton data = mrq->data; 121f95f3850SWill Newton stop = mrq->stop; 122f95f3850SWill Newton 123f95f3850SWill Newton if (cmd) 124f95f3850SWill Newton seq_printf(s, 125f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 126f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 127f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 128f95f3850SWill Newton cmd->resp[2], cmd->error); 129f95f3850SWill Newton if (data) 130f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 131f95f3850SWill Newton data->bytes_xfered, data->blocks, 132f95f3850SWill Newton data->blksz, data->flags, data->error); 133f95f3850SWill Newton if (stop) 134f95f3850SWill Newton seq_printf(s, 135f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 136f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 137f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 138f95f3850SWill Newton stop->resp[2], stop->error); 139f95f3850SWill Newton } 140f95f3850SWill Newton 141f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 142f95f3850SWill Newton 143f95f3850SWill Newton return 0; 144f95f3850SWill Newton } 145f95f3850SWill Newton 146f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 147f95f3850SWill Newton { 148f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 149f95f3850SWill Newton } 150f95f3850SWill Newton 151f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 152f95f3850SWill Newton .owner = THIS_MODULE, 153f95f3850SWill Newton .open = dw_mci_req_open, 154f95f3850SWill Newton .read = seq_read, 155f95f3850SWill Newton .llseek = seq_lseek, 156f95f3850SWill Newton .release = single_release, 157f95f3850SWill Newton }; 158f95f3850SWill Newton 159f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 160f95f3850SWill Newton { 161f95f3850SWill Newton seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); 162f95f3850SWill Newton seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); 163f95f3850SWill Newton seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); 164f95f3850SWill Newton seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); 165f95f3850SWill Newton seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); 166f95f3850SWill Newton seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); 167f95f3850SWill Newton 168f95f3850SWill Newton return 0; 169f95f3850SWill Newton } 170f95f3850SWill Newton 171f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 172f95f3850SWill Newton { 173f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 174f95f3850SWill Newton } 175f95f3850SWill Newton 176f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 177f95f3850SWill Newton .owner = THIS_MODULE, 178f95f3850SWill Newton .open = dw_mci_regs_open, 179f95f3850SWill Newton .read = seq_read, 180f95f3850SWill Newton .llseek = seq_lseek, 181f95f3850SWill Newton .release = single_release, 182f95f3850SWill Newton }; 183f95f3850SWill Newton 184f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 185f95f3850SWill Newton { 186f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 187f95f3850SWill Newton struct dw_mci *host = slot->host; 188f95f3850SWill Newton struct dentry *root; 189f95f3850SWill Newton struct dentry *node; 190f95f3850SWill Newton 191f95f3850SWill Newton root = mmc->debugfs_root; 192f95f3850SWill Newton if (!root) 193f95f3850SWill Newton return; 194f95f3850SWill Newton 195f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 196f95f3850SWill Newton &dw_mci_regs_fops); 197f95f3850SWill Newton if (!node) 198f95f3850SWill Newton goto err; 199f95f3850SWill Newton 200f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 201f95f3850SWill Newton &dw_mci_req_fops); 202f95f3850SWill Newton if (!node) 203f95f3850SWill Newton goto err; 204f95f3850SWill Newton 205f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 206f95f3850SWill Newton if (!node) 207f95f3850SWill Newton goto err; 208f95f3850SWill Newton 209f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 210f95f3850SWill Newton (u32 *)&host->pending_events); 211f95f3850SWill Newton if (!node) 212f95f3850SWill Newton goto err; 213f95f3850SWill Newton 214f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 215f95f3850SWill Newton (u32 *)&host->completed_events); 216f95f3850SWill Newton if (!node) 217f95f3850SWill Newton goto err; 218f95f3850SWill Newton 219f95f3850SWill Newton return; 220f95f3850SWill Newton 221f95f3850SWill Newton err: 222f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 223f95f3850SWill Newton } 224f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 225f95f3850SWill Newton 22601730558SDoug Anderson static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg); 22701730558SDoug Anderson 228f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 229f95f3850SWill Newton { 230f95f3850SWill Newton struct mmc_data *data; 231800d78bfSThomas Abraham struct dw_mci_slot *slot = mmc_priv(mmc); 23201730558SDoug Anderson struct dw_mci *host = slot->host; 233e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 234f95f3850SWill Newton u32 cmdr; 235f95f3850SWill Newton cmd->error = -EINPROGRESS; 236f95f3850SWill Newton 237f95f3850SWill Newton cmdr = cmd->opcode; 238f95f3850SWill Newton 23990c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 24090c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 24190c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 24290c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 24390c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 244f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 2454a1b27adSJaehoon Chung else if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 246f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 247f95f3850SWill Newton 24801730558SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 24901730558SDoug Anderson u32 clk_en_a; 25001730558SDoug Anderson 25101730558SDoug Anderson /* Special bit makes CMD11 not die */ 25201730558SDoug Anderson cmdr |= SDMMC_CMD_VOLT_SWITCH; 25301730558SDoug Anderson 25401730558SDoug Anderson /* Change state to continue to handle CMD11 weirdness */ 25501730558SDoug Anderson WARN_ON(slot->host->state != STATE_SENDING_CMD); 25601730558SDoug Anderson slot->host->state = STATE_SENDING_CMD11; 25701730558SDoug Anderson 25801730558SDoug Anderson /* 25901730558SDoug Anderson * We need to disable low power mode (automatic clock stop) 26001730558SDoug Anderson * while doing voltage switch so we don't confuse the card, 26101730558SDoug Anderson * since stopping the clock is a specific part of the UHS 26201730558SDoug Anderson * voltage change dance. 26301730558SDoug Anderson * 26401730558SDoug Anderson * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be 26501730558SDoug Anderson * unconditionally turned back on in dw_mci_setup_bus() if it's 26601730558SDoug Anderson * ever called with a non-zero clock. That shouldn't happen 26701730558SDoug Anderson * until the voltage change is all done. 26801730558SDoug Anderson */ 26901730558SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 27001730558SDoug Anderson clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id); 27101730558SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 27201730558SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 27301730558SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 27401730558SDoug Anderson } 27501730558SDoug Anderson 276f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 277f95f3850SWill Newton /* We expect a response, so set this bit */ 278f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 279f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 280f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 281f95f3850SWill Newton } 282f95f3850SWill Newton 283f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 284f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 285f95f3850SWill Newton 286f95f3850SWill Newton data = cmd->data; 287f95f3850SWill Newton if (data) { 288f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 289f95f3850SWill Newton if (data->flags & MMC_DATA_STREAM) 290f95f3850SWill Newton cmdr |= SDMMC_CMD_STRM_MODE; 291f95f3850SWill Newton if (data->flags & MMC_DATA_WRITE) 292f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 293f95f3850SWill Newton } 294f95f3850SWill Newton 295cb27a843SJames Hogan if (drv_data && drv_data->prepare_command) 296cb27a843SJames Hogan drv_data->prepare_command(slot->host, &cmdr); 297800d78bfSThomas Abraham 298f95f3850SWill Newton return cmdr; 299f95f3850SWill Newton } 300f95f3850SWill Newton 30190c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) 30290c2143aSSeungwon Jeon { 30390c2143aSSeungwon Jeon struct mmc_command *stop; 30490c2143aSSeungwon Jeon u32 cmdr; 30590c2143aSSeungwon Jeon 30690c2143aSSeungwon Jeon if (!cmd->data) 30790c2143aSSeungwon Jeon return 0; 30890c2143aSSeungwon Jeon 30990c2143aSSeungwon Jeon stop = &host->stop_abort; 31090c2143aSSeungwon Jeon cmdr = cmd->opcode; 31190c2143aSSeungwon Jeon memset(stop, 0, sizeof(struct mmc_command)); 31290c2143aSSeungwon Jeon 31390c2143aSSeungwon Jeon if (cmdr == MMC_READ_SINGLE_BLOCK || 31490c2143aSSeungwon Jeon cmdr == MMC_READ_MULTIPLE_BLOCK || 31590c2143aSSeungwon Jeon cmdr == MMC_WRITE_BLOCK || 31690c2143aSSeungwon Jeon cmdr == MMC_WRITE_MULTIPLE_BLOCK) { 31790c2143aSSeungwon Jeon stop->opcode = MMC_STOP_TRANSMISSION; 31890c2143aSSeungwon Jeon stop->arg = 0; 31990c2143aSSeungwon Jeon stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 32090c2143aSSeungwon Jeon } else if (cmdr == SD_IO_RW_EXTENDED) { 32190c2143aSSeungwon Jeon stop->opcode = SD_IO_RW_DIRECT; 32290c2143aSSeungwon Jeon stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | 32390c2143aSSeungwon Jeon ((cmd->arg >> 28) & 0x7); 32490c2143aSSeungwon Jeon stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; 32590c2143aSSeungwon Jeon } else { 32690c2143aSSeungwon Jeon return 0; 32790c2143aSSeungwon Jeon } 32890c2143aSSeungwon Jeon 32990c2143aSSeungwon Jeon cmdr = stop->opcode | SDMMC_CMD_STOP | 33090c2143aSSeungwon Jeon SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; 33190c2143aSSeungwon Jeon 33290c2143aSSeungwon Jeon return cmdr; 33390c2143aSSeungwon Jeon } 33490c2143aSSeungwon Jeon 335f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 336f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 337f95f3850SWill Newton { 338f95f3850SWill Newton host->cmd = cmd; 3394a90920cSThomas Abraham dev_vdbg(host->dev, 340f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 341f95f3850SWill Newton cmd->arg, cmd_flags); 342f95f3850SWill Newton 343f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 344f95f3850SWill Newton wmb(); 345f95f3850SWill Newton 346f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 347f95f3850SWill Newton } 348f95f3850SWill Newton 34990c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 350f95f3850SWill Newton { 35190c2143aSSeungwon Jeon struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; 35290c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 353f95f3850SWill Newton } 354f95f3850SWill Newton 355f95f3850SWill Newton /* DMA interface functions */ 356f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 357f95f3850SWill Newton { 35803e8cb53SJames Hogan if (host->using_dma) { 359f95f3850SWill Newton host->dma_ops->stop(host); 360f95f3850SWill Newton host->dma_ops->cleanup(host); 361aa50f259SSeungwon Jeon } 362aa50f259SSeungwon Jeon 363f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 364f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 365f95f3850SWill Newton } 366f95f3850SWill Newton 3679aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 3689aa51408SSeungwon Jeon { 3699aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 3709aa51408SSeungwon Jeon return DMA_TO_DEVICE; 3719aa51408SSeungwon Jeon else 3729aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 3739aa51408SSeungwon Jeon } 3749aa51408SSeungwon Jeon 3759beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 376f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 377f95f3850SWill Newton { 378f95f3850SWill Newton struct mmc_data *data = host->data; 379f95f3850SWill Newton 380f95f3850SWill Newton if (data) 3819aa51408SSeungwon Jeon if (!data->host_cookie) 3824a90920cSThomas Abraham dma_unmap_sg(host->dev, 3839aa51408SSeungwon Jeon data->sg, 3849aa51408SSeungwon Jeon data->sg_len, 3859aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 386f95f3850SWill Newton } 387f95f3850SWill Newton 3885ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host) 3895ce9d961SSeungwon Jeon { 3905ce9d961SSeungwon Jeon u32 bmod = mci_readl(host, BMOD); 3915ce9d961SSeungwon Jeon /* Software reset of DMA */ 3925ce9d961SSeungwon Jeon bmod |= SDMMC_IDMAC_SWRESET; 3935ce9d961SSeungwon Jeon mci_writel(host, BMOD, bmod); 3945ce9d961SSeungwon Jeon } 3955ce9d961SSeungwon Jeon 396f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 397f95f3850SWill Newton { 398f95f3850SWill Newton u32 temp; 399f95f3850SWill Newton 400f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 401f95f3850SWill Newton temp = mci_readl(host, CTRL); 402f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 403f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 404f95f3850SWill Newton mci_writel(host, CTRL, temp); 405f95f3850SWill Newton 406f95f3850SWill Newton /* Stop the IDMAC running */ 407f95f3850SWill Newton temp = mci_readl(host, BMOD); 408a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 4095ce9d961SSeungwon Jeon temp |= SDMMC_IDMAC_SWRESET; 410f95f3850SWill Newton mci_writel(host, BMOD, temp); 411f95f3850SWill Newton } 412f95f3850SWill Newton 413f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host) 414f95f3850SWill Newton { 415f95f3850SWill Newton struct mmc_data *data = host->data; 416f95f3850SWill Newton 4174a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 418f95f3850SWill Newton 419f95f3850SWill Newton host->dma_ops->cleanup(host); 420f95f3850SWill Newton 421f95f3850SWill Newton /* 422f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 423f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 424f95f3850SWill Newton */ 425f95f3850SWill Newton if (data) { 426f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 427f95f3850SWill Newton tasklet_schedule(&host->tasklet); 428f95f3850SWill Newton } 429f95f3850SWill Newton } 430f95f3850SWill Newton 431f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, 432f95f3850SWill Newton unsigned int sg_len) 433f95f3850SWill Newton { 434f95f3850SWill Newton int i; 43569d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 43669d99fdcSPrabu Thangamuthu struct idmac_desc_64addr *desc = host->sg_cpu; 43769d99fdcSPrabu Thangamuthu 43869d99fdcSPrabu Thangamuthu for (i = 0; i < sg_len; i++, desc++) { 43969d99fdcSPrabu Thangamuthu unsigned int length = sg_dma_len(&data->sg[i]); 44069d99fdcSPrabu Thangamuthu u64 mem_addr = sg_dma_address(&data->sg[i]); 44169d99fdcSPrabu Thangamuthu 44269d99fdcSPrabu Thangamuthu /* 44369d99fdcSPrabu Thangamuthu * Set the OWN bit and disable interrupts for this 44469d99fdcSPrabu Thangamuthu * descriptor 44569d99fdcSPrabu Thangamuthu */ 44669d99fdcSPrabu Thangamuthu desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | 44769d99fdcSPrabu Thangamuthu IDMAC_DES0_CH; 44869d99fdcSPrabu Thangamuthu /* Buffer length */ 44969d99fdcSPrabu Thangamuthu IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length); 45069d99fdcSPrabu Thangamuthu 45169d99fdcSPrabu Thangamuthu /* Physical address to DMA to/from */ 45269d99fdcSPrabu Thangamuthu desc->des4 = mem_addr & 0xffffffff; 45369d99fdcSPrabu Thangamuthu desc->des5 = mem_addr >> 32; 45469d99fdcSPrabu Thangamuthu } 45569d99fdcSPrabu Thangamuthu 45669d99fdcSPrabu Thangamuthu /* Set first descriptor */ 45769d99fdcSPrabu Thangamuthu desc = host->sg_cpu; 45869d99fdcSPrabu Thangamuthu desc->des0 |= IDMAC_DES0_FD; 45969d99fdcSPrabu Thangamuthu 46069d99fdcSPrabu Thangamuthu /* Set last descriptor */ 46169d99fdcSPrabu Thangamuthu desc = host->sg_cpu + (i - 1) * 46269d99fdcSPrabu Thangamuthu sizeof(struct idmac_desc_64addr); 46369d99fdcSPrabu Thangamuthu desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 46469d99fdcSPrabu Thangamuthu desc->des0 |= IDMAC_DES0_LD; 46569d99fdcSPrabu Thangamuthu 46669d99fdcSPrabu Thangamuthu } else { 467f95f3850SWill Newton struct idmac_desc *desc = host->sg_cpu; 468f95f3850SWill Newton 469f95f3850SWill Newton for (i = 0; i < sg_len; i++, desc++) { 470f95f3850SWill Newton unsigned int length = sg_dma_len(&data->sg[i]); 471f95f3850SWill Newton u32 mem_addr = sg_dma_address(&data->sg[i]); 472f95f3850SWill Newton 47369d99fdcSPrabu Thangamuthu /* 47469d99fdcSPrabu Thangamuthu * Set the OWN bit and disable interrupts for this 47569d99fdcSPrabu Thangamuthu * descriptor 47669d99fdcSPrabu Thangamuthu */ 47769d99fdcSPrabu Thangamuthu desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | 47869d99fdcSPrabu Thangamuthu IDMAC_DES0_CH; 479f95f3850SWill Newton /* Buffer length */ 480f95f3850SWill Newton IDMAC_SET_BUFFER1_SIZE(desc, length); 481f95f3850SWill Newton 482f95f3850SWill Newton /* Physical address to DMA to/from */ 483f95f3850SWill Newton desc->des2 = mem_addr; 484f95f3850SWill Newton } 485f95f3850SWill Newton 486f95f3850SWill Newton /* Set first descriptor */ 487f95f3850SWill Newton desc = host->sg_cpu; 488f95f3850SWill Newton desc->des0 |= IDMAC_DES0_FD; 489f95f3850SWill Newton 490f95f3850SWill Newton /* Set last descriptor */ 491f95f3850SWill Newton desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); 492f95f3850SWill Newton desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 493f95f3850SWill Newton desc->des0 |= IDMAC_DES0_LD; 49469d99fdcSPrabu Thangamuthu } 495f95f3850SWill Newton 496f95f3850SWill Newton wmb(); 497f95f3850SWill Newton } 498f95f3850SWill Newton 499f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 500f95f3850SWill Newton { 501f95f3850SWill Newton u32 temp; 502f95f3850SWill Newton 503f95f3850SWill Newton dw_mci_translate_sglist(host, host->data, sg_len); 504f95f3850SWill Newton 505536f6b91SSonny Rao /* Make sure to reset DMA in case we did PIO before this */ 506536f6b91SSonny Rao dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET); 507536f6b91SSonny Rao dw_mci_idmac_reset(host); 508536f6b91SSonny Rao 509f95f3850SWill Newton /* Select IDMAC interface */ 510f95f3850SWill Newton temp = mci_readl(host, CTRL); 511f95f3850SWill Newton temp |= SDMMC_CTRL_USE_IDMAC; 512f95f3850SWill Newton mci_writel(host, CTRL, temp); 513f95f3850SWill Newton 514f95f3850SWill Newton wmb(); 515f95f3850SWill Newton 516f95f3850SWill Newton /* Enable the IDMAC */ 517f95f3850SWill Newton temp = mci_readl(host, BMOD); 518a5289a43SJaehoon Chung temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 519f95f3850SWill Newton mci_writel(host, BMOD, temp); 520f95f3850SWill Newton 521f95f3850SWill Newton /* Start it running */ 522f95f3850SWill Newton mci_writel(host, PLDMND, 1); 523f95f3850SWill Newton } 524f95f3850SWill Newton 525f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 526f95f3850SWill Newton { 527897b69e7SSeungwon Jeon int i; 528f95f3850SWill Newton 52969d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 53069d99fdcSPrabu Thangamuthu struct idmac_desc_64addr *p; 53169d99fdcSPrabu Thangamuthu /* Number of descriptors in the ring buffer */ 53269d99fdcSPrabu Thangamuthu host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr); 53369d99fdcSPrabu Thangamuthu 53469d99fdcSPrabu Thangamuthu /* Forward link the descriptor list */ 53569d99fdcSPrabu Thangamuthu for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; 53669d99fdcSPrabu Thangamuthu i++, p++) { 53769d99fdcSPrabu Thangamuthu p->des6 = (host->sg_dma + 53869d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 53969d99fdcSPrabu Thangamuthu (i + 1))) & 0xffffffff; 54069d99fdcSPrabu Thangamuthu 54169d99fdcSPrabu Thangamuthu p->des7 = (u64)(host->sg_dma + 54269d99fdcSPrabu Thangamuthu (sizeof(struct idmac_desc_64addr) * 54369d99fdcSPrabu Thangamuthu (i + 1))) >> 32; 54469d99fdcSPrabu Thangamuthu /* Initialize reserved and buffer size fields to "0" */ 54569d99fdcSPrabu Thangamuthu p->des1 = 0; 54669d99fdcSPrabu Thangamuthu p->des2 = 0; 54769d99fdcSPrabu Thangamuthu p->des3 = 0; 54869d99fdcSPrabu Thangamuthu } 54969d99fdcSPrabu Thangamuthu 55069d99fdcSPrabu Thangamuthu /* Set the last descriptor as the end-of-ring descriptor */ 55169d99fdcSPrabu Thangamuthu p->des6 = host->sg_dma & 0xffffffff; 55269d99fdcSPrabu Thangamuthu p->des7 = (u64)host->sg_dma >> 32; 55369d99fdcSPrabu Thangamuthu p->des0 = IDMAC_DES0_ER; 55469d99fdcSPrabu Thangamuthu 55569d99fdcSPrabu Thangamuthu } else { 55669d99fdcSPrabu Thangamuthu struct idmac_desc *p; 557f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 558f95f3850SWill Newton host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 559f95f3850SWill Newton 560f95f3850SWill Newton /* Forward link the descriptor list */ 561f95f3850SWill Newton for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) 56269d99fdcSPrabu Thangamuthu p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * 56369d99fdcSPrabu Thangamuthu (i + 1)); 564f95f3850SWill Newton 565f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 566f95f3850SWill Newton p->des3 = host->sg_dma; 567f95f3850SWill Newton p->des0 = IDMAC_DES0_ER; 56869d99fdcSPrabu Thangamuthu } 569f95f3850SWill Newton 5705ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 571141a712aSSeungwon Jeon 57269d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 57369d99fdcSPrabu Thangamuthu /* Mask out interrupts - get Tx & Rx complete only */ 57469d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, IDMAC_INT_CLR); 57569d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI | 57669d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 57769d99fdcSPrabu Thangamuthu 57869d99fdcSPrabu Thangamuthu /* Set the descriptor base address */ 57969d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff); 58069d99fdcSPrabu Thangamuthu mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32); 58169d99fdcSPrabu Thangamuthu 58269d99fdcSPrabu Thangamuthu } else { 583f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 584fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 58569d99fdcSPrabu Thangamuthu mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | 58669d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); 587f95f3850SWill Newton 588f95f3850SWill Newton /* Set the descriptor base address */ 589f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 59069d99fdcSPrabu Thangamuthu } 59169d99fdcSPrabu Thangamuthu 592f95f3850SWill Newton return 0; 593f95f3850SWill Newton } 594f95f3850SWill Newton 5958e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 596885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 597885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 598885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 599885c3e80SSeungwon Jeon .complete = dw_mci_idmac_complete_dma, 600885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 601885c3e80SSeungwon Jeon }; 602885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */ 603885c3e80SSeungwon Jeon 6049aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 6059aa51408SSeungwon Jeon struct mmc_data *data, 6069aa51408SSeungwon Jeon bool next) 607f95f3850SWill Newton { 608f95f3850SWill Newton struct scatterlist *sg; 6099aa51408SSeungwon Jeon unsigned int i, sg_len; 610f95f3850SWill Newton 6119aa51408SSeungwon Jeon if (!next && data->host_cookie) 6129aa51408SSeungwon Jeon return data->host_cookie; 613f95f3850SWill Newton 614f95f3850SWill Newton /* 615f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 616f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 617f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 618f95f3850SWill Newton */ 619f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 620f95f3850SWill Newton return -EINVAL; 6219aa51408SSeungwon Jeon 622f95f3850SWill Newton if (data->blksz & 3) 623f95f3850SWill Newton return -EINVAL; 624f95f3850SWill Newton 625f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 626f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 627f95f3850SWill Newton return -EINVAL; 628f95f3850SWill Newton } 629f95f3850SWill Newton 6304a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 6319aa51408SSeungwon Jeon data->sg, 6329aa51408SSeungwon Jeon data->sg_len, 6339aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 6349aa51408SSeungwon Jeon if (sg_len == 0) 6359aa51408SSeungwon Jeon return -EINVAL; 6369aa51408SSeungwon Jeon 6379aa51408SSeungwon Jeon if (next) 6389aa51408SSeungwon Jeon data->host_cookie = sg_len; 6399aa51408SSeungwon Jeon 6409aa51408SSeungwon Jeon return sg_len; 6419aa51408SSeungwon Jeon } 6429aa51408SSeungwon Jeon 6439aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 6449aa51408SSeungwon Jeon struct mmc_request *mrq, 6459aa51408SSeungwon Jeon bool is_first_req) 6469aa51408SSeungwon Jeon { 6479aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 6489aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 6499aa51408SSeungwon Jeon 6509aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 6519aa51408SSeungwon Jeon return; 6529aa51408SSeungwon Jeon 6539aa51408SSeungwon Jeon if (data->host_cookie) { 6549aa51408SSeungwon Jeon data->host_cookie = 0; 6559aa51408SSeungwon Jeon return; 6569aa51408SSeungwon Jeon } 6579aa51408SSeungwon Jeon 6589aa51408SSeungwon Jeon if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) 6599aa51408SSeungwon Jeon data->host_cookie = 0; 6609aa51408SSeungwon Jeon } 6619aa51408SSeungwon Jeon 6629aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 6639aa51408SSeungwon Jeon struct mmc_request *mrq, 6649aa51408SSeungwon Jeon int err) 6659aa51408SSeungwon Jeon { 6669aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 6679aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 6689aa51408SSeungwon Jeon 6699aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 6709aa51408SSeungwon Jeon return; 6719aa51408SSeungwon Jeon 6729aa51408SSeungwon Jeon if (data->host_cookie) 6734a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 6749aa51408SSeungwon Jeon data->sg, 6759aa51408SSeungwon Jeon data->sg_len, 6769aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 6779aa51408SSeungwon Jeon data->host_cookie = 0; 6789aa51408SSeungwon Jeon } 6799aa51408SSeungwon Jeon 68052426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 68152426899SSeungwon Jeon { 68252426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC 68352426899SSeungwon Jeon unsigned int blksz = data->blksz; 68452426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 68552426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 68652426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 68752426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 68852426899SSeungwon Jeon int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1; 68952426899SSeungwon Jeon 69052426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 69152426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 69252426899SSeungwon Jeon 69352426899SSeungwon Jeon /* 69452426899SSeungwon Jeon * MSIZE is '1', 69552426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 69652426899SSeungwon Jeon */ 69752426899SSeungwon Jeon if (blksz % fifo_width) { 69852426899SSeungwon Jeon msize = 0; 69952426899SSeungwon Jeon rx_wmark = 1; 70052426899SSeungwon Jeon goto done; 70152426899SSeungwon Jeon } 70252426899SSeungwon Jeon 70352426899SSeungwon Jeon do { 70452426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 70552426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 70652426899SSeungwon Jeon msize = idx; 70752426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 70852426899SSeungwon Jeon break; 70952426899SSeungwon Jeon } 71052426899SSeungwon Jeon } while (--idx > 0); 71152426899SSeungwon Jeon /* 71252426899SSeungwon Jeon * If idx is '0', it won't be tried 71352426899SSeungwon Jeon * Thus, initial values are uesed 71452426899SSeungwon Jeon */ 71552426899SSeungwon Jeon done: 71652426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 71752426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 71852426899SSeungwon Jeon #endif 71952426899SSeungwon Jeon } 72052426899SSeungwon Jeon 721f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) 722f1d2736cSSeungwon Jeon { 723f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 724f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 725f1d2736cSSeungwon Jeon u16 thld_size; 726f1d2736cSSeungwon Jeon 727f1d2736cSSeungwon Jeon WARN_ON(!(data->flags & MMC_DATA_READ)); 728f1d2736cSSeungwon Jeon 729f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 730f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 731f1d2736cSSeungwon Jeon goto disable; 732f1d2736cSSeungwon Jeon 733f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 734f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 735f1d2736cSSeungwon Jeon 736f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 737f1d2736cSSeungwon Jeon goto disable; 738f1d2736cSSeungwon Jeon 739f1d2736cSSeungwon Jeon /* 740f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 741f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 742f1d2736cSSeungwon Jeon * Currently just choose blksz. 743f1d2736cSSeungwon Jeon */ 744f1d2736cSSeungwon Jeon thld_size = blksz; 745f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1)); 746f1d2736cSSeungwon Jeon return; 747f1d2736cSSeungwon Jeon 748f1d2736cSSeungwon Jeon disable: 749f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0)); 750f1d2736cSSeungwon Jeon } 751f1d2736cSSeungwon Jeon 7529aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 7539aa51408SSeungwon Jeon { 7549aa51408SSeungwon Jeon int sg_len; 7559aa51408SSeungwon Jeon u32 temp; 7569aa51408SSeungwon Jeon 7579aa51408SSeungwon Jeon host->using_dma = 0; 7589aa51408SSeungwon Jeon 7599aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 7609aa51408SSeungwon Jeon if (!host->use_dma) 7619aa51408SSeungwon Jeon return -ENODEV; 7629aa51408SSeungwon Jeon 7639aa51408SSeungwon Jeon sg_len = dw_mci_pre_dma_transfer(host, data, 0); 764a99aa9b9SSeungwon Jeon if (sg_len < 0) { 765a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 7669aa51408SSeungwon Jeon return sg_len; 767a99aa9b9SSeungwon Jeon } 7689aa51408SSeungwon Jeon 76903e8cb53SJames Hogan host->using_dma = 1; 77003e8cb53SJames Hogan 7714a90920cSThomas Abraham dev_vdbg(host->dev, 772f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 773f95f3850SWill Newton (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, 774f95f3850SWill Newton sg_len); 775f95f3850SWill Newton 77652426899SSeungwon Jeon /* 77752426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 77852426899SSeungwon Jeon * If current block size is same with previous size, 77952426899SSeungwon Jeon * no need to update fifoth. 78052426899SSeungwon Jeon */ 78152426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 78252426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 78352426899SSeungwon Jeon 784f95f3850SWill Newton /* Enable the DMA interface */ 785f95f3850SWill Newton temp = mci_readl(host, CTRL); 786f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 787f95f3850SWill Newton mci_writel(host, CTRL, temp); 788f95f3850SWill Newton 789f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 790f95f3850SWill Newton temp = mci_readl(host, INTMASK); 791f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 792f95f3850SWill Newton mci_writel(host, INTMASK, temp); 793f95f3850SWill Newton 794f95f3850SWill Newton host->dma_ops->start(host, sg_len); 795f95f3850SWill Newton 796f95f3850SWill Newton return 0; 797f95f3850SWill Newton } 798f95f3850SWill Newton 799f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 800f95f3850SWill Newton { 801f95f3850SWill Newton u32 temp; 802f95f3850SWill Newton 803f95f3850SWill Newton data->error = -EINPROGRESS; 804f95f3850SWill Newton 805f95f3850SWill Newton WARN_ON(host->data); 806f95f3850SWill Newton host->sg = NULL; 807f95f3850SWill Newton host->data = data; 808f95f3850SWill Newton 809f1d2736cSSeungwon Jeon if (data->flags & MMC_DATA_READ) { 81055c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 811f1d2736cSSeungwon Jeon dw_mci_ctrl_rd_thld(host, data); 812f1d2736cSSeungwon Jeon } else { 81355c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 814f1d2736cSSeungwon Jeon } 81555c5efbcSJames Hogan 816f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 817f9c2a0dcSSeungwon Jeon int flags = SG_MITER_ATOMIC; 818f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 819f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 820f9c2a0dcSSeungwon Jeon else 821f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 822f9c2a0dcSSeungwon Jeon 823f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 824f95f3850SWill Newton host->sg = data->sg; 82534b664a2SJames Hogan host->part_buf_start = 0; 82634b664a2SJames Hogan host->part_buf_count = 0; 827f95f3850SWill Newton 828b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 829f95f3850SWill Newton temp = mci_readl(host, INTMASK); 830f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 831f95f3850SWill Newton mci_writel(host, INTMASK, temp); 832f95f3850SWill Newton 833f95f3850SWill Newton temp = mci_readl(host, CTRL); 834f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 835f95f3850SWill Newton mci_writel(host, CTRL, temp); 83652426899SSeungwon Jeon 83752426899SSeungwon Jeon /* 83852426899SSeungwon Jeon * Use the initial fifoth_val for PIO mode. 83952426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 84052426899SSeungwon Jeon * prev_blksz should be invalidated. 84152426899SSeungwon Jeon */ 84252426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 84352426899SSeungwon Jeon host->prev_blksz = 0; 84452426899SSeungwon Jeon } else { 84552426899SSeungwon Jeon /* 84652426899SSeungwon Jeon * Keep the current block size. 84752426899SSeungwon Jeon * It will be used to decide whether to update 84852426899SSeungwon Jeon * fifoth register next time. 84952426899SSeungwon Jeon */ 85052426899SSeungwon Jeon host->prev_blksz = data->blksz; 851f95f3850SWill Newton } 852f95f3850SWill Newton } 853f95f3850SWill Newton 854f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 855f95f3850SWill Newton { 856f95f3850SWill Newton struct dw_mci *host = slot->host; 857f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 858f95f3850SWill Newton unsigned int cmd_status = 0; 859f95f3850SWill Newton 860f95f3850SWill Newton mci_writel(host, CMDARG, arg); 861f95f3850SWill Newton wmb(); 862f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 863f95f3850SWill Newton 864f95f3850SWill Newton while (time_before(jiffies, timeout)) { 865f95f3850SWill Newton cmd_status = mci_readl(host, CMD); 866f95f3850SWill Newton if (!(cmd_status & SDMMC_CMD_START)) 867f95f3850SWill Newton return; 868f95f3850SWill Newton } 869f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 870f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 871f95f3850SWill Newton cmd, arg, cmd_status); 872f95f3850SWill Newton } 873f95f3850SWill Newton 874ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 875f95f3850SWill Newton { 876f95f3850SWill Newton struct dw_mci *host = slot->host; 877fdf492a1SDoug Anderson unsigned int clock = slot->clock; 878f95f3850SWill Newton u32 div; 8799623b5b9SDoug Anderson u32 clk_en_a; 88001730558SDoug Anderson u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT; 88101730558SDoug Anderson 88201730558SDoug Anderson /* We must continue to set bit 28 in CMD until the change is complete */ 88301730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) 88401730558SDoug Anderson sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; 885f95f3850SWill Newton 886fdf492a1SDoug Anderson if (!clock) { 887fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 88801730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 889fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 890fdf492a1SDoug Anderson div = host->bus_hz / clock; 891fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 892f95f3850SWill Newton /* 893f95f3850SWill Newton * move the + 1 after the divide to prevent 894f95f3850SWill Newton * over-clocking the card. 895f95f3850SWill Newton */ 896e419990bSSeungwon Jeon div += 1; 897e419990bSSeungwon Jeon 898fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 899f95f3850SWill Newton 900fdf492a1SDoug Anderson if ((clock << div) != slot->__clk_old || force_clkinit) 901f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 902fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 903fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 904fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 905fdf492a1SDoug Anderson host->bus_hz, div); 906f95f3850SWill Newton 907f95f3850SWill Newton /* disable clock */ 908f95f3850SWill Newton mci_writel(host, CLKENA, 0); 909f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 910f95f3850SWill Newton 911f95f3850SWill Newton /* inform CIU */ 91201730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 913f95f3850SWill Newton 914f95f3850SWill Newton /* set clock to desired speed */ 915f95f3850SWill Newton mci_writel(host, CLKDIV, div); 916f95f3850SWill Newton 917f95f3850SWill Newton /* inform CIU */ 91801730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 919f95f3850SWill Newton 9209623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 9219623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 92276756234SAddy Ke if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->sdio_id))) 9239623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 9249623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 925f95f3850SWill Newton 926f95f3850SWill Newton /* inform CIU */ 92701730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 928f95f3850SWill Newton 929fdf492a1SDoug Anderson /* keep the clock with reflecting clock dividor */ 930fdf492a1SDoug Anderson slot->__clk_old = clock << div; 931f95f3850SWill Newton } 932f95f3850SWill Newton 933fdf492a1SDoug Anderson host->current_speed = clock; 934fdf492a1SDoug Anderson 935f95f3850SWill Newton /* Set the current slot bus width */ 9361d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 937f95f3850SWill Newton } 938f95f3850SWill Newton 939053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 940053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 941053b3ce6SSeungwon Jeon struct mmc_command *cmd) 942f95f3850SWill Newton { 943f95f3850SWill Newton struct mmc_request *mrq; 944f95f3850SWill Newton struct mmc_data *data; 945f95f3850SWill Newton u32 cmdflags; 946f95f3850SWill Newton 947f95f3850SWill Newton mrq = slot->mrq; 948f95f3850SWill Newton 949f95f3850SWill Newton host->cur_slot = slot; 950f95f3850SWill Newton host->mrq = mrq; 951f95f3850SWill Newton 952f95f3850SWill Newton host->pending_events = 0; 953f95f3850SWill Newton host->completed_events = 0; 954e352c813SSeungwon Jeon host->cmd_status = 0; 955f95f3850SWill Newton host->data_status = 0; 956e352c813SSeungwon Jeon host->dir_status = 0; 957f95f3850SWill Newton 958053b3ce6SSeungwon Jeon data = cmd->data; 959f95f3850SWill Newton if (data) { 960f16afa88SJaehoon Chung mci_writel(host, TMOUT, 0xFFFFFFFF); 961f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 962f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 963f95f3850SWill Newton } 964f95f3850SWill Newton 965f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 966f95f3850SWill Newton 967f95f3850SWill Newton /* this is the first command, send the initialization clock */ 968f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 969f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 970f95f3850SWill Newton 971f95f3850SWill Newton if (data) { 972f95f3850SWill Newton dw_mci_submit_data(host, data); 973f95f3850SWill Newton wmb(); 974f95f3850SWill Newton } 975f95f3850SWill Newton 976f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 977f95f3850SWill Newton 978f95f3850SWill Newton if (mrq->stop) 979f95f3850SWill Newton host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 98090c2143aSSeungwon Jeon else 98190c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 982f95f3850SWill Newton } 983f95f3850SWill Newton 984053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 985053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 986053b3ce6SSeungwon Jeon { 987053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 988053b3ce6SSeungwon Jeon struct mmc_command *cmd; 989053b3ce6SSeungwon Jeon 990053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 991053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 992053b3ce6SSeungwon Jeon } 993053b3ce6SSeungwon Jeon 9947456caaeSJames Hogan /* must be called with host->lock held */ 995f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 996f95f3850SWill Newton struct mmc_request *mrq) 997f95f3850SWill Newton { 998f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 999f95f3850SWill Newton host->state); 1000f95f3850SWill Newton 1001f95f3850SWill Newton slot->mrq = mrq; 1002f95f3850SWill Newton 100301730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) { 100401730558SDoug Anderson dev_warn(&slot->mmc->class_dev, 100501730558SDoug Anderson "Voltage change didn't complete\n"); 100601730558SDoug Anderson /* 100701730558SDoug Anderson * this case isn't expected to happen, so we can 100801730558SDoug Anderson * either crash here or just try to continue on 100901730558SDoug Anderson * in the closest possible state 101001730558SDoug Anderson */ 101101730558SDoug Anderson host->state = STATE_IDLE; 101201730558SDoug Anderson } 101301730558SDoug Anderson 1014f95f3850SWill Newton if (host->state == STATE_IDLE) { 1015f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1016f95f3850SWill Newton dw_mci_start_request(host, slot); 1017f95f3850SWill Newton } else { 1018f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 1019f95f3850SWill Newton } 1020f95f3850SWill Newton } 1021f95f3850SWill Newton 1022f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1023f95f3850SWill Newton { 1024f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1025f95f3850SWill Newton struct dw_mci *host = slot->host; 1026f95f3850SWill Newton 1027f95f3850SWill Newton WARN_ON(slot->mrq); 1028f95f3850SWill Newton 10297456caaeSJames Hogan /* 10307456caaeSJames Hogan * The check for card presence and queueing of the request must be 10317456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 10327456caaeSJames Hogan * request wouldn't fail until another card was inserted. 10337456caaeSJames Hogan */ 10347456caaeSJames Hogan spin_lock_bh(&host->lock); 10357456caaeSJames Hogan 1036f95f3850SWill Newton if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { 10377456caaeSJames Hogan spin_unlock_bh(&host->lock); 1038f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1039f95f3850SWill Newton mmc_request_done(mmc, mrq); 1040f95f3850SWill Newton return; 1041f95f3850SWill Newton } 1042f95f3850SWill Newton 1043f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 10447456caaeSJames Hogan 10457456caaeSJames Hogan spin_unlock_bh(&host->lock); 1046f95f3850SWill Newton } 1047f95f3850SWill Newton 1048f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 1049f95f3850SWill Newton { 1050f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1051e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 105241babf75SJaehoon Chung u32 regs; 105351da2240SYuvaraj CD int ret; 1054f95f3850SWill Newton 1055f95f3850SWill Newton switch (ios->bus_width) { 1056f95f3850SWill Newton case MMC_BUS_WIDTH_4: 1057f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 1058f95f3850SWill Newton break; 1059c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 1060c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 1061c9b2a06fSJaehoon Chung break; 1062b2f7cb45SJaehoon Chung default: 1063b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 1064b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 1065f95f3850SWill Newton } 1066f95f3850SWill Newton 106741babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 10683f514291SSeungwon Jeon 10693f514291SSeungwon Jeon /* DDR mode set */ 1070cab3a802SSeungwon Jeon if (ios->timing == MMC_TIMING_MMC_DDR52) 1071c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 10723f514291SSeungwon Jeon else 1073c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 10743f514291SSeungwon Jeon 107541babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 1076f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 107741babf75SJaehoon Chung 1078f95f3850SWill Newton /* 1079f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 1080f95f3850SWill Newton * core ios update when finding the minimum. 1081f95f3850SWill Newton */ 1082f95f3850SWill Newton slot->clock = ios->clock; 1083f95f3850SWill Newton 1084cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 1085cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 1086800d78bfSThomas Abraham 1087bf7cb224SJaehoon Chung /* Slot specific timing and width adjustment */ 1088bf7cb224SJaehoon Chung dw_mci_setup_bus(slot, false); 1089bf7cb224SJaehoon Chung 109001730558SDoug Anderson if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) 109101730558SDoug Anderson slot->host->state = STATE_IDLE; 109201730558SDoug Anderson 1093f95f3850SWill Newton switch (ios->power_mode) { 1094f95f3850SWill Newton case MMC_POWER_UP: 109551da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) { 109651da2240SYuvaraj CD ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 109751da2240SYuvaraj CD ios->vdd); 109851da2240SYuvaraj CD if (ret) { 109951da2240SYuvaraj CD dev_err(slot->host->dev, 110051da2240SYuvaraj CD "failed to enable vmmc regulator\n"); 110151da2240SYuvaraj CD /*return, if failed turn on vmmc*/ 110251da2240SYuvaraj CD return; 110351da2240SYuvaraj CD } 110451da2240SYuvaraj CD } 110551da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) { 110651da2240SYuvaraj CD ret = regulator_enable(mmc->supply.vqmmc); 110751da2240SYuvaraj CD if (ret < 0) 110851da2240SYuvaraj CD dev_err(slot->host->dev, 110951da2240SYuvaraj CD "failed to enable vqmmc regulator\n"); 111051da2240SYuvaraj CD else 111151da2240SYuvaraj CD slot->host->vqmmc_enabled = true; 111251da2240SYuvaraj CD } 1113f95f3850SWill Newton set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 11144366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 11154366dcc5SJaehoon Chung regs |= (1 << slot->id); 11164366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1117e6f34e2fSJames Hogan break; 1118e6f34e2fSJames Hogan case MMC_POWER_OFF: 111951da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) 112051da2240SYuvaraj CD mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 112151da2240SYuvaraj CD 112251da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) { 112351da2240SYuvaraj CD regulator_disable(mmc->supply.vqmmc); 112451da2240SYuvaraj CD slot->host->vqmmc_enabled = false; 112551da2240SYuvaraj CD } 112651da2240SYuvaraj CD 11274366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 11284366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 11294366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1130f95f3850SWill Newton break; 1131f95f3850SWill Newton default: 1132f95f3850SWill Newton break; 1133f95f3850SWill Newton } 1134f95f3850SWill Newton } 1135f95f3850SWill Newton 113601730558SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc) 113701730558SDoug Anderson { 113801730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 113901730558SDoug Anderson u32 status; 114001730558SDoug Anderson 114101730558SDoug Anderson /* 114201730558SDoug Anderson * Check the busy bit which is low when DAT[3:0] 114301730558SDoug Anderson * (the data lines) are 0000 114401730558SDoug Anderson */ 114501730558SDoug Anderson status = mci_readl(slot->host, STATUS); 114601730558SDoug Anderson 114701730558SDoug Anderson return !!(status & SDMMC_STATUS_BUSY); 114801730558SDoug Anderson } 114901730558SDoug Anderson 115001730558SDoug Anderson static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) 115101730558SDoug Anderson { 115201730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 115301730558SDoug Anderson struct dw_mci *host = slot->host; 115401730558SDoug Anderson u32 uhs; 115501730558SDoug Anderson u32 v18 = SDMMC_UHS_18V << slot->id; 115601730558SDoug Anderson int min_uv, max_uv; 115701730558SDoug Anderson int ret; 115801730558SDoug Anderson 115901730558SDoug Anderson /* 116001730558SDoug Anderson * Program the voltage. Note that some instances of dw_mmc may use 116101730558SDoug Anderson * the UHS_REG for this. For other instances (like exynos) the UHS_REG 116201730558SDoug Anderson * does no harm but you need to set the regulator directly. Try both. 116301730558SDoug Anderson */ 116401730558SDoug Anderson uhs = mci_readl(host, UHS_REG); 116501730558SDoug Anderson if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 116601730558SDoug Anderson min_uv = 2700000; 116701730558SDoug Anderson max_uv = 3600000; 116801730558SDoug Anderson uhs &= ~v18; 116901730558SDoug Anderson } else { 117001730558SDoug Anderson min_uv = 1700000; 117101730558SDoug Anderson max_uv = 1950000; 117201730558SDoug Anderson uhs |= v18; 117301730558SDoug Anderson } 117401730558SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 117501730558SDoug Anderson ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); 117601730558SDoug Anderson 117701730558SDoug Anderson if (ret) { 1178b19caf37SDoug Anderson dev_dbg(&mmc->class_dev, 117901730558SDoug Anderson "Regulator set error %d: %d - %d\n", 118001730558SDoug Anderson ret, min_uv, max_uv); 118101730558SDoug Anderson return ret; 118201730558SDoug Anderson } 118301730558SDoug Anderson } 118401730558SDoug Anderson mci_writel(host, UHS_REG, uhs); 118501730558SDoug Anderson 118601730558SDoug Anderson return 0; 118701730558SDoug Anderson } 118801730558SDoug Anderson 1189f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 1190f95f3850SWill Newton { 1191f95f3850SWill Newton int read_only; 1192f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 11939795a846SJaehoon Chung int gpio_ro = mmc_gpio_get_ro(mmc); 1194f95f3850SWill Newton 1195f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 119626375b5cSJaehoon Chung if ((slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) || 119726375b5cSJaehoon Chung (slot->host->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT)) 1198b4967aa5SThomas Abraham read_only = 0; 11999795a846SJaehoon Chung else if (!IS_ERR_VALUE(gpio_ro)) 12009795a846SJaehoon Chung read_only = gpio_ro; 1201f95f3850SWill Newton else 1202f95f3850SWill Newton read_only = 1203f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1204f95f3850SWill Newton 1205f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1206f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1207f95f3850SWill Newton 1208f95f3850SWill Newton return read_only; 1209f95f3850SWill Newton } 1210f95f3850SWill Newton 1211f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1212f95f3850SWill Newton { 1213f95f3850SWill Newton int present; 1214f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1215f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 12167cf347bdSZhangfei Gao struct dw_mci *host = slot->host; 12177cf347bdSZhangfei Gao int gpio_cd = mmc_gpio_get_cd(mmc); 1218f95f3850SWill Newton 1219f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 1220fc3d7720SJaehoon Chung if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) 1221fc3d7720SJaehoon Chung present = 1; 1222bf626e55SZhangfei Gao else if (!IS_ERR_VALUE(gpio_cd)) 12237cf347bdSZhangfei Gao present = gpio_cd; 1224f95f3850SWill Newton else 1225f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1226f95f3850SWill Newton == 0 ? 1 : 0; 1227f95f3850SWill Newton 12287cf347bdSZhangfei Gao spin_lock_bh(&host->lock); 1229bf626e55SZhangfei Gao if (present) { 1230bf626e55SZhangfei Gao set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1231f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 1232bf626e55SZhangfei Gao } else { 1233bf626e55SZhangfei Gao clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1234f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 1235bf626e55SZhangfei Gao } 12367cf347bdSZhangfei Gao spin_unlock_bh(&host->lock); 1237f95f3850SWill Newton 1238f95f3850SWill Newton return present; 1239f95f3850SWill Newton } 1240f95f3850SWill Newton 12419623b5b9SDoug Anderson /* 12429623b5b9SDoug Anderson * Disable lower power mode. 12439623b5b9SDoug Anderson * 12449623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 12459623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 12469623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 12479623b5b9SDoug Anderson * 12489623b5b9SDoug Anderson * This function is fast if low power mode is already disabled. 12499623b5b9SDoug Anderson */ 12509623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot) 12519623b5b9SDoug Anderson { 12529623b5b9SDoug Anderson struct dw_mci *host = slot->host; 12539623b5b9SDoug Anderson u32 clk_en_a; 12549623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 12559623b5b9SDoug Anderson 12569623b5b9SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 12579623b5b9SDoug Anderson 12589623b5b9SDoug Anderson if (clk_en_a & clken_low_pwr) { 12599623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); 12609623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 12619623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 12629623b5b9SDoug Anderson } 12639623b5b9SDoug Anderson } 12649623b5b9SDoug Anderson 12651a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 12661a5c8e1fSShashidhar Hiremath { 12671a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 12681a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 12691a5c8e1fSShashidhar Hiremath u32 int_mask; 12701a5c8e1fSShashidhar Hiremath 12711a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 12721a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 12731a5c8e1fSShashidhar Hiremath if (enb) { 12749623b5b9SDoug Anderson /* 12759623b5b9SDoug Anderson * Turn off low power mode if it was enabled. This is a bit of 12769623b5b9SDoug Anderson * a heavy operation and we disable / enable IRQs a lot, so 12779623b5b9SDoug Anderson * we'll leave low power mode disabled and it will get 12789623b5b9SDoug Anderson * re-enabled again in dw_mci_setup_bus(). 12799623b5b9SDoug Anderson */ 12809623b5b9SDoug Anderson dw_mci_disable_low_power(slot); 12819623b5b9SDoug Anderson 12821a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 128376756234SAddy Ke (int_mask | SDMMC_INT_SDIO(slot->sdio_id))); 12841a5c8e1fSShashidhar Hiremath } else { 12851a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 128676756234SAddy Ke (int_mask & ~SDMMC_INT_SDIO(slot->sdio_id))); 12871a5c8e1fSShashidhar Hiremath } 12881a5c8e1fSShashidhar Hiremath } 12891a5c8e1fSShashidhar Hiremath 12900976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 12910976f16dSSeungwon Jeon { 12920976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 12930976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 12940976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 12950976f16dSSeungwon Jeon struct dw_mci_tuning_data tuning_data; 12960976f16dSSeungwon Jeon int err = -ENOSYS; 12970976f16dSSeungwon Jeon 12980976f16dSSeungwon Jeon if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { 12990976f16dSSeungwon Jeon if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { 13000976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_8bit; 13010976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); 13020976f16dSSeungwon Jeon } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { 13030976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 13040976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 13050976f16dSSeungwon Jeon } else { 13060976f16dSSeungwon Jeon return -EINVAL; 13070976f16dSSeungwon Jeon } 13080976f16dSSeungwon Jeon } else if (opcode == MMC_SEND_TUNING_BLOCK) { 13090976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 13100976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 13110976f16dSSeungwon Jeon } else { 13120976f16dSSeungwon Jeon dev_err(host->dev, 13130976f16dSSeungwon Jeon "Undefined command(%d) for tuning\n", opcode); 13140976f16dSSeungwon Jeon return -EINVAL; 13150976f16dSSeungwon Jeon } 13160976f16dSSeungwon Jeon 13170976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 13180976f16dSSeungwon Jeon err = drv_data->execute_tuning(slot, opcode, &tuning_data); 13190976f16dSSeungwon Jeon return err; 13200976f16dSSeungwon Jeon } 13210976f16dSSeungwon Jeon 1322f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1323f95f3850SWill Newton .request = dw_mci_request, 13249aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 13259aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1326f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1327f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1328f95f3850SWill Newton .get_cd = dw_mci_get_cd, 13291a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 13300976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 133101730558SDoug Anderson .card_busy = dw_mci_card_busy, 133201730558SDoug Anderson .start_signal_voltage_switch = dw_mci_switch_voltage, 133301730558SDoug Anderson 1334f95f3850SWill Newton }; 1335f95f3850SWill Newton 1336f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1337f95f3850SWill Newton __releases(&host->lock) 1338f95f3850SWill Newton __acquires(&host->lock) 1339f95f3850SWill Newton { 1340f95f3850SWill Newton struct dw_mci_slot *slot; 1341f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1342f95f3850SWill Newton 1343f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1344f95f3850SWill Newton 1345f95f3850SWill Newton host->cur_slot->mrq = NULL; 1346f95f3850SWill Newton host->mrq = NULL; 1347f95f3850SWill Newton if (!list_empty(&host->queue)) { 1348f95f3850SWill Newton slot = list_entry(host->queue.next, 1349f95f3850SWill Newton struct dw_mci_slot, queue_node); 1350f95f3850SWill Newton list_del(&slot->queue_node); 13514a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1352f95f3850SWill Newton mmc_hostname(slot->mmc)); 1353f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1354f95f3850SWill Newton dw_mci_start_request(host, slot); 1355f95f3850SWill Newton } else { 13564a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 135701730558SDoug Anderson 135801730558SDoug Anderson if (host->state == STATE_SENDING_CMD11) 135901730558SDoug Anderson host->state = STATE_WAITING_CMD11_DONE; 136001730558SDoug Anderson else 1361f95f3850SWill Newton host->state = STATE_IDLE; 1362f95f3850SWill Newton } 1363f95f3850SWill Newton 1364f95f3850SWill Newton spin_unlock(&host->lock); 1365f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1366f95f3850SWill Newton spin_lock(&host->lock); 1367f95f3850SWill Newton } 1368f95f3850SWill Newton 1369e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1370f95f3850SWill Newton { 1371f95f3850SWill Newton u32 status = host->cmd_status; 1372f95f3850SWill Newton 1373f95f3850SWill Newton host->cmd_status = 0; 1374f95f3850SWill Newton 1375f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1376f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1377f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1378f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1379f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1380f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1381f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1382f95f3850SWill Newton } else { 1383f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1384f95f3850SWill Newton cmd->resp[1] = 0; 1385f95f3850SWill Newton cmd->resp[2] = 0; 1386f95f3850SWill Newton cmd->resp[3] = 0; 1387f95f3850SWill Newton } 1388f95f3850SWill Newton } 1389f95f3850SWill Newton 1390f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1391f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1392f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1393f95f3850SWill Newton cmd->error = -EILSEQ; 1394f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1395f95f3850SWill Newton cmd->error = -EIO; 1396f95f3850SWill Newton else 1397f95f3850SWill Newton cmd->error = 0; 1398f95f3850SWill Newton 1399f95f3850SWill Newton if (cmd->error) { 1400f95f3850SWill Newton /* newer ip versions need a delay between retries */ 1401f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) 1402f95f3850SWill Newton mdelay(20); 1403f95f3850SWill Newton } 1404e352c813SSeungwon Jeon 1405e352c813SSeungwon Jeon return cmd->error; 1406e352c813SSeungwon Jeon } 1407e352c813SSeungwon Jeon 1408e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) 1409e352c813SSeungwon Jeon { 141031bff450SSeungwon Jeon u32 status = host->data_status; 1411e352c813SSeungwon Jeon 1412e352c813SSeungwon Jeon if (status & DW_MCI_DATA_ERROR_FLAGS) { 1413e352c813SSeungwon Jeon if (status & SDMMC_INT_DRTO) { 1414e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1415e352c813SSeungwon Jeon } else if (status & SDMMC_INT_DCRC) { 1416e352c813SSeungwon Jeon data->error = -EILSEQ; 1417e352c813SSeungwon Jeon } else if (status & SDMMC_INT_EBE) { 1418e352c813SSeungwon Jeon if (host->dir_status == 1419e352c813SSeungwon Jeon DW_MCI_SEND_STATUS) { 1420e352c813SSeungwon Jeon /* 1421e352c813SSeungwon Jeon * No data CRC status was returned. 1422e352c813SSeungwon Jeon * The number of bytes transferred 1423e352c813SSeungwon Jeon * will be exaggerated in PIO mode. 1424e352c813SSeungwon Jeon */ 1425e352c813SSeungwon Jeon data->bytes_xfered = 0; 1426e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1427e352c813SSeungwon Jeon } else if (host->dir_status == 1428e352c813SSeungwon Jeon DW_MCI_RECV_STATUS) { 1429e352c813SSeungwon Jeon data->error = -EIO; 1430e352c813SSeungwon Jeon } 1431e352c813SSeungwon Jeon } else { 1432e352c813SSeungwon Jeon /* SDMMC_INT_SBE is included */ 1433e352c813SSeungwon Jeon data->error = -EIO; 1434e352c813SSeungwon Jeon } 1435e352c813SSeungwon Jeon 1436e6cc0123SDoug Anderson dev_dbg(host->dev, "data error, status 0x%08x\n", status); 1437e352c813SSeungwon Jeon 1438e352c813SSeungwon Jeon /* 1439e352c813SSeungwon Jeon * After an error, there may be data lingering 144031bff450SSeungwon Jeon * in the FIFO 1441e352c813SSeungwon Jeon */ 14423a33a94cSSonny Rao dw_mci_reset(host); 1443e352c813SSeungwon Jeon } else { 1444e352c813SSeungwon Jeon data->bytes_xfered = data->blocks * data->blksz; 1445e352c813SSeungwon Jeon data->error = 0; 1446e352c813SSeungwon Jeon } 1447e352c813SSeungwon Jeon 1448e352c813SSeungwon Jeon return data->error; 1449f95f3850SWill Newton } 1450f95f3850SWill Newton 1451f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1452f95f3850SWill Newton { 1453f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1454f95f3850SWill Newton struct mmc_data *data; 1455f95f3850SWill Newton struct mmc_command *cmd; 1456e352c813SSeungwon Jeon struct mmc_request *mrq; 1457f95f3850SWill Newton enum dw_mci_state state; 1458f95f3850SWill Newton enum dw_mci_state prev_state; 1459e352c813SSeungwon Jeon unsigned int err; 1460f95f3850SWill Newton 1461f95f3850SWill Newton spin_lock(&host->lock); 1462f95f3850SWill Newton 1463f95f3850SWill Newton state = host->state; 1464f95f3850SWill Newton data = host->data; 1465e352c813SSeungwon Jeon mrq = host->mrq; 1466f95f3850SWill Newton 1467f95f3850SWill Newton do { 1468f95f3850SWill Newton prev_state = state; 1469f95f3850SWill Newton 1470f95f3850SWill Newton switch (state) { 1471f95f3850SWill Newton case STATE_IDLE: 147201730558SDoug Anderson case STATE_WAITING_CMD11_DONE: 1473f95f3850SWill Newton break; 1474f95f3850SWill Newton 147501730558SDoug Anderson case STATE_SENDING_CMD11: 1476f95f3850SWill Newton case STATE_SENDING_CMD: 1477f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1478f95f3850SWill Newton &host->pending_events)) 1479f95f3850SWill Newton break; 1480f95f3850SWill Newton 1481f95f3850SWill Newton cmd = host->cmd; 1482f95f3850SWill Newton host->cmd = NULL; 1483f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1484e352c813SSeungwon Jeon err = dw_mci_command_complete(host, cmd); 1485e352c813SSeungwon Jeon if (cmd == mrq->sbc && !err) { 1486053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1487053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1488e352c813SSeungwon Jeon mrq->cmd); 1489053b3ce6SSeungwon Jeon goto unlock; 1490053b3ce6SSeungwon Jeon } 1491053b3ce6SSeungwon Jeon 1492e352c813SSeungwon Jeon if (cmd->data && err) { 149371abb133SSeungwon Jeon dw_mci_stop_dma(host); 149490c2143aSSeungwon Jeon send_stop_abort(host, data); 149571abb133SSeungwon Jeon state = STATE_SENDING_STOP; 149671abb133SSeungwon Jeon break; 149771abb133SSeungwon Jeon } 149871abb133SSeungwon Jeon 1499e352c813SSeungwon Jeon if (!cmd->data || err) { 1500e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1501f95f3850SWill Newton goto unlock; 1502f95f3850SWill Newton } 1503f95f3850SWill Newton 1504f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1505f95f3850SWill Newton /* fall through */ 1506f95f3850SWill Newton 1507f95f3850SWill Newton case STATE_SENDING_DATA: 15082aa35465SDoug Anderson /* 15092aa35465SDoug Anderson * We could get a data error and never a transfer 15102aa35465SDoug Anderson * complete so we'd better check for it here. 15112aa35465SDoug Anderson * 15122aa35465SDoug Anderson * Note that we don't really care if we also got a 15132aa35465SDoug Anderson * transfer complete; stopping the DMA and sending an 15142aa35465SDoug Anderson * abort won't hurt. 15152aa35465SDoug Anderson */ 1516f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1517f95f3850SWill Newton &host->pending_events)) { 1518f95f3850SWill Newton dw_mci_stop_dma(host); 151990c2143aSSeungwon Jeon send_stop_abort(host, data); 1520f95f3850SWill Newton state = STATE_DATA_ERROR; 1521f95f3850SWill Newton break; 1522f95f3850SWill Newton } 1523f95f3850SWill Newton 1524f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1525f95f3850SWill Newton &host->pending_events)) 1526f95f3850SWill Newton break; 1527f95f3850SWill Newton 1528f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 15292aa35465SDoug Anderson 15302aa35465SDoug Anderson /* 15312aa35465SDoug Anderson * Handle an EVENT_DATA_ERROR that might have shown up 15322aa35465SDoug Anderson * before the transfer completed. This might not have 15332aa35465SDoug Anderson * been caught by the check above because the interrupt 15342aa35465SDoug Anderson * could have gone off between the previous check and 15352aa35465SDoug Anderson * the check for transfer complete. 15362aa35465SDoug Anderson * 15372aa35465SDoug Anderson * Technically this ought not be needed assuming we 15382aa35465SDoug Anderson * get a DATA_COMPLETE eventually (we'll notice the 15392aa35465SDoug Anderson * error and end the request), but it shouldn't hurt. 15402aa35465SDoug Anderson * 15412aa35465SDoug Anderson * This has the advantage of sending the stop command. 15422aa35465SDoug Anderson */ 15432aa35465SDoug Anderson if (test_and_clear_bit(EVENT_DATA_ERROR, 15442aa35465SDoug Anderson &host->pending_events)) { 15452aa35465SDoug Anderson dw_mci_stop_dma(host); 15462aa35465SDoug Anderson send_stop_abort(host, data); 15472aa35465SDoug Anderson state = STATE_DATA_ERROR; 15482aa35465SDoug Anderson break; 15492aa35465SDoug Anderson } 1550f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 15512aa35465SDoug Anderson 1552f95f3850SWill Newton /* fall through */ 1553f95f3850SWill Newton 1554f95f3850SWill Newton case STATE_DATA_BUSY: 1555f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 1556f95f3850SWill Newton &host->pending_events)) 1557f95f3850SWill Newton break; 1558f95f3850SWill Newton 1559f95f3850SWill Newton host->data = NULL; 1560f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 1561e352c813SSeungwon Jeon err = dw_mci_data_complete(host, data); 1562f95f3850SWill Newton 1563e352c813SSeungwon Jeon if (!err) { 1564e352c813SSeungwon Jeon if (!data->stop || mrq->sbc) { 156517c8bc85SSachin Kamat if (mrq->sbc && data->stop) 1566053b3ce6SSeungwon Jeon data->stop->error = 0; 1567e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1568053b3ce6SSeungwon Jeon goto unlock; 1569053b3ce6SSeungwon Jeon } 1570053b3ce6SSeungwon Jeon 157190c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 1572e352c813SSeungwon Jeon if (data->stop) 157390c2143aSSeungwon Jeon send_stop_abort(host, data); 15742aa35465SDoug Anderson } else { 15752aa35465SDoug Anderson /* 15762aa35465SDoug Anderson * If we don't have a command complete now we'll 15772aa35465SDoug Anderson * never get one since we just reset everything; 15782aa35465SDoug Anderson * better end the request. 15792aa35465SDoug Anderson * 15802aa35465SDoug Anderson * If we do have a command complete we'll fall 15812aa35465SDoug Anderson * through to the SENDING_STOP command and 15822aa35465SDoug Anderson * everything will be peachy keen. 15832aa35465SDoug Anderson */ 15842aa35465SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, 15852aa35465SDoug Anderson &host->pending_events)) { 15862aa35465SDoug Anderson host->cmd = NULL; 15872aa35465SDoug Anderson dw_mci_request_end(host, mrq); 15882aa35465SDoug Anderson goto unlock; 15892aa35465SDoug Anderson } 159090c2143aSSeungwon Jeon } 1591e352c813SSeungwon Jeon 1592e352c813SSeungwon Jeon /* 1593e352c813SSeungwon Jeon * If err has non-zero, 1594e352c813SSeungwon Jeon * stop-abort command has been already issued. 1595e352c813SSeungwon Jeon */ 1596e352c813SSeungwon Jeon prev_state = state = STATE_SENDING_STOP; 1597e352c813SSeungwon Jeon 1598f95f3850SWill Newton /* fall through */ 1599f95f3850SWill Newton 1600f95f3850SWill Newton case STATE_SENDING_STOP: 1601f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1602f95f3850SWill Newton &host->pending_events)) 1603f95f3850SWill Newton break; 1604f95f3850SWill Newton 160571abb133SSeungwon Jeon /* CMD error in data command */ 160631bff450SSeungwon Jeon if (mrq->cmd->error && mrq->data) 16073a33a94cSSonny Rao dw_mci_reset(host); 160871abb133SSeungwon Jeon 1609f95f3850SWill Newton host->cmd = NULL; 161071abb133SSeungwon Jeon host->data = NULL; 161190c2143aSSeungwon Jeon 1612e352c813SSeungwon Jeon if (mrq->stop) 1613e352c813SSeungwon Jeon dw_mci_command_complete(host, mrq->stop); 161490c2143aSSeungwon Jeon else 161590c2143aSSeungwon Jeon host->cmd_status = 0; 161690c2143aSSeungwon Jeon 1617e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1618f95f3850SWill Newton goto unlock; 1619f95f3850SWill Newton 1620f95f3850SWill Newton case STATE_DATA_ERROR: 1621f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1622f95f3850SWill Newton &host->pending_events)) 1623f95f3850SWill Newton break; 1624f95f3850SWill Newton 1625f95f3850SWill Newton state = STATE_DATA_BUSY; 1626f95f3850SWill Newton break; 1627f95f3850SWill Newton } 1628f95f3850SWill Newton } while (state != prev_state); 1629f95f3850SWill Newton 1630f95f3850SWill Newton host->state = state; 1631f95f3850SWill Newton unlock: 1632f95f3850SWill Newton spin_unlock(&host->lock); 1633f95f3850SWill Newton 1634f95f3850SWill Newton } 1635f95f3850SWill Newton 163634b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 163734b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 163834b664a2SJames Hogan { 163934b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 164034b664a2SJames Hogan host->part_buf_count = cnt; 164134b664a2SJames Hogan } 164234b664a2SJames Hogan 164334b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 164434b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 164534b664a2SJames Hogan { 164634b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 164734b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 164834b664a2SJames Hogan host->part_buf_count += cnt; 164934b664a2SJames Hogan return cnt; 165034b664a2SJames Hogan } 165134b664a2SJames Hogan 165234b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 165334b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 165434b664a2SJames Hogan { 165534b664a2SJames Hogan cnt = min(cnt, (int)host->part_buf_count); 165634b664a2SJames Hogan if (cnt) { 165734b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 165834b664a2SJames Hogan cnt); 165934b664a2SJames Hogan host->part_buf_count -= cnt; 166034b664a2SJames Hogan host->part_buf_start += cnt; 166134b664a2SJames Hogan } 166234b664a2SJames Hogan return cnt; 166334b664a2SJames Hogan } 166434b664a2SJames Hogan 166534b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 166634b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 166734b664a2SJames Hogan { 166834b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 166934b664a2SJames Hogan host->part_buf_start = cnt; 167034b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 167134b664a2SJames Hogan } 167234b664a2SJames Hogan 1673f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 1674f95f3850SWill Newton { 1675cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1676cfbeb59cSMarkos Chandras int init_cnt = cnt; 1677cfbeb59cSMarkos Chandras 167834b664a2SJames Hogan /* try and push anything in the part_buf */ 167934b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 168034b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 168134b664a2SJames Hogan buf += len; 168234b664a2SJames Hogan cnt -= len; 1683cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 16844e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 16854e0a5adfSJaehoon Chung host->part_buf16); 168634b664a2SJames Hogan host->part_buf_count = 0; 168734b664a2SJames Hogan } 168834b664a2SJames Hogan } 168934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 169034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 169134b664a2SJames Hogan while (cnt >= 2) { 169234b664a2SJames Hogan u16 aligned_buf[64]; 169334b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 169434b664a2SJames Hogan int items = len >> 1; 169534b664a2SJames Hogan int i; 169634b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 169734b664a2SJames Hogan memcpy(aligned_buf, buf, len); 169834b664a2SJames Hogan buf += len; 169934b664a2SJames Hogan cnt -= len; 170034b664a2SJames Hogan /* push data from aligned buffer into fifo */ 170134b664a2SJames Hogan for (i = 0; i < items; ++i) 17024e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 17034e0a5adfSJaehoon Chung aligned_buf[i]); 170434b664a2SJames Hogan } 170534b664a2SJames Hogan } else 170634b664a2SJames Hogan #endif 170734b664a2SJames Hogan { 170834b664a2SJames Hogan u16 *pdata = buf; 170934b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 17104e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), *pdata++); 171134b664a2SJames Hogan buf = pdata; 171234b664a2SJames Hogan } 171334b664a2SJames Hogan /* put anything remaining in the part_buf */ 171434b664a2SJames Hogan if (cnt) { 171534b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1716cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1717cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1718cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 17194e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 17204e0a5adfSJaehoon Chung host->part_buf16); 1721f95f3850SWill Newton } 1722f95f3850SWill Newton } 1723f95f3850SWill Newton 1724f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 1725f95f3850SWill Newton { 172634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 172734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 172834b664a2SJames Hogan while (cnt >= 2) { 172934b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 173034b664a2SJames Hogan u16 aligned_buf[64]; 173134b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 173234b664a2SJames Hogan int items = len >> 1; 173334b664a2SJames Hogan int i; 173434b664a2SJames Hogan for (i = 0; i < items; ++i) 17354e0a5adfSJaehoon Chung aligned_buf[i] = mci_readw(host, 17364e0a5adfSJaehoon Chung DATA(host->data_offset)); 173734b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 173834b664a2SJames Hogan memcpy(buf, aligned_buf, len); 173934b664a2SJames Hogan buf += len; 174034b664a2SJames Hogan cnt -= len; 174134b664a2SJames Hogan } 174234b664a2SJames Hogan } else 174334b664a2SJames Hogan #endif 174434b664a2SJames Hogan { 174534b664a2SJames Hogan u16 *pdata = buf; 174634b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 17474e0a5adfSJaehoon Chung *pdata++ = mci_readw(host, DATA(host->data_offset)); 174834b664a2SJames Hogan buf = pdata; 174934b664a2SJames Hogan } 175034b664a2SJames Hogan if (cnt) { 17514e0a5adfSJaehoon Chung host->part_buf16 = mci_readw(host, DATA(host->data_offset)); 175234b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1753f95f3850SWill Newton } 1754f95f3850SWill Newton } 1755f95f3850SWill Newton 1756f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 1757f95f3850SWill Newton { 1758cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1759cfbeb59cSMarkos Chandras int init_cnt = cnt; 1760cfbeb59cSMarkos Chandras 176134b664a2SJames Hogan /* try and push anything in the part_buf */ 176234b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 176334b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 176434b664a2SJames Hogan buf += len; 176534b664a2SJames Hogan cnt -= len; 1766cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 17674e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 17684e0a5adfSJaehoon Chung host->part_buf32); 176934b664a2SJames Hogan host->part_buf_count = 0; 177034b664a2SJames Hogan } 177134b664a2SJames Hogan } 177234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 177334b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 177434b664a2SJames Hogan while (cnt >= 4) { 177534b664a2SJames Hogan u32 aligned_buf[32]; 177634b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 177734b664a2SJames Hogan int items = len >> 2; 177834b664a2SJames Hogan int i; 177934b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 178034b664a2SJames Hogan memcpy(aligned_buf, buf, len); 178134b664a2SJames Hogan buf += len; 178234b664a2SJames Hogan cnt -= len; 178334b664a2SJames Hogan /* push data from aligned buffer into fifo */ 178434b664a2SJames Hogan for (i = 0; i < items; ++i) 17854e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 17864e0a5adfSJaehoon Chung aligned_buf[i]); 178734b664a2SJames Hogan } 178834b664a2SJames Hogan } else 178934b664a2SJames Hogan #endif 179034b664a2SJames Hogan { 179134b664a2SJames Hogan u32 *pdata = buf; 179234b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 17934e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), *pdata++); 179434b664a2SJames Hogan buf = pdata; 179534b664a2SJames Hogan } 179634b664a2SJames Hogan /* put anything remaining in the part_buf */ 179734b664a2SJames Hogan if (cnt) { 179834b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1799cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1800cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1801cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 18024e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 18034e0a5adfSJaehoon Chung host->part_buf32); 1804f95f3850SWill Newton } 1805f95f3850SWill Newton } 1806f95f3850SWill Newton 1807f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 1808f95f3850SWill Newton { 180934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 181034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 181134b664a2SJames Hogan while (cnt >= 4) { 181234b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 181334b664a2SJames Hogan u32 aligned_buf[32]; 181434b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 181534b664a2SJames Hogan int items = len >> 2; 181634b664a2SJames Hogan int i; 181734b664a2SJames Hogan for (i = 0; i < items; ++i) 18184e0a5adfSJaehoon Chung aligned_buf[i] = mci_readl(host, 18194e0a5adfSJaehoon Chung DATA(host->data_offset)); 182034b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 182134b664a2SJames Hogan memcpy(buf, aligned_buf, len); 182234b664a2SJames Hogan buf += len; 182334b664a2SJames Hogan cnt -= len; 182434b664a2SJames Hogan } 182534b664a2SJames Hogan } else 182634b664a2SJames Hogan #endif 182734b664a2SJames Hogan { 182834b664a2SJames Hogan u32 *pdata = buf; 182934b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 18304e0a5adfSJaehoon Chung *pdata++ = mci_readl(host, DATA(host->data_offset)); 183134b664a2SJames Hogan buf = pdata; 183234b664a2SJames Hogan } 183334b664a2SJames Hogan if (cnt) { 18344e0a5adfSJaehoon Chung host->part_buf32 = mci_readl(host, DATA(host->data_offset)); 183534b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1836f95f3850SWill Newton } 1837f95f3850SWill Newton } 1838f95f3850SWill Newton 1839f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 1840f95f3850SWill Newton { 1841cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1842cfbeb59cSMarkos Chandras int init_cnt = cnt; 1843cfbeb59cSMarkos Chandras 184434b664a2SJames Hogan /* try and push anything in the part_buf */ 184534b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 184634b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 184734b664a2SJames Hogan buf += len; 184834b664a2SJames Hogan cnt -= len; 1849c09fbd74SSeungwon Jeon 1850cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 1851c09fbd74SSeungwon Jeon mci_writeq(host, DATA(host->data_offset), 18524e0a5adfSJaehoon Chung host->part_buf); 185334b664a2SJames Hogan host->part_buf_count = 0; 185434b664a2SJames Hogan } 185534b664a2SJames Hogan } 185634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 185734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 185834b664a2SJames Hogan while (cnt >= 8) { 185934b664a2SJames Hogan u64 aligned_buf[16]; 186034b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 186134b664a2SJames Hogan int items = len >> 3; 186234b664a2SJames Hogan int i; 186334b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 186434b664a2SJames Hogan memcpy(aligned_buf, buf, len); 186534b664a2SJames Hogan buf += len; 186634b664a2SJames Hogan cnt -= len; 186734b664a2SJames Hogan /* push data from aligned buffer into fifo */ 186834b664a2SJames Hogan for (i = 0; i < items; ++i) 18694e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 18704e0a5adfSJaehoon Chung aligned_buf[i]); 187134b664a2SJames Hogan } 187234b664a2SJames Hogan } else 187334b664a2SJames Hogan #endif 187434b664a2SJames Hogan { 187534b664a2SJames Hogan u64 *pdata = buf; 187634b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 18774e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), *pdata++); 187834b664a2SJames Hogan buf = pdata; 187934b664a2SJames Hogan } 188034b664a2SJames Hogan /* put anything remaining in the part_buf */ 188134b664a2SJames Hogan if (cnt) { 188234b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1883cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1884cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1885cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 18864e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 18874e0a5adfSJaehoon Chung host->part_buf); 1888f95f3850SWill Newton } 1889f95f3850SWill Newton } 1890f95f3850SWill Newton 1891f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 1892f95f3850SWill Newton { 189334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 189434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 189534b664a2SJames Hogan while (cnt >= 8) { 189634b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 189734b664a2SJames Hogan u64 aligned_buf[16]; 189834b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 189934b664a2SJames Hogan int items = len >> 3; 190034b664a2SJames Hogan int i; 190134b664a2SJames Hogan for (i = 0; i < items; ++i) 19024e0a5adfSJaehoon Chung aligned_buf[i] = mci_readq(host, 19034e0a5adfSJaehoon Chung DATA(host->data_offset)); 190434b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 190534b664a2SJames Hogan memcpy(buf, aligned_buf, len); 190634b664a2SJames Hogan buf += len; 190734b664a2SJames Hogan cnt -= len; 1908f95f3850SWill Newton } 190934b664a2SJames Hogan } else 191034b664a2SJames Hogan #endif 191134b664a2SJames Hogan { 191234b664a2SJames Hogan u64 *pdata = buf; 191334b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 19144e0a5adfSJaehoon Chung *pdata++ = mci_readq(host, DATA(host->data_offset)); 191534b664a2SJames Hogan buf = pdata; 191634b664a2SJames Hogan } 191734b664a2SJames Hogan if (cnt) { 19184e0a5adfSJaehoon Chung host->part_buf = mci_readq(host, DATA(host->data_offset)); 191934b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 192034b664a2SJames Hogan } 192134b664a2SJames Hogan } 192234b664a2SJames Hogan 192334b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 192434b664a2SJames Hogan { 192534b664a2SJames Hogan int len; 192634b664a2SJames Hogan 192734b664a2SJames Hogan /* get remaining partial bytes */ 192834b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 192934b664a2SJames Hogan if (unlikely(len == cnt)) 193034b664a2SJames Hogan return; 193134b664a2SJames Hogan buf += len; 193234b664a2SJames Hogan cnt -= len; 193334b664a2SJames Hogan 193434b664a2SJames Hogan /* get the rest of the data */ 193534b664a2SJames Hogan host->pull_data(host, buf, cnt); 1936f95f3850SWill Newton } 1937f95f3850SWill Newton 193887a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 1939f95f3850SWill Newton { 1940f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1941f9c2a0dcSSeungwon Jeon void *buf; 1942f9c2a0dcSSeungwon Jeon unsigned int offset; 1943f95f3850SWill Newton struct mmc_data *data = host->data; 1944f95f3850SWill Newton int shift = host->data_shift; 1945f95f3850SWill Newton u32 status; 19463e4b0d8bSMarkos Chandras unsigned int len; 1947f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 1948f95f3850SWill Newton 1949f95f3850SWill Newton do { 1950f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1951f9c2a0dcSSeungwon Jeon goto done; 1952f95f3850SWill Newton 19534225fc85SImre Deak host->sg = sg_miter->piter.sg; 1954f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 1955f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 1956f9c2a0dcSSeungwon Jeon offset = 0; 1957f9c2a0dcSSeungwon Jeon 1958f9c2a0dcSSeungwon Jeon do { 1959f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 1960f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 1961f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 1962f9c2a0dcSSeungwon Jeon if (!len) 1963f9c2a0dcSSeungwon Jeon break; 1964f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 19653e4b0d8bSMarkos Chandras data->bytes_xfered += len; 1966f95f3850SWill Newton offset += len; 1967f9c2a0dcSSeungwon Jeon remain -= len; 1968f9c2a0dcSSeungwon Jeon } while (remain); 1969f95f3850SWill Newton 1970e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 1971f95f3850SWill Newton status = mci_readl(host, MINTSTS); 1972f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 197387a74d39SKyoungil Kim /* if the RXDR is ready read again */ 197487a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 197587a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 1976f9c2a0dcSSeungwon Jeon 1977f9c2a0dcSSeungwon Jeon if (!remain) { 1978f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1979f9c2a0dcSSeungwon Jeon goto done; 1980f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 1981f9c2a0dcSSeungwon Jeon } 1982f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1983f95f3850SWill Newton return; 1984f95f3850SWill Newton 1985f95f3850SWill Newton done: 1986f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1987f9c2a0dcSSeungwon Jeon host->sg = NULL; 1988f95f3850SWill Newton smp_wmb(); 1989f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1990f95f3850SWill Newton } 1991f95f3850SWill Newton 1992f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 1993f95f3850SWill Newton { 1994f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1995f9c2a0dcSSeungwon Jeon void *buf; 1996f9c2a0dcSSeungwon Jeon unsigned int offset; 1997f95f3850SWill Newton struct mmc_data *data = host->data; 1998f95f3850SWill Newton int shift = host->data_shift; 1999f95f3850SWill Newton u32 status; 20003e4b0d8bSMarkos Chandras unsigned int len; 2001f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 2002f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 2003f95f3850SWill Newton 2004f95f3850SWill Newton do { 2005f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2006f9c2a0dcSSeungwon Jeon goto done; 2007f95f3850SWill Newton 20084225fc85SImre Deak host->sg = sg_miter->piter.sg; 2009f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 2010f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 2011f9c2a0dcSSeungwon Jeon offset = 0; 2012f9c2a0dcSSeungwon Jeon 2013f9c2a0dcSSeungwon Jeon do { 2014f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 2015f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 2016f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 2017f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 2018f9c2a0dcSSeungwon Jeon if (!len) 2019f9c2a0dcSSeungwon Jeon break; 2020f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 20213e4b0d8bSMarkos Chandras data->bytes_xfered += len; 2022f95f3850SWill Newton offset += len; 2023f9c2a0dcSSeungwon Jeon remain -= len; 2024f9c2a0dcSSeungwon Jeon } while (remain); 2025f95f3850SWill Newton 2026e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 2027f95f3850SWill Newton status = mci_readl(host, MINTSTS); 2028f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2029f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 2030f9c2a0dcSSeungwon Jeon 2031f9c2a0dcSSeungwon Jeon if (!remain) { 2032f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 2033f9c2a0dcSSeungwon Jeon goto done; 2034f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 2035f9c2a0dcSSeungwon Jeon } 2036f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2037f95f3850SWill Newton return; 2038f95f3850SWill Newton 2039f95f3850SWill Newton done: 2040f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 2041f9c2a0dcSSeungwon Jeon host->sg = NULL; 2042f95f3850SWill Newton smp_wmb(); 2043f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 2044f95f3850SWill Newton } 2045f95f3850SWill Newton 2046f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 2047f95f3850SWill Newton { 2048f95f3850SWill Newton if (!host->cmd_status) 2049f95f3850SWill Newton host->cmd_status = status; 2050f95f3850SWill Newton 2051f95f3850SWill Newton smp_wmb(); 2052f95f3850SWill Newton 2053f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2054f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2055f95f3850SWill Newton } 2056f95f3850SWill Newton 20576130e7a9SDoug Anderson static void dw_mci_handle_cd(struct dw_mci *host) 20586130e7a9SDoug Anderson { 20596130e7a9SDoug Anderson int i; 20606130e7a9SDoug Anderson 20616130e7a9SDoug Anderson for (i = 0; i < host->num_slots; i++) { 20626130e7a9SDoug Anderson struct dw_mci_slot *slot = host->slot[i]; 20636130e7a9SDoug Anderson 20646130e7a9SDoug Anderson if (!slot) 20656130e7a9SDoug Anderson continue; 20666130e7a9SDoug Anderson 20676130e7a9SDoug Anderson if (slot->mmc->ops->card_event) 20686130e7a9SDoug Anderson slot->mmc->ops->card_event(slot->mmc); 20696130e7a9SDoug Anderson mmc_detect_change(slot->mmc, 20706130e7a9SDoug Anderson msecs_to_jiffies(host->pdata->detect_delay_ms)); 20716130e7a9SDoug Anderson } 20726130e7a9SDoug Anderson } 20736130e7a9SDoug Anderson 2074f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 2075f95f3850SWill Newton { 2076f95f3850SWill Newton struct dw_mci *host = dev_id; 2077182c9081SSeungwon Jeon u32 pending; 20781a5c8e1fSShashidhar Hiremath int i; 2079f95f3850SWill Newton 2080f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 2081f95f3850SWill Newton 2082f95f3850SWill Newton /* 2083f95f3850SWill Newton * DTO fix - version 2.10a and below, and only if internal DMA 2084f95f3850SWill Newton * is configured. 2085f95f3850SWill Newton */ 2086f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { 2087f95f3850SWill Newton if (!pending && 2088f95f3850SWill Newton ((mci_readl(host, STATUS) >> 17) & 0x1fff)) 2089f95f3850SWill Newton pending |= SDMMC_INT_DATA_OVER; 2090f95f3850SWill Newton } 2091f95f3850SWill Newton 2092476d79f1SDoug Anderson if (pending) { 209301730558SDoug Anderson /* Check volt switch first, since it can look like an error */ 209401730558SDoug Anderson if ((host->state == STATE_SENDING_CMD11) && 209501730558SDoug Anderson (pending & SDMMC_INT_VOLT_SWITCH)) { 209601730558SDoug Anderson mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); 209701730558SDoug Anderson pending &= ~SDMMC_INT_VOLT_SWITCH; 209801730558SDoug Anderson dw_mci_cmd_interrupt(host, pending); 209901730558SDoug Anderson } 210001730558SDoug Anderson 2101f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 2102f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 2103182c9081SSeungwon Jeon host->cmd_status = pending; 2104f95f3850SWill Newton smp_wmb(); 2105f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2106f95f3850SWill Newton } 2107f95f3850SWill Newton 2108f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 2109f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 2110f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 2111182c9081SSeungwon Jeon host->data_status = pending; 2112f95f3850SWill Newton smp_wmb(); 2113f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 2114f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2115f95f3850SWill Newton } 2116f95f3850SWill Newton 2117f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 2118f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 2119f95f3850SWill Newton if (!host->data_status) 2120182c9081SSeungwon Jeon host->data_status = pending; 2121f95f3850SWill Newton smp_wmb(); 2122f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 2123f95f3850SWill Newton if (host->sg != NULL) 212487a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 2125f95f3850SWill Newton } 2126f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 2127f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2128f95f3850SWill Newton } 2129f95f3850SWill Newton 2130f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 2131f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 2132b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 213387a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 2134f95f3850SWill Newton } 2135f95f3850SWill Newton 2136f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 2137f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2138b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 2139f95f3850SWill Newton dw_mci_write_data_pio(host); 2140f95f3850SWill Newton } 2141f95f3850SWill Newton 2142f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 2143f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 2144182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 2145f95f3850SWill Newton } 2146f95f3850SWill Newton 2147f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 2148f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 21496130e7a9SDoug Anderson dw_mci_handle_cd(host); 2150f95f3850SWill Newton } 2151f95f3850SWill Newton 21521a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 21531a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 21541a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 215576756234SAddy Ke if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { 215676756234SAddy Ke mci_writel(host, RINTSTS, 215776756234SAddy Ke SDMMC_INT_SDIO(slot->sdio_id)); 21581a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 21591a5c8e1fSShashidhar Hiremath } 21601a5c8e1fSShashidhar Hiremath } 21611a5c8e1fSShashidhar Hiremath 21621fb5f68aSMarkos Chandras } 2163f95f3850SWill Newton 2164f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2165f95f3850SWill Newton /* Handle DMA interrupts */ 216669d99fdcSPrabu Thangamuthu if (host->dma_64bit_address == 1) { 216769d99fdcSPrabu Thangamuthu pending = mci_readl(host, IDSTS64); 216869d99fdcSPrabu Thangamuthu if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 216969d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | 217069d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 217169d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); 217269d99fdcSPrabu Thangamuthu host->dma_ops->complete(host); 217369d99fdcSPrabu Thangamuthu } 217469d99fdcSPrabu Thangamuthu } else { 2175f95f3850SWill Newton pending = mci_readl(host, IDSTS); 2176f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 217769d99fdcSPrabu Thangamuthu mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | 217869d99fdcSPrabu Thangamuthu SDMMC_IDMAC_INT_RI); 2179f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 2180f95f3850SWill Newton host->dma_ops->complete(host); 2181f95f3850SWill Newton } 218269d99fdcSPrabu Thangamuthu } 2183f95f3850SWill Newton #endif 2184f95f3850SWill Newton 2185f95f3850SWill Newton return IRQ_HANDLED; 2186f95f3850SWill Newton } 2187f95f3850SWill Newton 2188c91eab4bSThomas Abraham #ifdef CONFIG_OF 2189c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */ 2190c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 2191c91eab4bSThomas Abraham { 2192c91eab4bSThomas Abraham struct device_node *np; 2193c91eab4bSThomas Abraham const __be32 *addr; 2194c91eab4bSThomas Abraham int len; 2195c91eab4bSThomas Abraham 2196c91eab4bSThomas Abraham if (!dev || !dev->of_node) 2197c91eab4bSThomas Abraham return NULL; 2198c91eab4bSThomas Abraham 2199c91eab4bSThomas Abraham for_each_child_of_node(dev->of_node, np) { 2200c91eab4bSThomas Abraham addr = of_get_property(np, "reg", &len); 2201c91eab4bSThomas Abraham if (!addr || (len < sizeof(int))) 2202c91eab4bSThomas Abraham continue; 2203c91eab4bSThomas Abraham if (be32_to_cpup(addr) == slot) 2204c91eab4bSThomas Abraham return np; 2205c91eab4bSThomas Abraham } 2206c91eab4bSThomas Abraham return NULL; 2207c91eab4bSThomas Abraham } 2208c91eab4bSThomas Abraham 2209a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks { 2210a70aaa64SDoug Anderson char *quirk; 2211a70aaa64SDoug Anderson int id; 2212a70aaa64SDoug Anderson } of_slot_quirks[] = { 2213a70aaa64SDoug Anderson { 2214a70aaa64SDoug Anderson .quirk = "disable-wp", 2215a70aaa64SDoug Anderson .id = DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT, 2216a70aaa64SDoug Anderson }, 2217a70aaa64SDoug Anderson }; 2218a70aaa64SDoug Anderson 2219a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2220a70aaa64SDoug Anderson { 2221a70aaa64SDoug Anderson struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 2222a70aaa64SDoug Anderson int quirks = 0; 2223a70aaa64SDoug Anderson int idx; 2224a70aaa64SDoug Anderson 2225a70aaa64SDoug Anderson /* get quirks */ 2226a70aaa64SDoug Anderson for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++) 222726375b5cSJaehoon Chung if (of_get_property(np, of_slot_quirks[idx].quirk, NULL)) { 222826375b5cSJaehoon Chung dev_warn(dev, "Slot quirk %s is deprecated\n", 222926375b5cSJaehoon Chung of_slot_quirks[idx].quirk); 2230a70aaa64SDoug Anderson quirks |= of_slot_quirks[idx].id; 223126375b5cSJaehoon Chung } 2232a70aaa64SDoug Anderson 2233a70aaa64SDoug Anderson return quirks; 2234a70aaa64SDoug Anderson } 2235c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2236a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2237a70aaa64SDoug Anderson { 2238a70aaa64SDoug Anderson return 0; 2239a70aaa64SDoug Anderson } 2240c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2241c91eab4bSThomas Abraham 224236c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2243f95f3850SWill Newton { 2244f95f3850SWill Newton struct mmc_host *mmc; 2245f95f3850SWill Newton struct dw_mci_slot *slot; 2246e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2247800d78bfSThomas Abraham int ctrl_id, ret; 22481f44a2a5SSeungwon Jeon u32 freq[2]; 2249f95f3850SWill Newton 22504a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2251f95f3850SWill Newton if (!mmc) 2252f95f3850SWill Newton return -ENOMEM; 2253f95f3850SWill Newton 2254f95f3850SWill Newton slot = mmc_priv(mmc); 2255f95f3850SWill Newton slot->id = id; 225676756234SAddy Ke slot->sdio_id = host->sdio_id0 + id; 2257f95f3850SWill Newton slot->mmc = mmc; 2258f95f3850SWill Newton slot->host = host; 2259c91eab4bSThomas Abraham host->slot[id] = slot; 2260f95f3850SWill Newton 2261a70aaa64SDoug Anderson slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id); 2262a70aaa64SDoug Anderson 2263f95f3850SWill Newton mmc->ops = &dw_mci_ops; 22641f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 22651f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 22661f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 22671f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 22681f44a2a5SSeungwon Jeon } else { 22691f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 22701f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 22711f44a2a5SSeungwon Jeon } 2272f95f3850SWill Newton 227351da2240SYuvaraj CD /*if there are external regulators, get them*/ 227451da2240SYuvaraj CD ret = mmc_regulator_get_supply(mmc); 227551da2240SYuvaraj CD if (ret == -EPROBE_DEFER) 22763cf890fcSDoug Anderson goto err_host_allocated; 227751da2240SYuvaraj CD 227851da2240SYuvaraj CD if (!mmc->ocr_avail) 2279f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2280f95f3850SWill Newton 2281fc3d7720SJaehoon Chung if (host->pdata->caps) 2282fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2283fc3d7720SJaehoon Chung 2284ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2285ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2286ab269128SAbhilash Kesavan 2287800d78bfSThomas Abraham if (host->dev->of_node) { 2288800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2289800d78bfSThomas Abraham if (ctrl_id < 0) 2290800d78bfSThomas Abraham ctrl_id = 0; 2291800d78bfSThomas Abraham } else { 2292800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2293800d78bfSThomas Abraham } 2294cb27a843SJames Hogan if (drv_data && drv_data->caps) 2295cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2296800d78bfSThomas Abraham 22974f408cc6SSeungwon Jeon if (host->pdata->caps2) 22984f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 22994f408cc6SSeungwon Jeon 23003cf890fcSDoug Anderson ret = mmc_of_parse(mmc); 23013cf890fcSDoug Anderson if (ret) 23023cf890fcSDoug Anderson goto err_host_allocated; 2303f95f3850SWill Newton 2304f95f3850SWill Newton if (host->pdata->blk_settings) { 2305f95f3850SWill Newton mmc->max_segs = host->pdata->blk_settings->max_segs; 2306f95f3850SWill Newton mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; 2307f95f3850SWill Newton mmc->max_blk_count = host->pdata->blk_settings->max_blk_count; 2308f95f3850SWill Newton mmc->max_req_size = host->pdata->blk_settings->max_req_size; 2309f95f3850SWill Newton mmc->max_seg_size = host->pdata->blk_settings->max_seg_size; 2310f95f3850SWill Newton } else { 2311f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 2312a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 2313a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2314a39e5746SJaehoon Chung mmc->max_blk_size = 65536; 2315a39e5746SJaehoon Chung mmc->max_blk_count = host->ring_size; 2316a39e5746SJaehoon Chung mmc->max_seg_size = 0x1000; 2317a39e5746SJaehoon Chung mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; 2318a39e5746SJaehoon Chung #else 2319f95f3850SWill Newton mmc->max_segs = 64; 2320f95f3850SWill Newton mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ 2321f95f3850SWill Newton mmc->max_blk_count = 512; 2322f95f3850SWill Newton mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 2323f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2324f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 2325a39e5746SJaehoon Chung } 2326f95f3850SWill Newton 2327ae0eb348SJaehoon Chung if (dw_mci_get_cd(mmc)) 2328ae0eb348SJaehoon Chung set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2329ae0eb348SJaehoon Chung else 2330ae0eb348SJaehoon Chung clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2331ae0eb348SJaehoon Chung 23320cea529dSJaehoon Chung ret = mmc_add_host(mmc); 23330cea529dSJaehoon Chung if (ret) 23343cf890fcSDoug Anderson goto err_host_allocated; 2335f95f3850SWill Newton 2336f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2337f95f3850SWill Newton dw_mci_init_debugfs(slot); 2338f95f3850SWill Newton #endif 2339f95f3850SWill Newton 2340f95f3850SWill Newton return 0; 2341800d78bfSThomas Abraham 23423cf890fcSDoug Anderson err_host_allocated: 2343800d78bfSThomas Abraham mmc_free_host(mmc); 234451da2240SYuvaraj CD return ret; 2345f95f3850SWill Newton } 2346f95f3850SWill Newton 2347f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2348f95f3850SWill Newton { 2349f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2350f95f3850SWill Newton mmc_remove_host(slot->mmc); 2351f95f3850SWill Newton slot->host->slot[id] = NULL; 2352f95f3850SWill Newton mmc_free_host(slot->mmc); 2353f95f3850SWill Newton } 2354f95f3850SWill Newton 2355f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2356f95f3850SWill Newton { 235769d99fdcSPrabu Thangamuthu int addr_config; 235869d99fdcSPrabu Thangamuthu /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ 235969d99fdcSPrabu Thangamuthu addr_config = (mci_readl(host, HCON) >> 27) & 0x01; 236069d99fdcSPrabu Thangamuthu 236169d99fdcSPrabu Thangamuthu if (addr_config == 1) { 236269d99fdcSPrabu Thangamuthu /* host supports IDMAC in 64-bit address mode */ 236369d99fdcSPrabu Thangamuthu host->dma_64bit_address = 1; 236469d99fdcSPrabu Thangamuthu dev_info(host->dev, "IDMAC supports 64-bit address mode.\n"); 236569d99fdcSPrabu Thangamuthu if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) 236669d99fdcSPrabu Thangamuthu dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64)); 236769d99fdcSPrabu Thangamuthu } else { 236869d99fdcSPrabu Thangamuthu /* host supports IDMAC in 32-bit address mode */ 236969d99fdcSPrabu Thangamuthu host->dma_64bit_address = 0; 237069d99fdcSPrabu Thangamuthu dev_info(host->dev, "IDMAC supports 32-bit address mode.\n"); 237169d99fdcSPrabu Thangamuthu } 237269d99fdcSPrabu Thangamuthu 2373f95f3850SWill Newton /* Alloc memory for sg translation */ 2374780f22afSSeungwon Jeon host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, 2375f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2376f95f3850SWill Newton if (!host->sg_cpu) { 23774a90920cSThomas Abraham dev_err(host->dev, "%s: could not alloc DMA memory\n", 2378f95f3850SWill Newton __func__); 2379f95f3850SWill Newton goto no_dma; 2380f95f3850SWill Newton } 2381f95f3850SWill Newton 2382f95f3850SWill Newton /* Determine which DMA interface to use */ 2383f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2384f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 238500956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 2386f95f3850SWill Newton #endif 2387f95f3850SWill Newton 2388f95f3850SWill Newton if (!host->dma_ops) 2389f95f3850SWill Newton goto no_dma; 2390f95f3850SWill Newton 2391e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2392e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2393f95f3850SWill Newton if (host->dma_ops->init(host)) { 23944a90920cSThomas Abraham dev_err(host->dev, "%s: Unable to initialize " 2395f95f3850SWill Newton "DMA Controller.\n", __func__); 2396f95f3850SWill Newton goto no_dma; 2397f95f3850SWill Newton } 2398f95f3850SWill Newton } else { 23994a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2400f95f3850SWill Newton goto no_dma; 2401f95f3850SWill Newton } 2402f95f3850SWill Newton 2403f95f3850SWill Newton host->use_dma = 1; 2404f95f3850SWill Newton return; 2405f95f3850SWill Newton 2406f95f3850SWill Newton no_dma: 24074a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 2408f95f3850SWill Newton host->use_dma = 0; 2409f95f3850SWill Newton return; 2410f95f3850SWill Newton } 2411f95f3850SWill Newton 241231bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) 2413f95f3850SWill Newton { 2414f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 241531bff450SSeungwon Jeon u32 ctrl; 2416f95f3850SWill Newton 241731bff450SSeungwon Jeon ctrl = mci_readl(host, CTRL); 241831bff450SSeungwon Jeon ctrl |= reset; 241931bff450SSeungwon Jeon mci_writel(host, CTRL, ctrl); 2420f95f3850SWill Newton 2421f95f3850SWill Newton /* wait till resets clear */ 2422f95f3850SWill Newton do { 2423f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 242431bff450SSeungwon Jeon if (!(ctrl & reset)) 2425f95f3850SWill Newton return true; 2426f95f3850SWill Newton } while (time_before(jiffies, timeout)); 2427f95f3850SWill Newton 242831bff450SSeungwon Jeon dev_err(host->dev, 242931bff450SSeungwon Jeon "Timeout resetting block (ctrl reset %#x)\n", 243031bff450SSeungwon Jeon ctrl & reset); 2431f95f3850SWill Newton 2432f95f3850SWill Newton return false; 2433f95f3850SWill Newton } 2434f95f3850SWill Newton 24353a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host) 243631bff450SSeungwon Jeon { 24373a33a94cSSonny Rao u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; 24383a33a94cSSonny Rao bool ret = false; 24393a33a94cSSonny Rao 244031bff450SSeungwon Jeon /* 244131bff450SSeungwon Jeon * Reseting generates a block interrupt, hence setting 244231bff450SSeungwon Jeon * the scatter-gather pointer to NULL. 244331bff450SSeungwon Jeon */ 244431bff450SSeungwon Jeon if (host->sg) { 244531bff450SSeungwon Jeon sg_miter_stop(&host->sg_miter); 244631bff450SSeungwon Jeon host->sg = NULL; 244731bff450SSeungwon Jeon } 244831bff450SSeungwon Jeon 24493a33a94cSSonny Rao if (host->use_dma) 24503a33a94cSSonny Rao flags |= SDMMC_CTRL_DMA_RESET; 24513a33a94cSSonny Rao 24523a33a94cSSonny Rao if (dw_mci_ctrl_reset(host, flags)) { 24533a33a94cSSonny Rao /* 24543a33a94cSSonny Rao * In all cases we clear the RAWINTS register to clear any 24553a33a94cSSonny Rao * interrupts. 24563a33a94cSSonny Rao */ 24573a33a94cSSonny Rao mci_writel(host, RINTSTS, 0xFFFFFFFF); 24583a33a94cSSonny Rao 24593a33a94cSSonny Rao /* if using dma we wait for dma_req to clear */ 24603a33a94cSSonny Rao if (host->use_dma) { 24613a33a94cSSonny Rao unsigned long timeout = jiffies + msecs_to_jiffies(500); 24623a33a94cSSonny Rao u32 status; 24633a33a94cSSonny Rao do { 24643a33a94cSSonny Rao status = mci_readl(host, STATUS); 24653a33a94cSSonny Rao if (!(status & SDMMC_STATUS_DMA_REQ)) 24663a33a94cSSonny Rao break; 24673a33a94cSSonny Rao cpu_relax(); 24683a33a94cSSonny Rao } while (time_before(jiffies, timeout)); 24693a33a94cSSonny Rao 24703a33a94cSSonny Rao if (status & SDMMC_STATUS_DMA_REQ) { 24713a33a94cSSonny Rao dev_err(host->dev, 24723a33a94cSSonny Rao "%s: Timeout waiting for dma_req to " 24733a33a94cSSonny Rao "clear during reset\n", __func__); 24743a33a94cSSonny Rao goto ciu_out; 247531bff450SSeungwon Jeon } 247631bff450SSeungwon Jeon 24773a33a94cSSonny Rao /* when using DMA next we reset the fifo again */ 24783a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) 24793a33a94cSSonny Rao goto ciu_out; 24803a33a94cSSonny Rao } 24813a33a94cSSonny Rao } else { 24823a33a94cSSonny Rao /* if the controller reset bit did clear, then set clock regs */ 24833a33a94cSSonny Rao if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { 24843a33a94cSSonny Rao dev_err(host->dev, "%s: fifo/dma reset bits didn't " 24853a33a94cSSonny Rao "clear but ciu was reset, doing clock update\n", 24863a33a94cSSonny Rao __func__); 24873a33a94cSSonny Rao goto ciu_out; 24883a33a94cSSonny Rao } 24893a33a94cSSonny Rao } 24903a33a94cSSonny Rao 24913a33a94cSSonny Rao #if IS_ENABLED(CONFIG_MMC_DW_IDMAC) 24923a33a94cSSonny Rao /* It is also recommended that we reset and reprogram idmac */ 24933a33a94cSSonny Rao dw_mci_idmac_reset(host); 24943a33a94cSSonny Rao #endif 24953a33a94cSSonny Rao 24963a33a94cSSonny Rao ret = true; 24973a33a94cSSonny Rao 24983a33a94cSSonny Rao ciu_out: 24993a33a94cSSonny Rao /* After a CTRL reset we need to have CIU set clock registers */ 25003a33a94cSSonny Rao mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); 25013a33a94cSSonny Rao 25023a33a94cSSonny Rao return ret; 250331bff450SSeungwon Jeon } 250431bff450SSeungwon Jeon 2505c91eab4bSThomas Abraham #ifdef CONFIG_OF 2506c91eab4bSThomas Abraham static struct dw_mci_of_quirks { 2507c91eab4bSThomas Abraham char *quirk; 2508c91eab4bSThomas Abraham int id; 2509c91eab4bSThomas Abraham } of_quirks[] = { 2510c91eab4bSThomas Abraham { 2511c91eab4bSThomas Abraham .quirk = "broken-cd", 2512c91eab4bSThomas Abraham .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, 251326375b5cSJaehoon Chung }, { 251426375b5cSJaehoon Chung .quirk = "disable-wp", 251526375b5cSJaehoon Chung .id = DW_MCI_QUIRK_NO_WRITE_PROTECT, 2516c91eab4bSThomas Abraham }, 2517c91eab4bSThomas Abraham }; 2518c91eab4bSThomas Abraham 2519c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2520c91eab4bSThomas Abraham { 2521c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2522c91eab4bSThomas Abraham struct device *dev = host->dev; 2523c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2524e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2525800d78bfSThomas Abraham int idx, ret; 25263c6d89eaSDoug Anderson u32 clock_frequency; 2527c91eab4bSThomas Abraham 2528c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2529c91eab4bSThomas Abraham if (!pdata) { 2530c91eab4bSThomas Abraham dev_err(dev, "could not allocate memory for pdata\n"); 2531c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2532c91eab4bSThomas Abraham } 2533c91eab4bSThomas Abraham 2534c91eab4bSThomas Abraham /* find out number of slots supported */ 2535c91eab4bSThomas Abraham if (of_property_read_u32(dev->of_node, "num-slots", 2536c91eab4bSThomas Abraham &pdata->num_slots)) { 2537c91eab4bSThomas Abraham dev_info(dev, "num-slots property not found, " 2538c91eab4bSThomas Abraham "assuming 1 slot is available\n"); 2539c91eab4bSThomas Abraham pdata->num_slots = 1; 2540c91eab4bSThomas Abraham } 2541c91eab4bSThomas Abraham 2542c91eab4bSThomas Abraham /* get quirks */ 2543c91eab4bSThomas Abraham for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) 2544c91eab4bSThomas Abraham if (of_get_property(np, of_quirks[idx].quirk, NULL)) 2545c91eab4bSThomas Abraham pdata->quirks |= of_quirks[idx].id; 2546c91eab4bSThomas Abraham 2547c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 2548c91eab4bSThomas Abraham dev_info(dev, "fifo-depth property not found, using " 2549c91eab4bSThomas Abraham "value of FIFOTH register as default\n"); 2550c91eab4bSThomas Abraham 2551c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2552c91eab4bSThomas Abraham 25533c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 25543c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 25553c6d89eaSDoug Anderson 2556cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2557cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2558800d78bfSThomas Abraham if (ret) 2559800d78bfSThomas Abraham return ERR_PTR(ret); 2560800d78bfSThomas Abraham } 2561800d78bfSThomas Abraham 256210b49841SSeungwon Jeon if (of_find_property(np, "supports-highspeed", NULL)) 256310b49841SSeungwon Jeon pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; 256410b49841SSeungwon Jeon 2565c91eab4bSThomas Abraham return pdata; 2566c91eab4bSThomas Abraham } 2567c91eab4bSThomas Abraham 2568c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2569c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2570c91eab4bSThomas Abraham { 2571c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2572c91eab4bSThomas Abraham } 2573c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2574c91eab4bSThomas Abraham 257562ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 2576f95f3850SWill Newton { 2577e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 257862ca8034SShashidhar Hiremath int width, i, ret = 0; 2579f95f3850SWill Newton u32 fifo_size; 25801c2215b7SThomas Abraham int init_slots = 0; 2581f95f3850SWill Newton 2582c91eab4bSThomas Abraham if (!host->pdata) { 2583c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 2584c91eab4bSThomas Abraham if (IS_ERR(host->pdata)) { 2585c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 2586c91eab4bSThomas Abraham return -EINVAL; 2587c91eab4bSThomas Abraham } 2588f95f3850SWill Newton } 2589f95f3850SWill Newton 2590907abd51SJaehoon Chung if (host->pdata->num_slots > 1) { 25914a90920cSThomas Abraham dev_err(host->dev, 2592907abd51SJaehoon Chung "Platform data must supply num_slots.\n"); 259362ca8034SShashidhar Hiremath return -ENODEV; 2594f95f3850SWill Newton } 2595f95f3850SWill Newton 2596780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 2597f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 2598f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 2599f90a0612SThomas Abraham } else { 2600f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 2601f90a0612SThomas Abraham if (ret) { 2602f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 2603f90a0612SThomas Abraham return ret; 2604f90a0612SThomas Abraham } 2605f95f3850SWill Newton } 2606f95f3850SWill Newton 2607780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 2608f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 2609f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 26103c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 2611f90a0612SThomas Abraham } else { 2612f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 2613f90a0612SThomas Abraham if (ret) { 2614f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 2615f90a0612SThomas Abraham goto err_clk_biu; 2616f90a0612SThomas Abraham } 2617f90a0612SThomas Abraham 26183c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 26193c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 26203c6d89eaSDoug Anderson if (ret) 26213c6d89eaSDoug Anderson dev_warn(host->dev, 2622612de4c1SJaehoon Chung "Unable to set bus rate to %uHz\n", 26233c6d89eaSDoug Anderson host->pdata->bus_hz); 26243c6d89eaSDoug Anderson } 2625f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 26263c6d89eaSDoug Anderson } 2627f90a0612SThomas Abraham 2628612de4c1SJaehoon Chung if (!host->bus_hz) { 2629612de4c1SJaehoon Chung dev_err(host->dev, 2630612de4c1SJaehoon Chung "Platform data must supply bus speed\n"); 2631612de4c1SJaehoon Chung ret = -ENODEV; 2632612de4c1SJaehoon Chung goto err_clk_ciu; 2633612de4c1SJaehoon Chung } 2634612de4c1SJaehoon Chung 2635002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 2636002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 2637002f0d5cSYuvaraj Kumar C D if (ret) { 2638002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 2639002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 2640002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 2641002f0d5cSYuvaraj Kumar C D } 2642002f0d5cSYuvaraj Kumar C D } 2643002f0d5cSYuvaraj Kumar C D 2644cb27a843SJames Hogan if (drv_data && drv_data->setup_clock) { 2645cb27a843SJames Hogan ret = drv_data->setup_clock(host); 2646800d78bfSThomas Abraham if (ret) { 2647800d78bfSThomas Abraham dev_err(host->dev, 2648800d78bfSThomas Abraham "implementation specific clock setup failed\n"); 2649800d78bfSThomas Abraham goto err_clk_ciu; 2650800d78bfSThomas Abraham } 2651800d78bfSThomas Abraham } 2652800d78bfSThomas Abraham 265362ca8034SShashidhar Hiremath host->quirks = host->pdata->quirks; 2654f95f3850SWill Newton 2655f95f3850SWill Newton spin_lock_init(&host->lock); 2656f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 2657f95f3850SWill Newton 2658f95f3850SWill Newton /* 2659f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 2660f95f3850SWill Newton * the correct values. 2661f95f3850SWill Newton */ 2662f95f3850SWill Newton i = (mci_readl(host, HCON) >> 7) & 0x7; 2663f95f3850SWill Newton if (!i) { 2664f95f3850SWill Newton host->push_data = dw_mci_push_data16; 2665f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 2666f95f3850SWill Newton width = 16; 2667f95f3850SWill Newton host->data_shift = 1; 2668f95f3850SWill Newton } else if (i == 2) { 2669f95f3850SWill Newton host->push_data = dw_mci_push_data64; 2670f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 2671f95f3850SWill Newton width = 64; 2672f95f3850SWill Newton host->data_shift = 3; 2673f95f3850SWill Newton } else { 2674f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 2675f95f3850SWill Newton WARN((i != 1), 2676f95f3850SWill Newton "HCON reports a reserved host data width!\n" 2677f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 2678f95f3850SWill Newton host->push_data = dw_mci_push_data32; 2679f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 2680f95f3850SWill Newton width = 32; 2681f95f3850SWill Newton host->data_shift = 2; 2682f95f3850SWill Newton } 2683f95f3850SWill Newton 2684f95f3850SWill Newton /* Reset all blocks */ 26853a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) 2686141a712aSSeungwon Jeon return -ENODEV; 2687141a712aSSeungwon Jeon 2688141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 2689141a712aSSeungwon Jeon dw_mci_init_dma(host); 2690f95f3850SWill Newton 2691f95f3850SWill Newton /* Clear the interrupts for the host controller */ 2692f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2693f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2694f95f3850SWill Newton 2695f95f3850SWill Newton /* Put in max timeout */ 2696f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 2697f95f3850SWill Newton 2698f95f3850SWill Newton /* 2699f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 2700f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 2701f95f3850SWill Newton */ 2702b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 2703b86d8253SJames Hogan /* 2704b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 2705b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 2706b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 2707b86d8253SJames Hogan * should put it in the platform data. 2708b86d8253SJames Hogan */ 2709f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 27108234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 2711b86d8253SJames Hogan } else { 2712b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 2713b86d8253SJames Hogan } 2714b86d8253SJames Hogan host->fifo_depth = fifo_size; 271552426899SSeungwon Jeon host->fifoth_val = 271652426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 2717e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 2718f95f3850SWill Newton 2719f95f3850SWill Newton /* disable clock to CIU */ 2720f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2721f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2722f95f3850SWill Newton 272363008768SJames Hogan /* 272463008768SJames Hogan * In 2.40a spec, Data offset is changed. 272563008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 272663008768SJames Hogan */ 272763008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 272863008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 272963008768SJames Hogan 273063008768SJames Hogan if (host->verid < DW_MMC_240A) 273163008768SJames Hogan host->data_offset = DATA_OFFSET; 273263008768SJames Hogan else 273363008768SJames Hogan host->data_offset = DATA_240A_OFFSET; 273463008768SJames Hogan 2735f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 2736780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 2737780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 2738f95f3850SWill Newton if (ret) 27396130e7a9SDoug Anderson goto err_dmaunmap; 2740f95f3850SWill Newton 2741f95f3850SWill Newton if (host->pdata->num_slots) 2742f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 2743f95f3850SWill Newton else 2744f95f3850SWill Newton host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; 2745f95f3850SWill Newton 27462da1d7f2SYuvaraj CD /* 27472da1d7f2SYuvaraj CD * Enable interrupts for command done, data over, data empty, card det, 27482da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 27492da1d7f2SYuvaraj CD */ 27502da1d7f2SYuvaraj CD mci_writel(host, RINTSTS, 0xFFFFFFFF); 27512da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 27522da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 27532da1d7f2SYuvaraj CD DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 27542da1d7f2SYuvaraj CD mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ 27552da1d7f2SYuvaraj CD 27562da1d7f2SYuvaraj CD dev_info(host->dev, "DW MMC controller at irq %d, " 27572da1d7f2SYuvaraj CD "%d bit host data width, " 27582da1d7f2SYuvaraj CD "%u deep fifo\n", 27592da1d7f2SYuvaraj CD host->irq, width, fifo_size); 27602da1d7f2SYuvaraj CD 2761f95f3850SWill Newton /* We need at least one slot to succeed */ 2762f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2763f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 27641c2215b7SThomas Abraham if (ret) 27651c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 27661c2215b7SThomas Abraham else 27671c2215b7SThomas Abraham init_slots++; 2768f95f3850SWill Newton } 27691c2215b7SThomas Abraham 27701c2215b7SThomas Abraham if (init_slots) { 27711c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 27721c2215b7SThomas Abraham } else { 27731c2215b7SThomas Abraham dev_dbg(host->dev, "attempted to initialize %d slots, " 27741c2215b7SThomas Abraham "but failed on all\n", host->num_slots); 27756130e7a9SDoug Anderson goto err_dmaunmap; 2776f95f3850SWill Newton } 2777f95f3850SWill Newton 2778f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) 27794a90920cSThomas Abraham dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); 2780f95f3850SWill Newton 2781f95f3850SWill Newton return 0; 2782f95f3850SWill Newton 2783f95f3850SWill Newton err_dmaunmap: 2784f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2785f95f3850SWill Newton host->dma_ops->exit(host); 2786f90a0612SThomas Abraham 2787f90a0612SThomas Abraham err_clk_ciu: 2788780f22afSSeungwon Jeon if (!IS_ERR(host->ciu_clk)) 2789f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2790780f22afSSeungwon Jeon 2791f90a0612SThomas Abraham err_clk_biu: 2792780f22afSSeungwon Jeon if (!IS_ERR(host->biu_clk)) 2793f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2794780f22afSSeungwon Jeon 2795f95f3850SWill Newton return ret; 2796f95f3850SWill Newton } 279762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 2798f95f3850SWill Newton 279962ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 2800f95f3850SWill Newton { 2801f95f3850SWill Newton int i; 2802f95f3850SWill Newton 2803f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2804f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2805f95f3850SWill Newton 2806f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 28074a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 2808f95f3850SWill Newton if (host->slot[i]) 2809f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 2810f95f3850SWill Newton } 2811f95f3850SWill Newton 2812f95f3850SWill Newton /* disable clock to CIU */ 2813f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2814f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2815f95f3850SWill Newton 2816f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2817f95f3850SWill Newton host->dma_ops->exit(host); 2818f95f3850SWill Newton 2819f90a0612SThomas Abraham if (!IS_ERR(host->ciu_clk)) 2820f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2821780f22afSSeungwon Jeon 2822f90a0612SThomas Abraham if (!IS_ERR(host->biu_clk)) 2823f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2824f95f3850SWill Newton } 282562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 282662ca8034SShashidhar Hiremath 282762ca8034SShashidhar Hiremath 2828f95f3850SWill Newton 28296fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP 2830f95f3850SWill Newton /* 2831f95f3850SWill Newton * TODO: we should probably disable the clock to the card in the suspend path. 2832f95f3850SWill Newton */ 283362ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host) 2834f95f3850SWill Newton { 2835f95f3850SWill Newton return 0; 2836f95f3850SWill Newton } 283762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend); 2838f95f3850SWill Newton 283962ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host) 2840f95f3850SWill Newton { 2841f95f3850SWill Newton int i, ret; 2842f95f3850SWill Newton 28433a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 2844e61cf118SJaehoon Chung ret = -ENODEV; 2845e61cf118SJaehoon Chung return ret; 2846e61cf118SJaehoon Chung } 2847e61cf118SJaehoon Chung 28483bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 2849141a712aSSeungwon Jeon host->dma_ops->init(host); 2850141a712aSSeungwon Jeon 285152426899SSeungwon Jeon /* 285252426899SSeungwon Jeon * Restore the initial value at FIFOTH register 285352426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 285452426899SSeungwon Jeon */ 2855e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 285652426899SSeungwon Jeon host->prev_blksz = 0; 2857e61cf118SJaehoon Chung 28582eb2944fSDoug Anderson /* Put in max timeout */ 28592eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 28602eb2944fSDoug Anderson 2861e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 2862e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 2863e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 2864e61cf118SJaehoon Chung DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 2865e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 2866e61cf118SJaehoon Chung 2867f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2868f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 2869f95f3850SWill Newton if (!slot) 2870f95f3850SWill Newton continue; 2871ab269128SAbhilash Kesavan if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { 2872ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 2873ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 2874ab269128SAbhilash Kesavan } 2875f95f3850SWill Newton } 2876f95f3850SWill Newton return 0; 2877f95f3850SWill Newton } 287862ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume); 28796fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */ 28806fe8890dSJaehoon Chung 2881f95f3850SWill Newton static int __init dw_mci_init(void) 2882f95f3850SWill Newton { 28838e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 288462ca8034SShashidhar Hiremath return 0; 2885f95f3850SWill Newton } 2886f95f3850SWill Newton 2887f95f3850SWill Newton static void __exit dw_mci_exit(void) 2888f95f3850SWill Newton { 2889f95f3850SWill Newton } 2890f95f3850SWill Newton 2891f95f3850SWill Newton module_init(dw_mci_init); 2892f95f3850SWill Newton module_exit(dw_mci_exit); 2893f95f3850SWill Newton 2894f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 2895f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 2896f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 2897f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 2898