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*90c2143aSSeungwon Jeon #include <linux/mmc/sdio.h> 33f95f3850SWill Newton #include <linux/mmc/dw_mmc.h> 34f95f3850SWill Newton #include <linux/bitops.h> 35c07946a3SJaehoon Chung #include <linux/regulator/consumer.h> 361791b13eSJames Hogan #include <linux/workqueue.h> 37c91eab4bSThomas Abraham #include <linux/of.h> 3855a6ceb2SDoug Anderson #include <linux/of_gpio.h> 39f95f3850SWill Newton 40f95f3850SWill Newton #include "dw_mmc.h" 41f95f3850SWill Newton 42f95f3850SWill Newton /* Common flag combinations */ 433f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ 44f95f3850SWill Newton SDMMC_INT_HTO | SDMMC_INT_SBE | \ 45f95f3850SWill Newton SDMMC_INT_EBE) 46f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ 47f95f3850SWill Newton SDMMC_INT_RESP_ERR) 48f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \ 49f95f3850SWill Newton DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE) 50f95f3850SWill Newton #define DW_MCI_SEND_STATUS 1 51f95f3850SWill Newton #define DW_MCI_RECV_STATUS 2 52f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD 16 53f95f3850SWill Newton 541f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */ 551f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN 400000 /* unit: HZ */ 561f44a2a5SSeungwon Jeon 57f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 58fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ 59fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ 60fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ 61fc79a4d6SJoonyoung Shim SDMMC_IDMAC_INT_TI) 62fc79a4d6SJoonyoung Shim 63f95f3850SWill Newton struct idmac_desc { 64f95f3850SWill Newton u32 des0; /* Control Descriptor */ 65f95f3850SWill Newton #define IDMAC_DES0_DIC BIT(1) 66f95f3850SWill Newton #define IDMAC_DES0_LD BIT(2) 67f95f3850SWill Newton #define IDMAC_DES0_FD BIT(3) 68f95f3850SWill Newton #define IDMAC_DES0_CH BIT(4) 69f95f3850SWill Newton #define IDMAC_DES0_ER BIT(5) 70f95f3850SWill Newton #define IDMAC_DES0_CES BIT(30) 71f95f3850SWill Newton #define IDMAC_DES0_OWN BIT(31) 72f95f3850SWill Newton 73f95f3850SWill Newton u32 des1; /* Buffer sizes */ 74f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \ 759b7bbe10SShashidhar Hiremath ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) 76f95f3850SWill Newton 77f95f3850SWill Newton u32 des2; /* buffer 1 physical address */ 78f95f3850SWill Newton 79f95f3850SWill Newton u32 des3; /* buffer 2 physical address */ 80f95f3850SWill Newton }; 81f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 82f95f3850SWill Newton 830976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = { 840976f16dSSeungwon Jeon 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 850976f16dSSeungwon Jeon 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 860976f16dSSeungwon Jeon 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 870976f16dSSeungwon Jeon 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 880976f16dSSeungwon Jeon 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 890976f16dSSeungwon Jeon 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 900976f16dSSeungwon Jeon 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 910976f16dSSeungwon Jeon 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 920976f16dSSeungwon Jeon }; 93f95f3850SWill Newton 940976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = { 950976f16dSSeungwon Jeon 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 960976f16dSSeungwon Jeon 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 970976f16dSSeungwon Jeon 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 980976f16dSSeungwon Jeon 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 990976f16dSSeungwon Jeon 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 1000976f16dSSeungwon Jeon 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 1010976f16dSSeungwon Jeon 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 1020976f16dSSeungwon Jeon 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 1030976f16dSSeungwon Jeon 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 1040976f16dSSeungwon Jeon 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 1050976f16dSSeungwon Jeon 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 1060976f16dSSeungwon Jeon 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 1070976f16dSSeungwon Jeon 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 1080976f16dSSeungwon Jeon 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 1090976f16dSSeungwon Jeon 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 1100976f16dSSeungwon Jeon 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 111f95f3850SWill Newton }; 112f95f3850SWill Newton 113f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 114f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 115f95f3850SWill Newton { 116f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 117f95f3850SWill Newton struct mmc_request *mrq; 118f95f3850SWill Newton struct mmc_command *cmd; 119f95f3850SWill Newton struct mmc_command *stop; 120f95f3850SWill Newton struct mmc_data *data; 121f95f3850SWill Newton 122f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 123f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 124f95f3850SWill Newton mrq = slot->mrq; 125f95f3850SWill Newton 126f95f3850SWill Newton if (mrq) { 127f95f3850SWill Newton cmd = mrq->cmd; 128f95f3850SWill Newton data = mrq->data; 129f95f3850SWill Newton stop = mrq->stop; 130f95f3850SWill Newton 131f95f3850SWill Newton if (cmd) 132f95f3850SWill Newton seq_printf(s, 133f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 134f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 135f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 136f95f3850SWill Newton cmd->resp[2], cmd->error); 137f95f3850SWill Newton if (data) 138f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 139f95f3850SWill Newton data->bytes_xfered, data->blocks, 140f95f3850SWill Newton data->blksz, data->flags, data->error); 141f95f3850SWill Newton if (stop) 142f95f3850SWill Newton seq_printf(s, 143f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 144f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 145f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 146f95f3850SWill Newton stop->resp[2], stop->error); 147f95f3850SWill Newton } 148f95f3850SWill Newton 149f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 150f95f3850SWill Newton 151f95f3850SWill Newton return 0; 152f95f3850SWill Newton } 153f95f3850SWill Newton 154f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 155f95f3850SWill Newton { 156f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 157f95f3850SWill Newton } 158f95f3850SWill Newton 159f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 160f95f3850SWill Newton .owner = THIS_MODULE, 161f95f3850SWill Newton .open = dw_mci_req_open, 162f95f3850SWill Newton .read = seq_read, 163f95f3850SWill Newton .llseek = seq_lseek, 164f95f3850SWill Newton .release = single_release, 165f95f3850SWill Newton }; 166f95f3850SWill Newton 167f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 168f95f3850SWill Newton { 169f95f3850SWill Newton seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); 170f95f3850SWill Newton seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); 171f95f3850SWill Newton seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); 172f95f3850SWill Newton seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); 173f95f3850SWill Newton seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); 174f95f3850SWill Newton seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); 175f95f3850SWill Newton 176f95f3850SWill Newton return 0; 177f95f3850SWill Newton } 178f95f3850SWill Newton 179f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 180f95f3850SWill Newton { 181f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 182f95f3850SWill Newton } 183f95f3850SWill Newton 184f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 185f95f3850SWill Newton .owner = THIS_MODULE, 186f95f3850SWill Newton .open = dw_mci_regs_open, 187f95f3850SWill Newton .read = seq_read, 188f95f3850SWill Newton .llseek = seq_lseek, 189f95f3850SWill Newton .release = single_release, 190f95f3850SWill Newton }; 191f95f3850SWill Newton 192f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 193f95f3850SWill Newton { 194f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 195f95f3850SWill Newton struct dw_mci *host = slot->host; 196f95f3850SWill Newton struct dentry *root; 197f95f3850SWill Newton struct dentry *node; 198f95f3850SWill Newton 199f95f3850SWill Newton root = mmc->debugfs_root; 200f95f3850SWill Newton if (!root) 201f95f3850SWill Newton return; 202f95f3850SWill Newton 203f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 204f95f3850SWill Newton &dw_mci_regs_fops); 205f95f3850SWill Newton if (!node) 206f95f3850SWill Newton goto err; 207f95f3850SWill Newton 208f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 209f95f3850SWill Newton &dw_mci_req_fops); 210f95f3850SWill Newton if (!node) 211f95f3850SWill Newton goto err; 212f95f3850SWill Newton 213f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 214f95f3850SWill Newton if (!node) 215f95f3850SWill Newton goto err; 216f95f3850SWill Newton 217f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 218f95f3850SWill Newton (u32 *)&host->pending_events); 219f95f3850SWill Newton if (!node) 220f95f3850SWill Newton goto err; 221f95f3850SWill Newton 222f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 223f95f3850SWill Newton (u32 *)&host->completed_events); 224f95f3850SWill Newton if (!node) 225f95f3850SWill Newton goto err; 226f95f3850SWill Newton 227f95f3850SWill Newton return; 228f95f3850SWill Newton 229f95f3850SWill Newton err: 230f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 231f95f3850SWill Newton } 232f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 233f95f3850SWill Newton 234f95f3850SWill Newton static void dw_mci_set_timeout(struct dw_mci *host) 235f95f3850SWill Newton { 236f95f3850SWill Newton /* timeout (maximum) */ 237f95f3850SWill Newton mci_writel(host, TMOUT, 0xffffffff); 238f95f3850SWill Newton } 239f95f3850SWill Newton 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); 244e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 245f95f3850SWill Newton u32 cmdr; 246f95f3850SWill Newton cmd->error = -EINPROGRESS; 247f95f3850SWill Newton 248f95f3850SWill Newton cmdr = cmd->opcode; 249f95f3850SWill Newton 250*90c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 251*90c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 252*90c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 253*90c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 254*90c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 255f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 256f95f3850SWill Newton else 257*90c2143aSSeungwon Jeon if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 258f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 259f95f3850SWill Newton 260f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 261f95f3850SWill Newton /* We expect a response, so set this bit */ 262f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 263f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 264f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 265f95f3850SWill Newton } 266f95f3850SWill Newton 267f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 268f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 269f95f3850SWill Newton 270f95f3850SWill Newton data = cmd->data; 271f95f3850SWill Newton if (data) { 272f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 273f95f3850SWill Newton if (data->flags & MMC_DATA_STREAM) 274f95f3850SWill Newton cmdr |= SDMMC_CMD_STRM_MODE; 275f95f3850SWill Newton if (data->flags & MMC_DATA_WRITE) 276f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 277f95f3850SWill Newton } 278f95f3850SWill Newton 279cb27a843SJames Hogan if (drv_data && drv_data->prepare_command) 280cb27a843SJames Hogan drv_data->prepare_command(slot->host, &cmdr); 281800d78bfSThomas Abraham 282f95f3850SWill Newton return cmdr; 283f95f3850SWill Newton } 284f95f3850SWill Newton 285*90c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) 286*90c2143aSSeungwon Jeon { 287*90c2143aSSeungwon Jeon struct mmc_command *stop; 288*90c2143aSSeungwon Jeon u32 cmdr; 289*90c2143aSSeungwon Jeon 290*90c2143aSSeungwon Jeon if (!cmd->data) 291*90c2143aSSeungwon Jeon return 0; 292*90c2143aSSeungwon Jeon 293*90c2143aSSeungwon Jeon stop = &host->stop_abort; 294*90c2143aSSeungwon Jeon cmdr = cmd->opcode; 295*90c2143aSSeungwon Jeon memset(stop, 0, sizeof(struct mmc_command)); 296*90c2143aSSeungwon Jeon 297*90c2143aSSeungwon Jeon if (cmdr == MMC_READ_SINGLE_BLOCK || 298*90c2143aSSeungwon Jeon cmdr == MMC_READ_MULTIPLE_BLOCK || 299*90c2143aSSeungwon Jeon cmdr == MMC_WRITE_BLOCK || 300*90c2143aSSeungwon Jeon cmdr == MMC_WRITE_MULTIPLE_BLOCK) { 301*90c2143aSSeungwon Jeon stop->opcode = MMC_STOP_TRANSMISSION; 302*90c2143aSSeungwon Jeon stop->arg = 0; 303*90c2143aSSeungwon Jeon stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 304*90c2143aSSeungwon Jeon } else if (cmdr == SD_IO_RW_EXTENDED) { 305*90c2143aSSeungwon Jeon stop->opcode = SD_IO_RW_DIRECT; 306*90c2143aSSeungwon Jeon stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | 307*90c2143aSSeungwon Jeon ((cmd->arg >> 28) & 0x7); 308*90c2143aSSeungwon Jeon stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; 309*90c2143aSSeungwon Jeon } else { 310*90c2143aSSeungwon Jeon return 0; 311*90c2143aSSeungwon Jeon } 312*90c2143aSSeungwon Jeon 313*90c2143aSSeungwon Jeon cmdr = stop->opcode | SDMMC_CMD_STOP | 314*90c2143aSSeungwon Jeon SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; 315*90c2143aSSeungwon Jeon 316*90c2143aSSeungwon Jeon return cmdr; 317*90c2143aSSeungwon Jeon } 318*90c2143aSSeungwon Jeon 319f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 320f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 321f95f3850SWill Newton { 322f95f3850SWill Newton host->cmd = cmd; 3234a90920cSThomas Abraham dev_vdbg(host->dev, 324f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 325f95f3850SWill Newton cmd->arg, cmd_flags); 326f95f3850SWill Newton 327f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 328f95f3850SWill Newton wmb(); 329f95f3850SWill Newton 330f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 331f95f3850SWill Newton } 332f95f3850SWill Newton 333*90c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 334f95f3850SWill Newton { 335*90c2143aSSeungwon Jeon struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; 336*90c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 337f95f3850SWill Newton } 338f95f3850SWill Newton 339f95f3850SWill Newton /* DMA interface functions */ 340f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 341f95f3850SWill Newton { 34203e8cb53SJames Hogan if (host->using_dma) { 343f95f3850SWill Newton host->dma_ops->stop(host); 344f95f3850SWill Newton host->dma_ops->cleanup(host); 345f95f3850SWill Newton } else { 346f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 347f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 348f95f3850SWill Newton } 349f95f3850SWill Newton } 350f95f3850SWill Newton 3519aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 3529aa51408SSeungwon Jeon { 3539aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 3549aa51408SSeungwon Jeon return DMA_TO_DEVICE; 3559aa51408SSeungwon Jeon else 3569aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 3579aa51408SSeungwon Jeon } 3589aa51408SSeungwon Jeon 3599beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 360f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 361f95f3850SWill Newton { 362f95f3850SWill Newton struct mmc_data *data = host->data; 363f95f3850SWill Newton 364f95f3850SWill Newton if (data) 3659aa51408SSeungwon Jeon if (!data->host_cookie) 3664a90920cSThomas Abraham dma_unmap_sg(host->dev, 3679aa51408SSeungwon Jeon data->sg, 3689aa51408SSeungwon Jeon data->sg_len, 3699aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 370f95f3850SWill Newton } 371f95f3850SWill Newton 372f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 373f95f3850SWill Newton { 374f95f3850SWill Newton u32 temp; 375f95f3850SWill Newton 376f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 377f95f3850SWill Newton temp = mci_readl(host, CTRL); 378f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 379f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 380f95f3850SWill Newton mci_writel(host, CTRL, temp); 381f95f3850SWill Newton 382f95f3850SWill Newton /* Stop the IDMAC running */ 383f95f3850SWill Newton temp = mci_readl(host, BMOD); 384a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 385f95f3850SWill Newton mci_writel(host, BMOD, temp); 386f95f3850SWill Newton } 387f95f3850SWill Newton 388f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host) 389f95f3850SWill Newton { 390f95f3850SWill Newton struct mmc_data *data = host->data; 391f95f3850SWill Newton 3924a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 393f95f3850SWill Newton 394f95f3850SWill Newton host->dma_ops->cleanup(host); 395f95f3850SWill Newton 396f95f3850SWill Newton /* 397f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 398f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 399f95f3850SWill Newton */ 400f95f3850SWill Newton if (data) { 401f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 402f95f3850SWill Newton tasklet_schedule(&host->tasklet); 403f95f3850SWill Newton } 404f95f3850SWill Newton } 405f95f3850SWill Newton 406f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, 407f95f3850SWill Newton unsigned int sg_len) 408f95f3850SWill Newton { 409f95f3850SWill Newton int i; 410f95f3850SWill Newton struct idmac_desc *desc = host->sg_cpu; 411f95f3850SWill Newton 412f95f3850SWill Newton for (i = 0; i < sg_len; i++, desc++) { 413f95f3850SWill Newton unsigned int length = sg_dma_len(&data->sg[i]); 414f95f3850SWill Newton u32 mem_addr = sg_dma_address(&data->sg[i]); 415f95f3850SWill Newton 416f95f3850SWill Newton /* Set the OWN bit and disable interrupts for this descriptor */ 417f95f3850SWill Newton desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; 418f95f3850SWill Newton 419f95f3850SWill Newton /* Buffer length */ 420f95f3850SWill Newton IDMAC_SET_BUFFER1_SIZE(desc, length); 421f95f3850SWill Newton 422f95f3850SWill Newton /* Physical address to DMA to/from */ 423f95f3850SWill Newton desc->des2 = mem_addr; 424f95f3850SWill Newton } 425f95f3850SWill Newton 426f95f3850SWill Newton /* Set first descriptor */ 427f95f3850SWill Newton desc = host->sg_cpu; 428f95f3850SWill Newton desc->des0 |= IDMAC_DES0_FD; 429f95f3850SWill Newton 430f95f3850SWill Newton /* Set last descriptor */ 431f95f3850SWill Newton desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); 432f95f3850SWill Newton desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 433f95f3850SWill Newton desc->des0 |= IDMAC_DES0_LD; 434f95f3850SWill Newton 435f95f3850SWill Newton wmb(); 436f95f3850SWill Newton } 437f95f3850SWill Newton 438f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 439f95f3850SWill Newton { 440f95f3850SWill Newton u32 temp; 441f95f3850SWill Newton 442f95f3850SWill Newton dw_mci_translate_sglist(host, host->data, sg_len); 443f95f3850SWill Newton 444f95f3850SWill Newton /* Select IDMAC interface */ 445f95f3850SWill Newton temp = mci_readl(host, CTRL); 446f95f3850SWill Newton temp |= SDMMC_CTRL_USE_IDMAC; 447f95f3850SWill Newton mci_writel(host, CTRL, temp); 448f95f3850SWill Newton 449f95f3850SWill Newton wmb(); 450f95f3850SWill Newton 451f95f3850SWill Newton /* Enable the IDMAC */ 452f95f3850SWill Newton temp = mci_readl(host, BMOD); 453a5289a43SJaehoon Chung temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 454f95f3850SWill Newton mci_writel(host, BMOD, temp); 455f95f3850SWill Newton 456f95f3850SWill Newton /* Start it running */ 457f95f3850SWill Newton mci_writel(host, PLDMND, 1); 458f95f3850SWill Newton } 459f95f3850SWill Newton 460f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 461f95f3850SWill Newton { 462f95f3850SWill Newton struct idmac_desc *p; 463897b69e7SSeungwon Jeon int i; 464f95f3850SWill Newton 465f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 466f95f3850SWill Newton host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 467f95f3850SWill Newton 468f95f3850SWill Newton /* Forward link the descriptor list */ 469f95f3850SWill Newton for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) 470f95f3850SWill Newton p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); 471f95f3850SWill Newton 472f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 473f95f3850SWill Newton p->des3 = host->sg_dma; 474f95f3850SWill Newton p->des0 = IDMAC_DES0_ER; 475f95f3850SWill Newton 476141a712aSSeungwon Jeon mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET); 477141a712aSSeungwon Jeon 478f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 479fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 480f95f3850SWill Newton mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | 481f95f3850SWill Newton SDMMC_IDMAC_INT_TI); 482f95f3850SWill Newton 483f95f3850SWill Newton /* Set the descriptor base address */ 484f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 485f95f3850SWill Newton return 0; 486f95f3850SWill Newton } 487f95f3850SWill Newton 4888e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 489885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 490885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 491885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 492885c3e80SSeungwon Jeon .complete = dw_mci_idmac_complete_dma, 493885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 494885c3e80SSeungwon Jeon }; 495885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */ 496885c3e80SSeungwon Jeon 4979aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 4989aa51408SSeungwon Jeon struct mmc_data *data, 4999aa51408SSeungwon Jeon bool next) 500f95f3850SWill Newton { 501f95f3850SWill Newton struct scatterlist *sg; 5029aa51408SSeungwon Jeon unsigned int i, sg_len; 503f95f3850SWill Newton 5049aa51408SSeungwon Jeon if (!next && data->host_cookie) 5059aa51408SSeungwon Jeon return data->host_cookie; 506f95f3850SWill Newton 507f95f3850SWill Newton /* 508f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 509f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 510f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 511f95f3850SWill Newton */ 512f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 513f95f3850SWill Newton return -EINVAL; 5149aa51408SSeungwon Jeon 515f95f3850SWill Newton if (data->blksz & 3) 516f95f3850SWill Newton return -EINVAL; 517f95f3850SWill Newton 518f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 519f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 520f95f3850SWill Newton return -EINVAL; 521f95f3850SWill Newton } 522f95f3850SWill Newton 5234a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 5249aa51408SSeungwon Jeon data->sg, 5259aa51408SSeungwon Jeon data->sg_len, 5269aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 5279aa51408SSeungwon Jeon if (sg_len == 0) 5289aa51408SSeungwon Jeon return -EINVAL; 5299aa51408SSeungwon Jeon 5309aa51408SSeungwon Jeon if (next) 5319aa51408SSeungwon Jeon data->host_cookie = sg_len; 5329aa51408SSeungwon Jeon 5339aa51408SSeungwon Jeon return sg_len; 5349aa51408SSeungwon Jeon } 5359aa51408SSeungwon Jeon 5369aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 5379aa51408SSeungwon Jeon struct mmc_request *mrq, 5389aa51408SSeungwon Jeon bool is_first_req) 5399aa51408SSeungwon Jeon { 5409aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 5419aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 5429aa51408SSeungwon Jeon 5439aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 5449aa51408SSeungwon Jeon return; 5459aa51408SSeungwon Jeon 5469aa51408SSeungwon Jeon if (data->host_cookie) { 5479aa51408SSeungwon Jeon data->host_cookie = 0; 5489aa51408SSeungwon Jeon return; 5499aa51408SSeungwon Jeon } 5509aa51408SSeungwon Jeon 5519aa51408SSeungwon Jeon if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) 5529aa51408SSeungwon Jeon data->host_cookie = 0; 5539aa51408SSeungwon Jeon } 5549aa51408SSeungwon Jeon 5559aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 5569aa51408SSeungwon Jeon struct mmc_request *mrq, 5579aa51408SSeungwon Jeon int err) 5589aa51408SSeungwon Jeon { 5599aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 5609aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 5619aa51408SSeungwon Jeon 5629aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 5639aa51408SSeungwon Jeon return; 5649aa51408SSeungwon Jeon 5659aa51408SSeungwon Jeon if (data->host_cookie) 5664a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 5679aa51408SSeungwon Jeon data->sg, 5689aa51408SSeungwon Jeon data->sg_len, 5699aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 5709aa51408SSeungwon Jeon data->host_cookie = 0; 5719aa51408SSeungwon Jeon } 5729aa51408SSeungwon Jeon 57352426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 57452426899SSeungwon Jeon { 57552426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC 57652426899SSeungwon Jeon unsigned int blksz = data->blksz; 57752426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 57852426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 57952426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 58052426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 58152426899SSeungwon Jeon int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1; 58252426899SSeungwon Jeon 58352426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 58452426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 58552426899SSeungwon Jeon 58652426899SSeungwon Jeon /* 58752426899SSeungwon Jeon * MSIZE is '1', 58852426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 58952426899SSeungwon Jeon */ 59052426899SSeungwon Jeon if (blksz % fifo_width) { 59152426899SSeungwon Jeon msize = 0; 59252426899SSeungwon Jeon rx_wmark = 1; 59352426899SSeungwon Jeon goto done; 59452426899SSeungwon Jeon } 59552426899SSeungwon Jeon 59652426899SSeungwon Jeon do { 59752426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 59852426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 59952426899SSeungwon Jeon msize = idx; 60052426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 60152426899SSeungwon Jeon break; 60252426899SSeungwon Jeon } 60352426899SSeungwon Jeon } while (--idx > 0); 60452426899SSeungwon Jeon /* 60552426899SSeungwon Jeon * If idx is '0', it won't be tried 60652426899SSeungwon Jeon * Thus, initial values are uesed 60752426899SSeungwon Jeon */ 60852426899SSeungwon Jeon done: 60952426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 61052426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 61152426899SSeungwon Jeon #endif 61252426899SSeungwon Jeon } 61352426899SSeungwon Jeon 614f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) 615f1d2736cSSeungwon Jeon { 616f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 617f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 618f1d2736cSSeungwon Jeon u16 thld_size; 619f1d2736cSSeungwon Jeon 620f1d2736cSSeungwon Jeon WARN_ON(!(data->flags & MMC_DATA_READ)); 621f1d2736cSSeungwon Jeon 622f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 623f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 624f1d2736cSSeungwon Jeon goto disable; 625f1d2736cSSeungwon Jeon 626f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 627f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 628f1d2736cSSeungwon Jeon 629f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 630f1d2736cSSeungwon Jeon goto disable; 631f1d2736cSSeungwon Jeon 632f1d2736cSSeungwon Jeon /* 633f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 634f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 635f1d2736cSSeungwon Jeon * Currently just choose blksz. 636f1d2736cSSeungwon Jeon */ 637f1d2736cSSeungwon Jeon thld_size = blksz; 638f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1)); 639f1d2736cSSeungwon Jeon return; 640f1d2736cSSeungwon Jeon 641f1d2736cSSeungwon Jeon disable: 642f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0)); 643f1d2736cSSeungwon Jeon } 644f1d2736cSSeungwon Jeon 6459aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 6469aa51408SSeungwon Jeon { 6479aa51408SSeungwon Jeon int sg_len; 6489aa51408SSeungwon Jeon u32 temp; 6499aa51408SSeungwon Jeon 6509aa51408SSeungwon Jeon host->using_dma = 0; 6519aa51408SSeungwon Jeon 6529aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 6539aa51408SSeungwon Jeon if (!host->use_dma) 6549aa51408SSeungwon Jeon return -ENODEV; 6559aa51408SSeungwon Jeon 6569aa51408SSeungwon Jeon sg_len = dw_mci_pre_dma_transfer(host, data, 0); 657a99aa9b9SSeungwon Jeon if (sg_len < 0) { 658a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 6599aa51408SSeungwon Jeon return sg_len; 660a99aa9b9SSeungwon Jeon } 6619aa51408SSeungwon Jeon 66203e8cb53SJames Hogan host->using_dma = 1; 66303e8cb53SJames Hogan 6644a90920cSThomas Abraham dev_vdbg(host->dev, 665f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 666f95f3850SWill Newton (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, 667f95f3850SWill Newton sg_len); 668f95f3850SWill Newton 66952426899SSeungwon Jeon /* 67052426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 67152426899SSeungwon Jeon * If current block size is same with previous size, 67252426899SSeungwon Jeon * no need to update fifoth. 67352426899SSeungwon Jeon */ 67452426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 67552426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 67652426899SSeungwon Jeon 677f95f3850SWill Newton /* Enable the DMA interface */ 678f95f3850SWill Newton temp = mci_readl(host, CTRL); 679f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 680f95f3850SWill Newton mci_writel(host, CTRL, temp); 681f95f3850SWill Newton 682f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 683f95f3850SWill Newton temp = mci_readl(host, INTMASK); 684f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 685f95f3850SWill Newton mci_writel(host, INTMASK, temp); 686f95f3850SWill Newton 687f95f3850SWill Newton host->dma_ops->start(host, sg_len); 688f95f3850SWill Newton 689f95f3850SWill Newton return 0; 690f95f3850SWill Newton } 691f95f3850SWill Newton 692f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 693f95f3850SWill Newton { 694f95f3850SWill Newton u32 temp; 695f95f3850SWill Newton 696f95f3850SWill Newton data->error = -EINPROGRESS; 697f95f3850SWill Newton 698f95f3850SWill Newton WARN_ON(host->data); 699f95f3850SWill Newton host->sg = NULL; 700f95f3850SWill Newton host->data = data; 701f95f3850SWill Newton 702f1d2736cSSeungwon Jeon if (data->flags & MMC_DATA_READ) { 70355c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 704f1d2736cSSeungwon Jeon dw_mci_ctrl_rd_thld(host, data); 705f1d2736cSSeungwon Jeon } else { 70655c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 707f1d2736cSSeungwon Jeon } 70855c5efbcSJames Hogan 709f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 710f9c2a0dcSSeungwon Jeon int flags = SG_MITER_ATOMIC; 711f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 712f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 713f9c2a0dcSSeungwon Jeon else 714f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 715f9c2a0dcSSeungwon Jeon 716f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 717f95f3850SWill Newton host->sg = data->sg; 71834b664a2SJames Hogan host->part_buf_start = 0; 71934b664a2SJames Hogan host->part_buf_count = 0; 720f95f3850SWill Newton 721b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 722f95f3850SWill Newton temp = mci_readl(host, INTMASK); 723f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 724f95f3850SWill Newton mci_writel(host, INTMASK, temp); 725f95f3850SWill Newton 726f95f3850SWill Newton temp = mci_readl(host, CTRL); 727f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 728f95f3850SWill Newton mci_writel(host, CTRL, temp); 72952426899SSeungwon Jeon 73052426899SSeungwon Jeon /* 73152426899SSeungwon Jeon * Use the initial fifoth_val for PIO mode. 73252426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 73352426899SSeungwon Jeon * prev_blksz should be invalidated. 73452426899SSeungwon Jeon */ 73552426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 73652426899SSeungwon Jeon host->prev_blksz = 0; 73752426899SSeungwon Jeon } else { 73852426899SSeungwon Jeon /* 73952426899SSeungwon Jeon * Keep the current block size. 74052426899SSeungwon Jeon * It will be used to decide whether to update 74152426899SSeungwon Jeon * fifoth register next time. 74252426899SSeungwon Jeon */ 74352426899SSeungwon Jeon host->prev_blksz = data->blksz; 744f95f3850SWill Newton } 745f95f3850SWill Newton } 746f95f3850SWill Newton 747f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 748f95f3850SWill Newton { 749f95f3850SWill Newton struct dw_mci *host = slot->host; 750f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 751f95f3850SWill Newton unsigned int cmd_status = 0; 752f95f3850SWill Newton 753f95f3850SWill Newton mci_writel(host, CMDARG, arg); 754f95f3850SWill Newton wmb(); 755f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 756f95f3850SWill Newton 757f95f3850SWill Newton while (time_before(jiffies, timeout)) { 758f95f3850SWill Newton cmd_status = mci_readl(host, CMD); 759f95f3850SWill Newton if (!(cmd_status & SDMMC_CMD_START)) 760f95f3850SWill Newton return; 761f95f3850SWill Newton } 762f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 763f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 764f95f3850SWill Newton cmd, arg, cmd_status); 765f95f3850SWill Newton } 766f95f3850SWill Newton 767ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 768f95f3850SWill Newton { 769f95f3850SWill Newton struct dw_mci *host = slot->host; 770fdf492a1SDoug Anderson unsigned int clock = slot->clock; 771f95f3850SWill Newton u32 div; 7729623b5b9SDoug Anderson u32 clk_en_a; 773f95f3850SWill Newton 774fdf492a1SDoug Anderson if (!clock) { 775fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 776fdf492a1SDoug Anderson mci_send_cmd(slot, 777fdf492a1SDoug Anderson SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 778fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 779fdf492a1SDoug Anderson div = host->bus_hz / clock; 780fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 781f95f3850SWill Newton /* 782f95f3850SWill Newton * move the + 1 after the divide to prevent 783f95f3850SWill Newton * over-clocking the card. 784f95f3850SWill Newton */ 785e419990bSSeungwon Jeon div += 1; 786e419990bSSeungwon Jeon 787fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 788f95f3850SWill Newton 789fdf492a1SDoug Anderson if ((clock << div) != slot->__clk_old || force_clkinit) 790f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 791fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 792fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 793fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 794fdf492a1SDoug Anderson host->bus_hz, div); 795f95f3850SWill Newton 796f95f3850SWill Newton /* disable clock */ 797f95f3850SWill Newton mci_writel(host, CLKENA, 0); 798f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 799f95f3850SWill Newton 800f95f3850SWill Newton /* inform CIU */ 801f95f3850SWill Newton mci_send_cmd(slot, 802f95f3850SWill Newton SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 803f95f3850SWill Newton 804f95f3850SWill Newton /* set clock to desired speed */ 805f95f3850SWill Newton mci_writel(host, CLKDIV, div); 806f95f3850SWill Newton 807f95f3850SWill Newton /* inform CIU */ 808f95f3850SWill Newton mci_send_cmd(slot, 809f95f3850SWill Newton SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 810f95f3850SWill Newton 8119623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 8129623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 8139623b5b9SDoug Anderson if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) 8149623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 8159623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 816f95f3850SWill Newton 817f95f3850SWill Newton /* inform CIU */ 818f95f3850SWill Newton mci_send_cmd(slot, 819f95f3850SWill Newton SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 820f95f3850SWill Newton 821fdf492a1SDoug Anderson /* keep the clock with reflecting clock dividor */ 822fdf492a1SDoug Anderson slot->__clk_old = clock << div; 823f95f3850SWill Newton } 824f95f3850SWill Newton 825fdf492a1SDoug Anderson host->current_speed = clock; 826fdf492a1SDoug Anderson 827f95f3850SWill Newton /* Set the current slot bus width */ 8281d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 829f95f3850SWill Newton } 830f95f3850SWill Newton 831053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 832053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 833053b3ce6SSeungwon Jeon struct mmc_command *cmd) 834f95f3850SWill Newton { 835f95f3850SWill Newton struct mmc_request *mrq; 836f95f3850SWill Newton struct mmc_data *data; 837f95f3850SWill Newton u32 cmdflags; 838f95f3850SWill Newton 839f95f3850SWill Newton mrq = slot->mrq; 840f95f3850SWill Newton if (host->pdata->select_slot) 841f95f3850SWill Newton host->pdata->select_slot(slot->id); 842f95f3850SWill Newton 843f95f3850SWill Newton host->cur_slot = slot; 844f95f3850SWill Newton host->mrq = mrq; 845f95f3850SWill Newton 846f95f3850SWill Newton host->pending_events = 0; 847f95f3850SWill Newton host->completed_events = 0; 848f95f3850SWill Newton host->data_status = 0; 849f95f3850SWill Newton 850053b3ce6SSeungwon Jeon data = cmd->data; 851f95f3850SWill Newton if (data) { 852f95f3850SWill Newton dw_mci_set_timeout(host); 853f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 854f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 855f95f3850SWill Newton } 856f95f3850SWill Newton 857f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 858f95f3850SWill Newton 859f95f3850SWill Newton /* this is the first command, send the initialization clock */ 860f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 861f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 862f95f3850SWill Newton 863f95f3850SWill Newton if (data) { 864f95f3850SWill Newton dw_mci_submit_data(host, data); 865f95f3850SWill Newton wmb(); 866f95f3850SWill Newton } 867f95f3850SWill Newton 868f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 869f95f3850SWill Newton 870f95f3850SWill Newton if (mrq->stop) 871f95f3850SWill Newton host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 872*90c2143aSSeungwon Jeon else 873*90c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 874f95f3850SWill Newton } 875f95f3850SWill Newton 876053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 877053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 878053b3ce6SSeungwon Jeon { 879053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 880053b3ce6SSeungwon Jeon struct mmc_command *cmd; 881053b3ce6SSeungwon Jeon 882053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 883053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 884053b3ce6SSeungwon Jeon } 885053b3ce6SSeungwon Jeon 8867456caaeSJames Hogan /* must be called with host->lock held */ 887f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 888f95f3850SWill Newton struct mmc_request *mrq) 889f95f3850SWill Newton { 890f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 891f95f3850SWill Newton host->state); 892f95f3850SWill Newton 893f95f3850SWill Newton slot->mrq = mrq; 894f95f3850SWill Newton 895f95f3850SWill Newton if (host->state == STATE_IDLE) { 896f95f3850SWill Newton host->state = STATE_SENDING_CMD; 897f95f3850SWill Newton dw_mci_start_request(host, slot); 898f95f3850SWill Newton } else { 899f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 900f95f3850SWill Newton } 901f95f3850SWill Newton } 902f95f3850SWill Newton 903f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 904f95f3850SWill Newton { 905f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 906f95f3850SWill Newton struct dw_mci *host = slot->host; 907f95f3850SWill Newton 908f95f3850SWill Newton WARN_ON(slot->mrq); 909f95f3850SWill Newton 9107456caaeSJames Hogan /* 9117456caaeSJames Hogan * The check for card presence and queueing of the request must be 9127456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 9137456caaeSJames Hogan * request wouldn't fail until another card was inserted. 9147456caaeSJames Hogan */ 9157456caaeSJames Hogan spin_lock_bh(&host->lock); 9167456caaeSJames Hogan 917f95f3850SWill Newton if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { 9187456caaeSJames Hogan spin_unlock_bh(&host->lock); 919f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 920f95f3850SWill Newton mmc_request_done(mmc, mrq); 921f95f3850SWill Newton return; 922f95f3850SWill Newton } 923f95f3850SWill Newton 924f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 9257456caaeSJames Hogan 9267456caaeSJames Hogan spin_unlock_bh(&host->lock); 927f95f3850SWill Newton } 928f95f3850SWill Newton 929f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 930f95f3850SWill Newton { 931f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 932e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 93341babf75SJaehoon Chung u32 regs; 934f95f3850SWill Newton 935f95f3850SWill Newton switch (ios->bus_width) { 936f95f3850SWill Newton case MMC_BUS_WIDTH_4: 937f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 938f95f3850SWill Newton break; 939c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 940c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 941c9b2a06fSJaehoon Chung break; 942b2f7cb45SJaehoon Chung default: 943b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 944b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 945f95f3850SWill Newton } 946f95f3850SWill Newton 94741babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 9483f514291SSeungwon Jeon 9493f514291SSeungwon Jeon /* DDR mode set */ 9503f514291SSeungwon Jeon if (ios->timing == MMC_TIMING_UHS_DDR50) 951c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 9523f514291SSeungwon Jeon else 953c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 9543f514291SSeungwon Jeon 95541babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 956f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 95741babf75SJaehoon Chung 958f95f3850SWill Newton /* 959f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 960f95f3850SWill Newton * core ios update when finding the minimum. 961f95f3850SWill Newton */ 962f95f3850SWill Newton slot->clock = ios->clock; 963f95f3850SWill Newton 964cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 965cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 966800d78bfSThomas Abraham 967bf7cb224SJaehoon Chung /* Slot specific timing and width adjustment */ 968bf7cb224SJaehoon Chung dw_mci_setup_bus(slot, false); 969bf7cb224SJaehoon Chung 970f95f3850SWill Newton switch (ios->power_mode) { 971f95f3850SWill Newton case MMC_POWER_UP: 972f95f3850SWill Newton set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 973e6f34e2fSJames Hogan /* Power up slot */ 974e6f34e2fSJames Hogan if (slot->host->pdata->setpower) 975e6f34e2fSJames Hogan slot->host->pdata->setpower(slot->id, mmc->ocr_avail); 9764366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 9774366dcc5SJaehoon Chung regs |= (1 << slot->id); 9784366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 979e6f34e2fSJames Hogan break; 980e6f34e2fSJames Hogan case MMC_POWER_OFF: 981e6f34e2fSJames Hogan /* Power down slot */ 982e6f34e2fSJames Hogan if (slot->host->pdata->setpower) 983e6f34e2fSJames Hogan slot->host->pdata->setpower(slot->id, 0); 9844366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 9854366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 9864366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 987f95f3850SWill Newton break; 988f95f3850SWill Newton default: 989f95f3850SWill Newton break; 990f95f3850SWill Newton } 991f95f3850SWill Newton } 992f95f3850SWill Newton 993f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 994f95f3850SWill Newton { 995f95f3850SWill Newton int read_only; 996f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 997f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 998f95f3850SWill Newton 999f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 10009640639bSDoug Anderson if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) 1001b4967aa5SThomas Abraham read_only = 0; 1002b4967aa5SThomas Abraham else if (brd->get_ro) 1003f95f3850SWill Newton read_only = brd->get_ro(slot->id); 100455a6ceb2SDoug Anderson else if (gpio_is_valid(slot->wp_gpio)) 100555a6ceb2SDoug Anderson read_only = gpio_get_value(slot->wp_gpio); 1006f95f3850SWill Newton else 1007f95f3850SWill Newton read_only = 1008f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1009f95f3850SWill Newton 1010f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1011f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1012f95f3850SWill Newton 1013f95f3850SWill Newton return read_only; 1014f95f3850SWill Newton } 1015f95f3850SWill Newton 1016f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1017f95f3850SWill Newton { 1018f95f3850SWill Newton int present; 1019f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1020f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 1021f95f3850SWill Newton 1022f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 1023fc3d7720SJaehoon Chung if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) 1024fc3d7720SJaehoon Chung present = 1; 1025fc3d7720SJaehoon Chung else if (brd->get_cd) 1026f95f3850SWill Newton present = !brd->get_cd(slot->id); 1027f95f3850SWill Newton else 1028f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1029f95f3850SWill Newton == 0 ? 1 : 0; 1030f95f3850SWill Newton 1031f95f3850SWill Newton if (present) 1032f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 1033f95f3850SWill Newton else 1034f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 1035f95f3850SWill Newton 1036f95f3850SWill Newton return present; 1037f95f3850SWill Newton } 1038f95f3850SWill Newton 10399623b5b9SDoug Anderson /* 10409623b5b9SDoug Anderson * Disable lower power mode. 10419623b5b9SDoug Anderson * 10429623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 10439623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 10449623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 10459623b5b9SDoug Anderson * 10469623b5b9SDoug Anderson * This function is fast if low power mode is already disabled. 10479623b5b9SDoug Anderson */ 10489623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot) 10499623b5b9SDoug Anderson { 10509623b5b9SDoug Anderson struct dw_mci *host = slot->host; 10519623b5b9SDoug Anderson u32 clk_en_a; 10529623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 10539623b5b9SDoug Anderson 10549623b5b9SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 10559623b5b9SDoug Anderson 10569623b5b9SDoug Anderson if (clk_en_a & clken_low_pwr) { 10579623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); 10589623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 10599623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 10609623b5b9SDoug Anderson } 10619623b5b9SDoug Anderson } 10629623b5b9SDoug Anderson 10631a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 10641a5c8e1fSShashidhar Hiremath { 10651a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 10661a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 10671a5c8e1fSShashidhar Hiremath u32 int_mask; 10681a5c8e1fSShashidhar Hiremath 10691a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 10701a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 10711a5c8e1fSShashidhar Hiremath if (enb) { 10729623b5b9SDoug Anderson /* 10739623b5b9SDoug Anderson * Turn off low power mode if it was enabled. This is a bit of 10749623b5b9SDoug Anderson * a heavy operation and we disable / enable IRQs a lot, so 10759623b5b9SDoug Anderson * we'll leave low power mode disabled and it will get 10769623b5b9SDoug Anderson * re-enabled again in dw_mci_setup_bus(). 10779623b5b9SDoug Anderson */ 10789623b5b9SDoug Anderson dw_mci_disable_low_power(slot); 10799623b5b9SDoug Anderson 10801a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 1081705ad047SKyoungil Kim (int_mask | SDMMC_INT_SDIO(slot->id))); 10821a5c8e1fSShashidhar Hiremath } else { 10831a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 1084705ad047SKyoungil Kim (int_mask & ~SDMMC_INT_SDIO(slot->id))); 10851a5c8e1fSShashidhar Hiremath } 10861a5c8e1fSShashidhar Hiremath } 10871a5c8e1fSShashidhar Hiremath 10880976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 10890976f16dSSeungwon Jeon { 10900976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 10910976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 10920976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 10930976f16dSSeungwon Jeon struct dw_mci_tuning_data tuning_data; 10940976f16dSSeungwon Jeon int err = -ENOSYS; 10950976f16dSSeungwon Jeon 10960976f16dSSeungwon Jeon if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { 10970976f16dSSeungwon Jeon if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { 10980976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_8bit; 10990976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); 11000976f16dSSeungwon Jeon } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { 11010976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 11020976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 11030976f16dSSeungwon Jeon } else { 11040976f16dSSeungwon Jeon return -EINVAL; 11050976f16dSSeungwon Jeon } 11060976f16dSSeungwon Jeon } else if (opcode == MMC_SEND_TUNING_BLOCK) { 11070976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 11080976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 11090976f16dSSeungwon Jeon } else { 11100976f16dSSeungwon Jeon dev_err(host->dev, 11110976f16dSSeungwon Jeon "Undefined command(%d) for tuning\n", opcode); 11120976f16dSSeungwon Jeon return -EINVAL; 11130976f16dSSeungwon Jeon } 11140976f16dSSeungwon Jeon 11150976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 11160976f16dSSeungwon Jeon err = drv_data->execute_tuning(slot, opcode, &tuning_data); 11170976f16dSSeungwon Jeon return err; 11180976f16dSSeungwon Jeon } 11190976f16dSSeungwon Jeon 1120f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1121f95f3850SWill Newton .request = dw_mci_request, 11229aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 11239aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1124f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1125f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1126f95f3850SWill Newton .get_cd = dw_mci_get_cd, 11271a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 11280976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 1129f95f3850SWill Newton }; 1130f95f3850SWill Newton 1131f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1132f95f3850SWill Newton __releases(&host->lock) 1133f95f3850SWill Newton __acquires(&host->lock) 1134f95f3850SWill Newton { 1135f95f3850SWill Newton struct dw_mci_slot *slot; 1136f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1137f95f3850SWill Newton 1138f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1139f95f3850SWill Newton 1140f95f3850SWill Newton host->cur_slot->mrq = NULL; 1141f95f3850SWill Newton host->mrq = NULL; 1142f95f3850SWill Newton if (!list_empty(&host->queue)) { 1143f95f3850SWill Newton slot = list_entry(host->queue.next, 1144f95f3850SWill Newton struct dw_mci_slot, queue_node); 1145f95f3850SWill Newton list_del(&slot->queue_node); 11464a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1147f95f3850SWill Newton mmc_hostname(slot->mmc)); 1148f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1149f95f3850SWill Newton dw_mci_start_request(host, slot); 1150f95f3850SWill Newton } else { 11514a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 1152f95f3850SWill Newton host->state = STATE_IDLE; 1153f95f3850SWill Newton } 1154f95f3850SWill Newton 1155f95f3850SWill Newton spin_unlock(&host->lock); 1156f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1157f95f3850SWill Newton spin_lock(&host->lock); 1158f95f3850SWill Newton } 1159f95f3850SWill Newton 1160f95f3850SWill Newton static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1161f95f3850SWill Newton { 1162f95f3850SWill Newton u32 status = host->cmd_status; 1163f95f3850SWill Newton 1164f95f3850SWill Newton host->cmd_status = 0; 1165f95f3850SWill Newton 1166f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1167f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1168f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1169f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1170f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1171f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1172f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1173f95f3850SWill Newton } else { 1174f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1175f95f3850SWill Newton cmd->resp[1] = 0; 1176f95f3850SWill Newton cmd->resp[2] = 0; 1177f95f3850SWill Newton cmd->resp[3] = 0; 1178f95f3850SWill Newton } 1179f95f3850SWill Newton } 1180f95f3850SWill Newton 1181f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1182f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1183f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1184f95f3850SWill Newton cmd->error = -EILSEQ; 1185f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1186f95f3850SWill Newton cmd->error = -EIO; 1187f95f3850SWill Newton else 1188f95f3850SWill Newton cmd->error = 0; 1189f95f3850SWill Newton 1190f95f3850SWill Newton if (cmd->error) { 1191f95f3850SWill Newton /* newer ip versions need a delay between retries */ 1192f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) 1193f95f3850SWill Newton mdelay(20); 1194f95f3850SWill Newton } 1195f95f3850SWill Newton } 1196f95f3850SWill Newton 1197f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1198f95f3850SWill Newton { 1199f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1200f95f3850SWill Newton struct mmc_data *data; 1201f95f3850SWill Newton struct mmc_command *cmd; 1202f95f3850SWill Newton enum dw_mci_state state; 1203f95f3850SWill Newton enum dw_mci_state prev_state; 120494dd5b33SJames Hogan u32 status, ctrl; 1205f95f3850SWill Newton 1206f95f3850SWill Newton spin_lock(&host->lock); 1207f95f3850SWill Newton 1208f95f3850SWill Newton state = host->state; 1209f95f3850SWill Newton data = host->data; 1210f95f3850SWill Newton 1211f95f3850SWill Newton do { 1212f95f3850SWill Newton prev_state = state; 1213f95f3850SWill Newton 1214f95f3850SWill Newton switch (state) { 1215f95f3850SWill Newton case STATE_IDLE: 1216f95f3850SWill Newton break; 1217f95f3850SWill Newton 1218f95f3850SWill Newton case STATE_SENDING_CMD: 1219f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1220f95f3850SWill Newton &host->pending_events)) 1221f95f3850SWill Newton break; 1222f95f3850SWill Newton 1223f95f3850SWill Newton cmd = host->cmd; 1224f95f3850SWill Newton host->cmd = NULL; 1225f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1226053b3ce6SSeungwon Jeon dw_mci_command_complete(host, cmd); 1227053b3ce6SSeungwon Jeon if (cmd == host->mrq->sbc && !cmd->error) { 1228053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1229053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1230053b3ce6SSeungwon Jeon host->mrq->cmd); 1231053b3ce6SSeungwon Jeon goto unlock; 1232053b3ce6SSeungwon Jeon } 1233053b3ce6SSeungwon Jeon 123471abb133SSeungwon Jeon if (cmd->data && cmd->error) { 123571abb133SSeungwon Jeon dw_mci_stop_dma(host); 1236*90c2143aSSeungwon Jeon send_stop_abort(host, data); 123771abb133SSeungwon Jeon state = STATE_SENDING_STOP; 123871abb133SSeungwon Jeon break; 123971abb133SSeungwon Jeon } 124071abb133SSeungwon Jeon 1241f95f3850SWill Newton if (!host->mrq->data || cmd->error) { 1242f95f3850SWill Newton dw_mci_request_end(host, host->mrq); 1243f95f3850SWill Newton goto unlock; 1244f95f3850SWill Newton } 1245f95f3850SWill Newton 1246f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1247f95f3850SWill Newton /* fall through */ 1248f95f3850SWill Newton 1249f95f3850SWill Newton case STATE_SENDING_DATA: 1250f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1251f95f3850SWill Newton &host->pending_events)) { 1252f95f3850SWill Newton dw_mci_stop_dma(host); 1253*90c2143aSSeungwon Jeon send_stop_abort(host, data); 1254f95f3850SWill Newton state = STATE_DATA_ERROR; 1255f95f3850SWill Newton break; 1256f95f3850SWill Newton } 1257f95f3850SWill Newton 1258f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1259f95f3850SWill Newton &host->pending_events)) 1260f95f3850SWill Newton break; 1261f95f3850SWill Newton 1262f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 1263f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 1264f95f3850SWill Newton /* fall through */ 1265f95f3850SWill Newton 1266f95f3850SWill Newton case STATE_DATA_BUSY: 1267f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 1268f95f3850SWill Newton &host->pending_events)) 1269f95f3850SWill Newton break; 1270f95f3850SWill Newton 1271f95f3850SWill Newton host->data = NULL; 1272f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 1273f95f3850SWill Newton status = host->data_status; 1274f95f3850SWill Newton 1275f95f3850SWill Newton if (status & DW_MCI_DATA_ERROR_FLAGS) { 12763f7eec62SJaehoon Chung if (status & SDMMC_INT_DRTO) { 1277f95f3850SWill Newton data->error = -ETIMEDOUT; 1278f95f3850SWill Newton } else if (status & SDMMC_INT_DCRC) { 1279f95f3850SWill Newton data->error = -EILSEQ; 128055c5efbcSJames Hogan } else if (status & SDMMC_INT_EBE && 128155c5efbcSJames Hogan host->dir_status == 128255c5efbcSJames Hogan DW_MCI_SEND_STATUS) { 128355c5efbcSJames Hogan /* 128455c5efbcSJames Hogan * No data CRC status was returned. 128555c5efbcSJames Hogan * The number of bytes transferred will 128655c5efbcSJames Hogan * be exaggerated in PIO mode. 128755c5efbcSJames Hogan */ 128855c5efbcSJames Hogan data->bytes_xfered = 0; 128955c5efbcSJames Hogan data->error = -ETIMEDOUT; 1290f95f3850SWill Newton } else { 12914a90920cSThomas Abraham dev_err(host->dev, 1292f95f3850SWill Newton "data FIFO error " 1293f95f3850SWill Newton "(status=%08x)\n", 1294f95f3850SWill Newton status); 1295f95f3850SWill Newton data->error = -EIO; 1296f95f3850SWill Newton } 129794dd5b33SJames Hogan /* 129894dd5b33SJames Hogan * After an error, there may be data lingering 129994dd5b33SJames Hogan * in the FIFO, so reset it - doing so 130094dd5b33SJames Hogan * generates a block interrupt, hence setting 130194dd5b33SJames Hogan * the scatter-gather pointer to NULL. 130294dd5b33SJames Hogan */ 1303f9c2a0dcSSeungwon Jeon sg_miter_stop(&host->sg_miter); 130494dd5b33SJames Hogan host->sg = NULL; 130594dd5b33SJames Hogan ctrl = mci_readl(host, CTRL); 130694dd5b33SJames Hogan ctrl |= SDMMC_CTRL_FIFO_RESET; 130794dd5b33SJames Hogan mci_writel(host, CTRL, ctrl); 1308f95f3850SWill Newton } else { 1309f95f3850SWill Newton data->bytes_xfered = data->blocks * data->blksz; 1310f95f3850SWill Newton data->error = 0; 1311f95f3850SWill Newton } 1312f95f3850SWill Newton 1313*90c2143aSSeungwon Jeon if (!data->stop && !data->error) { 1314f95f3850SWill Newton dw_mci_request_end(host, host->mrq); 1315f95f3850SWill Newton goto unlock; 1316f95f3850SWill Newton } 1317f95f3850SWill Newton 1318053b3ce6SSeungwon Jeon if (host->mrq->sbc && !data->error) { 1319053b3ce6SSeungwon Jeon data->stop->error = 0; 1320053b3ce6SSeungwon Jeon dw_mci_request_end(host, host->mrq); 1321053b3ce6SSeungwon Jeon goto unlock; 1322053b3ce6SSeungwon Jeon } 1323053b3ce6SSeungwon Jeon 1324f95f3850SWill Newton prev_state = state = STATE_SENDING_STOP; 1325*90c2143aSSeungwon Jeon if (data->stop && !data->error) { 1326*90c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 1327*90c2143aSSeungwon Jeon send_stop_abort(host, data); 1328*90c2143aSSeungwon Jeon } 1329f95f3850SWill Newton /* fall through */ 1330f95f3850SWill Newton 1331f95f3850SWill Newton case STATE_SENDING_STOP: 1332f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1333f95f3850SWill Newton &host->pending_events)) 1334f95f3850SWill Newton break; 1335f95f3850SWill Newton 133671abb133SSeungwon Jeon /* CMD error in data command */ 133771abb133SSeungwon Jeon if (host->mrq->cmd->error && host->mrq->data) { 133871abb133SSeungwon Jeon sg_miter_stop(&host->sg_miter); 133971abb133SSeungwon Jeon host->sg = NULL; 134071abb133SSeungwon Jeon ctrl = mci_readl(host, CTRL); 134171abb133SSeungwon Jeon ctrl |= SDMMC_CTRL_FIFO_RESET; 134271abb133SSeungwon Jeon mci_writel(host, CTRL, ctrl); 134371abb133SSeungwon Jeon } 134471abb133SSeungwon Jeon 1345f95f3850SWill Newton host->cmd = NULL; 134671abb133SSeungwon Jeon host->data = NULL; 1347*90c2143aSSeungwon Jeon 1348*90c2143aSSeungwon Jeon if (host->mrq->stop) 1349f95f3850SWill Newton dw_mci_command_complete(host, host->mrq->stop); 1350*90c2143aSSeungwon Jeon else 1351*90c2143aSSeungwon Jeon host->cmd_status = 0; 1352*90c2143aSSeungwon Jeon 1353f95f3850SWill Newton dw_mci_request_end(host, host->mrq); 1354f95f3850SWill Newton goto unlock; 1355f95f3850SWill Newton 1356f95f3850SWill Newton case STATE_DATA_ERROR: 1357f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1358f95f3850SWill Newton &host->pending_events)) 1359f95f3850SWill Newton break; 1360f95f3850SWill Newton 1361f95f3850SWill Newton state = STATE_DATA_BUSY; 1362f95f3850SWill Newton break; 1363f95f3850SWill Newton } 1364f95f3850SWill Newton } while (state != prev_state); 1365f95f3850SWill Newton 1366f95f3850SWill Newton host->state = state; 1367f95f3850SWill Newton unlock: 1368f95f3850SWill Newton spin_unlock(&host->lock); 1369f95f3850SWill Newton 1370f95f3850SWill Newton } 1371f95f3850SWill Newton 137234b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 137334b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 137434b664a2SJames Hogan { 137534b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 137634b664a2SJames Hogan host->part_buf_count = cnt; 137734b664a2SJames Hogan } 137834b664a2SJames Hogan 137934b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 138034b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 138134b664a2SJames Hogan { 138234b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 138334b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 138434b664a2SJames Hogan host->part_buf_count += cnt; 138534b664a2SJames Hogan return cnt; 138634b664a2SJames Hogan } 138734b664a2SJames Hogan 138834b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 138934b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 139034b664a2SJames Hogan { 139134b664a2SJames Hogan cnt = min(cnt, (int)host->part_buf_count); 139234b664a2SJames Hogan if (cnt) { 139334b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 139434b664a2SJames Hogan cnt); 139534b664a2SJames Hogan host->part_buf_count -= cnt; 139634b664a2SJames Hogan host->part_buf_start += cnt; 139734b664a2SJames Hogan } 139834b664a2SJames Hogan return cnt; 139934b664a2SJames Hogan } 140034b664a2SJames Hogan 140134b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 140234b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 140334b664a2SJames Hogan { 140434b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 140534b664a2SJames Hogan host->part_buf_start = cnt; 140634b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 140734b664a2SJames Hogan } 140834b664a2SJames Hogan 1409f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 1410f95f3850SWill Newton { 1411cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1412cfbeb59cSMarkos Chandras int init_cnt = cnt; 1413cfbeb59cSMarkos Chandras 141434b664a2SJames Hogan /* try and push anything in the part_buf */ 141534b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 141634b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 141734b664a2SJames Hogan buf += len; 141834b664a2SJames Hogan cnt -= len; 1419cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 14204e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 14214e0a5adfSJaehoon Chung host->part_buf16); 142234b664a2SJames Hogan host->part_buf_count = 0; 142334b664a2SJames Hogan } 142434b664a2SJames Hogan } 142534b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 142634b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 142734b664a2SJames Hogan while (cnt >= 2) { 142834b664a2SJames Hogan u16 aligned_buf[64]; 142934b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 143034b664a2SJames Hogan int items = len >> 1; 143134b664a2SJames Hogan int i; 143234b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 143334b664a2SJames Hogan memcpy(aligned_buf, buf, len); 143434b664a2SJames Hogan buf += len; 143534b664a2SJames Hogan cnt -= len; 143634b664a2SJames Hogan /* push data from aligned buffer into fifo */ 143734b664a2SJames Hogan for (i = 0; i < items; ++i) 14384e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 14394e0a5adfSJaehoon Chung aligned_buf[i]); 144034b664a2SJames Hogan } 144134b664a2SJames Hogan } else 144234b664a2SJames Hogan #endif 144334b664a2SJames Hogan { 144434b664a2SJames Hogan u16 *pdata = buf; 144534b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 14464e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), *pdata++); 144734b664a2SJames Hogan buf = pdata; 144834b664a2SJames Hogan } 144934b664a2SJames Hogan /* put anything remaining in the part_buf */ 145034b664a2SJames Hogan if (cnt) { 145134b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1452cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1453cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1454cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 14554e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 14564e0a5adfSJaehoon Chung host->part_buf16); 1457f95f3850SWill Newton } 1458f95f3850SWill Newton } 1459f95f3850SWill Newton 1460f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 1461f95f3850SWill Newton { 146234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 146334b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 146434b664a2SJames Hogan while (cnt >= 2) { 146534b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 146634b664a2SJames Hogan u16 aligned_buf[64]; 146734b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 146834b664a2SJames Hogan int items = len >> 1; 146934b664a2SJames Hogan int i; 147034b664a2SJames Hogan for (i = 0; i < items; ++i) 14714e0a5adfSJaehoon Chung aligned_buf[i] = mci_readw(host, 14724e0a5adfSJaehoon Chung DATA(host->data_offset)); 147334b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 147434b664a2SJames Hogan memcpy(buf, aligned_buf, len); 147534b664a2SJames Hogan buf += len; 147634b664a2SJames Hogan cnt -= len; 147734b664a2SJames Hogan } 147834b664a2SJames Hogan } else 147934b664a2SJames Hogan #endif 148034b664a2SJames Hogan { 148134b664a2SJames Hogan u16 *pdata = buf; 148234b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 14834e0a5adfSJaehoon Chung *pdata++ = mci_readw(host, DATA(host->data_offset)); 148434b664a2SJames Hogan buf = pdata; 148534b664a2SJames Hogan } 148634b664a2SJames Hogan if (cnt) { 14874e0a5adfSJaehoon Chung host->part_buf16 = mci_readw(host, DATA(host->data_offset)); 148834b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1489f95f3850SWill Newton } 1490f95f3850SWill Newton } 1491f95f3850SWill Newton 1492f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 1493f95f3850SWill Newton { 1494cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1495cfbeb59cSMarkos Chandras int init_cnt = cnt; 1496cfbeb59cSMarkos Chandras 149734b664a2SJames Hogan /* try and push anything in the part_buf */ 149834b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 149934b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 150034b664a2SJames Hogan buf += len; 150134b664a2SJames Hogan cnt -= len; 1502cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 15034e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 15044e0a5adfSJaehoon Chung host->part_buf32); 150534b664a2SJames Hogan host->part_buf_count = 0; 150634b664a2SJames Hogan } 150734b664a2SJames Hogan } 150834b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 150934b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 151034b664a2SJames Hogan while (cnt >= 4) { 151134b664a2SJames Hogan u32 aligned_buf[32]; 151234b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 151334b664a2SJames Hogan int items = len >> 2; 151434b664a2SJames Hogan int i; 151534b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 151634b664a2SJames Hogan memcpy(aligned_buf, buf, len); 151734b664a2SJames Hogan buf += len; 151834b664a2SJames Hogan cnt -= len; 151934b664a2SJames Hogan /* push data from aligned buffer into fifo */ 152034b664a2SJames Hogan for (i = 0; i < items; ++i) 15214e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 15224e0a5adfSJaehoon Chung aligned_buf[i]); 152334b664a2SJames Hogan } 152434b664a2SJames Hogan } else 152534b664a2SJames Hogan #endif 152634b664a2SJames Hogan { 152734b664a2SJames Hogan u32 *pdata = buf; 152834b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 15294e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), *pdata++); 153034b664a2SJames Hogan buf = pdata; 153134b664a2SJames Hogan } 153234b664a2SJames Hogan /* put anything remaining in the part_buf */ 153334b664a2SJames Hogan if (cnt) { 153434b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1535cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1536cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1537cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 15384e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 15394e0a5adfSJaehoon Chung host->part_buf32); 1540f95f3850SWill Newton } 1541f95f3850SWill Newton } 1542f95f3850SWill Newton 1543f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 1544f95f3850SWill Newton { 154534b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 154634b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 154734b664a2SJames Hogan while (cnt >= 4) { 154834b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 154934b664a2SJames Hogan u32 aligned_buf[32]; 155034b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 155134b664a2SJames Hogan int items = len >> 2; 155234b664a2SJames Hogan int i; 155334b664a2SJames Hogan for (i = 0; i < items; ++i) 15544e0a5adfSJaehoon Chung aligned_buf[i] = mci_readl(host, 15554e0a5adfSJaehoon Chung DATA(host->data_offset)); 155634b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 155734b664a2SJames Hogan memcpy(buf, aligned_buf, len); 155834b664a2SJames Hogan buf += len; 155934b664a2SJames Hogan cnt -= len; 156034b664a2SJames Hogan } 156134b664a2SJames Hogan } else 156234b664a2SJames Hogan #endif 156334b664a2SJames Hogan { 156434b664a2SJames Hogan u32 *pdata = buf; 156534b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 15664e0a5adfSJaehoon Chung *pdata++ = mci_readl(host, DATA(host->data_offset)); 156734b664a2SJames Hogan buf = pdata; 156834b664a2SJames Hogan } 156934b664a2SJames Hogan if (cnt) { 15704e0a5adfSJaehoon Chung host->part_buf32 = mci_readl(host, DATA(host->data_offset)); 157134b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1572f95f3850SWill Newton } 1573f95f3850SWill Newton } 1574f95f3850SWill Newton 1575f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 1576f95f3850SWill Newton { 1577cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1578cfbeb59cSMarkos Chandras int init_cnt = cnt; 1579cfbeb59cSMarkos Chandras 158034b664a2SJames Hogan /* try and push anything in the part_buf */ 158134b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 158234b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 158334b664a2SJames Hogan buf += len; 158434b664a2SJames Hogan cnt -= len; 1585c09fbd74SSeungwon Jeon 1586cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 1587c09fbd74SSeungwon Jeon mci_writeq(host, DATA(host->data_offset), 15884e0a5adfSJaehoon Chung host->part_buf); 158934b664a2SJames Hogan host->part_buf_count = 0; 159034b664a2SJames Hogan } 159134b664a2SJames Hogan } 159234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 159334b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 159434b664a2SJames Hogan while (cnt >= 8) { 159534b664a2SJames Hogan u64 aligned_buf[16]; 159634b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 159734b664a2SJames Hogan int items = len >> 3; 159834b664a2SJames Hogan int i; 159934b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 160034b664a2SJames Hogan memcpy(aligned_buf, buf, len); 160134b664a2SJames Hogan buf += len; 160234b664a2SJames Hogan cnt -= len; 160334b664a2SJames Hogan /* push data from aligned buffer into fifo */ 160434b664a2SJames Hogan for (i = 0; i < items; ++i) 16054e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 16064e0a5adfSJaehoon Chung aligned_buf[i]); 160734b664a2SJames Hogan } 160834b664a2SJames Hogan } else 160934b664a2SJames Hogan #endif 161034b664a2SJames Hogan { 161134b664a2SJames Hogan u64 *pdata = buf; 161234b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 16134e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), *pdata++); 161434b664a2SJames Hogan buf = pdata; 161534b664a2SJames Hogan } 161634b664a2SJames Hogan /* put anything remaining in the part_buf */ 161734b664a2SJames Hogan if (cnt) { 161834b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1619cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1620cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1621cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 16224e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 16234e0a5adfSJaehoon Chung host->part_buf); 1624f95f3850SWill Newton } 1625f95f3850SWill Newton } 1626f95f3850SWill Newton 1627f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 1628f95f3850SWill Newton { 162934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 163034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 163134b664a2SJames Hogan while (cnt >= 8) { 163234b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 163334b664a2SJames Hogan u64 aligned_buf[16]; 163434b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 163534b664a2SJames Hogan int items = len >> 3; 163634b664a2SJames Hogan int i; 163734b664a2SJames Hogan for (i = 0; i < items; ++i) 16384e0a5adfSJaehoon Chung aligned_buf[i] = mci_readq(host, 16394e0a5adfSJaehoon Chung DATA(host->data_offset)); 164034b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 164134b664a2SJames Hogan memcpy(buf, aligned_buf, len); 164234b664a2SJames Hogan buf += len; 164334b664a2SJames Hogan cnt -= len; 1644f95f3850SWill Newton } 164534b664a2SJames Hogan } else 164634b664a2SJames Hogan #endif 164734b664a2SJames Hogan { 164834b664a2SJames Hogan u64 *pdata = buf; 164934b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 16504e0a5adfSJaehoon Chung *pdata++ = mci_readq(host, DATA(host->data_offset)); 165134b664a2SJames Hogan buf = pdata; 165234b664a2SJames Hogan } 165334b664a2SJames Hogan if (cnt) { 16544e0a5adfSJaehoon Chung host->part_buf = mci_readq(host, DATA(host->data_offset)); 165534b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 165634b664a2SJames Hogan } 165734b664a2SJames Hogan } 165834b664a2SJames Hogan 165934b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 166034b664a2SJames Hogan { 166134b664a2SJames Hogan int len; 166234b664a2SJames Hogan 166334b664a2SJames Hogan /* get remaining partial bytes */ 166434b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 166534b664a2SJames Hogan if (unlikely(len == cnt)) 166634b664a2SJames Hogan return; 166734b664a2SJames Hogan buf += len; 166834b664a2SJames Hogan cnt -= len; 166934b664a2SJames Hogan 167034b664a2SJames Hogan /* get the rest of the data */ 167134b664a2SJames Hogan host->pull_data(host, buf, cnt); 1672f95f3850SWill Newton } 1673f95f3850SWill Newton 167487a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 1675f95f3850SWill Newton { 1676f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1677f9c2a0dcSSeungwon Jeon void *buf; 1678f9c2a0dcSSeungwon Jeon unsigned int offset; 1679f95f3850SWill Newton struct mmc_data *data = host->data; 1680f95f3850SWill Newton int shift = host->data_shift; 1681f95f3850SWill Newton u32 status; 16823e4b0d8bSMarkos Chandras unsigned int len; 1683f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 1684f95f3850SWill Newton 1685f95f3850SWill Newton do { 1686f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1687f9c2a0dcSSeungwon Jeon goto done; 1688f95f3850SWill Newton 16894225fc85SImre Deak host->sg = sg_miter->piter.sg; 1690f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 1691f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 1692f9c2a0dcSSeungwon Jeon offset = 0; 1693f9c2a0dcSSeungwon Jeon 1694f9c2a0dcSSeungwon Jeon do { 1695f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 1696f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 1697f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 1698f9c2a0dcSSeungwon Jeon if (!len) 1699f9c2a0dcSSeungwon Jeon break; 1700f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 17013e4b0d8bSMarkos Chandras data->bytes_xfered += len; 1702f95f3850SWill Newton offset += len; 1703f9c2a0dcSSeungwon Jeon remain -= len; 1704f9c2a0dcSSeungwon Jeon } while (remain); 1705f95f3850SWill Newton 1706e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 1707f95f3850SWill Newton status = mci_readl(host, MINTSTS); 1708f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 170987a74d39SKyoungil Kim /* if the RXDR is ready read again */ 171087a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 171187a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 1712f9c2a0dcSSeungwon Jeon 1713f9c2a0dcSSeungwon Jeon if (!remain) { 1714f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1715f9c2a0dcSSeungwon Jeon goto done; 1716f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 1717f9c2a0dcSSeungwon Jeon } 1718f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1719f95f3850SWill Newton return; 1720f95f3850SWill Newton 1721f95f3850SWill Newton done: 1722f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1723f9c2a0dcSSeungwon Jeon host->sg = NULL; 1724f95f3850SWill Newton smp_wmb(); 1725f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1726f95f3850SWill Newton } 1727f95f3850SWill Newton 1728f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 1729f95f3850SWill Newton { 1730f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1731f9c2a0dcSSeungwon Jeon void *buf; 1732f9c2a0dcSSeungwon Jeon unsigned int offset; 1733f95f3850SWill Newton struct mmc_data *data = host->data; 1734f95f3850SWill Newton int shift = host->data_shift; 1735f95f3850SWill Newton u32 status; 17363e4b0d8bSMarkos Chandras unsigned int len; 1737f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 1738f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 1739f95f3850SWill Newton 1740f95f3850SWill Newton do { 1741f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1742f9c2a0dcSSeungwon Jeon goto done; 1743f95f3850SWill Newton 17444225fc85SImre Deak host->sg = sg_miter->piter.sg; 1745f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 1746f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 1747f9c2a0dcSSeungwon Jeon offset = 0; 1748f9c2a0dcSSeungwon Jeon 1749f9c2a0dcSSeungwon Jeon do { 1750f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 1751f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 1752f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 1753f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 1754f9c2a0dcSSeungwon Jeon if (!len) 1755f9c2a0dcSSeungwon Jeon break; 1756f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 17573e4b0d8bSMarkos Chandras data->bytes_xfered += len; 1758f95f3850SWill Newton offset += len; 1759f9c2a0dcSSeungwon Jeon remain -= len; 1760f9c2a0dcSSeungwon Jeon } while (remain); 1761f95f3850SWill Newton 1762e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 1763f95f3850SWill Newton status = mci_readl(host, MINTSTS); 1764f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 1765f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 1766f9c2a0dcSSeungwon Jeon 1767f9c2a0dcSSeungwon Jeon if (!remain) { 1768f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1769f9c2a0dcSSeungwon Jeon goto done; 1770f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 1771f9c2a0dcSSeungwon Jeon } 1772f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1773f95f3850SWill Newton return; 1774f95f3850SWill Newton 1775f95f3850SWill Newton done: 1776f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1777f9c2a0dcSSeungwon Jeon host->sg = NULL; 1778f95f3850SWill Newton smp_wmb(); 1779f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1780f95f3850SWill Newton } 1781f95f3850SWill Newton 1782f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 1783f95f3850SWill Newton { 1784f95f3850SWill Newton if (!host->cmd_status) 1785f95f3850SWill Newton host->cmd_status = status; 1786f95f3850SWill Newton 1787f95f3850SWill Newton smp_wmb(); 1788f95f3850SWill Newton 1789f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 1790f95f3850SWill Newton tasklet_schedule(&host->tasklet); 1791f95f3850SWill Newton } 1792f95f3850SWill Newton 1793f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 1794f95f3850SWill Newton { 1795f95f3850SWill Newton struct dw_mci *host = dev_id; 1796182c9081SSeungwon Jeon u32 pending; 17971a5c8e1fSShashidhar Hiremath int i; 1798f95f3850SWill Newton 1799f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 1800f95f3850SWill Newton 1801f95f3850SWill Newton /* 1802f95f3850SWill Newton * DTO fix - version 2.10a and below, and only if internal DMA 1803f95f3850SWill Newton * is configured. 1804f95f3850SWill Newton */ 1805f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { 1806f95f3850SWill Newton if (!pending && 1807f95f3850SWill Newton ((mci_readl(host, STATUS) >> 17) & 0x1fff)) 1808f95f3850SWill Newton pending |= SDMMC_INT_DATA_OVER; 1809f95f3850SWill Newton } 1810f95f3850SWill Newton 1811476d79f1SDoug Anderson if (pending) { 1812f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 1813f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 1814182c9081SSeungwon Jeon host->cmd_status = pending; 1815f95f3850SWill Newton smp_wmb(); 1816f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 1817f95f3850SWill Newton } 1818f95f3850SWill Newton 1819f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 1820f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 1821f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 1822182c9081SSeungwon Jeon host->data_status = pending; 1823f95f3850SWill Newton smp_wmb(); 1824f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 1825f95f3850SWill Newton tasklet_schedule(&host->tasklet); 1826f95f3850SWill Newton } 1827f95f3850SWill Newton 1828f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 1829f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 1830f95f3850SWill Newton if (!host->data_status) 1831182c9081SSeungwon Jeon host->data_status = pending; 1832f95f3850SWill Newton smp_wmb(); 1833f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 1834f95f3850SWill Newton if (host->sg != NULL) 183587a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 1836f95f3850SWill Newton } 1837f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 1838f95f3850SWill Newton tasklet_schedule(&host->tasklet); 1839f95f3850SWill Newton } 1840f95f3850SWill Newton 1841f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 1842f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 1843b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 184487a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 1845f95f3850SWill Newton } 1846f95f3850SWill Newton 1847f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 1848f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 1849b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 1850f95f3850SWill Newton dw_mci_write_data_pio(host); 1851f95f3850SWill Newton } 1852f95f3850SWill Newton 1853f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 1854f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 1855182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 1856f95f3850SWill Newton } 1857f95f3850SWill Newton 1858f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 1859f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 186095dcc2cbSThomas Abraham queue_work(host->card_workqueue, &host->card_work); 1861f95f3850SWill Newton } 1862f95f3850SWill Newton 18631a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 18641a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 18651a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 18661a5c8e1fSShashidhar Hiremath if (pending & SDMMC_INT_SDIO(i)) { 18671a5c8e1fSShashidhar Hiremath mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); 18681a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 18691a5c8e1fSShashidhar Hiremath } 18701a5c8e1fSShashidhar Hiremath } 18711a5c8e1fSShashidhar Hiremath 18721fb5f68aSMarkos Chandras } 1873f95f3850SWill Newton 1874f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 1875f95f3850SWill Newton /* Handle DMA interrupts */ 1876f95f3850SWill Newton pending = mci_readl(host, IDSTS); 1877f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 1878f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); 1879f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 1880f95f3850SWill Newton host->dma_ops->complete(host); 1881f95f3850SWill Newton } 1882f95f3850SWill Newton #endif 1883f95f3850SWill Newton 1884f95f3850SWill Newton return IRQ_HANDLED; 1885f95f3850SWill Newton } 1886f95f3850SWill Newton 18871791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work) 1888f95f3850SWill Newton { 18891791b13eSJames Hogan struct dw_mci *host = container_of(work, struct dw_mci, card_work); 1890f95f3850SWill Newton int i; 1891f95f3850SWill Newton 1892f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 1893f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 1894f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 1895f95f3850SWill Newton struct mmc_request *mrq; 1896f95f3850SWill Newton int present; 1897f95f3850SWill Newton u32 ctrl; 1898f95f3850SWill Newton 1899f95f3850SWill Newton present = dw_mci_get_cd(mmc); 1900f95f3850SWill Newton while (present != slot->last_detect_state) { 1901f95f3850SWill Newton dev_dbg(&slot->mmc->class_dev, "card %s\n", 1902f95f3850SWill Newton present ? "inserted" : "removed"); 1903f95f3850SWill Newton 19041791b13eSJames Hogan spin_lock_bh(&host->lock); 19051791b13eSJames Hogan 1906f95f3850SWill Newton /* Card change detected */ 1907f95f3850SWill Newton slot->last_detect_state = present; 1908f95f3850SWill Newton 19091791b13eSJames Hogan /* Mark card as present if applicable */ 19101791b13eSJames Hogan if (present != 0) 1911f95f3850SWill Newton set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1912f95f3850SWill Newton 1913f95f3850SWill Newton /* Clean up queue if present */ 1914f95f3850SWill Newton mrq = slot->mrq; 1915f95f3850SWill Newton if (mrq) { 1916f95f3850SWill Newton if (mrq == host->mrq) { 1917f95f3850SWill Newton host->data = NULL; 1918f95f3850SWill Newton host->cmd = NULL; 1919f95f3850SWill Newton 1920f95f3850SWill Newton switch (host->state) { 1921f95f3850SWill Newton case STATE_IDLE: 1922f95f3850SWill Newton break; 1923f95f3850SWill Newton case STATE_SENDING_CMD: 1924f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1925f95f3850SWill Newton if (!mrq->data) 1926f95f3850SWill Newton break; 1927f95f3850SWill Newton /* fall through */ 1928f95f3850SWill Newton case STATE_SENDING_DATA: 1929f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 1930f95f3850SWill Newton dw_mci_stop_dma(host); 1931f95f3850SWill Newton break; 1932f95f3850SWill Newton case STATE_DATA_BUSY: 1933f95f3850SWill Newton case STATE_DATA_ERROR: 1934f95f3850SWill Newton if (mrq->data->error == -EINPROGRESS) 1935f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 1936f95f3850SWill Newton /* fall through */ 1937f95f3850SWill Newton case STATE_SENDING_STOP: 1938*90c2143aSSeungwon Jeon if (mrq->stop) 1939f95f3850SWill Newton mrq->stop->error = -ENOMEDIUM; 1940f95f3850SWill Newton break; 1941f95f3850SWill Newton } 1942f95f3850SWill Newton 1943f95f3850SWill Newton dw_mci_request_end(host, mrq); 1944f95f3850SWill Newton } else { 1945f95f3850SWill Newton list_del(&slot->queue_node); 1946f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1947f95f3850SWill Newton if (mrq->data) 1948f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 1949f95f3850SWill Newton if (mrq->stop) 1950f95f3850SWill Newton mrq->stop->error = -ENOMEDIUM; 1951f95f3850SWill Newton 1952f95f3850SWill Newton spin_unlock(&host->lock); 1953f95f3850SWill Newton mmc_request_done(slot->mmc, mrq); 1954f95f3850SWill Newton spin_lock(&host->lock); 1955f95f3850SWill Newton } 1956f95f3850SWill Newton } 1957f95f3850SWill Newton 1958f95f3850SWill Newton /* Power down slot */ 1959f95f3850SWill Newton if (present == 0) { 1960f95f3850SWill Newton clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1961f95f3850SWill Newton 1962f95f3850SWill Newton /* 1963f95f3850SWill Newton * Clear down the FIFO - doing so generates a 1964f95f3850SWill Newton * block interrupt, hence setting the 1965f95f3850SWill Newton * scatter-gather pointer to NULL. 1966f95f3850SWill Newton */ 1967f9c2a0dcSSeungwon Jeon sg_miter_stop(&host->sg_miter); 1968f95f3850SWill Newton host->sg = NULL; 1969f95f3850SWill Newton 1970f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 1971f95f3850SWill Newton ctrl |= SDMMC_CTRL_FIFO_RESET; 1972f95f3850SWill Newton mci_writel(host, CTRL, ctrl); 1973f95f3850SWill Newton 1974f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 1975f95f3850SWill Newton ctrl = mci_readl(host, BMOD); 1976141a712aSSeungwon Jeon /* Software reset of DMA */ 1977141a712aSSeungwon Jeon ctrl |= SDMMC_IDMAC_SWRESET; 1978f95f3850SWill Newton mci_writel(host, BMOD, ctrl); 1979f95f3850SWill Newton #endif 1980f95f3850SWill Newton 1981f95f3850SWill Newton } 1982f95f3850SWill Newton 19831791b13eSJames Hogan spin_unlock_bh(&host->lock); 19841791b13eSJames Hogan 1985f95f3850SWill Newton present = dw_mci_get_cd(mmc); 1986f95f3850SWill Newton } 1987f95f3850SWill Newton 1988f95f3850SWill Newton mmc_detect_change(slot->mmc, 1989f95f3850SWill Newton msecs_to_jiffies(host->pdata->detect_delay_ms)); 1990f95f3850SWill Newton } 1991f95f3850SWill Newton } 1992f95f3850SWill Newton 1993c91eab4bSThomas Abraham #ifdef CONFIG_OF 1994c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */ 1995c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 1996c91eab4bSThomas Abraham { 1997c91eab4bSThomas Abraham struct device_node *np; 1998c91eab4bSThomas Abraham const __be32 *addr; 1999c91eab4bSThomas Abraham int len; 2000c91eab4bSThomas Abraham 2001c91eab4bSThomas Abraham if (!dev || !dev->of_node) 2002c91eab4bSThomas Abraham return NULL; 2003c91eab4bSThomas Abraham 2004c91eab4bSThomas Abraham for_each_child_of_node(dev->of_node, np) { 2005c91eab4bSThomas Abraham addr = of_get_property(np, "reg", &len); 2006c91eab4bSThomas Abraham if (!addr || (len < sizeof(int))) 2007c91eab4bSThomas Abraham continue; 2008c91eab4bSThomas Abraham if (be32_to_cpup(addr) == slot) 2009c91eab4bSThomas Abraham return np; 2010c91eab4bSThomas Abraham } 2011c91eab4bSThomas Abraham return NULL; 2012c91eab4bSThomas Abraham } 2013c91eab4bSThomas Abraham 2014a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks { 2015a70aaa64SDoug Anderson char *quirk; 2016a70aaa64SDoug Anderson int id; 2017a70aaa64SDoug Anderson } of_slot_quirks[] = { 2018a70aaa64SDoug Anderson { 2019a70aaa64SDoug Anderson .quirk = "disable-wp", 2020a70aaa64SDoug Anderson .id = DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT, 2021a70aaa64SDoug Anderson }, 2022a70aaa64SDoug Anderson }; 2023a70aaa64SDoug Anderson 2024a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2025a70aaa64SDoug Anderson { 2026a70aaa64SDoug Anderson struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 2027a70aaa64SDoug Anderson int quirks = 0; 2028a70aaa64SDoug Anderson int idx; 2029a70aaa64SDoug Anderson 2030a70aaa64SDoug Anderson /* get quirks */ 2031a70aaa64SDoug Anderson for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++) 2032a70aaa64SDoug Anderson if (of_get_property(np, of_slot_quirks[idx].quirk, NULL)) 2033a70aaa64SDoug Anderson quirks |= of_slot_quirks[idx].id; 2034a70aaa64SDoug Anderson 2035a70aaa64SDoug Anderson return quirks; 2036a70aaa64SDoug Anderson } 2037a70aaa64SDoug Anderson 2038c91eab4bSThomas Abraham /* find out bus-width for a given slot */ 2039c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) 2040c91eab4bSThomas Abraham { 2041c91eab4bSThomas Abraham struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 2042c91eab4bSThomas Abraham u32 bus_wd = 1; 2043c91eab4bSThomas Abraham 2044c91eab4bSThomas Abraham if (!np) 2045c91eab4bSThomas Abraham return 1; 2046c91eab4bSThomas Abraham 2047c91eab4bSThomas Abraham if (of_property_read_u32(np, "bus-width", &bus_wd)) 2048c91eab4bSThomas Abraham dev_err(dev, "bus-width property not found, assuming width" 2049c91eab4bSThomas Abraham " as 1\n"); 2050c91eab4bSThomas Abraham return bus_wd; 2051c91eab4bSThomas Abraham } 205255a6ceb2SDoug Anderson 205355a6ceb2SDoug Anderson /* find the write protect gpio for a given slot; or -1 if none specified */ 205455a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) 205555a6ceb2SDoug Anderson { 205655a6ceb2SDoug Anderson struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 205755a6ceb2SDoug Anderson int gpio; 205855a6ceb2SDoug Anderson 205955a6ceb2SDoug Anderson if (!np) 206055a6ceb2SDoug Anderson return -EINVAL; 206155a6ceb2SDoug Anderson 206255a6ceb2SDoug Anderson gpio = of_get_named_gpio(np, "wp-gpios", 0); 206355a6ceb2SDoug Anderson 206455a6ceb2SDoug Anderson /* Having a missing entry is valid; return silently */ 206555a6ceb2SDoug Anderson if (!gpio_is_valid(gpio)) 206655a6ceb2SDoug Anderson return -EINVAL; 206755a6ceb2SDoug Anderson 206855a6ceb2SDoug Anderson if (devm_gpio_request(dev, gpio, "dw-mci-wp")) { 206955a6ceb2SDoug Anderson dev_warn(dev, "gpio [%d] request failed\n", gpio); 207055a6ceb2SDoug Anderson return -EINVAL; 207155a6ceb2SDoug Anderson } 207255a6ceb2SDoug Anderson 207355a6ceb2SDoug Anderson return gpio; 207455a6ceb2SDoug Anderson } 2075c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2076a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2077a70aaa64SDoug Anderson { 2078a70aaa64SDoug Anderson return 0; 2079a70aaa64SDoug Anderson } 2080c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) 2081c91eab4bSThomas Abraham { 2082c91eab4bSThomas Abraham return 1; 2083c91eab4bSThomas Abraham } 2084c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 2085c91eab4bSThomas Abraham { 2086c91eab4bSThomas Abraham return NULL; 2087c91eab4bSThomas Abraham } 208855a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) 208955a6ceb2SDoug Anderson { 209055a6ceb2SDoug Anderson return -EINVAL; 209155a6ceb2SDoug Anderson } 2092c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2093c91eab4bSThomas Abraham 209436c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2095f95f3850SWill Newton { 2096f95f3850SWill Newton struct mmc_host *mmc; 2097f95f3850SWill Newton struct dw_mci_slot *slot; 2098e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2099800d78bfSThomas Abraham int ctrl_id, ret; 21001f44a2a5SSeungwon Jeon u32 freq[2]; 2101c91eab4bSThomas Abraham u8 bus_width; 2102f95f3850SWill Newton 21034a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2104f95f3850SWill Newton if (!mmc) 2105f95f3850SWill Newton return -ENOMEM; 2106f95f3850SWill Newton 2107f95f3850SWill Newton slot = mmc_priv(mmc); 2108f95f3850SWill Newton slot->id = id; 2109f95f3850SWill Newton slot->mmc = mmc; 2110f95f3850SWill Newton slot->host = host; 2111c91eab4bSThomas Abraham host->slot[id] = slot; 2112f95f3850SWill Newton 2113a70aaa64SDoug Anderson slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id); 2114a70aaa64SDoug Anderson 2115f95f3850SWill Newton mmc->ops = &dw_mci_ops; 21161f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 21171f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 21181f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 21191f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 21201f44a2a5SSeungwon Jeon } else { 21211f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 21221f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 21231f44a2a5SSeungwon Jeon } 2124f95f3850SWill Newton 2125f95f3850SWill Newton if (host->pdata->get_ocr) 2126f95f3850SWill Newton mmc->ocr_avail = host->pdata->get_ocr(id); 2127f95f3850SWill Newton else 2128f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2129f95f3850SWill Newton 2130f95f3850SWill Newton /* 2131f95f3850SWill Newton * Start with slot power disabled, it will be enabled when a card 2132f95f3850SWill Newton * is detected. 2133f95f3850SWill Newton */ 2134f95f3850SWill Newton if (host->pdata->setpower) 2135f95f3850SWill Newton host->pdata->setpower(id, 0); 2136f95f3850SWill Newton 2137fc3d7720SJaehoon Chung if (host->pdata->caps) 2138fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2139fc3d7720SJaehoon Chung 2140ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2141ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2142ab269128SAbhilash Kesavan 2143800d78bfSThomas Abraham if (host->dev->of_node) { 2144800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2145800d78bfSThomas Abraham if (ctrl_id < 0) 2146800d78bfSThomas Abraham ctrl_id = 0; 2147800d78bfSThomas Abraham } else { 2148800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2149800d78bfSThomas Abraham } 2150cb27a843SJames Hogan if (drv_data && drv_data->caps) 2151cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2152800d78bfSThomas Abraham 21534f408cc6SSeungwon Jeon if (host->pdata->caps2) 21544f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 21554f408cc6SSeungwon Jeon 2156f95f3850SWill Newton if (host->pdata->get_bus_wd) 2157c91eab4bSThomas Abraham bus_width = host->pdata->get_bus_wd(slot->id); 2158c91eab4bSThomas Abraham else if (host->dev->of_node) 2159c91eab4bSThomas Abraham bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id); 2160c91eab4bSThomas Abraham else 2161c91eab4bSThomas Abraham bus_width = 1; 2162c91eab4bSThomas Abraham 2163c91eab4bSThomas Abraham switch (bus_width) { 2164c91eab4bSThomas Abraham case 8: 2165c91eab4bSThomas Abraham mmc->caps |= MMC_CAP_8_BIT_DATA; 2166c91eab4bSThomas Abraham case 4: 2167f95f3850SWill Newton mmc->caps |= MMC_CAP_4_BIT_DATA; 2168c91eab4bSThomas Abraham } 2169f95f3850SWill Newton 2170f95f3850SWill Newton if (host->pdata->blk_settings) { 2171f95f3850SWill Newton mmc->max_segs = host->pdata->blk_settings->max_segs; 2172f95f3850SWill Newton mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; 2173f95f3850SWill Newton mmc->max_blk_count = host->pdata->blk_settings->max_blk_count; 2174f95f3850SWill Newton mmc->max_req_size = host->pdata->blk_settings->max_req_size; 2175f95f3850SWill Newton mmc->max_seg_size = host->pdata->blk_settings->max_seg_size; 2176f95f3850SWill Newton } else { 2177f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 2178a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 2179a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2180a39e5746SJaehoon Chung mmc->max_blk_size = 65536; 2181a39e5746SJaehoon Chung mmc->max_blk_count = host->ring_size; 2182a39e5746SJaehoon Chung mmc->max_seg_size = 0x1000; 2183a39e5746SJaehoon Chung mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; 2184a39e5746SJaehoon Chung #else 2185f95f3850SWill Newton mmc->max_segs = 64; 2186f95f3850SWill Newton mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ 2187f95f3850SWill Newton mmc->max_blk_count = 512; 2188f95f3850SWill Newton mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 2189f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2190f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 2191a39e5746SJaehoon Chung } 2192f95f3850SWill Newton 2193f95f3850SWill Newton if (dw_mci_get_cd(mmc)) 2194f95f3850SWill Newton set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2195f95f3850SWill Newton else 2196f95f3850SWill Newton clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2197f95f3850SWill Newton 219855a6ceb2SDoug Anderson slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); 219955a6ceb2SDoug Anderson 22000cea529dSJaehoon Chung ret = mmc_add_host(mmc); 22010cea529dSJaehoon Chung if (ret) 22020cea529dSJaehoon Chung goto err_setup_bus; 2203f95f3850SWill Newton 2204f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2205f95f3850SWill Newton dw_mci_init_debugfs(slot); 2206f95f3850SWill Newton #endif 2207f95f3850SWill Newton 2208f95f3850SWill Newton /* Card initially undetected */ 2209f95f3850SWill Newton slot->last_detect_state = 0; 2210f95f3850SWill Newton 2211f95f3850SWill Newton return 0; 2212800d78bfSThomas Abraham 2213800d78bfSThomas Abraham err_setup_bus: 2214800d78bfSThomas Abraham mmc_free_host(mmc); 2215800d78bfSThomas Abraham return -EINVAL; 2216f95f3850SWill Newton } 2217f95f3850SWill Newton 2218f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2219f95f3850SWill Newton { 2220f95f3850SWill Newton /* Shutdown detect IRQ */ 2221f95f3850SWill Newton if (slot->host->pdata->exit) 2222f95f3850SWill Newton slot->host->pdata->exit(id); 2223f95f3850SWill Newton 2224f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2225f95f3850SWill Newton mmc_remove_host(slot->mmc); 2226f95f3850SWill Newton slot->host->slot[id] = NULL; 2227f95f3850SWill Newton mmc_free_host(slot->mmc); 2228f95f3850SWill Newton } 2229f95f3850SWill Newton 2230f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2231f95f3850SWill Newton { 2232f95f3850SWill Newton /* Alloc memory for sg translation */ 2233780f22afSSeungwon Jeon host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, 2234f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2235f95f3850SWill Newton if (!host->sg_cpu) { 22364a90920cSThomas Abraham dev_err(host->dev, "%s: could not alloc DMA memory\n", 2237f95f3850SWill Newton __func__); 2238f95f3850SWill Newton goto no_dma; 2239f95f3850SWill Newton } 2240f95f3850SWill Newton 2241f95f3850SWill Newton /* Determine which DMA interface to use */ 2242f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2243f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 224400956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 2245f95f3850SWill Newton #endif 2246f95f3850SWill Newton 2247f95f3850SWill Newton if (!host->dma_ops) 2248f95f3850SWill Newton goto no_dma; 2249f95f3850SWill Newton 2250e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2251e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2252f95f3850SWill Newton if (host->dma_ops->init(host)) { 22534a90920cSThomas Abraham dev_err(host->dev, "%s: Unable to initialize " 2254f95f3850SWill Newton "DMA Controller.\n", __func__); 2255f95f3850SWill Newton goto no_dma; 2256f95f3850SWill Newton } 2257f95f3850SWill Newton } else { 22584a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2259f95f3850SWill Newton goto no_dma; 2260f95f3850SWill Newton } 2261f95f3850SWill Newton 2262f95f3850SWill Newton host->use_dma = 1; 2263f95f3850SWill Newton return; 2264f95f3850SWill Newton 2265f95f3850SWill Newton no_dma: 22664a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 2267f95f3850SWill Newton host->use_dma = 0; 2268f95f3850SWill Newton return; 2269f95f3850SWill Newton } 2270f95f3850SWill Newton 2271f95f3850SWill Newton static bool mci_wait_reset(struct device *dev, struct dw_mci *host) 2272f95f3850SWill Newton { 2273f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 2274f95f3850SWill Newton unsigned int ctrl; 2275f95f3850SWill Newton 2276f95f3850SWill Newton mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | 2277f95f3850SWill Newton SDMMC_CTRL_DMA_RESET)); 2278f95f3850SWill Newton 2279f95f3850SWill Newton /* wait till resets clear */ 2280f95f3850SWill Newton do { 2281f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 2282f95f3850SWill Newton if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | 2283f95f3850SWill Newton SDMMC_CTRL_DMA_RESET))) 2284f95f3850SWill Newton return true; 2285f95f3850SWill Newton } while (time_before(jiffies, timeout)); 2286f95f3850SWill Newton 2287f95f3850SWill Newton dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl); 2288f95f3850SWill Newton 2289f95f3850SWill Newton return false; 2290f95f3850SWill Newton } 2291f95f3850SWill Newton 2292c91eab4bSThomas Abraham #ifdef CONFIG_OF 2293c91eab4bSThomas Abraham static struct dw_mci_of_quirks { 2294c91eab4bSThomas Abraham char *quirk; 2295c91eab4bSThomas Abraham int id; 2296c91eab4bSThomas Abraham } of_quirks[] = { 2297c91eab4bSThomas Abraham { 2298c91eab4bSThomas Abraham .quirk = "broken-cd", 2299c91eab4bSThomas Abraham .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, 2300c91eab4bSThomas Abraham }, 2301c91eab4bSThomas Abraham }; 2302c91eab4bSThomas Abraham 2303c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2304c91eab4bSThomas Abraham { 2305c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2306c91eab4bSThomas Abraham struct device *dev = host->dev; 2307c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2308e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2309800d78bfSThomas Abraham int idx, ret; 23103c6d89eaSDoug Anderson u32 clock_frequency; 2311c91eab4bSThomas Abraham 2312c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2313c91eab4bSThomas Abraham if (!pdata) { 2314c91eab4bSThomas Abraham dev_err(dev, "could not allocate memory for pdata\n"); 2315c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2316c91eab4bSThomas Abraham } 2317c91eab4bSThomas Abraham 2318c91eab4bSThomas Abraham /* find out number of slots supported */ 2319c91eab4bSThomas Abraham if (of_property_read_u32(dev->of_node, "num-slots", 2320c91eab4bSThomas Abraham &pdata->num_slots)) { 2321c91eab4bSThomas Abraham dev_info(dev, "num-slots property not found, " 2322c91eab4bSThomas Abraham "assuming 1 slot is available\n"); 2323c91eab4bSThomas Abraham pdata->num_slots = 1; 2324c91eab4bSThomas Abraham } 2325c91eab4bSThomas Abraham 2326c91eab4bSThomas Abraham /* get quirks */ 2327c91eab4bSThomas Abraham for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) 2328c91eab4bSThomas Abraham if (of_get_property(np, of_quirks[idx].quirk, NULL)) 2329c91eab4bSThomas Abraham pdata->quirks |= of_quirks[idx].id; 2330c91eab4bSThomas Abraham 2331c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 2332c91eab4bSThomas Abraham dev_info(dev, "fifo-depth property not found, using " 2333c91eab4bSThomas Abraham "value of FIFOTH register as default\n"); 2334c91eab4bSThomas Abraham 2335c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2336c91eab4bSThomas Abraham 23373c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 23383c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 23393c6d89eaSDoug Anderson 2340cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2341cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2342800d78bfSThomas Abraham if (ret) 2343800d78bfSThomas Abraham return ERR_PTR(ret); 2344800d78bfSThomas Abraham } 2345800d78bfSThomas Abraham 2346ab269128SAbhilash Kesavan if (of_find_property(np, "keep-power-in-suspend", NULL)) 2347ab269128SAbhilash Kesavan pdata->pm_caps |= MMC_PM_KEEP_POWER; 2348ab269128SAbhilash Kesavan 2349ab269128SAbhilash Kesavan if (of_find_property(np, "enable-sdio-wakeup", NULL)) 2350ab269128SAbhilash Kesavan pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; 2351ab269128SAbhilash Kesavan 235210b49841SSeungwon Jeon if (of_find_property(np, "supports-highspeed", NULL)) 235310b49841SSeungwon Jeon pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; 235410b49841SSeungwon Jeon 23555dd63f52SSeungwon Jeon if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL)) 23565dd63f52SSeungwon Jeon pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR; 23575dd63f52SSeungwon Jeon 23585dd63f52SSeungwon Jeon if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL)) 23595dd63f52SSeungwon Jeon pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR; 23605dd63f52SSeungwon Jeon 2361c91eab4bSThomas Abraham return pdata; 2362c91eab4bSThomas Abraham } 2363c91eab4bSThomas Abraham 2364c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2365c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2366c91eab4bSThomas Abraham { 2367c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2368c91eab4bSThomas Abraham } 2369c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2370c91eab4bSThomas Abraham 237162ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 2372f95f3850SWill Newton { 2373e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 237462ca8034SShashidhar Hiremath int width, i, ret = 0; 2375f95f3850SWill Newton u32 fifo_size; 23761c2215b7SThomas Abraham int init_slots = 0; 2377f95f3850SWill Newton 2378c91eab4bSThomas Abraham if (!host->pdata) { 2379c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 2380c91eab4bSThomas Abraham if (IS_ERR(host->pdata)) { 2381c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 2382c91eab4bSThomas Abraham return -EINVAL; 2383c91eab4bSThomas Abraham } 2384f95f3850SWill Newton } 2385f95f3850SWill Newton 238662ca8034SShashidhar Hiremath if (!host->pdata->select_slot && host->pdata->num_slots > 1) { 23874a90920cSThomas Abraham dev_err(host->dev, 2388f95f3850SWill Newton "Platform data must supply select_slot function\n"); 238962ca8034SShashidhar Hiremath return -ENODEV; 2390f95f3850SWill Newton } 2391f95f3850SWill Newton 2392780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 2393f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 2394f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 2395f90a0612SThomas Abraham } else { 2396f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 2397f90a0612SThomas Abraham if (ret) { 2398f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 2399f90a0612SThomas Abraham return ret; 2400f90a0612SThomas Abraham } 2401f95f3850SWill Newton } 2402f95f3850SWill Newton 2403780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 2404f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 2405f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 24063c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 2407f90a0612SThomas Abraham } else { 2408f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 2409f90a0612SThomas Abraham if (ret) { 2410f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 2411f90a0612SThomas Abraham goto err_clk_biu; 2412f90a0612SThomas Abraham } 2413f90a0612SThomas Abraham 24143c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 24153c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 24163c6d89eaSDoug Anderson if (ret) 24173c6d89eaSDoug Anderson dev_warn(host->dev, 24183c6d89eaSDoug Anderson "Unable to set bus rate to %ul\n", 24193c6d89eaSDoug Anderson host->pdata->bus_hz); 24203c6d89eaSDoug Anderson } 2421f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 24223c6d89eaSDoug Anderson } 2423f90a0612SThomas Abraham 2424002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 2425002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 2426002f0d5cSYuvaraj Kumar C D if (ret) { 2427002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 2428002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 2429002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 2430002f0d5cSYuvaraj Kumar C D } 2431002f0d5cSYuvaraj Kumar C D } 2432002f0d5cSYuvaraj Kumar C D 2433cb27a843SJames Hogan if (drv_data && drv_data->setup_clock) { 2434cb27a843SJames Hogan ret = drv_data->setup_clock(host); 2435800d78bfSThomas Abraham if (ret) { 2436800d78bfSThomas Abraham dev_err(host->dev, 2437800d78bfSThomas Abraham "implementation specific clock setup failed\n"); 2438800d78bfSThomas Abraham goto err_clk_ciu; 2439800d78bfSThomas Abraham } 2440800d78bfSThomas Abraham } 2441800d78bfSThomas Abraham 2442a55d6ff0SMark Brown host->vmmc = devm_regulator_get_optional(host->dev, "vmmc"); 2443870556a3SDoug Anderson if (IS_ERR(host->vmmc)) { 2444870556a3SDoug Anderson ret = PTR_ERR(host->vmmc); 2445870556a3SDoug Anderson if (ret == -EPROBE_DEFER) 2446870556a3SDoug Anderson goto err_clk_ciu; 2447870556a3SDoug Anderson 2448870556a3SDoug Anderson dev_info(host->dev, "no vmmc regulator found: %d\n", ret); 2449870556a3SDoug Anderson host->vmmc = NULL; 2450870556a3SDoug Anderson } else { 2451870556a3SDoug Anderson ret = regulator_enable(host->vmmc); 2452870556a3SDoug Anderson if (ret) { 2453870556a3SDoug Anderson if (ret != -EPROBE_DEFER) 2454870556a3SDoug Anderson dev_err(host->dev, 2455870556a3SDoug Anderson "regulator_enable fail: %d\n", ret); 2456870556a3SDoug Anderson goto err_clk_ciu; 2457870556a3SDoug Anderson } 2458870556a3SDoug Anderson } 2459870556a3SDoug Anderson 2460f90a0612SThomas Abraham if (!host->bus_hz) { 2461f90a0612SThomas Abraham dev_err(host->dev, 2462f90a0612SThomas Abraham "Platform data must supply bus speed\n"); 2463f90a0612SThomas Abraham ret = -ENODEV; 2464870556a3SDoug Anderson goto err_regulator; 2465f90a0612SThomas Abraham } 2466f90a0612SThomas Abraham 246762ca8034SShashidhar Hiremath host->quirks = host->pdata->quirks; 2468f95f3850SWill Newton 2469f95f3850SWill Newton spin_lock_init(&host->lock); 2470f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 2471f95f3850SWill Newton 2472f95f3850SWill Newton /* 2473f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 2474f95f3850SWill Newton * the correct values. 2475f95f3850SWill Newton */ 2476f95f3850SWill Newton i = (mci_readl(host, HCON) >> 7) & 0x7; 2477f95f3850SWill Newton if (!i) { 2478f95f3850SWill Newton host->push_data = dw_mci_push_data16; 2479f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 2480f95f3850SWill Newton width = 16; 2481f95f3850SWill Newton host->data_shift = 1; 2482f95f3850SWill Newton } else if (i == 2) { 2483f95f3850SWill Newton host->push_data = dw_mci_push_data64; 2484f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 2485f95f3850SWill Newton width = 64; 2486f95f3850SWill Newton host->data_shift = 3; 2487f95f3850SWill Newton } else { 2488f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 2489f95f3850SWill Newton WARN((i != 1), 2490f95f3850SWill Newton "HCON reports a reserved host data width!\n" 2491f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 2492f95f3850SWill Newton host->push_data = dw_mci_push_data32; 2493f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 2494f95f3850SWill Newton width = 32; 2495f95f3850SWill Newton host->data_shift = 2; 2496f95f3850SWill Newton } 2497f95f3850SWill Newton 2498f95f3850SWill Newton /* Reset all blocks */ 24994a90920cSThomas Abraham if (!mci_wait_reset(host->dev, host)) 2500141a712aSSeungwon Jeon return -ENODEV; 2501141a712aSSeungwon Jeon 2502141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 2503141a712aSSeungwon Jeon dw_mci_init_dma(host); 2504f95f3850SWill Newton 2505f95f3850SWill Newton /* Clear the interrupts for the host controller */ 2506f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2507f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2508f95f3850SWill Newton 2509f95f3850SWill Newton /* Put in max timeout */ 2510f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 2511f95f3850SWill Newton 2512f95f3850SWill Newton /* 2513f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 2514f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 2515f95f3850SWill Newton */ 2516b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 2517b86d8253SJames Hogan /* 2518b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 2519b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 2520b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 2521b86d8253SJames Hogan * should put it in the platform data. 2522b86d8253SJames Hogan */ 2523f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 25248234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 2525b86d8253SJames Hogan } else { 2526b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 2527b86d8253SJames Hogan } 2528b86d8253SJames Hogan host->fifo_depth = fifo_size; 252952426899SSeungwon Jeon host->fifoth_val = 253052426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 2531e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 2532f95f3850SWill Newton 2533f95f3850SWill Newton /* disable clock to CIU */ 2534f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2535f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2536f95f3850SWill Newton 253763008768SJames Hogan /* 253863008768SJames Hogan * In 2.40a spec, Data offset is changed. 253963008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 254063008768SJames Hogan */ 254163008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 254263008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 254363008768SJames Hogan 254463008768SJames Hogan if (host->verid < DW_MMC_240A) 254563008768SJames Hogan host->data_offset = DATA_OFFSET; 254663008768SJames Hogan else 254763008768SJames Hogan host->data_offset = DATA_240A_OFFSET; 254863008768SJames Hogan 2549f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 255095dcc2cbSThomas Abraham host->card_workqueue = alloc_workqueue("dw-mci-card", 25511791b13eSJames Hogan WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); 2552ef7aef9aSWei Yongjun if (!host->card_workqueue) { 2553ef7aef9aSWei Yongjun ret = -ENOMEM; 25541791b13eSJames Hogan goto err_dmaunmap; 2555ef7aef9aSWei Yongjun } 25561791b13eSJames Hogan INIT_WORK(&host->card_work, dw_mci_work_routine_card); 2557780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 2558780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 2559f95f3850SWill Newton if (ret) 25601791b13eSJames Hogan goto err_workqueue; 2561f95f3850SWill Newton 2562f95f3850SWill Newton if (host->pdata->num_slots) 2563f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 2564f95f3850SWill Newton else 2565f95f3850SWill Newton host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; 2566f95f3850SWill Newton 25672da1d7f2SYuvaraj CD /* 25682da1d7f2SYuvaraj CD * Enable interrupts for command done, data over, data empty, card det, 25692da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 25702da1d7f2SYuvaraj CD */ 25712da1d7f2SYuvaraj CD mci_writel(host, RINTSTS, 0xFFFFFFFF); 25722da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 25732da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 25742da1d7f2SYuvaraj CD DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 25752da1d7f2SYuvaraj CD mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ 25762da1d7f2SYuvaraj CD 25772da1d7f2SYuvaraj CD dev_info(host->dev, "DW MMC controller at irq %d, " 25782da1d7f2SYuvaraj CD "%d bit host data width, " 25792da1d7f2SYuvaraj CD "%u deep fifo\n", 25802da1d7f2SYuvaraj CD host->irq, width, fifo_size); 25812da1d7f2SYuvaraj CD 2582f95f3850SWill Newton /* We need at least one slot to succeed */ 2583f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2584f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 25851c2215b7SThomas Abraham if (ret) 25861c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 25871c2215b7SThomas Abraham else 25881c2215b7SThomas Abraham init_slots++; 2589f95f3850SWill Newton } 25901c2215b7SThomas Abraham 25911c2215b7SThomas Abraham if (init_slots) { 25921c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 25931c2215b7SThomas Abraham } else { 25941c2215b7SThomas Abraham dev_dbg(host->dev, "attempted to initialize %d slots, " 25951c2215b7SThomas Abraham "but failed on all\n", host->num_slots); 2596780f22afSSeungwon Jeon goto err_workqueue; 2597f95f3850SWill Newton } 2598f95f3850SWill Newton 2599f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) 26004a90920cSThomas Abraham dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); 2601f95f3850SWill Newton 2602f95f3850SWill Newton return 0; 2603f95f3850SWill Newton 26041791b13eSJames Hogan err_workqueue: 260595dcc2cbSThomas Abraham destroy_workqueue(host->card_workqueue); 26061791b13eSJames Hogan 2607f95f3850SWill Newton err_dmaunmap: 2608f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2609f95f3850SWill Newton host->dma_ops->exit(host); 2610f95f3850SWill Newton 2611870556a3SDoug Anderson err_regulator: 2612780f22afSSeungwon Jeon if (host->vmmc) 2613c07946a3SJaehoon Chung regulator_disable(host->vmmc); 2614f90a0612SThomas Abraham 2615f90a0612SThomas Abraham err_clk_ciu: 2616780f22afSSeungwon Jeon if (!IS_ERR(host->ciu_clk)) 2617f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2618780f22afSSeungwon Jeon 2619f90a0612SThomas Abraham err_clk_biu: 2620780f22afSSeungwon Jeon if (!IS_ERR(host->biu_clk)) 2621f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2622780f22afSSeungwon Jeon 2623f95f3850SWill Newton return ret; 2624f95f3850SWill Newton } 262562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 2626f95f3850SWill Newton 262762ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 2628f95f3850SWill Newton { 2629f95f3850SWill Newton int i; 2630f95f3850SWill Newton 2631f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2632f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2633f95f3850SWill Newton 2634f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 26354a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 2636f95f3850SWill Newton if (host->slot[i]) 2637f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 2638f95f3850SWill Newton } 2639f95f3850SWill Newton 2640f95f3850SWill Newton /* disable clock to CIU */ 2641f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2642f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2643f95f3850SWill Newton 264495dcc2cbSThomas Abraham destroy_workqueue(host->card_workqueue); 2645f95f3850SWill Newton 2646f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2647f95f3850SWill Newton host->dma_ops->exit(host); 2648f95f3850SWill Newton 2649780f22afSSeungwon Jeon if (host->vmmc) 2650c07946a3SJaehoon Chung regulator_disable(host->vmmc); 2651c07946a3SJaehoon Chung 2652f90a0612SThomas Abraham if (!IS_ERR(host->ciu_clk)) 2653f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2654780f22afSSeungwon Jeon 2655f90a0612SThomas Abraham if (!IS_ERR(host->biu_clk)) 2656f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2657f95f3850SWill Newton } 265862ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 265962ca8034SShashidhar Hiremath 266062ca8034SShashidhar Hiremath 2661f95f3850SWill Newton 26626fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP 2663f95f3850SWill Newton /* 2664f95f3850SWill Newton * TODO: we should probably disable the clock to the card in the suspend path. 2665f95f3850SWill Newton */ 266662ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host) 2667f95f3850SWill Newton { 266862ca8034SShashidhar Hiremath int i, ret = 0; 2669f95f3850SWill Newton 2670f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2671f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 2672f95f3850SWill Newton if (!slot) 2673f95f3850SWill Newton continue; 2674f95f3850SWill Newton ret = mmc_suspend_host(slot->mmc); 2675f95f3850SWill Newton if (ret < 0) { 2676f95f3850SWill Newton while (--i >= 0) { 2677f95f3850SWill Newton slot = host->slot[i]; 2678f95f3850SWill Newton if (slot) 2679f95f3850SWill Newton mmc_resume_host(host->slot[i]->mmc); 2680f95f3850SWill Newton } 2681f95f3850SWill Newton return ret; 2682f95f3850SWill Newton } 2683f95f3850SWill Newton } 2684f95f3850SWill Newton 2685c07946a3SJaehoon Chung if (host->vmmc) 2686c07946a3SJaehoon Chung regulator_disable(host->vmmc); 2687c07946a3SJaehoon Chung 2688f95f3850SWill Newton return 0; 2689f95f3850SWill Newton } 269062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend); 2691f95f3850SWill Newton 269262ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host) 2693f95f3850SWill Newton { 2694f95f3850SWill Newton int i, ret; 2695f95f3850SWill Newton 2696f2f942ceSSachin Kamat if (host->vmmc) { 2697f2f942ceSSachin Kamat ret = regulator_enable(host->vmmc); 2698f2f942ceSSachin Kamat if (ret) { 2699f2f942ceSSachin Kamat dev_err(host->dev, 2700f2f942ceSSachin Kamat "failed to enable regulator: %d\n", ret); 2701f2f942ceSSachin Kamat return ret; 2702f2f942ceSSachin Kamat } 2703f2f942ceSSachin Kamat } 27041d6c4e0aSJaehoon Chung 27054a90920cSThomas Abraham if (!mci_wait_reset(host->dev, host)) { 2706e61cf118SJaehoon Chung ret = -ENODEV; 2707e61cf118SJaehoon Chung return ret; 2708e61cf118SJaehoon Chung } 2709e61cf118SJaehoon Chung 27103bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 2711141a712aSSeungwon Jeon host->dma_ops->init(host); 2712141a712aSSeungwon Jeon 271352426899SSeungwon Jeon /* 271452426899SSeungwon Jeon * Restore the initial value at FIFOTH register 271552426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 271652426899SSeungwon Jeon */ 2717e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 271852426899SSeungwon Jeon host->prev_blksz = 0; 2719e61cf118SJaehoon Chung 27202eb2944fSDoug Anderson /* Put in max timeout */ 27212eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 27222eb2944fSDoug Anderson 2723e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 2724e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 2725e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 2726e61cf118SJaehoon Chung DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 2727e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 2728e61cf118SJaehoon Chung 2729f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2730f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 2731f95f3850SWill Newton if (!slot) 2732f95f3850SWill Newton continue; 2733ab269128SAbhilash Kesavan if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { 2734ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 2735ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 2736ab269128SAbhilash Kesavan } 2737ab269128SAbhilash Kesavan 2738f95f3850SWill Newton ret = mmc_resume_host(host->slot[i]->mmc); 2739f95f3850SWill Newton if (ret < 0) 2740f95f3850SWill Newton return ret; 2741f95f3850SWill Newton } 2742f95f3850SWill Newton return 0; 2743f95f3850SWill Newton } 274462ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume); 27456fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */ 27466fe8890dSJaehoon Chung 2747f95f3850SWill Newton static int __init dw_mci_init(void) 2748f95f3850SWill Newton { 27498e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 275062ca8034SShashidhar Hiremath return 0; 2751f95f3850SWill Newton } 2752f95f3850SWill Newton 2753f95f3850SWill Newton static void __exit dw_mci_exit(void) 2754f95f3850SWill Newton { 2755f95f3850SWill Newton } 2756f95f3850SWill Newton 2757f95f3850SWill Newton module_init(dw_mci_init); 2758f95f3850SWill Newton module_exit(dw_mci_exit); 2759f95f3850SWill Newton 2760f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 2761f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 2762f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 2763f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 2764