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> 32*01730558SDoug 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> 371791b13eSJames Hogan #include <linux/workqueue.h> 38c91eab4bSThomas Abraham #include <linux/of.h> 3955a6ceb2SDoug Anderson #include <linux/of_gpio.h> 40bf626e55SZhangfei Gao #include <linux/mmc/slot-gpio.h> 41f95f3850SWill Newton 42f95f3850SWill Newton #include "dw_mmc.h" 43f95f3850SWill Newton 44f95f3850SWill Newton /* Common flag combinations */ 453f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ 46f95f3850SWill Newton SDMMC_INT_HTO | SDMMC_INT_SBE | \ 47f95f3850SWill Newton SDMMC_INT_EBE) 48f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ 49f95f3850SWill Newton SDMMC_INT_RESP_ERR) 50f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ 51f95f3850SWill Newton DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE) 52f95f3850SWill Newton #define DW_MCI_SEND_STATUS 1 53f95f3850SWill Newton #define DW_MCI_RECV_STATUS 2 54f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD 16 55f95f3850SWill Newton 561f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */ 571f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN 400000 /* unit: HZ */ 581f44a2a5SSeungwon Jeon 59f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 60fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ 61fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ 62fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ 63fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_TI) 64fc79a4d6SJoonyoung Shim 65f95f3850SWill Newton struct idmac_desc { 66f95f3850SWill Newton u32 des0; /* Control Descriptor */ 67f95f3850SWill Newton #define IDMAC_DES0_DIC BIT(1) 68f95f3850SWill Newton #define IDMAC_DES0_LD BIT(2) 69f95f3850SWill Newton #define IDMAC_DES0_FD BIT(3) 70f95f3850SWill Newton #define IDMAC_DES0_CH BIT(4) 71f95f3850SWill Newton #define IDMAC_DES0_ER BIT(5) 72f95f3850SWill Newton #define IDMAC_DES0_CES BIT(30) 73f95f3850SWill Newton #define IDMAC_DES0_OWN BIT(31) 74f95f3850SWill Newton 75f95f3850SWill Newton u32 des1; /* Buffer sizes */ 76f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \ 779b7bbe10SShashidhar Hiremath ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) 78f95f3850SWill Newton 79f95f3850SWill Newton u32 des2; /* buffer 1 physical address */ 80f95f3850SWill Newton 81f95f3850SWill Newton u32 des3; /* buffer 2 physical address */ 82f95f3850SWill Newton }; 83f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 84f95f3850SWill Newton 850976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = { 860976f16dSSeungwon Jeon 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 870976f16dSSeungwon Jeon 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 880976f16dSSeungwon Jeon 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 890976f16dSSeungwon Jeon 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 900976f16dSSeungwon Jeon 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 910976f16dSSeungwon Jeon 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 920976f16dSSeungwon Jeon 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 930976f16dSSeungwon Jeon 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 940976f16dSSeungwon Jeon }; 95f95f3850SWill Newton 960976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = { 970976f16dSSeungwon Jeon 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 980976f16dSSeungwon Jeon 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 990976f16dSSeungwon Jeon 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 1000976f16dSSeungwon Jeon 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 1010976f16dSSeungwon Jeon 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 1020976f16dSSeungwon Jeon 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 1030976f16dSSeungwon Jeon 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 1040976f16dSSeungwon Jeon 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 1050976f16dSSeungwon Jeon 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 1060976f16dSSeungwon Jeon 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 1070976f16dSSeungwon Jeon 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 1080976f16dSSeungwon Jeon 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 1090976f16dSSeungwon Jeon 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 1100976f16dSSeungwon Jeon 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 1110976f16dSSeungwon Jeon 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 1120976f16dSSeungwon Jeon 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 113f95f3850SWill Newton }; 114f95f3850SWill Newton 1153a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host); 11631bff450SSeungwon Jeon 117f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 118f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 119f95f3850SWill Newton { 120f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 121f95f3850SWill Newton struct mmc_request *mrq; 122f95f3850SWill Newton struct mmc_command *cmd; 123f95f3850SWill Newton struct mmc_command *stop; 124f95f3850SWill Newton struct mmc_data *data; 125f95f3850SWill Newton 126f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 127f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 128f95f3850SWill Newton mrq = slot->mrq; 129f95f3850SWill Newton 130f95f3850SWill Newton if (mrq) { 131f95f3850SWill Newton cmd = mrq->cmd; 132f95f3850SWill Newton data = mrq->data; 133f95f3850SWill Newton stop = mrq->stop; 134f95f3850SWill Newton 135f95f3850SWill Newton if (cmd) 136f95f3850SWill Newton seq_printf(s, 137f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 138f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 139f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 140f95f3850SWill Newton cmd->resp[2], cmd->error); 141f95f3850SWill Newton if (data) 142f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 143f95f3850SWill Newton data->bytes_xfered, data->blocks, 144f95f3850SWill Newton data->blksz, data->flags, data->error); 145f95f3850SWill Newton if (stop) 146f95f3850SWill Newton seq_printf(s, 147f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 148f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 149f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 150f95f3850SWill Newton stop->resp[2], stop->error); 151f95f3850SWill Newton } 152f95f3850SWill Newton 153f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 154f95f3850SWill Newton 155f95f3850SWill Newton return 0; 156f95f3850SWill Newton } 157f95f3850SWill Newton 158f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 159f95f3850SWill Newton { 160f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 161f95f3850SWill Newton } 162f95f3850SWill Newton 163f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 164f95f3850SWill Newton .owner = THIS_MODULE, 165f95f3850SWill Newton .open = dw_mci_req_open, 166f95f3850SWill Newton .read = seq_read, 167f95f3850SWill Newton .llseek = seq_lseek, 168f95f3850SWill Newton .release = single_release, 169f95f3850SWill Newton }; 170f95f3850SWill Newton 171f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 172f95f3850SWill Newton { 173f95f3850SWill Newton seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); 174f95f3850SWill Newton seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); 175f95f3850SWill Newton seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); 176f95f3850SWill Newton seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); 177f95f3850SWill Newton seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); 178f95f3850SWill Newton seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); 179f95f3850SWill Newton 180f95f3850SWill Newton return 0; 181f95f3850SWill Newton } 182f95f3850SWill Newton 183f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 184f95f3850SWill Newton { 185f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 186f95f3850SWill Newton } 187f95f3850SWill Newton 188f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 189f95f3850SWill Newton .owner = THIS_MODULE, 190f95f3850SWill Newton .open = dw_mci_regs_open, 191f95f3850SWill Newton .read = seq_read, 192f95f3850SWill Newton .llseek = seq_lseek, 193f95f3850SWill Newton .release = single_release, 194f95f3850SWill Newton }; 195f95f3850SWill Newton 196f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 197f95f3850SWill Newton { 198f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 199f95f3850SWill Newton struct dw_mci *host = slot->host; 200f95f3850SWill Newton struct dentry *root; 201f95f3850SWill Newton struct dentry *node; 202f95f3850SWill Newton 203f95f3850SWill Newton root = mmc->debugfs_root; 204f95f3850SWill Newton if (!root) 205f95f3850SWill Newton return; 206f95f3850SWill Newton 207f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 208f95f3850SWill Newton &dw_mci_regs_fops); 209f95f3850SWill Newton if (!node) 210f95f3850SWill Newton goto err; 211f95f3850SWill Newton 212f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 213f95f3850SWill Newton &dw_mci_req_fops); 214f95f3850SWill Newton if (!node) 215f95f3850SWill Newton goto err; 216f95f3850SWill Newton 217f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 218f95f3850SWill Newton if (!node) 219f95f3850SWill Newton goto err; 220f95f3850SWill Newton 221f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 222f95f3850SWill Newton (u32 *)&host->pending_events); 223f95f3850SWill Newton if (!node) 224f95f3850SWill Newton goto err; 225f95f3850SWill Newton 226f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 227f95f3850SWill Newton (u32 *)&host->completed_events); 228f95f3850SWill Newton if (!node) 229f95f3850SWill Newton goto err; 230f95f3850SWill Newton 231f95f3850SWill Newton return; 232f95f3850SWill Newton 233f95f3850SWill Newton err: 234f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 235f95f3850SWill Newton } 236f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 237f95f3850SWill Newton 238*01730558SDoug Anderson static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg); 239*01730558SDoug Anderson 240f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 241f95f3850SWill Newton { 242f95f3850SWill Newton struct mmc_data *data; 243800d78bfSThomas Abraham struct dw_mci_slot *slot = mmc_priv(mmc); 244*01730558SDoug Anderson struct dw_mci *host = slot->host; 245e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 246f95f3850SWill Newton u32 cmdr; 247f95f3850SWill Newton cmd->error = -EINPROGRESS; 248f95f3850SWill Newton 249f95f3850SWill Newton cmdr = cmd->opcode; 250f95f3850SWill Newton 25190c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 25290c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 25390c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 25490c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 25590c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 256f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 2574a1b27adSJaehoon Chung else if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 258f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 259f95f3850SWill Newton 260*01730558SDoug Anderson if (cmd->opcode == SD_SWITCH_VOLTAGE) { 261*01730558SDoug Anderson u32 clk_en_a; 262*01730558SDoug Anderson 263*01730558SDoug Anderson /* Special bit makes CMD11 not die */ 264*01730558SDoug Anderson cmdr |= SDMMC_CMD_VOLT_SWITCH; 265*01730558SDoug Anderson 266*01730558SDoug Anderson /* Change state to continue to handle CMD11 weirdness */ 267*01730558SDoug Anderson WARN_ON(slot->host->state != STATE_SENDING_CMD); 268*01730558SDoug Anderson slot->host->state = STATE_SENDING_CMD11; 269*01730558SDoug Anderson 270*01730558SDoug Anderson /* 271*01730558SDoug Anderson * We need to disable low power mode (automatic clock stop) 272*01730558SDoug Anderson * while doing voltage switch so we don't confuse the card, 273*01730558SDoug Anderson * since stopping the clock is a specific part of the UHS 274*01730558SDoug Anderson * voltage change dance. 275*01730558SDoug Anderson * 276*01730558SDoug Anderson * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be 277*01730558SDoug Anderson * unconditionally turned back on in dw_mci_setup_bus() if it's 278*01730558SDoug Anderson * ever called with a non-zero clock. That shouldn't happen 279*01730558SDoug Anderson * until the voltage change is all done. 280*01730558SDoug Anderson */ 281*01730558SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 282*01730558SDoug Anderson clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id); 283*01730558SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 284*01730558SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 285*01730558SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 286*01730558SDoug Anderson } 287*01730558SDoug Anderson 288f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 289f95f3850SWill Newton /* We expect a response, so set this bit */ 290f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 291f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 292f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 293f95f3850SWill Newton } 294f95f3850SWill Newton 295f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 296f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 297f95f3850SWill Newton 298f95f3850SWill Newton data = cmd->data; 299f95f3850SWill Newton if (data) { 300f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 301f95f3850SWill Newton if (data->flags & MMC_DATA_STREAM) 302f95f3850SWill Newton cmdr |= SDMMC_CMD_STRM_MODE; 303f95f3850SWill Newton if (data->flags & MMC_DATA_WRITE) 304f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 305f95f3850SWill Newton } 306f95f3850SWill Newton 307cb27a843SJames Hogan if (drv_data && drv_data->prepare_command) 308cb27a843SJames Hogan drv_data->prepare_command(slot->host, &cmdr); 309800d78bfSThomas Abraham 310f95f3850SWill Newton return cmdr; 311f95f3850SWill Newton } 312f95f3850SWill Newton 31390c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) 31490c2143aSSeungwon Jeon { 31590c2143aSSeungwon Jeon struct mmc_command *stop; 31690c2143aSSeungwon Jeon u32 cmdr; 31790c2143aSSeungwon Jeon 31890c2143aSSeungwon Jeon if (!cmd->data) 31990c2143aSSeungwon Jeon return 0; 32090c2143aSSeungwon Jeon 32190c2143aSSeungwon Jeon stop = &host->stop_abort; 32290c2143aSSeungwon Jeon cmdr = cmd->opcode; 32390c2143aSSeungwon Jeon memset(stop, 0, sizeof(struct mmc_command)); 32490c2143aSSeungwon Jeon 32590c2143aSSeungwon Jeon if (cmdr == MMC_READ_SINGLE_BLOCK || 32690c2143aSSeungwon Jeon cmdr == MMC_READ_MULTIPLE_BLOCK || 32790c2143aSSeungwon Jeon cmdr == MMC_WRITE_BLOCK || 32890c2143aSSeungwon Jeon cmdr == MMC_WRITE_MULTIPLE_BLOCK) { 32990c2143aSSeungwon Jeon stop->opcode = MMC_STOP_TRANSMISSION; 33090c2143aSSeungwon Jeon stop->arg = 0; 33190c2143aSSeungwon Jeon stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 33290c2143aSSeungwon Jeon } else if (cmdr == SD_IO_RW_EXTENDED) { 33390c2143aSSeungwon Jeon stop->opcode = SD_IO_RW_DIRECT; 33490c2143aSSeungwon Jeon stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | 33590c2143aSSeungwon Jeon ((cmd->arg >> 28) & 0x7); 33690c2143aSSeungwon Jeon stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; 33790c2143aSSeungwon Jeon } else { 33890c2143aSSeungwon Jeon return 0; 33990c2143aSSeungwon Jeon } 34090c2143aSSeungwon Jeon 34190c2143aSSeungwon Jeon cmdr = stop->opcode | SDMMC_CMD_STOP | 34290c2143aSSeungwon Jeon SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; 34390c2143aSSeungwon Jeon 34490c2143aSSeungwon Jeon return cmdr; 34590c2143aSSeungwon Jeon } 34690c2143aSSeungwon Jeon 347f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 348f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 349f95f3850SWill Newton { 350f95f3850SWill Newton host->cmd = cmd; 3514a90920cSThomas Abraham dev_vdbg(host->dev, 352f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 353f95f3850SWill Newton cmd->arg, cmd_flags); 354f95f3850SWill Newton 355f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 356f95f3850SWill Newton wmb(); 357f95f3850SWill Newton 358f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 359f95f3850SWill Newton } 360f95f3850SWill Newton 36190c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 362f95f3850SWill Newton { 36390c2143aSSeungwon Jeon struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; 36490c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 365f95f3850SWill Newton } 366f95f3850SWill Newton 367f95f3850SWill Newton /* DMA interface functions */ 368f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 369f95f3850SWill Newton { 37003e8cb53SJames Hogan if (host->using_dma) { 371f95f3850SWill Newton host->dma_ops->stop(host); 372f95f3850SWill Newton host->dma_ops->cleanup(host); 373aa50f259SSeungwon Jeon } 374aa50f259SSeungwon Jeon 375f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 376f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 377f95f3850SWill Newton } 378f95f3850SWill Newton 3799aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 3809aa51408SSeungwon Jeon { 3819aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 3829aa51408SSeungwon Jeon return DMA_TO_DEVICE; 3839aa51408SSeungwon Jeon else 3849aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 3859aa51408SSeungwon Jeon } 3869aa51408SSeungwon Jeon 3879beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 388f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 389f95f3850SWill Newton { 390f95f3850SWill Newton struct mmc_data *data = host->data; 391f95f3850SWill Newton 392f95f3850SWill Newton if (data) 3939aa51408SSeungwon Jeon if (!data->host_cookie) 3944a90920cSThomas Abraham dma_unmap_sg(host->dev, 3959aa51408SSeungwon Jeon data->sg, 3969aa51408SSeungwon Jeon data->sg_len, 3979aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 398f95f3850SWill Newton } 399f95f3850SWill Newton 4005ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host) 4015ce9d961SSeungwon Jeon { 4025ce9d961SSeungwon Jeon u32 bmod = mci_readl(host, BMOD); 4035ce9d961SSeungwon Jeon /* Software reset of DMA */ 4045ce9d961SSeungwon Jeon bmod |= SDMMC_IDMAC_SWRESET; 4055ce9d961SSeungwon Jeon mci_writel(host, BMOD, bmod); 4065ce9d961SSeungwon Jeon } 4075ce9d961SSeungwon Jeon 408f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 409f95f3850SWill Newton { 410f95f3850SWill Newton u32 temp; 411f95f3850SWill Newton 412f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 413f95f3850SWill Newton temp = mci_readl(host, CTRL); 414f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 415f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 416f95f3850SWill Newton mci_writel(host, CTRL, temp); 417f95f3850SWill Newton 418f95f3850SWill Newton /* Stop the IDMAC running */ 419f95f3850SWill Newton temp = mci_readl(host, BMOD); 420a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 4215ce9d961SSeungwon Jeon temp |= SDMMC_IDMAC_SWRESET; 422f95f3850SWill Newton mci_writel(host, BMOD, temp); 423f95f3850SWill Newton } 424f95f3850SWill Newton 425f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host) 426f95f3850SWill Newton { 427f95f3850SWill Newton struct mmc_data *data = host->data; 428f95f3850SWill Newton 4294a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 430f95f3850SWill Newton 431f95f3850SWill Newton host->dma_ops->cleanup(host); 432f95f3850SWill Newton 433f95f3850SWill Newton /* 434f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 435f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 436f95f3850SWill Newton */ 437f95f3850SWill Newton if (data) { 438f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 439f95f3850SWill Newton tasklet_schedule(&host->tasklet); 440f95f3850SWill Newton } 441f95f3850SWill Newton } 442f95f3850SWill Newton 443f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, 444f95f3850SWill Newton unsigned int sg_len) 445f95f3850SWill Newton { 446f95f3850SWill Newton int i; 447f95f3850SWill Newton struct idmac_desc *desc = host->sg_cpu; 448f95f3850SWill Newton 449f95f3850SWill Newton for (i = 0; i < sg_len; i++, desc++) { 450f95f3850SWill Newton unsigned int length = sg_dma_len(&data->sg[i]); 451f95f3850SWill Newton u32 mem_addr = sg_dma_address(&data->sg[i]); 452f95f3850SWill Newton 453f95f3850SWill Newton /* Set the OWN bit and disable interrupts for this descriptor */ 454f95f3850SWill Newton desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; 455f95f3850SWill Newton 456f95f3850SWill Newton /* Buffer length */ 457f95f3850SWill Newton IDMAC_SET_BUFFER1_SIZE(desc, length); 458f95f3850SWill Newton 459f95f3850SWill Newton /* Physical address to DMA to/from */ 460f95f3850SWill Newton desc->des2 = mem_addr; 461f95f3850SWill Newton } 462f95f3850SWill Newton 463f95f3850SWill Newton /* Set first descriptor */ 464f95f3850SWill Newton desc = host->sg_cpu; 465f95f3850SWill Newton desc->des0 |= IDMAC_DES0_FD; 466f95f3850SWill Newton 467f95f3850SWill Newton /* Set last descriptor */ 468f95f3850SWill Newton desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); 469f95f3850SWill Newton desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 470f95f3850SWill Newton desc->des0 |= IDMAC_DES0_LD; 471f95f3850SWill Newton 472f95f3850SWill Newton wmb(); 473f95f3850SWill Newton } 474f95f3850SWill Newton 475f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 476f95f3850SWill Newton { 477f95f3850SWill Newton u32 temp; 478f95f3850SWill Newton 479f95f3850SWill Newton dw_mci_translate_sglist(host, host->data, sg_len); 480f95f3850SWill Newton 481f95f3850SWill Newton /* Select IDMAC interface */ 482f95f3850SWill Newton temp = mci_readl(host, CTRL); 483f95f3850SWill Newton temp |= SDMMC_CTRL_USE_IDMAC; 484f95f3850SWill Newton mci_writel(host, CTRL, temp); 485f95f3850SWill Newton 486f95f3850SWill Newton wmb(); 487f95f3850SWill Newton 488f95f3850SWill Newton /* Enable the IDMAC */ 489f95f3850SWill Newton temp = mci_readl(host, BMOD); 490a5289a43SJaehoon Chung temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 491f95f3850SWill Newton mci_writel(host, BMOD, temp); 492f95f3850SWill Newton 493f95f3850SWill Newton /* Start it running */ 494f95f3850SWill Newton mci_writel(host, PLDMND, 1); 495f95f3850SWill Newton } 496f95f3850SWill Newton 497f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 498f95f3850SWill Newton { 499f95f3850SWill Newton struct idmac_desc *p; 500897b69e7SSeungwon Jeon int i; 501f95f3850SWill Newton 502f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 503f95f3850SWill Newton host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 504f95f3850SWill Newton 505f95f3850SWill Newton /* Forward link the descriptor list */ 506f95f3850SWill Newton for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) 507f95f3850SWill Newton p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); 508f95f3850SWill Newton 509f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 510f95f3850SWill Newton p->des3 = host->sg_dma; 511f95f3850SWill Newton p->des0 = IDMAC_DES0_ER; 512f95f3850SWill Newton 5135ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 514141a712aSSeungwon Jeon 515f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 516fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 517f95f3850SWill Newton mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | 518f95f3850SWill Newton SDMMC_IDMAC_INT_TI); 519f95f3850SWill Newton 520f95f3850SWill Newton /* Set the descriptor base address */ 521f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 522f95f3850SWill Newton return 0; 523f95f3850SWill Newton } 524f95f3850SWill Newton 5258e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 526885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 527885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 528885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 529885c3e80SSeungwon Jeon .complete = dw_mci_idmac_complete_dma, 530885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 531885c3e80SSeungwon Jeon }; 532885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */ 533885c3e80SSeungwon Jeon 5349aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 5359aa51408SSeungwon Jeon struct mmc_data *data, 5369aa51408SSeungwon Jeon bool next) 537f95f3850SWill Newton { 538f95f3850SWill Newton struct scatterlist *sg; 5399aa51408SSeungwon Jeon unsigned int i, sg_len; 540f95f3850SWill Newton 5419aa51408SSeungwon Jeon if (!next && data->host_cookie) 5429aa51408SSeungwon Jeon return data->host_cookie; 543f95f3850SWill Newton 544f95f3850SWill Newton /* 545f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 546f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 547f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 548f95f3850SWill Newton */ 549f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 550f95f3850SWill Newton return -EINVAL; 5519aa51408SSeungwon Jeon 552f95f3850SWill Newton if (data->blksz & 3) 553f95f3850SWill Newton return -EINVAL; 554f95f3850SWill Newton 555f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 556f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 557f95f3850SWill Newton return -EINVAL; 558f95f3850SWill Newton } 559f95f3850SWill Newton 5604a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 5619aa51408SSeungwon Jeon data->sg, 5629aa51408SSeungwon Jeon data->sg_len, 5639aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 5649aa51408SSeungwon Jeon if (sg_len == 0) 5659aa51408SSeungwon Jeon return -EINVAL; 5669aa51408SSeungwon Jeon 5679aa51408SSeungwon Jeon if (next) 5689aa51408SSeungwon Jeon data->host_cookie = sg_len; 5699aa51408SSeungwon Jeon 5709aa51408SSeungwon Jeon return sg_len; 5719aa51408SSeungwon Jeon } 5729aa51408SSeungwon Jeon 5739aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 5749aa51408SSeungwon Jeon struct mmc_request *mrq, 5759aa51408SSeungwon Jeon bool is_first_req) 5769aa51408SSeungwon Jeon { 5779aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 5789aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 5799aa51408SSeungwon Jeon 5809aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 5819aa51408SSeungwon Jeon return; 5829aa51408SSeungwon Jeon 5839aa51408SSeungwon Jeon if (data->host_cookie) { 5849aa51408SSeungwon Jeon data->host_cookie = 0; 5859aa51408SSeungwon Jeon return; 5869aa51408SSeungwon Jeon } 5879aa51408SSeungwon Jeon 5889aa51408SSeungwon Jeon if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) 5899aa51408SSeungwon Jeon data->host_cookie = 0; 5909aa51408SSeungwon Jeon } 5919aa51408SSeungwon Jeon 5929aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 5939aa51408SSeungwon Jeon struct mmc_request *mrq, 5949aa51408SSeungwon Jeon int err) 5959aa51408SSeungwon Jeon { 5969aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 5979aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 5989aa51408SSeungwon Jeon 5999aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 6009aa51408SSeungwon Jeon return; 6019aa51408SSeungwon Jeon 6029aa51408SSeungwon Jeon if (data->host_cookie) 6034a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 6049aa51408SSeungwon Jeon data->sg, 6059aa51408SSeungwon Jeon data->sg_len, 6069aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 6079aa51408SSeungwon Jeon data->host_cookie = 0; 6089aa51408SSeungwon Jeon } 6099aa51408SSeungwon Jeon 61052426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 61152426899SSeungwon Jeon { 61252426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC 61352426899SSeungwon Jeon unsigned int blksz = data->blksz; 61452426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 61552426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 61652426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 61752426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 61852426899SSeungwon Jeon int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1; 61952426899SSeungwon Jeon 62052426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 62152426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 62252426899SSeungwon Jeon 62352426899SSeungwon Jeon /* 62452426899SSeungwon Jeon * MSIZE is '1', 62552426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 62652426899SSeungwon Jeon */ 62752426899SSeungwon Jeon if (blksz % fifo_width) { 62852426899SSeungwon Jeon msize = 0; 62952426899SSeungwon Jeon rx_wmark = 1; 63052426899SSeungwon Jeon goto done; 63152426899SSeungwon Jeon } 63252426899SSeungwon Jeon 63352426899SSeungwon Jeon do { 63452426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 63552426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 63652426899SSeungwon Jeon msize = idx; 63752426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 63852426899SSeungwon Jeon break; 63952426899SSeungwon Jeon } 64052426899SSeungwon Jeon } while (--idx > 0); 64152426899SSeungwon Jeon /* 64252426899SSeungwon Jeon * If idx is '0', it won't be tried 64352426899SSeungwon Jeon * Thus, initial values are uesed 64452426899SSeungwon Jeon */ 64552426899SSeungwon Jeon done: 64652426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 64752426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 64852426899SSeungwon Jeon #endif 64952426899SSeungwon Jeon } 65052426899SSeungwon Jeon 651f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) 652f1d2736cSSeungwon Jeon { 653f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 654f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 655f1d2736cSSeungwon Jeon u16 thld_size; 656f1d2736cSSeungwon Jeon 657f1d2736cSSeungwon Jeon WARN_ON(!(data->flags & MMC_DATA_READ)); 658f1d2736cSSeungwon Jeon 659f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 660f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 661f1d2736cSSeungwon Jeon goto disable; 662f1d2736cSSeungwon Jeon 663f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 664f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 665f1d2736cSSeungwon Jeon 666f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 667f1d2736cSSeungwon Jeon goto disable; 668f1d2736cSSeungwon Jeon 669f1d2736cSSeungwon Jeon /* 670f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 671f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 672f1d2736cSSeungwon Jeon * Currently just choose blksz. 673f1d2736cSSeungwon Jeon */ 674f1d2736cSSeungwon Jeon thld_size = blksz; 675f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1)); 676f1d2736cSSeungwon Jeon return; 677f1d2736cSSeungwon Jeon 678f1d2736cSSeungwon Jeon disable: 679f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0)); 680f1d2736cSSeungwon Jeon } 681f1d2736cSSeungwon Jeon 6829aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 6839aa51408SSeungwon Jeon { 6849aa51408SSeungwon Jeon int sg_len; 6859aa51408SSeungwon Jeon u32 temp; 6869aa51408SSeungwon Jeon 6879aa51408SSeungwon Jeon host->using_dma = 0; 6889aa51408SSeungwon Jeon 6899aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 6909aa51408SSeungwon Jeon if (!host->use_dma) 6919aa51408SSeungwon Jeon return -ENODEV; 6929aa51408SSeungwon Jeon 6939aa51408SSeungwon Jeon sg_len = dw_mci_pre_dma_transfer(host, data, 0); 694a99aa9b9SSeungwon Jeon if (sg_len < 0) { 695a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 6969aa51408SSeungwon Jeon return sg_len; 697a99aa9b9SSeungwon Jeon } 6989aa51408SSeungwon Jeon 69903e8cb53SJames Hogan host->using_dma = 1; 70003e8cb53SJames Hogan 7014a90920cSThomas Abraham dev_vdbg(host->dev, 702f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 703f95f3850SWill Newton (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, 704f95f3850SWill Newton sg_len); 705f95f3850SWill Newton 70652426899SSeungwon Jeon /* 70752426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 70852426899SSeungwon Jeon * If current block size is same with previous size, 70952426899SSeungwon Jeon * no need to update fifoth. 71052426899SSeungwon Jeon */ 71152426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 71252426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 71352426899SSeungwon Jeon 714f95f3850SWill Newton /* Enable the DMA interface */ 715f95f3850SWill Newton temp = mci_readl(host, CTRL); 716f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 717f95f3850SWill Newton mci_writel(host, CTRL, temp); 718f95f3850SWill Newton 719f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 720f95f3850SWill Newton temp = mci_readl(host, INTMASK); 721f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 722f95f3850SWill Newton mci_writel(host, INTMASK, temp); 723f95f3850SWill Newton 724f95f3850SWill Newton host->dma_ops->start(host, sg_len); 725f95f3850SWill Newton 726f95f3850SWill Newton return 0; 727f95f3850SWill Newton } 728f95f3850SWill Newton 729f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 730f95f3850SWill Newton { 731f95f3850SWill Newton u32 temp; 732f95f3850SWill Newton 733f95f3850SWill Newton data->error = -EINPROGRESS; 734f95f3850SWill Newton 735f95f3850SWill Newton WARN_ON(host->data); 736f95f3850SWill Newton host->sg = NULL; 737f95f3850SWill Newton host->data = data; 738f95f3850SWill Newton 739f1d2736cSSeungwon Jeon if (data->flags & MMC_DATA_READ) { 74055c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 741f1d2736cSSeungwon Jeon dw_mci_ctrl_rd_thld(host, data); 742f1d2736cSSeungwon Jeon } else { 74355c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 744f1d2736cSSeungwon Jeon } 74555c5efbcSJames Hogan 746f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 747f9c2a0dcSSeungwon Jeon int flags = SG_MITER_ATOMIC; 748f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 749f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 750f9c2a0dcSSeungwon Jeon else 751f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 752f9c2a0dcSSeungwon Jeon 753f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 754f95f3850SWill Newton host->sg = data->sg; 75534b664a2SJames Hogan host->part_buf_start = 0; 75634b664a2SJames Hogan host->part_buf_count = 0; 757f95f3850SWill Newton 758b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 759f95f3850SWill Newton temp = mci_readl(host, INTMASK); 760f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 761f95f3850SWill Newton mci_writel(host, INTMASK, temp); 762f95f3850SWill Newton 763f95f3850SWill Newton temp = mci_readl(host, CTRL); 764f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 765f95f3850SWill Newton mci_writel(host, CTRL, temp); 76652426899SSeungwon Jeon 76752426899SSeungwon Jeon /* 76852426899SSeungwon Jeon * Use the initial fifoth_val for PIO mode. 76952426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 77052426899SSeungwon Jeon * prev_blksz should be invalidated. 77152426899SSeungwon Jeon */ 77252426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 77352426899SSeungwon Jeon host->prev_blksz = 0; 77452426899SSeungwon Jeon } else { 77552426899SSeungwon Jeon /* 77652426899SSeungwon Jeon * Keep the current block size. 77752426899SSeungwon Jeon * It will be used to decide whether to update 77852426899SSeungwon Jeon * fifoth register next time. 77952426899SSeungwon Jeon */ 78052426899SSeungwon Jeon host->prev_blksz = data->blksz; 781f95f3850SWill Newton } 782f95f3850SWill Newton } 783f95f3850SWill Newton 784f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 785f95f3850SWill Newton { 786f95f3850SWill Newton struct dw_mci *host = slot->host; 787f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 788f95f3850SWill Newton unsigned int cmd_status = 0; 789f95f3850SWill Newton 790f95f3850SWill Newton mci_writel(host, CMDARG, arg); 791f95f3850SWill Newton wmb(); 792f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 793f95f3850SWill Newton 794f95f3850SWill Newton while (time_before(jiffies, timeout)) { 795f95f3850SWill Newton cmd_status = mci_readl(host, CMD); 796f95f3850SWill Newton if (!(cmd_status & SDMMC_CMD_START)) 797f95f3850SWill Newton return; 798f95f3850SWill Newton } 799f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 800f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 801f95f3850SWill Newton cmd, arg, cmd_status); 802f95f3850SWill Newton } 803f95f3850SWill Newton 804ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 805f95f3850SWill Newton { 806f95f3850SWill Newton struct dw_mci *host = slot->host; 807fdf492a1SDoug Anderson unsigned int clock = slot->clock; 808f95f3850SWill Newton u32 div; 8099623b5b9SDoug Anderson u32 clk_en_a; 810*01730558SDoug Anderson u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT; 811*01730558SDoug Anderson 812*01730558SDoug Anderson /* We must continue to set bit 28 in CMD until the change is complete */ 813*01730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) 814*01730558SDoug Anderson sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH; 815f95f3850SWill Newton 816fdf492a1SDoug Anderson if (!clock) { 817fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 818*01730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 819fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 820fdf492a1SDoug Anderson div = host->bus_hz / clock; 821fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 822f95f3850SWill Newton /* 823f95f3850SWill Newton * move the + 1 after the divide to prevent 824f95f3850SWill Newton * over-clocking the card. 825f95f3850SWill Newton */ 826e419990bSSeungwon Jeon div += 1; 827e419990bSSeungwon Jeon 828fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 829f95f3850SWill Newton 830fdf492a1SDoug Anderson if ((clock << div) != slot->__clk_old || force_clkinit) 831f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 832fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 833fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 834fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 835fdf492a1SDoug Anderson host->bus_hz, div); 836f95f3850SWill Newton 837f95f3850SWill Newton /* disable clock */ 838f95f3850SWill Newton mci_writel(host, CLKENA, 0); 839f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 840f95f3850SWill Newton 841f95f3850SWill Newton /* inform CIU */ 842*01730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 843f95f3850SWill Newton 844f95f3850SWill Newton /* set clock to desired speed */ 845f95f3850SWill Newton mci_writel(host, CLKDIV, div); 846f95f3850SWill Newton 847f95f3850SWill Newton /* inform CIU */ 848*01730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 849f95f3850SWill Newton 8509623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 8519623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 8529623b5b9SDoug Anderson if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) 8539623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 8549623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 855f95f3850SWill Newton 856f95f3850SWill Newton /* inform CIU */ 857*01730558SDoug Anderson mci_send_cmd(slot, sdmmc_cmd_bits, 0); 858f95f3850SWill Newton 859fdf492a1SDoug Anderson /* keep the clock with reflecting clock dividor */ 860fdf492a1SDoug Anderson slot->__clk_old = clock << div; 861f95f3850SWill Newton } 862f95f3850SWill Newton 863fdf492a1SDoug Anderson host->current_speed = clock; 864fdf492a1SDoug Anderson 865f95f3850SWill Newton /* Set the current slot bus width */ 8661d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 867f95f3850SWill Newton } 868f95f3850SWill Newton 869053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 870053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 871053b3ce6SSeungwon Jeon struct mmc_command *cmd) 872f95f3850SWill Newton { 873f95f3850SWill Newton struct mmc_request *mrq; 874f95f3850SWill Newton struct mmc_data *data; 875f95f3850SWill Newton u32 cmdflags; 876f95f3850SWill Newton 877f95f3850SWill Newton mrq = slot->mrq; 878f95f3850SWill Newton 879f95f3850SWill Newton host->cur_slot = slot; 880f95f3850SWill Newton host->mrq = mrq; 881f95f3850SWill Newton 882f95f3850SWill Newton host->pending_events = 0; 883f95f3850SWill Newton host->completed_events = 0; 884e352c813SSeungwon Jeon host->cmd_status = 0; 885f95f3850SWill Newton host->data_status = 0; 886e352c813SSeungwon Jeon host->dir_status = 0; 887f95f3850SWill Newton 888053b3ce6SSeungwon Jeon data = cmd->data; 889f95f3850SWill Newton if (data) { 890f16afa88SJaehoon Chung mci_writel(host, TMOUT, 0xFFFFFFFF); 891f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 892f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 893f95f3850SWill Newton } 894f95f3850SWill Newton 895f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 896f95f3850SWill Newton 897f95f3850SWill Newton /* this is the first command, send the initialization clock */ 898f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 899f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 900f95f3850SWill Newton 901f95f3850SWill Newton if (data) { 902f95f3850SWill Newton dw_mci_submit_data(host, data); 903f95f3850SWill Newton wmb(); 904f95f3850SWill Newton } 905f95f3850SWill Newton 906f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 907f95f3850SWill Newton 908f95f3850SWill Newton if (mrq->stop) 909f95f3850SWill Newton host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 91090c2143aSSeungwon Jeon else 91190c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 912f95f3850SWill Newton } 913f95f3850SWill Newton 914053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 915053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 916053b3ce6SSeungwon Jeon { 917053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 918053b3ce6SSeungwon Jeon struct mmc_command *cmd; 919053b3ce6SSeungwon Jeon 920053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 921053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 922053b3ce6SSeungwon Jeon } 923053b3ce6SSeungwon Jeon 9247456caaeSJames Hogan /* must be called with host->lock held */ 925f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 926f95f3850SWill Newton struct mmc_request *mrq) 927f95f3850SWill Newton { 928f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 929f95f3850SWill Newton host->state); 930f95f3850SWill Newton 931f95f3850SWill Newton slot->mrq = mrq; 932f95f3850SWill Newton 933*01730558SDoug Anderson if (host->state == STATE_WAITING_CMD11_DONE) { 934*01730558SDoug Anderson dev_warn(&slot->mmc->class_dev, 935*01730558SDoug Anderson "Voltage change didn't complete\n"); 936*01730558SDoug Anderson /* 937*01730558SDoug Anderson * this case isn't expected to happen, so we can 938*01730558SDoug Anderson * either crash here or just try to continue on 939*01730558SDoug Anderson * in the closest possible state 940*01730558SDoug Anderson */ 941*01730558SDoug Anderson host->state = STATE_IDLE; 942*01730558SDoug Anderson } 943*01730558SDoug Anderson 944f95f3850SWill Newton if (host->state == STATE_IDLE) { 945f95f3850SWill Newton host->state = STATE_SENDING_CMD; 946f95f3850SWill Newton dw_mci_start_request(host, slot); 947f95f3850SWill Newton } else { 948f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 949f95f3850SWill Newton } 950f95f3850SWill Newton } 951f95f3850SWill Newton 952f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 953f95f3850SWill Newton { 954f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 955f95f3850SWill Newton struct dw_mci *host = slot->host; 956f95f3850SWill Newton 957f95f3850SWill Newton WARN_ON(slot->mrq); 958f95f3850SWill Newton 9597456caaeSJames Hogan /* 9607456caaeSJames Hogan * The check for card presence and queueing of the request must be 9617456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 9627456caaeSJames Hogan * request wouldn't fail until another card was inserted. 9637456caaeSJames Hogan */ 9647456caaeSJames Hogan spin_lock_bh(&host->lock); 9657456caaeSJames Hogan 966f95f3850SWill Newton if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { 9677456caaeSJames Hogan spin_unlock_bh(&host->lock); 968f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 969f95f3850SWill Newton mmc_request_done(mmc, mrq); 970f95f3850SWill Newton return; 971f95f3850SWill Newton } 972f95f3850SWill Newton 973f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 9747456caaeSJames Hogan 9757456caaeSJames Hogan spin_unlock_bh(&host->lock); 976f95f3850SWill Newton } 977f95f3850SWill Newton 978f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 979f95f3850SWill Newton { 980f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 981e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 98241babf75SJaehoon Chung u32 regs; 98351da2240SYuvaraj CD int ret; 984f95f3850SWill Newton 985f95f3850SWill Newton switch (ios->bus_width) { 986f95f3850SWill Newton case MMC_BUS_WIDTH_4: 987f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 988f95f3850SWill Newton break; 989c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 990c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 991c9b2a06fSJaehoon Chung break; 992b2f7cb45SJaehoon Chung default: 993b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 994b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 995f95f3850SWill Newton } 996f95f3850SWill Newton 99741babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 9983f514291SSeungwon Jeon 9993f514291SSeungwon Jeon /* DDR mode set */ 1000cab3a802SSeungwon Jeon if (ios->timing == MMC_TIMING_MMC_DDR52) 1001c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 10023f514291SSeungwon Jeon else 1003c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 10043f514291SSeungwon Jeon 100541babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 1006f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 100741babf75SJaehoon Chung 1008f95f3850SWill Newton /* 1009f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 1010f95f3850SWill Newton * core ios update when finding the minimum. 1011f95f3850SWill Newton */ 1012f95f3850SWill Newton slot->clock = ios->clock; 1013f95f3850SWill Newton 1014cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 1015cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 1016800d78bfSThomas Abraham 1017bf7cb224SJaehoon Chung /* Slot specific timing and width adjustment */ 1018bf7cb224SJaehoon Chung dw_mci_setup_bus(slot, false); 1019bf7cb224SJaehoon Chung 1020*01730558SDoug Anderson if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) 1021*01730558SDoug Anderson slot->host->state = STATE_IDLE; 1022*01730558SDoug Anderson 1023f95f3850SWill Newton switch (ios->power_mode) { 1024f95f3850SWill Newton case MMC_POWER_UP: 102551da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) { 102651da2240SYuvaraj CD ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 102751da2240SYuvaraj CD ios->vdd); 102851da2240SYuvaraj CD if (ret) { 102951da2240SYuvaraj CD dev_err(slot->host->dev, 103051da2240SYuvaraj CD "failed to enable vmmc regulator\n"); 103151da2240SYuvaraj CD /*return, if failed turn on vmmc*/ 103251da2240SYuvaraj CD return; 103351da2240SYuvaraj CD } 103451da2240SYuvaraj CD } 103551da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) { 103651da2240SYuvaraj CD ret = regulator_enable(mmc->supply.vqmmc); 103751da2240SYuvaraj CD if (ret < 0) 103851da2240SYuvaraj CD dev_err(slot->host->dev, 103951da2240SYuvaraj CD "failed to enable vqmmc regulator\n"); 104051da2240SYuvaraj CD else 104151da2240SYuvaraj CD slot->host->vqmmc_enabled = true; 104251da2240SYuvaraj CD } 1043f95f3850SWill Newton set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 10444366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 10454366dcc5SJaehoon Chung regs |= (1 << slot->id); 10464366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1047e6f34e2fSJames Hogan break; 1048e6f34e2fSJames Hogan case MMC_POWER_OFF: 104951da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vmmc)) 105051da2240SYuvaraj CD mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 105151da2240SYuvaraj CD 105251da2240SYuvaraj CD if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) { 105351da2240SYuvaraj CD regulator_disable(mmc->supply.vqmmc); 105451da2240SYuvaraj CD slot->host->vqmmc_enabled = false; 105551da2240SYuvaraj CD } 105651da2240SYuvaraj CD 10574366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 10584366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 10594366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1060f95f3850SWill Newton break; 1061f95f3850SWill Newton default: 1062f95f3850SWill Newton break; 1063f95f3850SWill Newton } 1064f95f3850SWill Newton } 1065f95f3850SWill Newton 1066*01730558SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc) 1067*01730558SDoug Anderson { 1068*01730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 1069*01730558SDoug Anderson u32 status; 1070*01730558SDoug Anderson 1071*01730558SDoug Anderson /* 1072*01730558SDoug Anderson * Check the busy bit which is low when DAT[3:0] 1073*01730558SDoug Anderson * (the data lines) are 0000 1074*01730558SDoug Anderson */ 1075*01730558SDoug Anderson status = mci_readl(slot->host, STATUS); 1076*01730558SDoug Anderson 1077*01730558SDoug Anderson return !!(status & SDMMC_STATUS_BUSY); 1078*01730558SDoug Anderson } 1079*01730558SDoug Anderson 1080*01730558SDoug Anderson static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) 1081*01730558SDoug Anderson { 1082*01730558SDoug Anderson struct dw_mci_slot *slot = mmc_priv(mmc); 1083*01730558SDoug Anderson struct dw_mci *host = slot->host; 1084*01730558SDoug Anderson u32 uhs; 1085*01730558SDoug Anderson u32 v18 = SDMMC_UHS_18V << slot->id; 1086*01730558SDoug Anderson int min_uv, max_uv; 1087*01730558SDoug Anderson int ret; 1088*01730558SDoug Anderson 1089*01730558SDoug Anderson /* 1090*01730558SDoug Anderson * Program the voltage. Note that some instances of dw_mmc may use 1091*01730558SDoug Anderson * the UHS_REG for this. For other instances (like exynos) the UHS_REG 1092*01730558SDoug Anderson * does no harm but you need to set the regulator directly. Try both. 1093*01730558SDoug Anderson */ 1094*01730558SDoug Anderson uhs = mci_readl(host, UHS_REG); 1095*01730558SDoug Anderson if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { 1096*01730558SDoug Anderson min_uv = 2700000; 1097*01730558SDoug Anderson max_uv = 3600000; 1098*01730558SDoug Anderson uhs &= ~v18; 1099*01730558SDoug Anderson } else { 1100*01730558SDoug Anderson min_uv = 1700000; 1101*01730558SDoug Anderson max_uv = 1950000; 1102*01730558SDoug Anderson uhs |= v18; 1103*01730558SDoug Anderson } 1104*01730558SDoug Anderson if (!IS_ERR(mmc->supply.vqmmc)) { 1105*01730558SDoug Anderson ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); 1106*01730558SDoug Anderson 1107*01730558SDoug Anderson if (ret) { 1108*01730558SDoug Anderson dev_err(&mmc->class_dev, 1109*01730558SDoug Anderson "Regulator set error %d: %d - %d\n", 1110*01730558SDoug Anderson ret, min_uv, max_uv); 1111*01730558SDoug Anderson return ret; 1112*01730558SDoug Anderson } 1113*01730558SDoug Anderson } 1114*01730558SDoug Anderson mci_writel(host, UHS_REG, uhs); 1115*01730558SDoug Anderson 1116*01730558SDoug Anderson return 0; 1117*01730558SDoug Anderson } 1118*01730558SDoug Anderson 1119f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 1120f95f3850SWill Newton { 1121f95f3850SWill Newton int read_only; 1122f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 11239795a846SJaehoon Chung int gpio_ro = mmc_gpio_get_ro(mmc); 1124f95f3850SWill Newton 1125f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 112626375b5cSJaehoon Chung if ((slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) || 112726375b5cSJaehoon Chung (slot->host->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT)) 1128b4967aa5SThomas Abraham read_only = 0; 11299795a846SJaehoon Chung else if (!IS_ERR_VALUE(gpio_ro)) 11309795a846SJaehoon Chung read_only = gpio_ro; 1131f95f3850SWill Newton else 1132f95f3850SWill Newton read_only = 1133f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1134f95f3850SWill Newton 1135f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1136f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1137f95f3850SWill Newton 1138f95f3850SWill Newton return read_only; 1139f95f3850SWill Newton } 1140f95f3850SWill Newton 1141f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1142f95f3850SWill Newton { 1143f95f3850SWill Newton int present; 1144f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1145f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 11467cf347bdSZhangfei Gao struct dw_mci *host = slot->host; 11477cf347bdSZhangfei Gao int gpio_cd = mmc_gpio_get_cd(mmc); 1148f95f3850SWill Newton 1149f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 1150fc3d7720SJaehoon Chung if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) 1151fc3d7720SJaehoon Chung present = 1; 1152bf626e55SZhangfei Gao else if (!IS_ERR_VALUE(gpio_cd)) 11537cf347bdSZhangfei Gao present = gpio_cd; 1154f95f3850SWill Newton else 1155f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1156f95f3850SWill Newton == 0 ? 1 : 0; 1157f95f3850SWill Newton 11587cf347bdSZhangfei Gao spin_lock_bh(&host->lock); 1159bf626e55SZhangfei Gao if (present) { 1160bf626e55SZhangfei Gao set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1161f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 1162bf626e55SZhangfei Gao } else { 1163bf626e55SZhangfei Gao clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1164f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 1165bf626e55SZhangfei Gao } 11667cf347bdSZhangfei Gao spin_unlock_bh(&host->lock); 1167f95f3850SWill Newton 1168f95f3850SWill Newton return present; 1169f95f3850SWill Newton } 1170f95f3850SWill Newton 11719623b5b9SDoug Anderson /* 11729623b5b9SDoug Anderson * Disable lower power mode. 11739623b5b9SDoug Anderson * 11749623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 11759623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 11769623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 11779623b5b9SDoug Anderson * 11789623b5b9SDoug Anderson * This function is fast if low power mode is already disabled. 11799623b5b9SDoug Anderson */ 11809623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot) 11819623b5b9SDoug Anderson { 11829623b5b9SDoug Anderson struct dw_mci *host = slot->host; 11839623b5b9SDoug Anderson u32 clk_en_a; 11849623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 11859623b5b9SDoug Anderson 11869623b5b9SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 11879623b5b9SDoug Anderson 11889623b5b9SDoug Anderson if (clk_en_a & clken_low_pwr) { 11899623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); 11909623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 11919623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 11929623b5b9SDoug Anderson } 11939623b5b9SDoug Anderson } 11949623b5b9SDoug Anderson 11951a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 11961a5c8e1fSShashidhar Hiremath { 11971a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 11981a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 11991a5c8e1fSShashidhar Hiremath u32 int_mask; 12001a5c8e1fSShashidhar Hiremath 12011a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 12021a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 12031a5c8e1fSShashidhar Hiremath if (enb) { 12049623b5b9SDoug Anderson /* 12059623b5b9SDoug Anderson * Turn off low power mode if it was enabled. This is a bit of 12069623b5b9SDoug Anderson * a heavy operation and we disable / enable IRQs a lot, so 12079623b5b9SDoug Anderson * we'll leave low power mode disabled and it will get 12089623b5b9SDoug Anderson * re-enabled again in dw_mci_setup_bus(). 12099623b5b9SDoug Anderson */ 12109623b5b9SDoug Anderson dw_mci_disable_low_power(slot); 12119623b5b9SDoug Anderson 12121a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 1213705ad047SKyoungil Kim (int_mask | SDMMC_INT_SDIO(slot->id))); 12141a5c8e1fSShashidhar Hiremath } else { 12151a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 1216705ad047SKyoungil Kim (int_mask & ~SDMMC_INT_SDIO(slot->id))); 12171a5c8e1fSShashidhar Hiremath } 12181a5c8e1fSShashidhar Hiremath } 12191a5c8e1fSShashidhar Hiremath 12200976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 12210976f16dSSeungwon Jeon { 12220976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 12230976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 12240976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 12250976f16dSSeungwon Jeon struct dw_mci_tuning_data tuning_data; 12260976f16dSSeungwon Jeon int err = -ENOSYS; 12270976f16dSSeungwon Jeon 12280976f16dSSeungwon Jeon if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { 12290976f16dSSeungwon Jeon if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { 12300976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_8bit; 12310976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); 12320976f16dSSeungwon Jeon } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { 12330976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 12340976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 12350976f16dSSeungwon Jeon } else { 12360976f16dSSeungwon Jeon return -EINVAL; 12370976f16dSSeungwon Jeon } 12380976f16dSSeungwon Jeon } else if (opcode == MMC_SEND_TUNING_BLOCK) { 12390976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 12400976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 12410976f16dSSeungwon Jeon } else { 12420976f16dSSeungwon Jeon dev_err(host->dev, 12430976f16dSSeungwon Jeon "Undefined command(%d) for tuning\n", opcode); 12440976f16dSSeungwon Jeon return -EINVAL; 12450976f16dSSeungwon Jeon } 12460976f16dSSeungwon Jeon 12470976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 12480976f16dSSeungwon Jeon err = drv_data->execute_tuning(slot, opcode, &tuning_data); 12490976f16dSSeungwon Jeon return err; 12500976f16dSSeungwon Jeon } 12510976f16dSSeungwon Jeon 1252f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1253f95f3850SWill Newton .request = dw_mci_request, 12549aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 12559aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1256f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1257f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1258f95f3850SWill Newton .get_cd = dw_mci_get_cd, 12591a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 12600976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 1261*01730558SDoug Anderson .card_busy = dw_mci_card_busy, 1262*01730558SDoug Anderson .start_signal_voltage_switch = dw_mci_switch_voltage, 1263*01730558SDoug Anderson 1264f95f3850SWill Newton }; 1265f95f3850SWill Newton 1266f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1267f95f3850SWill Newton __releases(&host->lock) 1268f95f3850SWill Newton __acquires(&host->lock) 1269f95f3850SWill Newton { 1270f95f3850SWill Newton struct dw_mci_slot *slot; 1271f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1272f95f3850SWill Newton 1273f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1274f95f3850SWill Newton 1275f95f3850SWill Newton host->cur_slot->mrq = NULL; 1276f95f3850SWill Newton host->mrq = NULL; 1277f95f3850SWill Newton if (!list_empty(&host->queue)) { 1278f95f3850SWill Newton slot = list_entry(host->queue.next, 1279f95f3850SWill Newton struct dw_mci_slot, queue_node); 1280f95f3850SWill Newton list_del(&slot->queue_node); 12814a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1282f95f3850SWill Newton mmc_hostname(slot->mmc)); 1283f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1284f95f3850SWill Newton dw_mci_start_request(host, slot); 1285f95f3850SWill Newton } else { 12864a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 1287*01730558SDoug Anderson 1288*01730558SDoug Anderson if (host->state == STATE_SENDING_CMD11) 1289*01730558SDoug Anderson host->state = STATE_WAITING_CMD11_DONE; 1290*01730558SDoug Anderson else 1291f95f3850SWill Newton host->state = STATE_IDLE; 1292f95f3850SWill Newton } 1293f95f3850SWill Newton 1294f95f3850SWill Newton spin_unlock(&host->lock); 1295f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1296f95f3850SWill Newton spin_lock(&host->lock); 1297f95f3850SWill Newton } 1298f95f3850SWill Newton 1299e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1300f95f3850SWill Newton { 1301f95f3850SWill Newton u32 status = host->cmd_status; 1302f95f3850SWill Newton 1303f95f3850SWill Newton host->cmd_status = 0; 1304f95f3850SWill Newton 1305f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1306f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1307f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1308f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1309f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1310f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1311f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1312f95f3850SWill Newton } else { 1313f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1314f95f3850SWill Newton cmd->resp[1] = 0; 1315f95f3850SWill Newton cmd->resp[2] = 0; 1316f95f3850SWill Newton cmd->resp[3] = 0; 1317f95f3850SWill Newton } 1318f95f3850SWill Newton } 1319f95f3850SWill Newton 1320f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1321f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1322f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1323f95f3850SWill Newton cmd->error = -EILSEQ; 1324f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1325f95f3850SWill Newton cmd->error = -EIO; 1326f95f3850SWill Newton else 1327f95f3850SWill Newton cmd->error = 0; 1328f95f3850SWill Newton 1329f95f3850SWill Newton if (cmd->error) { 1330f95f3850SWill Newton /* newer ip versions need a delay between retries */ 1331f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) 1332f95f3850SWill Newton mdelay(20); 1333f95f3850SWill Newton } 1334e352c813SSeungwon Jeon 1335e352c813SSeungwon Jeon return cmd->error; 1336e352c813SSeungwon Jeon } 1337e352c813SSeungwon Jeon 1338e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) 1339e352c813SSeungwon Jeon { 134031bff450SSeungwon Jeon u32 status = host->data_status; 1341e352c813SSeungwon Jeon 1342e352c813SSeungwon Jeon if (status & DW_MCI_DATA_ERROR_FLAGS) { 1343e352c813SSeungwon Jeon if (status & SDMMC_INT_DRTO) { 1344e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1345e352c813SSeungwon Jeon } else if (status & SDMMC_INT_DCRC) { 1346e352c813SSeungwon Jeon data->error = -EILSEQ; 1347e352c813SSeungwon Jeon } else if (status & SDMMC_INT_EBE) { 1348e352c813SSeungwon Jeon if (host->dir_status == 1349e352c813SSeungwon Jeon DW_MCI_SEND_STATUS) { 1350e352c813SSeungwon Jeon /* 1351e352c813SSeungwon Jeon * No data CRC status was returned. 1352e352c813SSeungwon Jeon * The number of bytes transferred 1353e352c813SSeungwon Jeon * will be exaggerated in PIO mode. 1354e352c813SSeungwon Jeon */ 1355e352c813SSeungwon Jeon data->bytes_xfered = 0; 1356e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1357e352c813SSeungwon Jeon } else if (host->dir_status == 1358e352c813SSeungwon Jeon DW_MCI_RECV_STATUS) { 1359e352c813SSeungwon Jeon data->error = -EIO; 1360e352c813SSeungwon Jeon } 1361e352c813SSeungwon Jeon } else { 1362e352c813SSeungwon Jeon /* SDMMC_INT_SBE is included */ 1363e352c813SSeungwon Jeon data->error = -EIO; 1364e352c813SSeungwon Jeon } 1365e352c813SSeungwon Jeon 1366e6cc0123SDoug Anderson dev_dbg(host->dev, "data error, status 0x%08x\n", status); 1367e352c813SSeungwon Jeon 1368e352c813SSeungwon Jeon /* 1369e352c813SSeungwon Jeon * After an error, there may be data lingering 137031bff450SSeungwon Jeon * in the FIFO 1371e352c813SSeungwon Jeon */ 13723a33a94cSSonny Rao dw_mci_reset(host); 1373e352c813SSeungwon Jeon } else { 1374e352c813SSeungwon Jeon data->bytes_xfered = data->blocks * data->blksz; 1375e352c813SSeungwon Jeon data->error = 0; 1376e352c813SSeungwon Jeon } 1377e352c813SSeungwon Jeon 1378e352c813SSeungwon Jeon return data->error; 1379f95f3850SWill Newton } 1380f95f3850SWill Newton 1381f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1382f95f3850SWill Newton { 1383f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1384f95f3850SWill Newton struct mmc_data *data; 1385f95f3850SWill Newton struct mmc_command *cmd; 1386e352c813SSeungwon Jeon struct mmc_request *mrq; 1387f95f3850SWill Newton enum dw_mci_state state; 1388f95f3850SWill Newton enum dw_mci_state prev_state; 1389e352c813SSeungwon Jeon unsigned int err; 1390f95f3850SWill Newton 1391f95f3850SWill Newton spin_lock(&host->lock); 1392f95f3850SWill Newton 1393f95f3850SWill Newton state = host->state; 1394f95f3850SWill Newton data = host->data; 1395e352c813SSeungwon Jeon mrq = host->mrq; 1396f95f3850SWill Newton 1397f95f3850SWill Newton do { 1398f95f3850SWill Newton prev_state = state; 1399f95f3850SWill Newton 1400f95f3850SWill Newton switch (state) { 1401f95f3850SWill Newton case STATE_IDLE: 1402*01730558SDoug Anderson case STATE_WAITING_CMD11_DONE: 1403f95f3850SWill Newton break; 1404f95f3850SWill Newton 1405*01730558SDoug Anderson case STATE_SENDING_CMD11: 1406f95f3850SWill Newton case STATE_SENDING_CMD: 1407f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1408f95f3850SWill Newton &host->pending_events)) 1409f95f3850SWill Newton break; 1410f95f3850SWill Newton 1411f95f3850SWill Newton cmd = host->cmd; 1412f95f3850SWill Newton host->cmd = NULL; 1413f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1414e352c813SSeungwon Jeon err = dw_mci_command_complete(host, cmd); 1415e352c813SSeungwon Jeon if (cmd == mrq->sbc && !err) { 1416053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1417053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1418e352c813SSeungwon Jeon mrq->cmd); 1419053b3ce6SSeungwon Jeon goto unlock; 1420053b3ce6SSeungwon Jeon } 1421053b3ce6SSeungwon Jeon 1422e352c813SSeungwon Jeon if (cmd->data && err) { 142371abb133SSeungwon Jeon dw_mci_stop_dma(host); 142490c2143aSSeungwon Jeon send_stop_abort(host, data); 142571abb133SSeungwon Jeon state = STATE_SENDING_STOP; 142671abb133SSeungwon Jeon break; 142771abb133SSeungwon Jeon } 142871abb133SSeungwon Jeon 1429e352c813SSeungwon Jeon if (!cmd->data || err) { 1430e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1431f95f3850SWill Newton goto unlock; 1432f95f3850SWill Newton } 1433f95f3850SWill Newton 1434f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1435f95f3850SWill Newton /* fall through */ 1436f95f3850SWill Newton 1437f95f3850SWill Newton case STATE_SENDING_DATA: 14382aa35465SDoug Anderson /* 14392aa35465SDoug Anderson * We could get a data error and never a transfer 14402aa35465SDoug Anderson * complete so we'd better check for it here. 14412aa35465SDoug Anderson * 14422aa35465SDoug Anderson * Note that we don't really care if we also got a 14432aa35465SDoug Anderson * transfer complete; stopping the DMA and sending an 14442aa35465SDoug Anderson * abort won't hurt. 14452aa35465SDoug Anderson */ 1446f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1447f95f3850SWill Newton &host->pending_events)) { 1448f95f3850SWill Newton dw_mci_stop_dma(host); 144990c2143aSSeungwon Jeon send_stop_abort(host, data); 1450f95f3850SWill Newton state = STATE_DATA_ERROR; 1451f95f3850SWill Newton break; 1452f95f3850SWill Newton } 1453f95f3850SWill Newton 1454f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1455f95f3850SWill Newton &host->pending_events)) 1456f95f3850SWill Newton break; 1457f95f3850SWill Newton 1458f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 14592aa35465SDoug Anderson 14602aa35465SDoug Anderson /* 14612aa35465SDoug Anderson * Handle an EVENT_DATA_ERROR that might have shown up 14622aa35465SDoug Anderson * before the transfer completed. This might not have 14632aa35465SDoug Anderson * been caught by the check above because the interrupt 14642aa35465SDoug Anderson * could have gone off between the previous check and 14652aa35465SDoug Anderson * the check for transfer complete. 14662aa35465SDoug Anderson * 14672aa35465SDoug Anderson * Technically this ought not be needed assuming we 14682aa35465SDoug Anderson * get a DATA_COMPLETE eventually (we'll notice the 14692aa35465SDoug Anderson * error and end the request), but it shouldn't hurt. 14702aa35465SDoug Anderson * 14712aa35465SDoug Anderson * This has the advantage of sending the stop command. 14722aa35465SDoug Anderson */ 14732aa35465SDoug Anderson if (test_and_clear_bit(EVENT_DATA_ERROR, 14742aa35465SDoug Anderson &host->pending_events)) { 14752aa35465SDoug Anderson dw_mci_stop_dma(host); 14762aa35465SDoug Anderson send_stop_abort(host, data); 14772aa35465SDoug Anderson state = STATE_DATA_ERROR; 14782aa35465SDoug Anderson break; 14792aa35465SDoug Anderson } 1480f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 14812aa35465SDoug Anderson 1482f95f3850SWill Newton /* fall through */ 1483f95f3850SWill Newton 1484f95f3850SWill Newton case STATE_DATA_BUSY: 1485f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 1486f95f3850SWill Newton &host->pending_events)) 1487f95f3850SWill Newton break; 1488f95f3850SWill Newton 1489f95f3850SWill Newton host->data = NULL; 1490f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 1491e352c813SSeungwon Jeon err = dw_mci_data_complete(host, data); 1492f95f3850SWill Newton 1493e352c813SSeungwon Jeon if (!err) { 1494e352c813SSeungwon Jeon if (!data->stop || mrq->sbc) { 149517c8bc85SSachin Kamat if (mrq->sbc && data->stop) 1496053b3ce6SSeungwon Jeon data->stop->error = 0; 1497e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1498053b3ce6SSeungwon Jeon goto unlock; 1499053b3ce6SSeungwon Jeon } 1500053b3ce6SSeungwon Jeon 150190c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 1502e352c813SSeungwon Jeon if (data->stop) 150390c2143aSSeungwon Jeon send_stop_abort(host, data); 15042aa35465SDoug Anderson } else { 15052aa35465SDoug Anderson /* 15062aa35465SDoug Anderson * If we don't have a command complete now we'll 15072aa35465SDoug Anderson * never get one since we just reset everything; 15082aa35465SDoug Anderson * better end the request. 15092aa35465SDoug Anderson * 15102aa35465SDoug Anderson * If we do have a command complete we'll fall 15112aa35465SDoug Anderson * through to the SENDING_STOP command and 15122aa35465SDoug Anderson * everything will be peachy keen. 15132aa35465SDoug Anderson */ 15142aa35465SDoug Anderson if (!test_bit(EVENT_CMD_COMPLETE, 15152aa35465SDoug Anderson &host->pending_events)) { 15162aa35465SDoug Anderson host->cmd = NULL; 15172aa35465SDoug Anderson dw_mci_request_end(host, mrq); 15182aa35465SDoug Anderson goto unlock; 15192aa35465SDoug Anderson } 152090c2143aSSeungwon Jeon } 1521e352c813SSeungwon Jeon 1522e352c813SSeungwon Jeon /* 1523e352c813SSeungwon Jeon * If err has non-zero, 1524e352c813SSeungwon Jeon * stop-abort command has been already issued. 1525e352c813SSeungwon Jeon */ 1526e352c813SSeungwon Jeon prev_state = state = STATE_SENDING_STOP; 1527e352c813SSeungwon Jeon 1528f95f3850SWill Newton /* fall through */ 1529f95f3850SWill Newton 1530f95f3850SWill Newton case STATE_SENDING_STOP: 1531f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1532f95f3850SWill Newton &host->pending_events)) 1533f95f3850SWill Newton break; 1534f95f3850SWill Newton 153571abb133SSeungwon Jeon /* CMD error in data command */ 153631bff450SSeungwon Jeon if (mrq->cmd->error && mrq->data) 15373a33a94cSSonny Rao dw_mci_reset(host); 153871abb133SSeungwon Jeon 1539f95f3850SWill Newton host->cmd = NULL; 154071abb133SSeungwon Jeon host->data = NULL; 154190c2143aSSeungwon Jeon 1542e352c813SSeungwon Jeon if (mrq->stop) 1543e352c813SSeungwon Jeon dw_mci_command_complete(host, mrq->stop); 154490c2143aSSeungwon Jeon else 154590c2143aSSeungwon Jeon host->cmd_status = 0; 154690c2143aSSeungwon Jeon 1547e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1548f95f3850SWill Newton goto unlock; 1549f95f3850SWill Newton 1550f95f3850SWill Newton case STATE_DATA_ERROR: 1551f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1552f95f3850SWill Newton &host->pending_events)) 1553f95f3850SWill Newton break; 1554f95f3850SWill Newton 1555f95f3850SWill Newton state = STATE_DATA_BUSY; 1556f95f3850SWill Newton break; 1557f95f3850SWill Newton } 1558f95f3850SWill Newton } while (state != prev_state); 1559f95f3850SWill Newton 1560f95f3850SWill Newton host->state = state; 1561f95f3850SWill Newton unlock: 1562f95f3850SWill Newton spin_unlock(&host->lock); 1563f95f3850SWill Newton 1564f95f3850SWill Newton } 1565f95f3850SWill Newton 156634b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 156734b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 156834b664a2SJames Hogan { 156934b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 157034b664a2SJames Hogan host->part_buf_count = cnt; 157134b664a2SJames Hogan } 157234b664a2SJames Hogan 157334b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 157434b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 157534b664a2SJames Hogan { 157634b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 157734b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 157834b664a2SJames Hogan host->part_buf_count += cnt; 157934b664a2SJames Hogan return cnt; 158034b664a2SJames Hogan } 158134b664a2SJames Hogan 158234b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 158334b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 158434b664a2SJames Hogan { 158534b664a2SJames Hogan cnt = min(cnt, (int)host->part_buf_count); 158634b664a2SJames Hogan if (cnt) { 158734b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 158834b664a2SJames Hogan cnt); 158934b664a2SJames Hogan host->part_buf_count -= cnt; 159034b664a2SJames Hogan host->part_buf_start += cnt; 159134b664a2SJames Hogan } 159234b664a2SJames Hogan return cnt; 159334b664a2SJames Hogan } 159434b664a2SJames Hogan 159534b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 159634b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 159734b664a2SJames Hogan { 159834b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 159934b664a2SJames Hogan host->part_buf_start = cnt; 160034b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 160134b664a2SJames Hogan } 160234b664a2SJames Hogan 1603f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 1604f95f3850SWill Newton { 1605cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1606cfbeb59cSMarkos Chandras int init_cnt = cnt; 1607cfbeb59cSMarkos Chandras 160834b664a2SJames Hogan /* try and push anything in the part_buf */ 160934b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 161034b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 161134b664a2SJames Hogan buf += len; 161234b664a2SJames Hogan cnt -= len; 1613cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 16144e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 16154e0a5adfSJaehoon Chung host->part_buf16); 161634b664a2SJames Hogan host->part_buf_count = 0; 161734b664a2SJames Hogan } 161834b664a2SJames Hogan } 161934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 162034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 162134b664a2SJames Hogan while (cnt >= 2) { 162234b664a2SJames Hogan u16 aligned_buf[64]; 162334b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 162434b664a2SJames Hogan int items = len >> 1; 162534b664a2SJames Hogan int i; 162634b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 162734b664a2SJames Hogan memcpy(aligned_buf, buf, len); 162834b664a2SJames Hogan buf += len; 162934b664a2SJames Hogan cnt -= len; 163034b664a2SJames Hogan /* push data from aligned buffer into fifo */ 163134b664a2SJames Hogan for (i = 0; i < items; ++i) 16324e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 16334e0a5adfSJaehoon Chung aligned_buf[i]); 163434b664a2SJames Hogan } 163534b664a2SJames Hogan } else 163634b664a2SJames Hogan #endif 163734b664a2SJames Hogan { 163834b664a2SJames Hogan u16 *pdata = buf; 163934b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 16404e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), *pdata++); 164134b664a2SJames Hogan buf = pdata; 164234b664a2SJames Hogan } 164334b664a2SJames Hogan /* put anything remaining in the part_buf */ 164434b664a2SJames Hogan if (cnt) { 164534b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1646cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1647cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1648cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 16494e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 16504e0a5adfSJaehoon Chung host->part_buf16); 1651f95f3850SWill Newton } 1652f95f3850SWill Newton } 1653f95f3850SWill Newton 1654f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 1655f95f3850SWill Newton { 165634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 165734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 165834b664a2SJames Hogan while (cnt >= 2) { 165934b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 166034b664a2SJames Hogan u16 aligned_buf[64]; 166134b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 166234b664a2SJames Hogan int items = len >> 1; 166334b664a2SJames Hogan int i; 166434b664a2SJames Hogan for (i = 0; i < items; ++i) 16654e0a5adfSJaehoon Chung aligned_buf[i] = mci_readw(host, 16664e0a5adfSJaehoon Chung DATA(host->data_offset)); 166734b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 166834b664a2SJames Hogan memcpy(buf, aligned_buf, len); 166934b664a2SJames Hogan buf += len; 167034b664a2SJames Hogan cnt -= len; 167134b664a2SJames Hogan } 167234b664a2SJames Hogan } else 167334b664a2SJames Hogan #endif 167434b664a2SJames Hogan { 167534b664a2SJames Hogan u16 *pdata = buf; 167634b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 16774e0a5adfSJaehoon Chung *pdata++ = mci_readw(host, DATA(host->data_offset)); 167834b664a2SJames Hogan buf = pdata; 167934b664a2SJames Hogan } 168034b664a2SJames Hogan if (cnt) { 16814e0a5adfSJaehoon Chung host->part_buf16 = mci_readw(host, DATA(host->data_offset)); 168234b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1683f95f3850SWill Newton } 1684f95f3850SWill Newton } 1685f95f3850SWill Newton 1686f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 1687f95f3850SWill Newton { 1688cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1689cfbeb59cSMarkos Chandras int init_cnt = cnt; 1690cfbeb59cSMarkos Chandras 169134b664a2SJames Hogan /* try and push anything in the part_buf */ 169234b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 169334b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 169434b664a2SJames Hogan buf += len; 169534b664a2SJames Hogan cnt -= len; 1696cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 16974e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 16984e0a5adfSJaehoon Chung host->part_buf32); 169934b664a2SJames Hogan host->part_buf_count = 0; 170034b664a2SJames Hogan } 170134b664a2SJames Hogan } 170234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 170334b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 170434b664a2SJames Hogan while (cnt >= 4) { 170534b664a2SJames Hogan u32 aligned_buf[32]; 170634b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 170734b664a2SJames Hogan int items = len >> 2; 170834b664a2SJames Hogan int i; 170934b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 171034b664a2SJames Hogan memcpy(aligned_buf, buf, len); 171134b664a2SJames Hogan buf += len; 171234b664a2SJames Hogan cnt -= len; 171334b664a2SJames Hogan /* push data from aligned buffer into fifo */ 171434b664a2SJames Hogan for (i = 0; i < items; ++i) 17154e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 17164e0a5adfSJaehoon Chung aligned_buf[i]); 171734b664a2SJames Hogan } 171834b664a2SJames Hogan } else 171934b664a2SJames Hogan #endif 172034b664a2SJames Hogan { 172134b664a2SJames Hogan u32 *pdata = buf; 172234b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 17234e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), *pdata++); 172434b664a2SJames Hogan buf = pdata; 172534b664a2SJames Hogan } 172634b664a2SJames Hogan /* put anything remaining in the part_buf */ 172734b664a2SJames Hogan if (cnt) { 172834b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1729cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1730cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1731cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 17324e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 17334e0a5adfSJaehoon Chung host->part_buf32); 1734f95f3850SWill Newton } 1735f95f3850SWill Newton } 1736f95f3850SWill Newton 1737f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 1738f95f3850SWill Newton { 173934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 174034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 174134b664a2SJames Hogan while (cnt >= 4) { 174234b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 174334b664a2SJames Hogan u32 aligned_buf[32]; 174434b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 174534b664a2SJames Hogan int items = len >> 2; 174634b664a2SJames Hogan int i; 174734b664a2SJames Hogan for (i = 0; i < items; ++i) 17484e0a5adfSJaehoon Chung aligned_buf[i] = mci_readl(host, 17494e0a5adfSJaehoon Chung DATA(host->data_offset)); 175034b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 175134b664a2SJames Hogan memcpy(buf, aligned_buf, len); 175234b664a2SJames Hogan buf += len; 175334b664a2SJames Hogan cnt -= len; 175434b664a2SJames Hogan } 175534b664a2SJames Hogan } else 175634b664a2SJames Hogan #endif 175734b664a2SJames Hogan { 175834b664a2SJames Hogan u32 *pdata = buf; 175934b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 17604e0a5adfSJaehoon Chung *pdata++ = mci_readl(host, DATA(host->data_offset)); 176134b664a2SJames Hogan buf = pdata; 176234b664a2SJames Hogan } 176334b664a2SJames Hogan if (cnt) { 17644e0a5adfSJaehoon Chung host->part_buf32 = mci_readl(host, DATA(host->data_offset)); 176534b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1766f95f3850SWill Newton } 1767f95f3850SWill Newton } 1768f95f3850SWill Newton 1769f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 1770f95f3850SWill Newton { 1771cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1772cfbeb59cSMarkos Chandras int init_cnt = cnt; 1773cfbeb59cSMarkos Chandras 177434b664a2SJames Hogan /* try and push anything in the part_buf */ 177534b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 177634b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 177734b664a2SJames Hogan buf += len; 177834b664a2SJames Hogan cnt -= len; 1779c09fbd74SSeungwon Jeon 1780cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 1781c09fbd74SSeungwon Jeon mci_writeq(host, DATA(host->data_offset), 17824e0a5adfSJaehoon Chung host->part_buf); 178334b664a2SJames Hogan host->part_buf_count = 0; 178434b664a2SJames Hogan } 178534b664a2SJames Hogan } 178634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 178734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 178834b664a2SJames Hogan while (cnt >= 8) { 178934b664a2SJames Hogan u64 aligned_buf[16]; 179034b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 179134b664a2SJames Hogan int items = len >> 3; 179234b664a2SJames Hogan int i; 179334b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 179434b664a2SJames Hogan memcpy(aligned_buf, buf, len); 179534b664a2SJames Hogan buf += len; 179634b664a2SJames Hogan cnt -= len; 179734b664a2SJames Hogan /* push data from aligned buffer into fifo */ 179834b664a2SJames Hogan for (i = 0; i < items; ++i) 17994e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 18004e0a5adfSJaehoon Chung aligned_buf[i]); 180134b664a2SJames Hogan } 180234b664a2SJames Hogan } else 180334b664a2SJames Hogan #endif 180434b664a2SJames Hogan { 180534b664a2SJames Hogan u64 *pdata = buf; 180634b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 18074e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), *pdata++); 180834b664a2SJames Hogan buf = pdata; 180934b664a2SJames Hogan } 181034b664a2SJames Hogan /* put anything remaining in the part_buf */ 181134b664a2SJames Hogan if (cnt) { 181234b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1813cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1814cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1815cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 18164e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 18174e0a5adfSJaehoon Chung host->part_buf); 1818f95f3850SWill Newton } 1819f95f3850SWill Newton } 1820f95f3850SWill Newton 1821f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 1822f95f3850SWill Newton { 182334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 182434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 182534b664a2SJames Hogan while (cnt >= 8) { 182634b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 182734b664a2SJames Hogan u64 aligned_buf[16]; 182834b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 182934b664a2SJames Hogan int items = len >> 3; 183034b664a2SJames Hogan int i; 183134b664a2SJames Hogan for (i = 0; i < items; ++i) 18324e0a5adfSJaehoon Chung aligned_buf[i] = mci_readq(host, 18334e0a5adfSJaehoon Chung DATA(host->data_offset)); 183434b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 183534b664a2SJames Hogan memcpy(buf, aligned_buf, len); 183634b664a2SJames Hogan buf += len; 183734b664a2SJames Hogan cnt -= len; 1838f95f3850SWill Newton } 183934b664a2SJames Hogan } else 184034b664a2SJames Hogan #endif 184134b664a2SJames Hogan { 184234b664a2SJames Hogan u64 *pdata = buf; 184334b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 18444e0a5adfSJaehoon Chung *pdata++ = mci_readq(host, DATA(host->data_offset)); 184534b664a2SJames Hogan buf = pdata; 184634b664a2SJames Hogan } 184734b664a2SJames Hogan if (cnt) { 18484e0a5adfSJaehoon Chung host->part_buf = mci_readq(host, DATA(host->data_offset)); 184934b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 185034b664a2SJames Hogan } 185134b664a2SJames Hogan } 185234b664a2SJames Hogan 185334b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 185434b664a2SJames Hogan { 185534b664a2SJames Hogan int len; 185634b664a2SJames Hogan 185734b664a2SJames Hogan /* get remaining partial bytes */ 185834b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 185934b664a2SJames Hogan if (unlikely(len == cnt)) 186034b664a2SJames Hogan return; 186134b664a2SJames Hogan buf += len; 186234b664a2SJames Hogan cnt -= len; 186334b664a2SJames Hogan 186434b664a2SJames Hogan /* get the rest of the data */ 186534b664a2SJames Hogan host->pull_data(host, buf, cnt); 1866f95f3850SWill Newton } 1867f95f3850SWill Newton 186887a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 1869f95f3850SWill Newton { 1870f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1871f9c2a0dcSSeungwon Jeon void *buf; 1872f9c2a0dcSSeungwon Jeon unsigned int offset; 1873f95f3850SWill Newton struct mmc_data *data = host->data; 1874f95f3850SWill Newton int shift = host->data_shift; 1875f95f3850SWill Newton u32 status; 18763e4b0d8bSMarkos Chandras unsigned int len; 1877f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 1878f95f3850SWill Newton 1879f95f3850SWill Newton do { 1880f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1881f9c2a0dcSSeungwon Jeon goto done; 1882f95f3850SWill Newton 18834225fc85SImre Deak host->sg = sg_miter->piter.sg; 1884f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 1885f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 1886f9c2a0dcSSeungwon Jeon offset = 0; 1887f9c2a0dcSSeungwon Jeon 1888f9c2a0dcSSeungwon Jeon do { 1889f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 1890f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 1891f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 1892f9c2a0dcSSeungwon Jeon if (!len) 1893f9c2a0dcSSeungwon Jeon break; 1894f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 18953e4b0d8bSMarkos Chandras data->bytes_xfered += len; 1896f95f3850SWill Newton offset += len; 1897f9c2a0dcSSeungwon Jeon remain -= len; 1898f9c2a0dcSSeungwon Jeon } while (remain); 1899f95f3850SWill Newton 1900e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 1901f95f3850SWill Newton status = mci_readl(host, MINTSTS); 1902f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 190387a74d39SKyoungil Kim /* if the RXDR is ready read again */ 190487a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 190587a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 1906f9c2a0dcSSeungwon Jeon 1907f9c2a0dcSSeungwon Jeon if (!remain) { 1908f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1909f9c2a0dcSSeungwon Jeon goto done; 1910f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 1911f9c2a0dcSSeungwon Jeon } 1912f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1913f95f3850SWill Newton return; 1914f95f3850SWill Newton 1915f95f3850SWill Newton done: 1916f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1917f9c2a0dcSSeungwon Jeon host->sg = NULL; 1918f95f3850SWill Newton smp_wmb(); 1919f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1920f95f3850SWill Newton } 1921f95f3850SWill Newton 1922f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 1923f95f3850SWill Newton { 1924f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1925f9c2a0dcSSeungwon Jeon void *buf; 1926f9c2a0dcSSeungwon Jeon unsigned int offset; 1927f95f3850SWill Newton struct mmc_data *data = host->data; 1928f95f3850SWill Newton int shift = host->data_shift; 1929f95f3850SWill Newton u32 status; 19303e4b0d8bSMarkos Chandras unsigned int len; 1931f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 1932f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 1933f95f3850SWill Newton 1934f95f3850SWill Newton do { 1935f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1936f9c2a0dcSSeungwon Jeon goto done; 1937f95f3850SWill Newton 19384225fc85SImre Deak host->sg = sg_miter->piter.sg; 1939f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 1940f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 1941f9c2a0dcSSeungwon Jeon offset = 0; 1942f9c2a0dcSSeungwon Jeon 1943f9c2a0dcSSeungwon Jeon do { 1944f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 1945f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 1946f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 1947f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 1948f9c2a0dcSSeungwon Jeon if (!len) 1949f9c2a0dcSSeungwon Jeon break; 1950f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 19513e4b0d8bSMarkos Chandras data->bytes_xfered += len; 1952f95f3850SWill Newton offset += len; 1953f9c2a0dcSSeungwon Jeon remain -= len; 1954f9c2a0dcSSeungwon Jeon } while (remain); 1955f95f3850SWill Newton 1956e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 1957f95f3850SWill Newton status = mci_readl(host, MINTSTS); 1958f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 1959f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 1960f9c2a0dcSSeungwon Jeon 1961f9c2a0dcSSeungwon Jeon if (!remain) { 1962f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1963f9c2a0dcSSeungwon Jeon goto done; 1964f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 1965f9c2a0dcSSeungwon Jeon } 1966f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1967f95f3850SWill Newton return; 1968f95f3850SWill Newton 1969f95f3850SWill Newton done: 1970f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1971f9c2a0dcSSeungwon Jeon host->sg = NULL; 1972f95f3850SWill Newton smp_wmb(); 1973f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1974f95f3850SWill Newton } 1975f95f3850SWill Newton 1976f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 1977f95f3850SWill Newton { 1978f95f3850SWill Newton if (!host->cmd_status) 1979f95f3850SWill Newton host->cmd_status = status; 1980f95f3850SWill Newton 1981f95f3850SWill Newton smp_wmb(); 1982f95f3850SWill Newton 1983f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 1984f95f3850SWill Newton tasklet_schedule(&host->tasklet); 1985f95f3850SWill Newton } 1986f95f3850SWill Newton 1987f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 1988f95f3850SWill Newton { 1989f95f3850SWill Newton struct dw_mci *host = dev_id; 1990182c9081SSeungwon Jeon u32 pending; 19911a5c8e1fSShashidhar Hiremath int i; 1992f95f3850SWill Newton 1993f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 1994f95f3850SWill Newton 1995f95f3850SWill Newton /* 1996f95f3850SWill Newton * DTO fix - version 2.10a and below, and only if internal DMA 1997f95f3850SWill Newton * is configured. 1998f95f3850SWill Newton */ 1999f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { 2000f95f3850SWill Newton if (!pending && 2001f95f3850SWill Newton ((mci_readl(host, STATUS) >> 17) & 0x1fff)) 2002f95f3850SWill Newton pending |= SDMMC_INT_DATA_OVER; 2003f95f3850SWill Newton } 2004f95f3850SWill Newton 2005476d79f1SDoug Anderson if (pending) { 2006*01730558SDoug Anderson /* Check volt switch first, since it can look like an error */ 2007*01730558SDoug Anderson if ((host->state == STATE_SENDING_CMD11) && 2008*01730558SDoug Anderson (pending & SDMMC_INT_VOLT_SWITCH)) { 2009*01730558SDoug Anderson mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); 2010*01730558SDoug Anderson pending &= ~SDMMC_INT_VOLT_SWITCH; 2011*01730558SDoug Anderson dw_mci_cmd_interrupt(host, pending); 2012*01730558SDoug Anderson } 2013*01730558SDoug Anderson 2014f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 2015f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 2016182c9081SSeungwon Jeon host->cmd_status = pending; 2017f95f3850SWill Newton smp_wmb(); 2018f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 2019f95f3850SWill Newton } 2020f95f3850SWill Newton 2021f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 2022f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 2023f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 2024182c9081SSeungwon Jeon host->data_status = pending; 2025f95f3850SWill Newton smp_wmb(); 2026f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 2027f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2028f95f3850SWill Newton } 2029f95f3850SWill Newton 2030f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 2031f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 2032f95f3850SWill Newton if (!host->data_status) 2033182c9081SSeungwon Jeon host->data_status = pending; 2034f95f3850SWill Newton smp_wmb(); 2035f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 2036f95f3850SWill Newton if (host->sg != NULL) 203787a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 2038f95f3850SWill Newton } 2039f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 2040f95f3850SWill Newton tasklet_schedule(&host->tasklet); 2041f95f3850SWill Newton } 2042f95f3850SWill Newton 2043f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 2044f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 2045b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 204687a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 2047f95f3850SWill Newton } 2048f95f3850SWill Newton 2049f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 2050f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 2051b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 2052f95f3850SWill Newton dw_mci_write_data_pio(host); 2053f95f3850SWill Newton } 2054f95f3850SWill Newton 2055f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 2056f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 2057182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 2058f95f3850SWill Newton } 2059f95f3850SWill Newton 2060f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 2061f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 206295dcc2cbSThomas Abraham queue_work(host->card_workqueue, &host->card_work); 2063f95f3850SWill Newton } 2064f95f3850SWill Newton 20651a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 20661a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 20671a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 20681a5c8e1fSShashidhar Hiremath if (pending & SDMMC_INT_SDIO(i)) { 20691a5c8e1fSShashidhar Hiremath mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); 20701a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 20711a5c8e1fSShashidhar Hiremath } 20721a5c8e1fSShashidhar Hiremath } 20731a5c8e1fSShashidhar Hiremath 20741fb5f68aSMarkos Chandras } 2075f95f3850SWill Newton 2076f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2077f95f3850SWill Newton /* Handle DMA interrupts */ 2078f95f3850SWill Newton pending = mci_readl(host, IDSTS); 2079f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 2080f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); 2081f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 2082f95f3850SWill Newton host->dma_ops->complete(host); 2083f95f3850SWill Newton } 2084f95f3850SWill Newton #endif 2085f95f3850SWill Newton 2086f95f3850SWill Newton return IRQ_HANDLED; 2087f95f3850SWill Newton } 2088f95f3850SWill Newton 20891791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work) 2090f95f3850SWill Newton { 20911791b13eSJames Hogan struct dw_mci *host = container_of(work, struct dw_mci, card_work); 2092f95f3850SWill Newton int i; 2093f95f3850SWill Newton 2094f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2095f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 2096f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 2097f95f3850SWill Newton struct mmc_request *mrq; 2098f95f3850SWill Newton int present; 2099f95f3850SWill Newton 2100f95f3850SWill Newton present = dw_mci_get_cd(mmc); 2101f95f3850SWill Newton while (present != slot->last_detect_state) { 2102f95f3850SWill Newton dev_dbg(&slot->mmc->class_dev, "card %s\n", 2103f95f3850SWill Newton present ? "inserted" : "removed"); 2104f95f3850SWill Newton 21051791b13eSJames Hogan spin_lock_bh(&host->lock); 21061791b13eSJames Hogan 2107f95f3850SWill Newton /* Card change detected */ 2108f95f3850SWill Newton slot->last_detect_state = present; 2109f95f3850SWill Newton 2110f95f3850SWill Newton /* Clean up queue if present */ 2111f95f3850SWill Newton mrq = slot->mrq; 2112f95f3850SWill Newton if (mrq) { 2113f95f3850SWill Newton if (mrq == host->mrq) { 2114f95f3850SWill Newton host->data = NULL; 2115f95f3850SWill Newton host->cmd = NULL; 2116f95f3850SWill Newton 2117f95f3850SWill Newton switch (host->state) { 2118f95f3850SWill Newton case STATE_IDLE: 2119*01730558SDoug Anderson case STATE_WAITING_CMD11_DONE: 2120f95f3850SWill Newton break; 2121*01730558SDoug Anderson case STATE_SENDING_CMD11: 2122f95f3850SWill Newton case STATE_SENDING_CMD: 2123f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 2124f95f3850SWill Newton if (!mrq->data) 2125f95f3850SWill Newton break; 2126f95f3850SWill Newton /* fall through */ 2127f95f3850SWill Newton case STATE_SENDING_DATA: 2128f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 2129f95f3850SWill Newton dw_mci_stop_dma(host); 2130f95f3850SWill Newton break; 2131f95f3850SWill Newton case STATE_DATA_BUSY: 2132f95f3850SWill Newton case STATE_DATA_ERROR: 2133f95f3850SWill Newton if (mrq->data->error == -EINPROGRESS) 2134f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 2135f95f3850SWill Newton /* fall through */ 2136f95f3850SWill Newton case STATE_SENDING_STOP: 213790c2143aSSeungwon Jeon if (mrq->stop) 2138f95f3850SWill Newton mrq->stop->error = -ENOMEDIUM; 2139f95f3850SWill Newton break; 2140f95f3850SWill Newton } 2141f95f3850SWill Newton 2142f95f3850SWill Newton dw_mci_request_end(host, mrq); 2143f95f3850SWill Newton } else { 2144f95f3850SWill Newton list_del(&slot->queue_node); 2145f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 2146f95f3850SWill Newton if (mrq->data) 2147f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 2148f95f3850SWill Newton if (mrq->stop) 2149f95f3850SWill Newton mrq->stop->error = -ENOMEDIUM; 2150f95f3850SWill Newton 2151f95f3850SWill Newton spin_unlock(&host->lock); 2152f95f3850SWill Newton mmc_request_done(slot->mmc, mrq); 2153f95f3850SWill Newton spin_lock(&host->lock); 2154f95f3850SWill Newton } 2155f95f3850SWill Newton } 2156f95f3850SWill Newton 2157f95f3850SWill Newton /* Power down slot */ 21583a33a94cSSonny Rao if (present == 0) 21593a33a94cSSonny Rao dw_mci_reset(host); 2160f95f3850SWill Newton 21611791b13eSJames Hogan spin_unlock_bh(&host->lock); 21621791b13eSJames Hogan 2163f95f3850SWill Newton present = dw_mci_get_cd(mmc); 2164f95f3850SWill Newton } 2165f95f3850SWill Newton 2166f95f3850SWill Newton mmc_detect_change(slot->mmc, 2167f95f3850SWill Newton msecs_to_jiffies(host->pdata->detect_delay_ms)); 2168f95f3850SWill Newton } 2169f95f3850SWill Newton } 2170f95f3850SWill Newton 2171c91eab4bSThomas Abraham #ifdef CONFIG_OF 2172c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */ 2173c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 2174c91eab4bSThomas Abraham { 2175c91eab4bSThomas Abraham struct device_node *np; 2176c91eab4bSThomas Abraham const __be32 *addr; 2177c91eab4bSThomas Abraham int len; 2178c91eab4bSThomas Abraham 2179c91eab4bSThomas Abraham if (!dev || !dev->of_node) 2180c91eab4bSThomas Abraham return NULL; 2181c91eab4bSThomas Abraham 2182c91eab4bSThomas Abraham for_each_child_of_node(dev->of_node, np) { 2183c91eab4bSThomas Abraham addr = of_get_property(np, "reg", &len); 2184c91eab4bSThomas Abraham if (!addr || (len < sizeof(int))) 2185c91eab4bSThomas Abraham continue; 2186c91eab4bSThomas Abraham if (be32_to_cpup(addr) == slot) 2187c91eab4bSThomas Abraham return np; 2188c91eab4bSThomas Abraham } 2189c91eab4bSThomas Abraham return NULL; 2190c91eab4bSThomas Abraham } 2191c91eab4bSThomas Abraham 2192a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks { 2193a70aaa64SDoug Anderson char *quirk; 2194a70aaa64SDoug Anderson int id; 2195a70aaa64SDoug Anderson } of_slot_quirks[] = { 2196a70aaa64SDoug Anderson { 2197a70aaa64SDoug Anderson .quirk = "disable-wp", 2198a70aaa64SDoug Anderson .id = DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT, 2199a70aaa64SDoug Anderson }, 2200a70aaa64SDoug Anderson }; 2201a70aaa64SDoug Anderson 2202a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2203a70aaa64SDoug Anderson { 2204a70aaa64SDoug Anderson struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 2205a70aaa64SDoug Anderson int quirks = 0; 2206a70aaa64SDoug Anderson int idx; 2207a70aaa64SDoug Anderson 2208a70aaa64SDoug Anderson /* get quirks */ 2209a70aaa64SDoug Anderson for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++) 221026375b5cSJaehoon Chung if (of_get_property(np, of_slot_quirks[idx].quirk, NULL)) { 221126375b5cSJaehoon Chung dev_warn(dev, "Slot quirk %s is deprecated\n", 221226375b5cSJaehoon Chung of_slot_quirks[idx].quirk); 2213a70aaa64SDoug Anderson quirks |= of_slot_quirks[idx].id; 221426375b5cSJaehoon Chung } 2215a70aaa64SDoug Anderson 2216a70aaa64SDoug Anderson return quirks; 2217a70aaa64SDoug Anderson } 2218c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2219a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2220a70aaa64SDoug Anderson { 2221a70aaa64SDoug Anderson return 0; 2222a70aaa64SDoug Anderson } 2223c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 2224c91eab4bSThomas Abraham { 2225c91eab4bSThomas Abraham return NULL; 2226c91eab4bSThomas Abraham } 2227c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2228c91eab4bSThomas Abraham 222936c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2230f95f3850SWill Newton { 2231f95f3850SWill Newton struct mmc_host *mmc; 2232f95f3850SWill Newton struct dw_mci_slot *slot; 2233e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2234800d78bfSThomas Abraham int ctrl_id, ret; 22351f44a2a5SSeungwon Jeon u32 freq[2]; 2236f95f3850SWill Newton 22374a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2238f95f3850SWill Newton if (!mmc) 2239f95f3850SWill Newton return -ENOMEM; 2240f95f3850SWill Newton 2241f95f3850SWill Newton slot = mmc_priv(mmc); 2242f95f3850SWill Newton slot->id = id; 2243f95f3850SWill Newton slot->mmc = mmc; 2244f95f3850SWill Newton slot->host = host; 2245c91eab4bSThomas Abraham host->slot[id] = slot; 2246f95f3850SWill Newton 2247a70aaa64SDoug Anderson slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id); 2248a70aaa64SDoug Anderson 2249f95f3850SWill Newton mmc->ops = &dw_mci_ops; 22501f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 22511f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 22521f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 22531f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 22541f44a2a5SSeungwon Jeon } else { 22551f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 22561f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 22571f44a2a5SSeungwon Jeon } 2258f95f3850SWill Newton 225951da2240SYuvaraj CD /*if there are external regulators, get them*/ 226051da2240SYuvaraj CD ret = mmc_regulator_get_supply(mmc); 226151da2240SYuvaraj CD if (ret == -EPROBE_DEFER) 226251da2240SYuvaraj CD goto err_setup_bus; 226351da2240SYuvaraj CD 226451da2240SYuvaraj CD if (!mmc->ocr_avail) 2265f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2266f95f3850SWill Newton 2267fc3d7720SJaehoon Chung if (host->pdata->caps) 2268fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2269fc3d7720SJaehoon Chung 2270ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2271ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2272ab269128SAbhilash Kesavan 2273800d78bfSThomas Abraham if (host->dev->of_node) { 2274800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2275800d78bfSThomas Abraham if (ctrl_id < 0) 2276800d78bfSThomas Abraham ctrl_id = 0; 2277800d78bfSThomas Abraham } else { 2278800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2279800d78bfSThomas Abraham } 2280cb27a843SJames Hogan if (drv_data && drv_data->caps) 2281cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2282800d78bfSThomas Abraham 22834f408cc6SSeungwon Jeon if (host->pdata->caps2) 22844f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 22854f408cc6SSeungwon Jeon 2286d8a4fb0eSJaehoon Chung mmc_of_parse(mmc); 2287f95f3850SWill Newton 2288f95f3850SWill Newton if (host->pdata->blk_settings) { 2289f95f3850SWill Newton mmc->max_segs = host->pdata->blk_settings->max_segs; 2290f95f3850SWill Newton mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; 2291f95f3850SWill Newton mmc->max_blk_count = host->pdata->blk_settings->max_blk_count; 2292f95f3850SWill Newton mmc->max_req_size = host->pdata->blk_settings->max_req_size; 2293f95f3850SWill Newton mmc->max_seg_size = host->pdata->blk_settings->max_seg_size; 2294f95f3850SWill Newton } else { 2295f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 2296a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 2297a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2298a39e5746SJaehoon Chung mmc->max_blk_size = 65536; 2299a39e5746SJaehoon Chung mmc->max_blk_count = host->ring_size; 2300a39e5746SJaehoon Chung mmc->max_seg_size = 0x1000; 2301a39e5746SJaehoon Chung mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; 2302a39e5746SJaehoon Chung #else 2303f95f3850SWill Newton mmc->max_segs = 64; 2304f95f3850SWill Newton mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ 2305f95f3850SWill Newton mmc->max_blk_count = 512; 2306f95f3850SWill Newton mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 2307f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2308f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 2309a39e5746SJaehoon Chung } 2310f95f3850SWill Newton 2311ae0eb348SJaehoon Chung if (dw_mci_get_cd(mmc)) 2312ae0eb348SJaehoon Chung set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2313ae0eb348SJaehoon Chung else 2314ae0eb348SJaehoon Chung clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2315ae0eb348SJaehoon Chung 23160cea529dSJaehoon Chung ret = mmc_add_host(mmc); 23170cea529dSJaehoon Chung if (ret) 23180cea529dSJaehoon Chung goto err_setup_bus; 2319f95f3850SWill Newton 2320f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2321f95f3850SWill Newton dw_mci_init_debugfs(slot); 2322f95f3850SWill Newton #endif 2323f95f3850SWill Newton 2324f95f3850SWill Newton /* Card initially undetected */ 2325f95f3850SWill Newton slot->last_detect_state = 0; 2326f95f3850SWill Newton 2327f95f3850SWill Newton return 0; 2328800d78bfSThomas Abraham 2329800d78bfSThomas Abraham err_setup_bus: 2330800d78bfSThomas Abraham mmc_free_host(mmc); 233151da2240SYuvaraj CD return ret; 2332f95f3850SWill Newton } 2333f95f3850SWill Newton 2334f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2335f95f3850SWill Newton { 2336f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2337f95f3850SWill Newton mmc_remove_host(slot->mmc); 2338f95f3850SWill Newton slot->host->slot[id] = NULL; 2339f95f3850SWill Newton mmc_free_host(slot->mmc); 2340f95f3850SWill Newton } 2341f95f3850SWill Newton 2342f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2343f95f3850SWill Newton { 2344f95f3850SWill Newton /* Alloc memory for sg translation */ 2345780f22afSSeungwon Jeon host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, 2346f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2347f95f3850SWill Newton if (!host->sg_cpu) { 23484a90920cSThomas Abraham dev_err(host->dev, "%s: could not alloc DMA memory\n", 2349f95f3850SWill Newton __func__); 2350f95f3850SWill Newton goto no_dma; 2351f95f3850SWill Newton } 2352f95f3850SWill Newton 2353f95f3850SWill Newton /* Determine which DMA interface to use */ 2354f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2355f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 235600956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 2357f95f3850SWill Newton #endif 2358f95f3850SWill Newton 2359f95f3850SWill Newton if (!host->dma_ops) 2360f95f3850SWill Newton goto no_dma; 2361f95f3850SWill Newton 2362e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2363e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2364f95f3850SWill Newton if (host->dma_ops->init(host)) { 23654a90920cSThomas Abraham dev_err(host->dev, "%s: Unable to initialize " 2366f95f3850SWill Newton "DMA Controller.\n", __func__); 2367f95f3850SWill Newton goto no_dma; 2368f95f3850SWill Newton } 2369f95f3850SWill Newton } else { 23704a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2371f95f3850SWill Newton goto no_dma; 2372f95f3850SWill Newton } 2373f95f3850SWill Newton 2374f95f3850SWill Newton host->use_dma = 1; 2375f95f3850SWill Newton return; 2376f95f3850SWill Newton 2377f95f3850SWill Newton no_dma: 23784a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 2379f95f3850SWill Newton host->use_dma = 0; 2380f95f3850SWill Newton return; 2381f95f3850SWill Newton } 2382f95f3850SWill Newton 238331bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) 2384f95f3850SWill Newton { 2385f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 238631bff450SSeungwon Jeon u32 ctrl; 2387f95f3850SWill Newton 238831bff450SSeungwon Jeon ctrl = mci_readl(host, CTRL); 238931bff450SSeungwon Jeon ctrl |= reset; 239031bff450SSeungwon Jeon mci_writel(host, CTRL, ctrl); 2391f95f3850SWill Newton 2392f95f3850SWill Newton /* wait till resets clear */ 2393f95f3850SWill Newton do { 2394f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 239531bff450SSeungwon Jeon if (!(ctrl & reset)) 2396f95f3850SWill Newton return true; 2397f95f3850SWill Newton } while (time_before(jiffies, timeout)); 2398f95f3850SWill Newton 239931bff450SSeungwon Jeon dev_err(host->dev, 240031bff450SSeungwon Jeon "Timeout resetting block (ctrl reset %#x)\n", 240131bff450SSeungwon Jeon ctrl & reset); 2402f95f3850SWill Newton 2403f95f3850SWill Newton return false; 2404f95f3850SWill Newton } 2405f95f3850SWill Newton 24063a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host) 240731bff450SSeungwon Jeon { 24083a33a94cSSonny Rao u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET; 24093a33a94cSSonny Rao bool ret = false; 24103a33a94cSSonny Rao 241131bff450SSeungwon Jeon /* 241231bff450SSeungwon Jeon * Reseting generates a block interrupt, hence setting 241331bff450SSeungwon Jeon * the scatter-gather pointer to NULL. 241431bff450SSeungwon Jeon */ 241531bff450SSeungwon Jeon if (host->sg) { 241631bff450SSeungwon Jeon sg_miter_stop(&host->sg_miter); 241731bff450SSeungwon Jeon host->sg = NULL; 241831bff450SSeungwon Jeon } 241931bff450SSeungwon Jeon 24203a33a94cSSonny Rao if (host->use_dma) 24213a33a94cSSonny Rao flags |= SDMMC_CTRL_DMA_RESET; 24223a33a94cSSonny Rao 24233a33a94cSSonny Rao if (dw_mci_ctrl_reset(host, flags)) { 24243a33a94cSSonny Rao /* 24253a33a94cSSonny Rao * In all cases we clear the RAWINTS register to clear any 24263a33a94cSSonny Rao * interrupts. 24273a33a94cSSonny Rao */ 24283a33a94cSSonny Rao mci_writel(host, RINTSTS, 0xFFFFFFFF); 24293a33a94cSSonny Rao 24303a33a94cSSonny Rao /* if using dma we wait for dma_req to clear */ 24313a33a94cSSonny Rao if (host->use_dma) { 24323a33a94cSSonny Rao unsigned long timeout = jiffies + msecs_to_jiffies(500); 24333a33a94cSSonny Rao u32 status; 24343a33a94cSSonny Rao do { 24353a33a94cSSonny Rao status = mci_readl(host, STATUS); 24363a33a94cSSonny Rao if (!(status & SDMMC_STATUS_DMA_REQ)) 24373a33a94cSSonny Rao break; 24383a33a94cSSonny Rao cpu_relax(); 24393a33a94cSSonny Rao } while (time_before(jiffies, timeout)); 24403a33a94cSSonny Rao 24413a33a94cSSonny Rao if (status & SDMMC_STATUS_DMA_REQ) { 24423a33a94cSSonny Rao dev_err(host->dev, 24433a33a94cSSonny Rao "%s: Timeout waiting for dma_req to " 24443a33a94cSSonny Rao "clear during reset\n", __func__); 24453a33a94cSSonny Rao goto ciu_out; 244631bff450SSeungwon Jeon } 244731bff450SSeungwon Jeon 24483a33a94cSSonny Rao /* when using DMA next we reset the fifo again */ 24493a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET)) 24503a33a94cSSonny Rao goto ciu_out; 24513a33a94cSSonny Rao } 24523a33a94cSSonny Rao } else { 24533a33a94cSSonny Rao /* if the controller reset bit did clear, then set clock regs */ 24543a33a94cSSonny Rao if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) { 24553a33a94cSSonny Rao dev_err(host->dev, "%s: fifo/dma reset bits didn't " 24563a33a94cSSonny Rao "clear but ciu was reset, doing clock update\n", 24573a33a94cSSonny Rao __func__); 24583a33a94cSSonny Rao goto ciu_out; 24593a33a94cSSonny Rao } 24603a33a94cSSonny Rao } 24613a33a94cSSonny Rao 24623a33a94cSSonny Rao #if IS_ENABLED(CONFIG_MMC_DW_IDMAC) 24633a33a94cSSonny Rao /* It is also recommended that we reset and reprogram idmac */ 24643a33a94cSSonny Rao dw_mci_idmac_reset(host); 24653a33a94cSSonny Rao #endif 24663a33a94cSSonny Rao 24673a33a94cSSonny Rao ret = true; 24683a33a94cSSonny Rao 24693a33a94cSSonny Rao ciu_out: 24703a33a94cSSonny Rao /* After a CTRL reset we need to have CIU set clock registers */ 24713a33a94cSSonny Rao mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0); 24723a33a94cSSonny Rao 24733a33a94cSSonny Rao return ret; 247431bff450SSeungwon Jeon } 247531bff450SSeungwon Jeon 2476c91eab4bSThomas Abraham #ifdef CONFIG_OF 2477c91eab4bSThomas Abraham static struct dw_mci_of_quirks { 2478c91eab4bSThomas Abraham char *quirk; 2479c91eab4bSThomas Abraham int id; 2480c91eab4bSThomas Abraham } of_quirks[] = { 2481c91eab4bSThomas Abraham { 2482c91eab4bSThomas Abraham .quirk = "broken-cd", 2483c91eab4bSThomas Abraham .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, 248426375b5cSJaehoon Chung }, { 248526375b5cSJaehoon Chung .quirk = "disable-wp", 248626375b5cSJaehoon Chung .id = DW_MCI_QUIRK_NO_WRITE_PROTECT, 2487c91eab4bSThomas Abraham }, 2488c91eab4bSThomas Abraham }; 2489c91eab4bSThomas Abraham 2490c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2491c91eab4bSThomas Abraham { 2492c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2493c91eab4bSThomas Abraham struct device *dev = host->dev; 2494c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2495e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2496800d78bfSThomas Abraham int idx, ret; 24973c6d89eaSDoug Anderson u32 clock_frequency; 2498c91eab4bSThomas Abraham 2499c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2500c91eab4bSThomas Abraham if (!pdata) { 2501c91eab4bSThomas Abraham dev_err(dev, "could not allocate memory for pdata\n"); 2502c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2503c91eab4bSThomas Abraham } 2504c91eab4bSThomas Abraham 2505c91eab4bSThomas Abraham /* find out number of slots supported */ 2506c91eab4bSThomas Abraham if (of_property_read_u32(dev->of_node, "num-slots", 2507c91eab4bSThomas Abraham &pdata->num_slots)) { 2508c91eab4bSThomas Abraham dev_info(dev, "num-slots property not found, " 2509c91eab4bSThomas Abraham "assuming 1 slot is available\n"); 2510c91eab4bSThomas Abraham pdata->num_slots = 1; 2511c91eab4bSThomas Abraham } 2512c91eab4bSThomas Abraham 2513c91eab4bSThomas Abraham /* get quirks */ 2514c91eab4bSThomas Abraham for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) 2515c91eab4bSThomas Abraham if (of_get_property(np, of_quirks[idx].quirk, NULL)) 2516c91eab4bSThomas Abraham pdata->quirks |= of_quirks[idx].id; 2517c91eab4bSThomas Abraham 2518c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 2519c91eab4bSThomas Abraham dev_info(dev, "fifo-depth property not found, using " 2520c91eab4bSThomas Abraham "value of FIFOTH register as default\n"); 2521c91eab4bSThomas Abraham 2522c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2523c91eab4bSThomas Abraham 25243c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 25253c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 25263c6d89eaSDoug Anderson 2527cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2528cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2529800d78bfSThomas Abraham if (ret) 2530800d78bfSThomas Abraham return ERR_PTR(ret); 2531800d78bfSThomas Abraham } 2532800d78bfSThomas Abraham 253310b49841SSeungwon Jeon if (of_find_property(np, "supports-highspeed", NULL)) 253410b49841SSeungwon Jeon pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; 253510b49841SSeungwon Jeon 2536c91eab4bSThomas Abraham return pdata; 2537c91eab4bSThomas Abraham } 2538c91eab4bSThomas Abraham 2539c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2540c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2541c91eab4bSThomas Abraham { 2542c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2543c91eab4bSThomas Abraham } 2544c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2545c91eab4bSThomas Abraham 254662ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 2547f95f3850SWill Newton { 2548e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 254962ca8034SShashidhar Hiremath int width, i, ret = 0; 2550f95f3850SWill Newton u32 fifo_size; 25511c2215b7SThomas Abraham int init_slots = 0; 2552f95f3850SWill Newton 2553c91eab4bSThomas Abraham if (!host->pdata) { 2554c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 2555c91eab4bSThomas Abraham if (IS_ERR(host->pdata)) { 2556c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 2557c91eab4bSThomas Abraham return -EINVAL; 2558c91eab4bSThomas Abraham } 2559f95f3850SWill Newton } 2560f95f3850SWill Newton 2561907abd51SJaehoon Chung if (host->pdata->num_slots > 1) { 25624a90920cSThomas Abraham dev_err(host->dev, 2563907abd51SJaehoon Chung "Platform data must supply num_slots.\n"); 256462ca8034SShashidhar Hiremath return -ENODEV; 2565f95f3850SWill Newton } 2566f95f3850SWill Newton 2567780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 2568f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 2569f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 2570f90a0612SThomas Abraham } else { 2571f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 2572f90a0612SThomas Abraham if (ret) { 2573f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 2574f90a0612SThomas Abraham return ret; 2575f90a0612SThomas Abraham } 2576f95f3850SWill Newton } 2577f95f3850SWill Newton 2578780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 2579f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 2580f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 25813c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 2582f90a0612SThomas Abraham } else { 2583f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 2584f90a0612SThomas Abraham if (ret) { 2585f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 2586f90a0612SThomas Abraham goto err_clk_biu; 2587f90a0612SThomas Abraham } 2588f90a0612SThomas Abraham 25893c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 25903c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 25913c6d89eaSDoug Anderson if (ret) 25923c6d89eaSDoug Anderson dev_warn(host->dev, 2593612de4c1SJaehoon Chung "Unable to set bus rate to %uHz\n", 25943c6d89eaSDoug Anderson host->pdata->bus_hz); 25953c6d89eaSDoug Anderson } 2596f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 25973c6d89eaSDoug Anderson } 2598f90a0612SThomas Abraham 2599612de4c1SJaehoon Chung if (!host->bus_hz) { 2600612de4c1SJaehoon Chung dev_err(host->dev, 2601612de4c1SJaehoon Chung "Platform data must supply bus speed\n"); 2602612de4c1SJaehoon Chung ret = -ENODEV; 2603612de4c1SJaehoon Chung goto err_clk_ciu; 2604612de4c1SJaehoon Chung } 2605612de4c1SJaehoon Chung 2606002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 2607002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 2608002f0d5cSYuvaraj Kumar C D if (ret) { 2609002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 2610002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 2611002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 2612002f0d5cSYuvaraj Kumar C D } 2613002f0d5cSYuvaraj Kumar C D } 2614002f0d5cSYuvaraj Kumar C D 2615cb27a843SJames Hogan if (drv_data && drv_data->setup_clock) { 2616cb27a843SJames Hogan ret = drv_data->setup_clock(host); 2617800d78bfSThomas Abraham if (ret) { 2618800d78bfSThomas Abraham dev_err(host->dev, 2619800d78bfSThomas Abraham "implementation specific clock setup failed\n"); 2620800d78bfSThomas Abraham goto err_clk_ciu; 2621800d78bfSThomas Abraham } 2622800d78bfSThomas Abraham } 2623800d78bfSThomas Abraham 262462ca8034SShashidhar Hiremath host->quirks = host->pdata->quirks; 2625f95f3850SWill Newton 2626f95f3850SWill Newton spin_lock_init(&host->lock); 2627f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 2628f95f3850SWill Newton 2629f95f3850SWill Newton /* 2630f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 2631f95f3850SWill Newton * the correct values. 2632f95f3850SWill Newton */ 2633f95f3850SWill Newton i = (mci_readl(host, HCON) >> 7) & 0x7; 2634f95f3850SWill Newton if (!i) { 2635f95f3850SWill Newton host->push_data = dw_mci_push_data16; 2636f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 2637f95f3850SWill Newton width = 16; 2638f95f3850SWill Newton host->data_shift = 1; 2639f95f3850SWill Newton } else if (i == 2) { 2640f95f3850SWill Newton host->push_data = dw_mci_push_data64; 2641f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 2642f95f3850SWill Newton width = 64; 2643f95f3850SWill Newton host->data_shift = 3; 2644f95f3850SWill Newton } else { 2645f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 2646f95f3850SWill Newton WARN((i != 1), 2647f95f3850SWill Newton "HCON reports a reserved host data width!\n" 2648f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 2649f95f3850SWill Newton host->push_data = dw_mci_push_data32; 2650f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 2651f95f3850SWill Newton width = 32; 2652f95f3850SWill Newton host->data_shift = 2; 2653f95f3850SWill Newton } 2654f95f3850SWill Newton 2655f95f3850SWill Newton /* Reset all blocks */ 26563a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) 2657141a712aSSeungwon Jeon return -ENODEV; 2658141a712aSSeungwon Jeon 2659141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 2660141a712aSSeungwon Jeon dw_mci_init_dma(host); 2661f95f3850SWill Newton 2662f95f3850SWill Newton /* Clear the interrupts for the host controller */ 2663f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2664f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2665f95f3850SWill Newton 2666f95f3850SWill Newton /* Put in max timeout */ 2667f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 2668f95f3850SWill Newton 2669f95f3850SWill Newton /* 2670f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 2671f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 2672f95f3850SWill Newton */ 2673b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 2674b86d8253SJames Hogan /* 2675b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 2676b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 2677b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 2678b86d8253SJames Hogan * should put it in the platform data. 2679b86d8253SJames Hogan */ 2680f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 26818234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 2682b86d8253SJames Hogan } else { 2683b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 2684b86d8253SJames Hogan } 2685b86d8253SJames Hogan host->fifo_depth = fifo_size; 268652426899SSeungwon Jeon host->fifoth_val = 268752426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 2688e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 2689f95f3850SWill Newton 2690f95f3850SWill Newton /* disable clock to CIU */ 2691f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2692f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2693f95f3850SWill Newton 269463008768SJames Hogan /* 269563008768SJames Hogan * In 2.40a spec, Data offset is changed. 269663008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 269763008768SJames Hogan */ 269863008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 269963008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 270063008768SJames Hogan 270163008768SJames Hogan if (host->verid < DW_MMC_240A) 270263008768SJames Hogan host->data_offset = DATA_OFFSET; 270363008768SJames Hogan else 270463008768SJames Hogan host->data_offset = DATA_240A_OFFSET; 270563008768SJames Hogan 2706f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 270795dcc2cbSThomas Abraham host->card_workqueue = alloc_workqueue("dw-mci-card", 270859ff3eb6SZhangZhen WQ_MEM_RECLAIM, 1); 2709ef7aef9aSWei Yongjun if (!host->card_workqueue) { 2710ef7aef9aSWei Yongjun ret = -ENOMEM; 27111791b13eSJames Hogan goto err_dmaunmap; 2712ef7aef9aSWei Yongjun } 27131791b13eSJames Hogan INIT_WORK(&host->card_work, dw_mci_work_routine_card); 2714780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 2715780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 2716f95f3850SWill Newton if (ret) 27171791b13eSJames Hogan goto err_workqueue; 2718f95f3850SWill Newton 2719f95f3850SWill Newton if (host->pdata->num_slots) 2720f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 2721f95f3850SWill Newton else 2722f95f3850SWill Newton host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; 2723f95f3850SWill Newton 27242da1d7f2SYuvaraj CD /* 27252da1d7f2SYuvaraj CD * Enable interrupts for command done, data over, data empty, card det, 27262da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 27272da1d7f2SYuvaraj CD */ 27282da1d7f2SYuvaraj CD mci_writel(host, RINTSTS, 0xFFFFFFFF); 27292da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 27302da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 27312da1d7f2SYuvaraj CD DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 27322da1d7f2SYuvaraj CD mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ 27332da1d7f2SYuvaraj CD 27342da1d7f2SYuvaraj CD dev_info(host->dev, "DW MMC controller at irq %d, " 27352da1d7f2SYuvaraj CD "%d bit host data width, " 27362da1d7f2SYuvaraj CD "%u deep fifo\n", 27372da1d7f2SYuvaraj CD host->irq, width, fifo_size); 27382da1d7f2SYuvaraj CD 2739f95f3850SWill Newton /* We need at least one slot to succeed */ 2740f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2741f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 27421c2215b7SThomas Abraham if (ret) 27431c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 27441c2215b7SThomas Abraham else 27451c2215b7SThomas Abraham init_slots++; 2746f95f3850SWill Newton } 27471c2215b7SThomas Abraham 27481c2215b7SThomas Abraham if (init_slots) { 27491c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 27501c2215b7SThomas Abraham } else { 27511c2215b7SThomas Abraham dev_dbg(host->dev, "attempted to initialize %d slots, " 27521c2215b7SThomas Abraham "but failed on all\n", host->num_slots); 2753780f22afSSeungwon Jeon goto err_workqueue; 2754f95f3850SWill Newton } 2755f95f3850SWill Newton 2756f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) 27574a90920cSThomas Abraham dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); 2758f95f3850SWill Newton 2759f95f3850SWill Newton return 0; 2760f95f3850SWill Newton 27611791b13eSJames Hogan err_workqueue: 276295dcc2cbSThomas Abraham destroy_workqueue(host->card_workqueue); 27631791b13eSJames Hogan 2764f95f3850SWill Newton err_dmaunmap: 2765f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2766f95f3850SWill Newton host->dma_ops->exit(host); 2767f90a0612SThomas Abraham 2768f90a0612SThomas Abraham err_clk_ciu: 2769780f22afSSeungwon Jeon if (!IS_ERR(host->ciu_clk)) 2770f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2771780f22afSSeungwon Jeon 2772f90a0612SThomas Abraham err_clk_biu: 2773780f22afSSeungwon Jeon if (!IS_ERR(host->biu_clk)) 2774f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2775780f22afSSeungwon Jeon 2776f95f3850SWill Newton return ret; 2777f95f3850SWill Newton } 277862ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 2779f95f3850SWill Newton 278062ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 2781f95f3850SWill Newton { 2782f95f3850SWill Newton int i; 2783f95f3850SWill Newton 2784f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2785f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2786f95f3850SWill Newton 2787f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 27884a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 2789f95f3850SWill Newton if (host->slot[i]) 2790f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 2791f95f3850SWill Newton } 2792f95f3850SWill Newton 2793f95f3850SWill Newton /* disable clock to CIU */ 2794f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2795f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2796f95f3850SWill Newton 279795dcc2cbSThomas Abraham destroy_workqueue(host->card_workqueue); 2798f95f3850SWill Newton 2799f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2800f95f3850SWill Newton host->dma_ops->exit(host); 2801f95f3850SWill Newton 2802f90a0612SThomas Abraham if (!IS_ERR(host->ciu_clk)) 2803f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2804780f22afSSeungwon Jeon 2805f90a0612SThomas Abraham if (!IS_ERR(host->biu_clk)) 2806f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2807f95f3850SWill Newton } 280862ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 280962ca8034SShashidhar Hiremath 281062ca8034SShashidhar Hiremath 2811f95f3850SWill Newton 28126fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP 2813f95f3850SWill Newton /* 2814f95f3850SWill Newton * TODO: we should probably disable the clock to the card in the suspend path. 2815f95f3850SWill Newton */ 281662ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host) 2817f95f3850SWill Newton { 2818f95f3850SWill Newton return 0; 2819f95f3850SWill Newton } 282062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend); 2821f95f3850SWill Newton 282262ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host) 2823f95f3850SWill Newton { 2824f95f3850SWill Newton int i, ret; 2825f95f3850SWill Newton 28263a33a94cSSonny Rao if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { 2827e61cf118SJaehoon Chung ret = -ENODEV; 2828e61cf118SJaehoon Chung return ret; 2829e61cf118SJaehoon Chung } 2830e61cf118SJaehoon Chung 28313bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 2832141a712aSSeungwon Jeon host->dma_ops->init(host); 2833141a712aSSeungwon Jeon 283452426899SSeungwon Jeon /* 283552426899SSeungwon Jeon * Restore the initial value at FIFOTH register 283652426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 283752426899SSeungwon Jeon */ 2838e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 283952426899SSeungwon Jeon host->prev_blksz = 0; 2840e61cf118SJaehoon Chung 28412eb2944fSDoug Anderson /* Put in max timeout */ 28422eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 28432eb2944fSDoug Anderson 2844e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 2845e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 2846e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 2847e61cf118SJaehoon Chung DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 2848e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 2849e61cf118SJaehoon Chung 2850f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2851f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 2852f95f3850SWill Newton if (!slot) 2853f95f3850SWill Newton continue; 2854ab269128SAbhilash Kesavan if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { 2855ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 2856ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 2857ab269128SAbhilash Kesavan } 2858f95f3850SWill Newton } 2859f95f3850SWill Newton return 0; 2860f95f3850SWill Newton } 286162ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume); 28626fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */ 28636fe8890dSJaehoon Chung 2864f95f3850SWill Newton static int __init dw_mci_init(void) 2865f95f3850SWill Newton { 28668e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 286762ca8034SShashidhar Hiremath return 0; 2868f95f3850SWill Newton } 2869f95f3850SWill Newton 2870f95f3850SWill Newton static void __exit dw_mci_exit(void) 2871f95f3850SWill Newton { 2872f95f3850SWill Newton } 2873f95f3850SWill Newton 2874f95f3850SWill Newton module_init(dw_mci_init); 2875f95f3850SWill Newton module_exit(dw_mci_exit); 2876f95f3850SWill Newton 2877f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 2878f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 2879f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 2880f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 2881