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> 3290c2143aSSeungwon 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 11331bff450SSeungwon Jeon static inline bool dw_mci_fifo_reset(struct dw_mci *host); 11431bff450SSeungwon Jeon static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); 11531bff450SSeungwon Jeon 116f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 117f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v) 118f95f3850SWill Newton { 119f95f3850SWill Newton struct dw_mci_slot *slot = s->private; 120f95f3850SWill Newton struct mmc_request *mrq; 121f95f3850SWill Newton struct mmc_command *cmd; 122f95f3850SWill Newton struct mmc_command *stop; 123f95f3850SWill Newton struct mmc_data *data; 124f95f3850SWill Newton 125f95f3850SWill Newton /* Make sure we get a consistent snapshot */ 126f95f3850SWill Newton spin_lock_bh(&slot->host->lock); 127f95f3850SWill Newton mrq = slot->mrq; 128f95f3850SWill Newton 129f95f3850SWill Newton if (mrq) { 130f95f3850SWill Newton cmd = mrq->cmd; 131f95f3850SWill Newton data = mrq->data; 132f95f3850SWill Newton stop = mrq->stop; 133f95f3850SWill Newton 134f95f3850SWill Newton if (cmd) 135f95f3850SWill Newton seq_printf(s, 136f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 137f95f3850SWill Newton cmd->opcode, cmd->arg, cmd->flags, 138f95f3850SWill Newton cmd->resp[0], cmd->resp[1], cmd->resp[2], 139f95f3850SWill Newton cmd->resp[2], cmd->error); 140f95f3850SWill Newton if (data) 141f95f3850SWill Newton seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", 142f95f3850SWill Newton data->bytes_xfered, data->blocks, 143f95f3850SWill Newton data->blksz, data->flags, data->error); 144f95f3850SWill Newton if (stop) 145f95f3850SWill Newton seq_printf(s, 146f95f3850SWill Newton "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", 147f95f3850SWill Newton stop->opcode, stop->arg, stop->flags, 148f95f3850SWill Newton stop->resp[0], stop->resp[1], stop->resp[2], 149f95f3850SWill Newton stop->resp[2], stop->error); 150f95f3850SWill Newton } 151f95f3850SWill Newton 152f95f3850SWill Newton spin_unlock_bh(&slot->host->lock); 153f95f3850SWill Newton 154f95f3850SWill Newton return 0; 155f95f3850SWill Newton } 156f95f3850SWill Newton 157f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file) 158f95f3850SWill Newton { 159f95f3850SWill Newton return single_open(file, dw_mci_req_show, inode->i_private); 160f95f3850SWill Newton } 161f95f3850SWill Newton 162f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = { 163f95f3850SWill Newton .owner = THIS_MODULE, 164f95f3850SWill Newton .open = dw_mci_req_open, 165f95f3850SWill Newton .read = seq_read, 166f95f3850SWill Newton .llseek = seq_lseek, 167f95f3850SWill Newton .release = single_release, 168f95f3850SWill Newton }; 169f95f3850SWill Newton 170f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v) 171f95f3850SWill Newton { 172f95f3850SWill Newton seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); 173f95f3850SWill Newton seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); 174f95f3850SWill Newton seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); 175f95f3850SWill Newton seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); 176f95f3850SWill Newton seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); 177f95f3850SWill Newton seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); 178f95f3850SWill Newton 179f95f3850SWill Newton return 0; 180f95f3850SWill Newton } 181f95f3850SWill Newton 182f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file) 183f95f3850SWill Newton { 184f95f3850SWill Newton return single_open(file, dw_mci_regs_show, inode->i_private); 185f95f3850SWill Newton } 186f95f3850SWill Newton 187f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = { 188f95f3850SWill Newton .owner = THIS_MODULE, 189f95f3850SWill Newton .open = dw_mci_regs_open, 190f95f3850SWill Newton .read = seq_read, 191f95f3850SWill Newton .llseek = seq_lseek, 192f95f3850SWill Newton .release = single_release, 193f95f3850SWill Newton }; 194f95f3850SWill Newton 195f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot) 196f95f3850SWill Newton { 197f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 198f95f3850SWill Newton struct dw_mci *host = slot->host; 199f95f3850SWill Newton struct dentry *root; 200f95f3850SWill Newton struct dentry *node; 201f95f3850SWill Newton 202f95f3850SWill Newton root = mmc->debugfs_root; 203f95f3850SWill Newton if (!root) 204f95f3850SWill Newton return; 205f95f3850SWill Newton 206f95f3850SWill Newton node = debugfs_create_file("regs", S_IRUSR, root, host, 207f95f3850SWill Newton &dw_mci_regs_fops); 208f95f3850SWill Newton if (!node) 209f95f3850SWill Newton goto err; 210f95f3850SWill Newton 211f95f3850SWill Newton node = debugfs_create_file("req", S_IRUSR, root, slot, 212f95f3850SWill Newton &dw_mci_req_fops); 213f95f3850SWill Newton if (!node) 214f95f3850SWill Newton goto err; 215f95f3850SWill Newton 216f95f3850SWill Newton node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); 217f95f3850SWill Newton if (!node) 218f95f3850SWill Newton goto err; 219f95f3850SWill Newton 220f95f3850SWill Newton node = debugfs_create_x32("pending_events", S_IRUSR, root, 221f95f3850SWill Newton (u32 *)&host->pending_events); 222f95f3850SWill Newton if (!node) 223f95f3850SWill Newton goto err; 224f95f3850SWill Newton 225f95f3850SWill Newton node = debugfs_create_x32("completed_events", S_IRUSR, root, 226f95f3850SWill Newton (u32 *)&host->completed_events); 227f95f3850SWill Newton if (!node) 228f95f3850SWill Newton goto err; 229f95f3850SWill Newton 230f95f3850SWill Newton return; 231f95f3850SWill Newton 232f95f3850SWill Newton err: 233f95f3850SWill Newton dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 234f95f3850SWill Newton } 235f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */ 236f95f3850SWill Newton 237f95f3850SWill Newton static void dw_mci_set_timeout(struct dw_mci *host) 238f95f3850SWill Newton { 239f95f3850SWill Newton /* timeout (maximum) */ 240f95f3850SWill Newton mci_writel(host, TMOUT, 0xffffffff); 241f95f3850SWill Newton } 242f95f3850SWill Newton 243f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) 244f95f3850SWill Newton { 245f95f3850SWill Newton struct mmc_data *data; 246800d78bfSThomas Abraham struct dw_mci_slot *slot = mmc_priv(mmc); 247e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 248f95f3850SWill Newton u32 cmdr; 249f95f3850SWill Newton cmd->error = -EINPROGRESS; 250f95f3850SWill Newton 251f95f3850SWill Newton cmdr = cmd->opcode; 252f95f3850SWill Newton 25390c2143aSSeungwon Jeon if (cmd->opcode == MMC_STOP_TRANSMISSION || 25490c2143aSSeungwon Jeon cmd->opcode == MMC_GO_IDLE_STATE || 25590c2143aSSeungwon Jeon cmd->opcode == MMC_GO_INACTIVE_STATE || 25690c2143aSSeungwon Jeon (cmd->opcode == SD_IO_RW_DIRECT && 25790c2143aSSeungwon Jeon ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) 258f95f3850SWill Newton cmdr |= SDMMC_CMD_STOP; 259f95f3850SWill Newton else 26090c2143aSSeungwon Jeon if (cmd->opcode != MMC_SEND_STATUS && cmd->data) 261f95f3850SWill Newton cmdr |= SDMMC_CMD_PRV_DAT_WAIT; 262f95f3850SWill Newton 263f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 264f95f3850SWill Newton /* We expect a response, so set this bit */ 265f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_EXP; 266f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) 267f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_LONG; 268f95f3850SWill Newton } 269f95f3850SWill Newton 270f95f3850SWill Newton if (cmd->flags & MMC_RSP_CRC) 271f95f3850SWill Newton cmdr |= SDMMC_CMD_RESP_CRC; 272f95f3850SWill Newton 273f95f3850SWill Newton data = cmd->data; 274f95f3850SWill Newton if (data) { 275f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_EXP; 276f95f3850SWill Newton if (data->flags & MMC_DATA_STREAM) 277f95f3850SWill Newton cmdr |= SDMMC_CMD_STRM_MODE; 278f95f3850SWill Newton if (data->flags & MMC_DATA_WRITE) 279f95f3850SWill Newton cmdr |= SDMMC_CMD_DAT_WR; 280f95f3850SWill Newton } 281f95f3850SWill Newton 282cb27a843SJames Hogan if (drv_data && drv_data->prepare_command) 283cb27a843SJames Hogan drv_data->prepare_command(slot->host, &cmdr); 284800d78bfSThomas Abraham 285f95f3850SWill Newton return cmdr; 286f95f3850SWill Newton } 287f95f3850SWill Newton 28890c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) 28990c2143aSSeungwon Jeon { 29090c2143aSSeungwon Jeon struct mmc_command *stop; 29190c2143aSSeungwon Jeon u32 cmdr; 29290c2143aSSeungwon Jeon 29390c2143aSSeungwon Jeon if (!cmd->data) 29490c2143aSSeungwon Jeon return 0; 29590c2143aSSeungwon Jeon 29690c2143aSSeungwon Jeon stop = &host->stop_abort; 29790c2143aSSeungwon Jeon cmdr = cmd->opcode; 29890c2143aSSeungwon Jeon memset(stop, 0, sizeof(struct mmc_command)); 29990c2143aSSeungwon Jeon 30090c2143aSSeungwon Jeon if (cmdr == MMC_READ_SINGLE_BLOCK || 30190c2143aSSeungwon Jeon cmdr == MMC_READ_MULTIPLE_BLOCK || 30290c2143aSSeungwon Jeon cmdr == MMC_WRITE_BLOCK || 30390c2143aSSeungwon Jeon cmdr == MMC_WRITE_MULTIPLE_BLOCK) { 30490c2143aSSeungwon Jeon stop->opcode = MMC_STOP_TRANSMISSION; 30590c2143aSSeungwon Jeon stop->arg = 0; 30690c2143aSSeungwon Jeon stop->flags = MMC_RSP_R1B | MMC_CMD_AC; 30790c2143aSSeungwon Jeon } else if (cmdr == SD_IO_RW_EXTENDED) { 30890c2143aSSeungwon Jeon stop->opcode = SD_IO_RW_DIRECT; 30990c2143aSSeungwon Jeon stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | 31090c2143aSSeungwon Jeon ((cmd->arg >> 28) & 0x7); 31190c2143aSSeungwon Jeon stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; 31290c2143aSSeungwon Jeon } else { 31390c2143aSSeungwon Jeon return 0; 31490c2143aSSeungwon Jeon } 31590c2143aSSeungwon Jeon 31690c2143aSSeungwon Jeon cmdr = stop->opcode | SDMMC_CMD_STOP | 31790c2143aSSeungwon Jeon SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; 31890c2143aSSeungwon Jeon 31990c2143aSSeungwon Jeon return cmdr; 32090c2143aSSeungwon Jeon } 32190c2143aSSeungwon Jeon 322f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host, 323f95f3850SWill Newton struct mmc_command *cmd, u32 cmd_flags) 324f95f3850SWill Newton { 325f95f3850SWill Newton host->cmd = cmd; 3264a90920cSThomas Abraham dev_vdbg(host->dev, 327f95f3850SWill Newton "start command: ARGR=0x%08x CMDR=0x%08x\n", 328f95f3850SWill Newton cmd->arg, cmd_flags); 329f95f3850SWill Newton 330f95f3850SWill Newton mci_writel(host, CMDARG, cmd->arg); 331f95f3850SWill Newton wmb(); 332f95f3850SWill Newton 333f95f3850SWill Newton mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); 334f95f3850SWill Newton } 335f95f3850SWill Newton 33690c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) 337f95f3850SWill Newton { 33890c2143aSSeungwon Jeon struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; 33990c2143aSSeungwon Jeon dw_mci_start_command(host, stop, host->stop_cmdr); 340f95f3850SWill Newton } 341f95f3850SWill Newton 342f95f3850SWill Newton /* DMA interface functions */ 343f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host) 344f95f3850SWill Newton { 34503e8cb53SJames Hogan if (host->using_dma) { 346f95f3850SWill Newton host->dma_ops->stop(host); 347f95f3850SWill Newton host->dma_ops->cleanup(host); 348f95f3850SWill Newton } else { 349f95f3850SWill Newton /* Data transfer was stopped by the interrupt handler */ 350f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 351f95f3850SWill Newton } 352f95f3850SWill Newton } 353f95f3850SWill Newton 3549aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data) 3559aa51408SSeungwon Jeon { 3569aa51408SSeungwon Jeon if (data->flags & MMC_DATA_WRITE) 3579aa51408SSeungwon Jeon return DMA_TO_DEVICE; 3589aa51408SSeungwon Jeon else 3599aa51408SSeungwon Jeon return DMA_FROM_DEVICE; 3609aa51408SSeungwon Jeon } 3619aa51408SSeungwon Jeon 3629beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 363f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host) 364f95f3850SWill Newton { 365f95f3850SWill Newton struct mmc_data *data = host->data; 366f95f3850SWill Newton 367f95f3850SWill Newton if (data) 3689aa51408SSeungwon Jeon if (!data->host_cookie) 3694a90920cSThomas Abraham dma_unmap_sg(host->dev, 3709aa51408SSeungwon Jeon data->sg, 3719aa51408SSeungwon Jeon data->sg_len, 3729aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 373f95f3850SWill Newton } 374f95f3850SWill Newton 375*5ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host) 376*5ce9d961SSeungwon Jeon { 377*5ce9d961SSeungwon Jeon u32 bmod = mci_readl(host, BMOD); 378*5ce9d961SSeungwon Jeon /* Software reset of DMA */ 379*5ce9d961SSeungwon Jeon bmod |= SDMMC_IDMAC_SWRESET; 380*5ce9d961SSeungwon Jeon mci_writel(host, BMOD, bmod); 381*5ce9d961SSeungwon Jeon } 382*5ce9d961SSeungwon Jeon 383f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host) 384f95f3850SWill Newton { 385f95f3850SWill Newton u32 temp; 386f95f3850SWill Newton 387f95f3850SWill Newton /* Disable and reset the IDMAC interface */ 388f95f3850SWill Newton temp = mci_readl(host, CTRL); 389f95f3850SWill Newton temp &= ~SDMMC_CTRL_USE_IDMAC; 390f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_RESET; 391f95f3850SWill Newton mci_writel(host, CTRL, temp); 392f95f3850SWill Newton 393f95f3850SWill Newton /* Stop the IDMAC running */ 394f95f3850SWill Newton temp = mci_readl(host, BMOD); 395a5289a43SJaehoon Chung temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); 396*5ce9d961SSeungwon Jeon temp |= SDMMC_IDMAC_SWRESET; 397f95f3850SWill Newton mci_writel(host, BMOD, temp); 398f95f3850SWill Newton } 399f95f3850SWill Newton 400f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host) 401f95f3850SWill Newton { 402f95f3850SWill Newton struct mmc_data *data = host->data; 403f95f3850SWill Newton 4044a90920cSThomas Abraham dev_vdbg(host->dev, "DMA complete\n"); 405f95f3850SWill Newton 406f95f3850SWill Newton host->dma_ops->cleanup(host); 407f95f3850SWill Newton 408f95f3850SWill Newton /* 409f95f3850SWill Newton * If the card was removed, data will be NULL. No point in trying to 410f95f3850SWill Newton * send the stop command or waiting for NBUSY in this case. 411f95f3850SWill Newton */ 412f95f3850SWill Newton if (data) { 413f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 414f95f3850SWill Newton tasklet_schedule(&host->tasklet); 415f95f3850SWill Newton } 416f95f3850SWill Newton } 417f95f3850SWill Newton 418f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, 419f95f3850SWill Newton unsigned int sg_len) 420f95f3850SWill Newton { 421f95f3850SWill Newton int i; 422f95f3850SWill Newton struct idmac_desc *desc = host->sg_cpu; 423f95f3850SWill Newton 424f95f3850SWill Newton for (i = 0; i < sg_len; i++, desc++) { 425f95f3850SWill Newton unsigned int length = sg_dma_len(&data->sg[i]); 426f95f3850SWill Newton u32 mem_addr = sg_dma_address(&data->sg[i]); 427f95f3850SWill Newton 428f95f3850SWill Newton /* Set the OWN bit and disable interrupts for this descriptor */ 429f95f3850SWill Newton desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; 430f95f3850SWill Newton 431f95f3850SWill Newton /* Buffer length */ 432f95f3850SWill Newton IDMAC_SET_BUFFER1_SIZE(desc, length); 433f95f3850SWill Newton 434f95f3850SWill Newton /* Physical address to DMA to/from */ 435f95f3850SWill Newton desc->des2 = mem_addr; 436f95f3850SWill Newton } 437f95f3850SWill Newton 438f95f3850SWill Newton /* Set first descriptor */ 439f95f3850SWill Newton desc = host->sg_cpu; 440f95f3850SWill Newton desc->des0 |= IDMAC_DES0_FD; 441f95f3850SWill Newton 442f95f3850SWill Newton /* Set last descriptor */ 443f95f3850SWill Newton desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); 444f95f3850SWill Newton desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); 445f95f3850SWill Newton desc->des0 |= IDMAC_DES0_LD; 446f95f3850SWill Newton 447f95f3850SWill Newton wmb(); 448f95f3850SWill Newton } 449f95f3850SWill Newton 450f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) 451f95f3850SWill Newton { 452f95f3850SWill Newton u32 temp; 453f95f3850SWill Newton 454f95f3850SWill Newton dw_mci_translate_sglist(host, host->data, sg_len); 455f95f3850SWill Newton 456f95f3850SWill Newton /* Select IDMAC interface */ 457f95f3850SWill Newton temp = mci_readl(host, CTRL); 458f95f3850SWill Newton temp |= SDMMC_CTRL_USE_IDMAC; 459f95f3850SWill Newton mci_writel(host, CTRL, temp); 460f95f3850SWill Newton 461f95f3850SWill Newton wmb(); 462f95f3850SWill Newton 463f95f3850SWill Newton /* Enable the IDMAC */ 464f95f3850SWill Newton temp = mci_readl(host, BMOD); 465a5289a43SJaehoon Chung temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; 466f95f3850SWill Newton mci_writel(host, BMOD, temp); 467f95f3850SWill Newton 468f95f3850SWill Newton /* Start it running */ 469f95f3850SWill Newton mci_writel(host, PLDMND, 1); 470f95f3850SWill Newton } 471f95f3850SWill Newton 472f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host) 473f95f3850SWill Newton { 474f95f3850SWill Newton struct idmac_desc *p; 475897b69e7SSeungwon Jeon int i; 476f95f3850SWill Newton 477f95f3850SWill Newton /* Number of descriptors in the ring buffer */ 478f95f3850SWill Newton host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 479f95f3850SWill Newton 480f95f3850SWill Newton /* Forward link the descriptor list */ 481f95f3850SWill Newton for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) 482f95f3850SWill Newton p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); 483f95f3850SWill Newton 484f95f3850SWill Newton /* Set the last descriptor as the end-of-ring descriptor */ 485f95f3850SWill Newton p->des3 = host->sg_dma; 486f95f3850SWill Newton p->des0 = IDMAC_DES0_ER; 487f95f3850SWill Newton 488*5ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 489141a712aSSeungwon Jeon 490f95f3850SWill Newton /* Mask out interrupts - get Tx & Rx complete only */ 491fc79a4d6SJoonyoung Shim mci_writel(host, IDSTS, IDMAC_INT_CLR); 492f95f3850SWill Newton mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | 493f95f3850SWill Newton SDMMC_IDMAC_INT_TI); 494f95f3850SWill Newton 495f95f3850SWill Newton /* Set the descriptor base address */ 496f95f3850SWill Newton mci_writel(host, DBADDR, host->sg_dma); 497f95f3850SWill Newton return 0; 498f95f3850SWill Newton } 499f95f3850SWill Newton 5008e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = { 501885c3e80SSeungwon Jeon .init = dw_mci_idmac_init, 502885c3e80SSeungwon Jeon .start = dw_mci_idmac_start_dma, 503885c3e80SSeungwon Jeon .stop = dw_mci_idmac_stop_dma, 504885c3e80SSeungwon Jeon .complete = dw_mci_idmac_complete_dma, 505885c3e80SSeungwon Jeon .cleanup = dw_mci_dma_cleanup, 506885c3e80SSeungwon Jeon }; 507885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */ 508885c3e80SSeungwon Jeon 5099aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host, 5109aa51408SSeungwon Jeon struct mmc_data *data, 5119aa51408SSeungwon Jeon bool next) 512f95f3850SWill Newton { 513f95f3850SWill Newton struct scatterlist *sg; 5149aa51408SSeungwon Jeon unsigned int i, sg_len; 515f95f3850SWill Newton 5169aa51408SSeungwon Jeon if (!next && data->host_cookie) 5179aa51408SSeungwon Jeon return data->host_cookie; 518f95f3850SWill Newton 519f95f3850SWill Newton /* 520f95f3850SWill Newton * We don't do DMA on "complex" transfers, i.e. with 521f95f3850SWill Newton * non-word-aligned buffers or lengths. Also, we don't bother 522f95f3850SWill Newton * with all the DMA setup overhead for short transfers. 523f95f3850SWill Newton */ 524f95f3850SWill Newton if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 525f95f3850SWill Newton return -EINVAL; 5269aa51408SSeungwon Jeon 527f95f3850SWill Newton if (data->blksz & 3) 528f95f3850SWill Newton return -EINVAL; 529f95f3850SWill Newton 530f95f3850SWill Newton for_each_sg(data->sg, sg, data->sg_len, i) { 531f95f3850SWill Newton if (sg->offset & 3 || sg->length & 3) 532f95f3850SWill Newton return -EINVAL; 533f95f3850SWill Newton } 534f95f3850SWill Newton 5354a90920cSThomas Abraham sg_len = dma_map_sg(host->dev, 5369aa51408SSeungwon Jeon data->sg, 5379aa51408SSeungwon Jeon data->sg_len, 5389aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 5399aa51408SSeungwon Jeon if (sg_len == 0) 5409aa51408SSeungwon Jeon return -EINVAL; 5419aa51408SSeungwon Jeon 5429aa51408SSeungwon Jeon if (next) 5439aa51408SSeungwon Jeon data->host_cookie = sg_len; 5449aa51408SSeungwon Jeon 5459aa51408SSeungwon Jeon return sg_len; 5469aa51408SSeungwon Jeon } 5479aa51408SSeungwon Jeon 5489aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc, 5499aa51408SSeungwon Jeon struct mmc_request *mrq, 5509aa51408SSeungwon Jeon bool is_first_req) 5519aa51408SSeungwon Jeon { 5529aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 5539aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 5549aa51408SSeungwon Jeon 5559aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 5569aa51408SSeungwon Jeon return; 5579aa51408SSeungwon Jeon 5589aa51408SSeungwon Jeon if (data->host_cookie) { 5599aa51408SSeungwon Jeon data->host_cookie = 0; 5609aa51408SSeungwon Jeon return; 5619aa51408SSeungwon Jeon } 5629aa51408SSeungwon Jeon 5639aa51408SSeungwon Jeon if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) 5649aa51408SSeungwon Jeon data->host_cookie = 0; 5659aa51408SSeungwon Jeon } 5669aa51408SSeungwon Jeon 5679aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc, 5689aa51408SSeungwon Jeon struct mmc_request *mrq, 5699aa51408SSeungwon Jeon int err) 5709aa51408SSeungwon Jeon { 5719aa51408SSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 5729aa51408SSeungwon Jeon struct mmc_data *data = mrq->data; 5739aa51408SSeungwon Jeon 5749aa51408SSeungwon Jeon if (!slot->host->use_dma || !data) 5759aa51408SSeungwon Jeon return; 5769aa51408SSeungwon Jeon 5779aa51408SSeungwon Jeon if (data->host_cookie) 5784a90920cSThomas Abraham dma_unmap_sg(slot->host->dev, 5799aa51408SSeungwon Jeon data->sg, 5809aa51408SSeungwon Jeon data->sg_len, 5819aa51408SSeungwon Jeon dw_mci_get_dma_dir(data)); 5829aa51408SSeungwon Jeon data->host_cookie = 0; 5839aa51408SSeungwon Jeon } 5849aa51408SSeungwon Jeon 58552426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) 58652426899SSeungwon Jeon { 58752426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC 58852426899SSeungwon Jeon unsigned int blksz = data->blksz; 58952426899SSeungwon Jeon const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; 59052426899SSeungwon Jeon u32 fifo_width = 1 << host->data_shift; 59152426899SSeungwon Jeon u32 blksz_depth = blksz / fifo_width, fifoth_val; 59252426899SSeungwon Jeon u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; 59352426899SSeungwon Jeon int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1; 59452426899SSeungwon Jeon 59552426899SSeungwon Jeon tx_wmark = (host->fifo_depth) / 2; 59652426899SSeungwon Jeon tx_wmark_invers = host->fifo_depth - tx_wmark; 59752426899SSeungwon Jeon 59852426899SSeungwon Jeon /* 59952426899SSeungwon Jeon * MSIZE is '1', 60052426899SSeungwon Jeon * if blksz is not a multiple of the FIFO width 60152426899SSeungwon Jeon */ 60252426899SSeungwon Jeon if (blksz % fifo_width) { 60352426899SSeungwon Jeon msize = 0; 60452426899SSeungwon Jeon rx_wmark = 1; 60552426899SSeungwon Jeon goto done; 60652426899SSeungwon Jeon } 60752426899SSeungwon Jeon 60852426899SSeungwon Jeon do { 60952426899SSeungwon Jeon if (!((blksz_depth % mszs[idx]) || 61052426899SSeungwon Jeon (tx_wmark_invers % mszs[idx]))) { 61152426899SSeungwon Jeon msize = idx; 61252426899SSeungwon Jeon rx_wmark = mszs[idx] - 1; 61352426899SSeungwon Jeon break; 61452426899SSeungwon Jeon } 61552426899SSeungwon Jeon } while (--idx > 0); 61652426899SSeungwon Jeon /* 61752426899SSeungwon Jeon * If idx is '0', it won't be tried 61852426899SSeungwon Jeon * Thus, initial values are uesed 61952426899SSeungwon Jeon */ 62052426899SSeungwon Jeon done: 62152426899SSeungwon Jeon fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark); 62252426899SSeungwon Jeon mci_writel(host, FIFOTH, fifoth_val); 62352426899SSeungwon Jeon #endif 62452426899SSeungwon Jeon } 62552426899SSeungwon Jeon 626f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) 627f1d2736cSSeungwon Jeon { 628f1d2736cSSeungwon Jeon unsigned int blksz = data->blksz; 629f1d2736cSSeungwon Jeon u32 blksz_depth, fifo_depth; 630f1d2736cSSeungwon Jeon u16 thld_size; 631f1d2736cSSeungwon Jeon 632f1d2736cSSeungwon Jeon WARN_ON(!(data->flags & MMC_DATA_READ)); 633f1d2736cSSeungwon Jeon 634f1d2736cSSeungwon Jeon if (host->timing != MMC_TIMING_MMC_HS200 && 635f1d2736cSSeungwon Jeon host->timing != MMC_TIMING_UHS_SDR104) 636f1d2736cSSeungwon Jeon goto disable; 637f1d2736cSSeungwon Jeon 638f1d2736cSSeungwon Jeon blksz_depth = blksz / (1 << host->data_shift); 639f1d2736cSSeungwon Jeon fifo_depth = host->fifo_depth; 640f1d2736cSSeungwon Jeon 641f1d2736cSSeungwon Jeon if (blksz_depth > fifo_depth) 642f1d2736cSSeungwon Jeon goto disable; 643f1d2736cSSeungwon Jeon 644f1d2736cSSeungwon Jeon /* 645f1d2736cSSeungwon Jeon * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz' 646f1d2736cSSeungwon Jeon * If (blksz_depth) < (fifo_depth >> 1), should be thld_size = blksz 647f1d2736cSSeungwon Jeon * Currently just choose blksz. 648f1d2736cSSeungwon Jeon */ 649f1d2736cSSeungwon Jeon thld_size = blksz; 650f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1)); 651f1d2736cSSeungwon Jeon return; 652f1d2736cSSeungwon Jeon 653f1d2736cSSeungwon Jeon disable: 654f1d2736cSSeungwon Jeon mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0)); 655f1d2736cSSeungwon Jeon } 656f1d2736cSSeungwon Jeon 6579aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) 6589aa51408SSeungwon Jeon { 6599aa51408SSeungwon Jeon int sg_len; 6609aa51408SSeungwon Jeon u32 temp; 6619aa51408SSeungwon Jeon 6629aa51408SSeungwon Jeon host->using_dma = 0; 6639aa51408SSeungwon Jeon 6649aa51408SSeungwon Jeon /* If we don't have a channel, we can't do DMA */ 6659aa51408SSeungwon Jeon if (!host->use_dma) 6669aa51408SSeungwon Jeon return -ENODEV; 6679aa51408SSeungwon Jeon 6689aa51408SSeungwon Jeon sg_len = dw_mci_pre_dma_transfer(host, data, 0); 669a99aa9b9SSeungwon Jeon if (sg_len < 0) { 670a99aa9b9SSeungwon Jeon host->dma_ops->stop(host); 6719aa51408SSeungwon Jeon return sg_len; 672a99aa9b9SSeungwon Jeon } 6739aa51408SSeungwon Jeon 67403e8cb53SJames Hogan host->using_dma = 1; 67503e8cb53SJames Hogan 6764a90920cSThomas Abraham dev_vdbg(host->dev, 677f95f3850SWill Newton "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 678f95f3850SWill Newton (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma, 679f95f3850SWill Newton sg_len); 680f95f3850SWill Newton 68152426899SSeungwon Jeon /* 68252426899SSeungwon Jeon * Decide the MSIZE and RX/TX Watermark. 68352426899SSeungwon Jeon * If current block size is same with previous size, 68452426899SSeungwon Jeon * no need to update fifoth. 68552426899SSeungwon Jeon */ 68652426899SSeungwon Jeon if (host->prev_blksz != data->blksz) 68752426899SSeungwon Jeon dw_mci_adjust_fifoth(host, data); 68852426899SSeungwon Jeon 689f95f3850SWill Newton /* Enable the DMA interface */ 690f95f3850SWill Newton temp = mci_readl(host, CTRL); 691f95f3850SWill Newton temp |= SDMMC_CTRL_DMA_ENABLE; 692f95f3850SWill Newton mci_writel(host, CTRL, temp); 693f95f3850SWill Newton 694f95f3850SWill Newton /* Disable RX/TX IRQs, let DMA handle it */ 695f95f3850SWill Newton temp = mci_readl(host, INTMASK); 696f95f3850SWill Newton temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); 697f95f3850SWill Newton mci_writel(host, INTMASK, temp); 698f95f3850SWill Newton 699f95f3850SWill Newton host->dma_ops->start(host, sg_len); 700f95f3850SWill Newton 701f95f3850SWill Newton return 0; 702f95f3850SWill Newton } 703f95f3850SWill Newton 704f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) 705f95f3850SWill Newton { 706f95f3850SWill Newton u32 temp; 707f95f3850SWill Newton 708f95f3850SWill Newton data->error = -EINPROGRESS; 709f95f3850SWill Newton 710f95f3850SWill Newton WARN_ON(host->data); 711f95f3850SWill Newton host->sg = NULL; 712f95f3850SWill Newton host->data = data; 713f95f3850SWill Newton 714f1d2736cSSeungwon Jeon if (data->flags & MMC_DATA_READ) { 71555c5efbcSJames Hogan host->dir_status = DW_MCI_RECV_STATUS; 716f1d2736cSSeungwon Jeon dw_mci_ctrl_rd_thld(host, data); 717f1d2736cSSeungwon Jeon } else { 71855c5efbcSJames Hogan host->dir_status = DW_MCI_SEND_STATUS; 719f1d2736cSSeungwon Jeon } 72055c5efbcSJames Hogan 721f95f3850SWill Newton if (dw_mci_submit_data_dma(host, data)) { 722f9c2a0dcSSeungwon Jeon int flags = SG_MITER_ATOMIC; 723f9c2a0dcSSeungwon Jeon if (host->data->flags & MMC_DATA_READ) 724f9c2a0dcSSeungwon Jeon flags |= SG_MITER_TO_SG; 725f9c2a0dcSSeungwon Jeon else 726f9c2a0dcSSeungwon Jeon flags |= SG_MITER_FROM_SG; 727f9c2a0dcSSeungwon Jeon 728f9c2a0dcSSeungwon Jeon sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 729f95f3850SWill Newton host->sg = data->sg; 73034b664a2SJames Hogan host->part_buf_start = 0; 73134b664a2SJames Hogan host->part_buf_count = 0; 732f95f3850SWill Newton 733b40af3aaSJames Hogan mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); 734f95f3850SWill Newton temp = mci_readl(host, INTMASK); 735f95f3850SWill Newton temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; 736f95f3850SWill Newton mci_writel(host, INTMASK, temp); 737f95f3850SWill Newton 738f95f3850SWill Newton temp = mci_readl(host, CTRL); 739f95f3850SWill Newton temp &= ~SDMMC_CTRL_DMA_ENABLE; 740f95f3850SWill Newton mci_writel(host, CTRL, temp); 74152426899SSeungwon Jeon 74252426899SSeungwon Jeon /* 74352426899SSeungwon Jeon * Use the initial fifoth_val for PIO mode. 74452426899SSeungwon Jeon * If next issued data may be transfered by DMA mode, 74552426899SSeungwon Jeon * prev_blksz should be invalidated. 74652426899SSeungwon Jeon */ 74752426899SSeungwon Jeon mci_writel(host, FIFOTH, host->fifoth_val); 74852426899SSeungwon Jeon host->prev_blksz = 0; 74952426899SSeungwon Jeon } else { 75052426899SSeungwon Jeon /* 75152426899SSeungwon Jeon * Keep the current block size. 75252426899SSeungwon Jeon * It will be used to decide whether to update 75352426899SSeungwon Jeon * fifoth register next time. 75452426899SSeungwon Jeon */ 75552426899SSeungwon Jeon host->prev_blksz = data->blksz; 756f95f3850SWill Newton } 757f95f3850SWill Newton } 758f95f3850SWill Newton 759f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) 760f95f3850SWill Newton { 761f95f3850SWill Newton struct dw_mci *host = slot->host; 762f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 763f95f3850SWill Newton unsigned int cmd_status = 0; 764f95f3850SWill Newton 765f95f3850SWill Newton mci_writel(host, CMDARG, arg); 766f95f3850SWill Newton wmb(); 767f95f3850SWill Newton mci_writel(host, CMD, SDMMC_CMD_START | cmd); 768f95f3850SWill Newton 769f95f3850SWill Newton while (time_before(jiffies, timeout)) { 770f95f3850SWill Newton cmd_status = mci_readl(host, CMD); 771f95f3850SWill Newton if (!(cmd_status & SDMMC_CMD_START)) 772f95f3850SWill Newton return; 773f95f3850SWill Newton } 774f95f3850SWill Newton dev_err(&slot->mmc->class_dev, 775f95f3850SWill Newton "Timeout sending command (cmd %#x arg %#x status %#x)\n", 776f95f3850SWill Newton cmd, arg, cmd_status); 777f95f3850SWill Newton } 778f95f3850SWill Newton 779ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) 780f95f3850SWill Newton { 781f95f3850SWill Newton struct dw_mci *host = slot->host; 782fdf492a1SDoug Anderson unsigned int clock = slot->clock; 783f95f3850SWill Newton u32 div; 7849623b5b9SDoug Anderson u32 clk_en_a; 785f95f3850SWill Newton 786fdf492a1SDoug Anderson if (!clock) { 787fdf492a1SDoug Anderson mci_writel(host, CLKENA, 0); 788fdf492a1SDoug Anderson mci_send_cmd(slot, 789fdf492a1SDoug Anderson SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 790fdf492a1SDoug Anderson } else if (clock != host->current_speed || force_clkinit) { 791fdf492a1SDoug Anderson div = host->bus_hz / clock; 792fdf492a1SDoug Anderson if (host->bus_hz % clock && host->bus_hz > clock) 793f95f3850SWill Newton /* 794f95f3850SWill Newton * move the + 1 after the divide to prevent 795f95f3850SWill Newton * over-clocking the card. 796f95f3850SWill Newton */ 797e419990bSSeungwon Jeon div += 1; 798e419990bSSeungwon Jeon 799fdf492a1SDoug Anderson div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; 800f95f3850SWill Newton 801fdf492a1SDoug Anderson if ((clock << div) != slot->__clk_old || force_clkinit) 802f95f3850SWill Newton dev_info(&slot->mmc->class_dev, 803fdf492a1SDoug Anderson "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", 804fdf492a1SDoug Anderson slot->id, host->bus_hz, clock, 805fdf492a1SDoug Anderson div ? ((host->bus_hz / div) >> 1) : 806fdf492a1SDoug Anderson host->bus_hz, div); 807f95f3850SWill Newton 808f95f3850SWill Newton /* disable clock */ 809f95f3850SWill Newton mci_writel(host, CLKENA, 0); 810f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 811f95f3850SWill Newton 812f95f3850SWill Newton /* inform CIU */ 813f95f3850SWill Newton mci_send_cmd(slot, 814f95f3850SWill Newton SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 815f95f3850SWill Newton 816f95f3850SWill Newton /* set clock to desired speed */ 817f95f3850SWill Newton mci_writel(host, CLKDIV, div); 818f95f3850SWill Newton 819f95f3850SWill Newton /* inform CIU */ 820f95f3850SWill Newton mci_send_cmd(slot, 821f95f3850SWill Newton SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 822f95f3850SWill Newton 8239623b5b9SDoug Anderson /* enable clock; only low power if no SDIO */ 8249623b5b9SDoug Anderson clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 8259623b5b9SDoug Anderson if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) 8269623b5b9SDoug Anderson clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; 8279623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a); 828f95f3850SWill Newton 829f95f3850SWill Newton /* inform CIU */ 830f95f3850SWill Newton mci_send_cmd(slot, 831f95f3850SWill Newton SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); 832f95f3850SWill Newton 833fdf492a1SDoug Anderson /* keep the clock with reflecting clock dividor */ 834fdf492a1SDoug Anderson slot->__clk_old = clock << div; 835f95f3850SWill Newton } 836f95f3850SWill Newton 837fdf492a1SDoug Anderson host->current_speed = clock; 838fdf492a1SDoug Anderson 839f95f3850SWill Newton /* Set the current slot bus width */ 8401d56c453SSeungwon Jeon mci_writel(host, CTYPE, (slot->ctype << slot->id)); 841f95f3850SWill Newton } 842f95f3850SWill Newton 843053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host, 844053b3ce6SSeungwon Jeon struct dw_mci_slot *slot, 845053b3ce6SSeungwon Jeon struct mmc_command *cmd) 846f95f3850SWill Newton { 847f95f3850SWill Newton struct mmc_request *mrq; 848f95f3850SWill Newton struct mmc_data *data; 849f95f3850SWill Newton u32 cmdflags; 850f95f3850SWill Newton 851f95f3850SWill Newton mrq = slot->mrq; 852f95f3850SWill Newton if (host->pdata->select_slot) 853f95f3850SWill Newton host->pdata->select_slot(slot->id); 854f95f3850SWill Newton 855f95f3850SWill Newton host->cur_slot = slot; 856f95f3850SWill Newton host->mrq = mrq; 857f95f3850SWill Newton 858f95f3850SWill Newton host->pending_events = 0; 859f95f3850SWill Newton host->completed_events = 0; 860e352c813SSeungwon Jeon host->cmd_status = 0; 861f95f3850SWill Newton host->data_status = 0; 862e352c813SSeungwon Jeon host->dir_status = 0; 863f95f3850SWill Newton 864053b3ce6SSeungwon Jeon data = cmd->data; 865f95f3850SWill Newton if (data) { 866f95f3850SWill Newton dw_mci_set_timeout(host); 867f95f3850SWill Newton mci_writel(host, BYTCNT, data->blksz*data->blocks); 868f95f3850SWill Newton mci_writel(host, BLKSIZ, data->blksz); 869f95f3850SWill Newton } 870f95f3850SWill Newton 871f95f3850SWill Newton cmdflags = dw_mci_prepare_command(slot->mmc, cmd); 872f95f3850SWill Newton 873f95f3850SWill Newton /* this is the first command, send the initialization clock */ 874f95f3850SWill Newton if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags)) 875f95f3850SWill Newton cmdflags |= SDMMC_CMD_INIT; 876f95f3850SWill Newton 877f95f3850SWill Newton if (data) { 878f95f3850SWill Newton dw_mci_submit_data(host, data); 879f95f3850SWill Newton wmb(); 880f95f3850SWill Newton } 881f95f3850SWill Newton 882f95f3850SWill Newton dw_mci_start_command(host, cmd, cmdflags); 883f95f3850SWill Newton 884f95f3850SWill Newton if (mrq->stop) 885f95f3850SWill Newton host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 88690c2143aSSeungwon Jeon else 88790c2143aSSeungwon Jeon host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); 888f95f3850SWill Newton } 889f95f3850SWill Newton 890053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host, 891053b3ce6SSeungwon Jeon struct dw_mci_slot *slot) 892053b3ce6SSeungwon Jeon { 893053b3ce6SSeungwon Jeon struct mmc_request *mrq = slot->mrq; 894053b3ce6SSeungwon Jeon struct mmc_command *cmd; 895053b3ce6SSeungwon Jeon 896053b3ce6SSeungwon Jeon cmd = mrq->sbc ? mrq->sbc : mrq->cmd; 897053b3ce6SSeungwon Jeon __dw_mci_start_request(host, slot, cmd); 898053b3ce6SSeungwon Jeon } 899053b3ce6SSeungwon Jeon 9007456caaeSJames Hogan /* must be called with host->lock held */ 901f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, 902f95f3850SWill Newton struct mmc_request *mrq) 903f95f3850SWill Newton { 904f95f3850SWill Newton dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n", 905f95f3850SWill Newton host->state); 906f95f3850SWill Newton 907f95f3850SWill Newton slot->mrq = mrq; 908f95f3850SWill Newton 909f95f3850SWill Newton if (host->state == STATE_IDLE) { 910f95f3850SWill Newton host->state = STATE_SENDING_CMD; 911f95f3850SWill Newton dw_mci_start_request(host, slot); 912f95f3850SWill Newton } else { 913f95f3850SWill Newton list_add_tail(&slot->queue_node, &host->queue); 914f95f3850SWill Newton } 915f95f3850SWill Newton } 916f95f3850SWill Newton 917f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) 918f95f3850SWill Newton { 919f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 920f95f3850SWill Newton struct dw_mci *host = slot->host; 921f95f3850SWill Newton 922f95f3850SWill Newton WARN_ON(slot->mrq); 923f95f3850SWill Newton 9247456caaeSJames Hogan /* 9257456caaeSJames Hogan * The check for card presence and queueing of the request must be 9267456caaeSJames Hogan * atomic, otherwise the card could be removed in between and the 9277456caaeSJames Hogan * request wouldn't fail until another card was inserted. 9287456caaeSJames Hogan */ 9297456caaeSJames Hogan spin_lock_bh(&host->lock); 9307456caaeSJames Hogan 931f95f3850SWill Newton if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { 9327456caaeSJames Hogan spin_unlock_bh(&host->lock); 933f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 934f95f3850SWill Newton mmc_request_done(mmc, mrq); 935f95f3850SWill Newton return; 936f95f3850SWill Newton } 937f95f3850SWill Newton 938f95f3850SWill Newton dw_mci_queue_request(host, slot, mrq); 9397456caaeSJames Hogan 9407456caaeSJames Hogan spin_unlock_bh(&host->lock); 941f95f3850SWill Newton } 942f95f3850SWill Newton 943f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 944f95f3850SWill Newton { 945f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 946e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = slot->host->drv_data; 94741babf75SJaehoon Chung u32 regs; 948f95f3850SWill Newton 949f95f3850SWill Newton switch (ios->bus_width) { 950f95f3850SWill Newton case MMC_BUS_WIDTH_4: 951f95f3850SWill Newton slot->ctype = SDMMC_CTYPE_4BIT; 952f95f3850SWill Newton break; 953c9b2a06fSJaehoon Chung case MMC_BUS_WIDTH_8: 954c9b2a06fSJaehoon Chung slot->ctype = SDMMC_CTYPE_8BIT; 955c9b2a06fSJaehoon Chung break; 956b2f7cb45SJaehoon Chung default: 957b2f7cb45SJaehoon Chung /* set default 1 bit mode */ 958b2f7cb45SJaehoon Chung slot->ctype = SDMMC_CTYPE_1BIT; 959f95f3850SWill Newton } 960f95f3850SWill Newton 96141babf75SJaehoon Chung regs = mci_readl(slot->host, UHS_REG); 9623f514291SSeungwon Jeon 9633f514291SSeungwon Jeon /* DDR mode set */ 9643f514291SSeungwon Jeon if (ios->timing == MMC_TIMING_UHS_DDR50) 965c69042a5SHyeonsu Kim regs |= ((0x1 << slot->id) << 16); 9663f514291SSeungwon Jeon else 967c69042a5SHyeonsu Kim regs &= ~((0x1 << slot->id) << 16); 9683f514291SSeungwon Jeon 96941babf75SJaehoon Chung mci_writel(slot->host, UHS_REG, regs); 970f1d2736cSSeungwon Jeon slot->host->timing = ios->timing; 97141babf75SJaehoon Chung 972f95f3850SWill Newton /* 973f95f3850SWill Newton * Use mirror of ios->clock to prevent race with mmc 974f95f3850SWill Newton * core ios update when finding the minimum. 975f95f3850SWill Newton */ 976f95f3850SWill Newton slot->clock = ios->clock; 977f95f3850SWill Newton 978cb27a843SJames Hogan if (drv_data && drv_data->set_ios) 979cb27a843SJames Hogan drv_data->set_ios(slot->host, ios); 980800d78bfSThomas Abraham 981bf7cb224SJaehoon Chung /* Slot specific timing and width adjustment */ 982bf7cb224SJaehoon Chung dw_mci_setup_bus(slot, false); 983bf7cb224SJaehoon Chung 984f95f3850SWill Newton switch (ios->power_mode) { 985f95f3850SWill Newton case MMC_POWER_UP: 986f95f3850SWill Newton set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 987e6f34e2fSJames Hogan /* Power up slot */ 988e6f34e2fSJames Hogan if (slot->host->pdata->setpower) 989e6f34e2fSJames Hogan slot->host->pdata->setpower(slot->id, mmc->ocr_avail); 9904366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 9914366dcc5SJaehoon Chung regs |= (1 << slot->id); 9924366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 993e6f34e2fSJames Hogan break; 994e6f34e2fSJames Hogan case MMC_POWER_OFF: 995e6f34e2fSJames Hogan /* Power down slot */ 996e6f34e2fSJames Hogan if (slot->host->pdata->setpower) 997e6f34e2fSJames Hogan slot->host->pdata->setpower(slot->id, 0); 9984366dcc5SJaehoon Chung regs = mci_readl(slot->host, PWREN); 9994366dcc5SJaehoon Chung regs &= ~(1 << slot->id); 10004366dcc5SJaehoon Chung mci_writel(slot->host, PWREN, regs); 1001f95f3850SWill Newton break; 1002f95f3850SWill Newton default: 1003f95f3850SWill Newton break; 1004f95f3850SWill Newton } 1005f95f3850SWill Newton } 1006f95f3850SWill Newton 1007f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc) 1008f95f3850SWill Newton { 1009f95f3850SWill Newton int read_only; 1010f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1011f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 1012f95f3850SWill Newton 1013f95f3850SWill Newton /* Use platform get_ro function, else try on board write protect */ 10149640639bSDoug Anderson if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) 1015b4967aa5SThomas Abraham read_only = 0; 1016b4967aa5SThomas Abraham else if (brd->get_ro) 1017f95f3850SWill Newton read_only = brd->get_ro(slot->id); 101855a6ceb2SDoug Anderson else if (gpio_is_valid(slot->wp_gpio)) 101955a6ceb2SDoug Anderson read_only = gpio_get_value(slot->wp_gpio); 1020f95f3850SWill Newton else 1021f95f3850SWill Newton read_only = 1022f95f3850SWill Newton mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; 1023f95f3850SWill Newton 1024f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is %s\n", 1025f95f3850SWill Newton read_only ? "read-only" : "read-write"); 1026f95f3850SWill Newton 1027f95f3850SWill Newton return read_only; 1028f95f3850SWill Newton } 1029f95f3850SWill Newton 1030f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc) 1031f95f3850SWill Newton { 1032f95f3850SWill Newton int present; 1033f95f3850SWill Newton struct dw_mci_slot *slot = mmc_priv(mmc); 1034f95f3850SWill Newton struct dw_mci_board *brd = slot->host->pdata; 1035f95f3850SWill Newton 1036f95f3850SWill Newton /* Use platform get_cd function, else try onboard card detect */ 1037fc3d7720SJaehoon Chung if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) 1038fc3d7720SJaehoon Chung present = 1; 1039fc3d7720SJaehoon Chung else if (brd->get_cd) 1040f95f3850SWill Newton present = !brd->get_cd(slot->id); 1041f95f3850SWill Newton else 1042f95f3850SWill Newton present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) 1043f95f3850SWill Newton == 0 ? 1 : 0; 1044f95f3850SWill Newton 1045f95f3850SWill Newton if (present) 1046f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is present\n"); 1047f95f3850SWill Newton else 1048f95f3850SWill Newton dev_dbg(&mmc->class_dev, "card is not present\n"); 1049f95f3850SWill Newton 1050f95f3850SWill Newton return present; 1051f95f3850SWill Newton } 1052f95f3850SWill Newton 10539623b5b9SDoug Anderson /* 10549623b5b9SDoug Anderson * Disable lower power mode. 10559623b5b9SDoug Anderson * 10569623b5b9SDoug Anderson * Low power mode will stop the card clock when idle. According to the 10579623b5b9SDoug Anderson * description of the CLKENA register we should disable low power mode 10589623b5b9SDoug Anderson * for SDIO cards if we need SDIO interrupts to work. 10599623b5b9SDoug Anderson * 10609623b5b9SDoug Anderson * This function is fast if low power mode is already disabled. 10619623b5b9SDoug Anderson */ 10629623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot) 10639623b5b9SDoug Anderson { 10649623b5b9SDoug Anderson struct dw_mci *host = slot->host; 10659623b5b9SDoug Anderson u32 clk_en_a; 10669623b5b9SDoug Anderson const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; 10679623b5b9SDoug Anderson 10689623b5b9SDoug Anderson clk_en_a = mci_readl(host, CLKENA); 10699623b5b9SDoug Anderson 10709623b5b9SDoug Anderson if (clk_en_a & clken_low_pwr) { 10719623b5b9SDoug Anderson mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); 10729623b5b9SDoug Anderson mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | 10739623b5b9SDoug Anderson SDMMC_CMD_PRV_DAT_WAIT, 0); 10749623b5b9SDoug Anderson } 10759623b5b9SDoug Anderson } 10769623b5b9SDoug Anderson 10771a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) 10781a5c8e1fSShashidhar Hiremath { 10791a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = mmc_priv(mmc); 10801a5c8e1fSShashidhar Hiremath struct dw_mci *host = slot->host; 10811a5c8e1fSShashidhar Hiremath u32 int_mask; 10821a5c8e1fSShashidhar Hiremath 10831a5c8e1fSShashidhar Hiremath /* Enable/disable Slot Specific SDIO interrupt */ 10841a5c8e1fSShashidhar Hiremath int_mask = mci_readl(host, INTMASK); 10851a5c8e1fSShashidhar Hiremath if (enb) { 10869623b5b9SDoug Anderson /* 10879623b5b9SDoug Anderson * Turn off low power mode if it was enabled. This is a bit of 10889623b5b9SDoug Anderson * a heavy operation and we disable / enable IRQs a lot, so 10899623b5b9SDoug Anderson * we'll leave low power mode disabled and it will get 10909623b5b9SDoug Anderson * re-enabled again in dw_mci_setup_bus(). 10919623b5b9SDoug Anderson */ 10929623b5b9SDoug Anderson dw_mci_disable_low_power(slot); 10939623b5b9SDoug Anderson 10941a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 1095705ad047SKyoungil Kim (int_mask | SDMMC_INT_SDIO(slot->id))); 10961a5c8e1fSShashidhar Hiremath } else { 10971a5c8e1fSShashidhar Hiremath mci_writel(host, INTMASK, 1098705ad047SKyoungil Kim (int_mask & ~SDMMC_INT_SDIO(slot->id))); 10991a5c8e1fSShashidhar Hiremath } 11001a5c8e1fSShashidhar Hiremath } 11011a5c8e1fSShashidhar Hiremath 11020976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) 11030976f16dSSeungwon Jeon { 11040976f16dSSeungwon Jeon struct dw_mci_slot *slot = mmc_priv(mmc); 11050976f16dSSeungwon Jeon struct dw_mci *host = slot->host; 11060976f16dSSeungwon Jeon const struct dw_mci_drv_data *drv_data = host->drv_data; 11070976f16dSSeungwon Jeon struct dw_mci_tuning_data tuning_data; 11080976f16dSSeungwon Jeon int err = -ENOSYS; 11090976f16dSSeungwon Jeon 11100976f16dSSeungwon Jeon if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { 11110976f16dSSeungwon Jeon if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { 11120976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_8bit; 11130976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); 11140976f16dSSeungwon Jeon } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { 11150976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 11160976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 11170976f16dSSeungwon Jeon } else { 11180976f16dSSeungwon Jeon return -EINVAL; 11190976f16dSSeungwon Jeon } 11200976f16dSSeungwon Jeon } else if (opcode == MMC_SEND_TUNING_BLOCK) { 11210976f16dSSeungwon Jeon tuning_data.blk_pattern = tuning_blk_pattern_4bit; 11220976f16dSSeungwon Jeon tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); 11230976f16dSSeungwon Jeon } else { 11240976f16dSSeungwon Jeon dev_err(host->dev, 11250976f16dSSeungwon Jeon "Undefined command(%d) for tuning\n", opcode); 11260976f16dSSeungwon Jeon return -EINVAL; 11270976f16dSSeungwon Jeon } 11280976f16dSSeungwon Jeon 11290976f16dSSeungwon Jeon if (drv_data && drv_data->execute_tuning) 11300976f16dSSeungwon Jeon err = drv_data->execute_tuning(slot, opcode, &tuning_data); 11310976f16dSSeungwon Jeon return err; 11320976f16dSSeungwon Jeon } 11330976f16dSSeungwon Jeon 1134f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = { 1135f95f3850SWill Newton .request = dw_mci_request, 11369aa51408SSeungwon Jeon .pre_req = dw_mci_pre_req, 11379aa51408SSeungwon Jeon .post_req = dw_mci_post_req, 1138f95f3850SWill Newton .set_ios = dw_mci_set_ios, 1139f95f3850SWill Newton .get_ro = dw_mci_get_ro, 1140f95f3850SWill Newton .get_cd = dw_mci_get_cd, 11411a5c8e1fSShashidhar Hiremath .enable_sdio_irq = dw_mci_enable_sdio_irq, 11420976f16dSSeungwon Jeon .execute_tuning = dw_mci_execute_tuning, 1143f95f3850SWill Newton }; 1144f95f3850SWill Newton 1145f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) 1146f95f3850SWill Newton __releases(&host->lock) 1147f95f3850SWill Newton __acquires(&host->lock) 1148f95f3850SWill Newton { 1149f95f3850SWill Newton struct dw_mci_slot *slot; 1150f95f3850SWill Newton struct mmc_host *prev_mmc = host->cur_slot->mmc; 1151f95f3850SWill Newton 1152f95f3850SWill Newton WARN_ON(host->cmd || host->data); 1153f95f3850SWill Newton 1154f95f3850SWill Newton host->cur_slot->mrq = NULL; 1155f95f3850SWill Newton host->mrq = NULL; 1156f95f3850SWill Newton if (!list_empty(&host->queue)) { 1157f95f3850SWill Newton slot = list_entry(host->queue.next, 1158f95f3850SWill Newton struct dw_mci_slot, queue_node); 1159f95f3850SWill Newton list_del(&slot->queue_node); 11604a90920cSThomas Abraham dev_vdbg(host->dev, "list not empty: %s is next\n", 1161f95f3850SWill Newton mmc_hostname(slot->mmc)); 1162f95f3850SWill Newton host->state = STATE_SENDING_CMD; 1163f95f3850SWill Newton dw_mci_start_request(host, slot); 1164f95f3850SWill Newton } else { 11654a90920cSThomas Abraham dev_vdbg(host->dev, "list empty\n"); 1166f95f3850SWill Newton host->state = STATE_IDLE; 1167f95f3850SWill Newton } 1168f95f3850SWill Newton 1169f95f3850SWill Newton spin_unlock(&host->lock); 1170f95f3850SWill Newton mmc_request_done(prev_mmc, mrq); 1171f95f3850SWill Newton spin_lock(&host->lock); 1172f95f3850SWill Newton } 1173f95f3850SWill Newton 1174e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd) 1175f95f3850SWill Newton { 1176f95f3850SWill Newton u32 status = host->cmd_status; 1177f95f3850SWill Newton 1178f95f3850SWill Newton host->cmd_status = 0; 1179f95f3850SWill Newton 1180f95f3850SWill Newton /* Read the response from the card (up to 16 bytes) */ 1181f95f3850SWill Newton if (cmd->flags & MMC_RSP_PRESENT) { 1182f95f3850SWill Newton if (cmd->flags & MMC_RSP_136) { 1183f95f3850SWill Newton cmd->resp[3] = mci_readl(host, RESP0); 1184f95f3850SWill Newton cmd->resp[2] = mci_readl(host, RESP1); 1185f95f3850SWill Newton cmd->resp[1] = mci_readl(host, RESP2); 1186f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP3); 1187f95f3850SWill Newton } else { 1188f95f3850SWill Newton cmd->resp[0] = mci_readl(host, RESP0); 1189f95f3850SWill Newton cmd->resp[1] = 0; 1190f95f3850SWill Newton cmd->resp[2] = 0; 1191f95f3850SWill Newton cmd->resp[3] = 0; 1192f95f3850SWill Newton } 1193f95f3850SWill Newton } 1194f95f3850SWill Newton 1195f95f3850SWill Newton if (status & SDMMC_INT_RTO) 1196f95f3850SWill Newton cmd->error = -ETIMEDOUT; 1197f95f3850SWill Newton else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)) 1198f95f3850SWill Newton cmd->error = -EILSEQ; 1199f95f3850SWill Newton else if (status & SDMMC_INT_RESP_ERR) 1200f95f3850SWill Newton cmd->error = -EIO; 1201f95f3850SWill Newton else 1202f95f3850SWill Newton cmd->error = 0; 1203f95f3850SWill Newton 1204f95f3850SWill Newton if (cmd->error) { 1205f95f3850SWill Newton /* newer ip versions need a delay between retries */ 1206f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) 1207f95f3850SWill Newton mdelay(20); 1208f95f3850SWill Newton } 1209e352c813SSeungwon Jeon 1210e352c813SSeungwon Jeon return cmd->error; 1211e352c813SSeungwon Jeon } 1212e352c813SSeungwon Jeon 1213e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) 1214e352c813SSeungwon Jeon { 121531bff450SSeungwon Jeon u32 status = host->data_status; 1216e352c813SSeungwon Jeon 1217e352c813SSeungwon Jeon if (status & DW_MCI_DATA_ERROR_FLAGS) { 1218e352c813SSeungwon Jeon if (status & SDMMC_INT_DRTO) { 1219e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1220e352c813SSeungwon Jeon } else if (status & SDMMC_INT_DCRC) { 1221e352c813SSeungwon Jeon data->error = -EILSEQ; 1222e352c813SSeungwon Jeon } else if (status & SDMMC_INT_EBE) { 1223e352c813SSeungwon Jeon if (host->dir_status == 1224e352c813SSeungwon Jeon DW_MCI_SEND_STATUS) { 1225e352c813SSeungwon Jeon /* 1226e352c813SSeungwon Jeon * No data CRC status was returned. 1227e352c813SSeungwon Jeon * The number of bytes transferred 1228e352c813SSeungwon Jeon * will be exaggerated in PIO mode. 1229e352c813SSeungwon Jeon */ 1230e352c813SSeungwon Jeon data->bytes_xfered = 0; 1231e352c813SSeungwon Jeon data->error = -ETIMEDOUT; 1232e352c813SSeungwon Jeon } else if (host->dir_status == 1233e352c813SSeungwon Jeon DW_MCI_RECV_STATUS) { 1234e352c813SSeungwon Jeon data->error = -EIO; 1235e352c813SSeungwon Jeon } 1236e352c813SSeungwon Jeon } else { 1237e352c813SSeungwon Jeon /* SDMMC_INT_SBE is included */ 1238e352c813SSeungwon Jeon data->error = -EIO; 1239e352c813SSeungwon Jeon } 1240e352c813SSeungwon Jeon 1241e352c813SSeungwon Jeon dev_err(host->dev, "data error, status 0x%08x\n", status); 1242e352c813SSeungwon Jeon 1243e352c813SSeungwon Jeon /* 1244e352c813SSeungwon Jeon * After an error, there may be data lingering 124531bff450SSeungwon Jeon * in the FIFO 1246e352c813SSeungwon Jeon */ 124731bff450SSeungwon Jeon dw_mci_fifo_reset(host); 1248e352c813SSeungwon Jeon } else { 1249e352c813SSeungwon Jeon data->bytes_xfered = data->blocks * data->blksz; 1250e352c813SSeungwon Jeon data->error = 0; 1251e352c813SSeungwon Jeon } 1252e352c813SSeungwon Jeon 1253e352c813SSeungwon Jeon return data->error; 1254f95f3850SWill Newton } 1255f95f3850SWill Newton 1256f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv) 1257f95f3850SWill Newton { 1258f95f3850SWill Newton struct dw_mci *host = (struct dw_mci *)priv; 1259f95f3850SWill Newton struct mmc_data *data; 1260f95f3850SWill Newton struct mmc_command *cmd; 1261e352c813SSeungwon Jeon struct mmc_request *mrq; 1262f95f3850SWill Newton enum dw_mci_state state; 1263f95f3850SWill Newton enum dw_mci_state prev_state; 1264e352c813SSeungwon Jeon unsigned int err; 1265f95f3850SWill Newton 1266f95f3850SWill Newton spin_lock(&host->lock); 1267f95f3850SWill Newton 1268f95f3850SWill Newton state = host->state; 1269f95f3850SWill Newton data = host->data; 1270e352c813SSeungwon Jeon mrq = host->mrq; 1271f95f3850SWill Newton 1272f95f3850SWill Newton do { 1273f95f3850SWill Newton prev_state = state; 1274f95f3850SWill Newton 1275f95f3850SWill Newton switch (state) { 1276f95f3850SWill Newton case STATE_IDLE: 1277f95f3850SWill Newton break; 1278f95f3850SWill Newton 1279f95f3850SWill Newton case STATE_SENDING_CMD: 1280f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1281f95f3850SWill Newton &host->pending_events)) 1282f95f3850SWill Newton break; 1283f95f3850SWill Newton 1284f95f3850SWill Newton cmd = host->cmd; 1285f95f3850SWill Newton host->cmd = NULL; 1286f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->completed_events); 1287e352c813SSeungwon Jeon err = dw_mci_command_complete(host, cmd); 1288e352c813SSeungwon Jeon if (cmd == mrq->sbc && !err) { 1289053b3ce6SSeungwon Jeon prev_state = state = STATE_SENDING_CMD; 1290053b3ce6SSeungwon Jeon __dw_mci_start_request(host, host->cur_slot, 1291e352c813SSeungwon Jeon mrq->cmd); 1292053b3ce6SSeungwon Jeon goto unlock; 1293053b3ce6SSeungwon Jeon } 1294053b3ce6SSeungwon Jeon 1295e352c813SSeungwon Jeon if (cmd->data && err) { 129671abb133SSeungwon Jeon dw_mci_stop_dma(host); 129790c2143aSSeungwon Jeon send_stop_abort(host, data); 129871abb133SSeungwon Jeon state = STATE_SENDING_STOP; 129971abb133SSeungwon Jeon break; 130071abb133SSeungwon Jeon } 130171abb133SSeungwon Jeon 1302e352c813SSeungwon Jeon if (!cmd->data || err) { 1303e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1304f95f3850SWill Newton goto unlock; 1305f95f3850SWill Newton } 1306f95f3850SWill Newton 1307f95f3850SWill Newton prev_state = state = STATE_SENDING_DATA; 1308f95f3850SWill Newton /* fall through */ 1309f95f3850SWill Newton 1310f95f3850SWill Newton case STATE_SENDING_DATA: 1311f95f3850SWill Newton if (test_and_clear_bit(EVENT_DATA_ERROR, 1312f95f3850SWill Newton &host->pending_events)) { 1313f95f3850SWill Newton dw_mci_stop_dma(host); 131490c2143aSSeungwon Jeon send_stop_abort(host, data); 1315f95f3850SWill Newton state = STATE_DATA_ERROR; 1316f95f3850SWill Newton break; 1317f95f3850SWill Newton } 1318f95f3850SWill Newton 1319f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1320f95f3850SWill Newton &host->pending_events)) 1321f95f3850SWill Newton break; 1322f95f3850SWill Newton 1323f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->completed_events); 1324f95f3850SWill Newton prev_state = state = STATE_DATA_BUSY; 1325f95f3850SWill Newton /* fall through */ 1326f95f3850SWill Newton 1327f95f3850SWill Newton case STATE_DATA_BUSY: 1328f95f3850SWill Newton if (!test_and_clear_bit(EVENT_DATA_COMPLETE, 1329f95f3850SWill Newton &host->pending_events)) 1330f95f3850SWill Newton break; 1331f95f3850SWill Newton 1332f95f3850SWill Newton host->data = NULL; 1333f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->completed_events); 1334e352c813SSeungwon Jeon err = dw_mci_data_complete(host, data); 1335f95f3850SWill Newton 1336e352c813SSeungwon Jeon if (!err) { 1337e352c813SSeungwon Jeon if (!data->stop || mrq->sbc) { 1338e352c813SSeungwon Jeon if (mrq->sbc) 1339053b3ce6SSeungwon Jeon data->stop->error = 0; 1340e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1341053b3ce6SSeungwon Jeon goto unlock; 1342053b3ce6SSeungwon Jeon } 1343053b3ce6SSeungwon Jeon 134490c2143aSSeungwon Jeon /* stop command for open-ended transfer*/ 1345e352c813SSeungwon Jeon if (data->stop) 134690c2143aSSeungwon Jeon send_stop_abort(host, data); 134790c2143aSSeungwon Jeon } 1348e352c813SSeungwon Jeon 1349e352c813SSeungwon Jeon /* 1350e352c813SSeungwon Jeon * If err has non-zero, 1351e352c813SSeungwon Jeon * stop-abort command has been already issued. 1352e352c813SSeungwon Jeon */ 1353e352c813SSeungwon Jeon prev_state = state = STATE_SENDING_STOP; 1354e352c813SSeungwon Jeon 1355f95f3850SWill Newton /* fall through */ 1356f95f3850SWill Newton 1357f95f3850SWill Newton case STATE_SENDING_STOP: 1358f95f3850SWill Newton if (!test_and_clear_bit(EVENT_CMD_COMPLETE, 1359f95f3850SWill Newton &host->pending_events)) 1360f95f3850SWill Newton break; 1361f95f3850SWill Newton 136271abb133SSeungwon Jeon /* CMD error in data command */ 136331bff450SSeungwon Jeon if (mrq->cmd->error && mrq->data) 136431bff450SSeungwon Jeon dw_mci_fifo_reset(host); 136571abb133SSeungwon Jeon 1366f95f3850SWill Newton host->cmd = NULL; 136771abb133SSeungwon Jeon host->data = NULL; 136890c2143aSSeungwon Jeon 1369e352c813SSeungwon Jeon if (mrq->stop) 1370e352c813SSeungwon Jeon dw_mci_command_complete(host, mrq->stop); 137190c2143aSSeungwon Jeon else 137290c2143aSSeungwon Jeon host->cmd_status = 0; 137390c2143aSSeungwon Jeon 1374e352c813SSeungwon Jeon dw_mci_request_end(host, mrq); 1375f95f3850SWill Newton goto unlock; 1376f95f3850SWill Newton 1377f95f3850SWill Newton case STATE_DATA_ERROR: 1378f95f3850SWill Newton if (!test_and_clear_bit(EVENT_XFER_COMPLETE, 1379f95f3850SWill Newton &host->pending_events)) 1380f95f3850SWill Newton break; 1381f95f3850SWill Newton 1382f95f3850SWill Newton state = STATE_DATA_BUSY; 1383f95f3850SWill Newton break; 1384f95f3850SWill Newton } 1385f95f3850SWill Newton } while (state != prev_state); 1386f95f3850SWill Newton 1387f95f3850SWill Newton host->state = state; 1388f95f3850SWill Newton unlock: 1389f95f3850SWill Newton spin_unlock(&host->lock); 1390f95f3850SWill Newton 1391f95f3850SWill Newton } 1392f95f3850SWill Newton 139334b664a2SJames Hogan /* push final bytes to part_buf, only use during push */ 139434b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt) 139534b664a2SJames Hogan { 139634b664a2SJames Hogan memcpy((void *)&host->part_buf, buf, cnt); 139734b664a2SJames Hogan host->part_buf_count = cnt; 139834b664a2SJames Hogan } 139934b664a2SJames Hogan 140034b664a2SJames Hogan /* append bytes to part_buf, only use during push */ 140134b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt) 140234b664a2SJames Hogan { 140334b664a2SJames Hogan cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count); 140434b664a2SJames Hogan memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt); 140534b664a2SJames Hogan host->part_buf_count += cnt; 140634b664a2SJames Hogan return cnt; 140734b664a2SJames Hogan } 140834b664a2SJames Hogan 140934b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */ 141034b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt) 141134b664a2SJames Hogan { 141234b664a2SJames Hogan cnt = min(cnt, (int)host->part_buf_count); 141334b664a2SJames Hogan if (cnt) { 141434b664a2SJames Hogan memcpy(buf, (void *)&host->part_buf + host->part_buf_start, 141534b664a2SJames Hogan cnt); 141634b664a2SJames Hogan host->part_buf_count -= cnt; 141734b664a2SJames Hogan host->part_buf_start += cnt; 141834b664a2SJames Hogan } 141934b664a2SJames Hogan return cnt; 142034b664a2SJames Hogan } 142134b664a2SJames Hogan 142234b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */ 142334b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) 142434b664a2SJames Hogan { 142534b664a2SJames Hogan memcpy(buf, &host->part_buf, cnt); 142634b664a2SJames Hogan host->part_buf_start = cnt; 142734b664a2SJames Hogan host->part_buf_count = (1 << host->data_shift) - cnt; 142834b664a2SJames Hogan } 142934b664a2SJames Hogan 1430f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) 1431f95f3850SWill Newton { 1432cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1433cfbeb59cSMarkos Chandras int init_cnt = cnt; 1434cfbeb59cSMarkos Chandras 143534b664a2SJames Hogan /* try and push anything in the part_buf */ 143634b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 143734b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 143834b664a2SJames Hogan buf += len; 143934b664a2SJames Hogan cnt -= len; 1440cfbeb59cSMarkos Chandras if (host->part_buf_count == 2) { 14414e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 14424e0a5adfSJaehoon Chung host->part_buf16); 144334b664a2SJames Hogan host->part_buf_count = 0; 144434b664a2SJames Hogan } 144534b664a2SJames Hogan } 144634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 144734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 144834b664a2SJames Hogan while (cnt >= 2) { 144934b664a2SJames Hogan u16 aligned_buf[64]; 145034b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 145134b664a2SJames Hogan int items = len >> 1; 145234b664a2SJames Hogan int i; 145334b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 145434b664a2SJames Hogan memcpy(aligned_buf, buf, len); 145534b664a2SJames Hogan buf += len; 145634b664a2SJames Hogan cnt -= len; 145734b664a2SJames Hogan /* push data from aligned buffer into fifo */ 145834b664a2SJames Hogan for (i = 0; i < items; ++i) 14594e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 14604e0a5adfSJaehoon Chung aligned_buf[i]); 146134b664a2SJames Hogan } 146234b664a2SJames Hogan } else 146334b664a2SJames Hogan #endif 146434b664a2SJames Hogan { 146534b664a2SJames Hogan u16 *pdata = buf; 146634b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 14674e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), *pdata++); 146834b664a2SJames Hogan buf = pdata; 146934b664a2SJames Hogan } 147034b664a2SJames Hogan /* put anything remaining in the part_buf */ 147134b664a2SJames Hogan if (cnt) { 147234b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1473cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1474cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1475cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 14764e0a5adfSJaehoon Chung mci_writew(host, DATA(host->data_offset), 14774e0a5adfSJaehoon Chung host->part_buf16); 1478f95f3850SWill Newton } 1479f95f3850SWill Newton } 1480f95f3850SWill Newton 1481f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) 1482f95f3850SWill Newton { 148334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 148434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x1)) { 148534b664a2SJames Hogan while (cnt >= 2) { 148634b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 148734b664a2SJames Hogan u16 aligned_buf[64]; 148834b664a2SJames Hogan int len = min(cnt & -2, (int)sizeof(aligned_buf)); 148934b664a2SJames Hogan int items = len >> 1; 149034b664a2SJames Hogan int i; 149134b664a2SJames Hogan for (i = 0; i < items; ++i) 14924e0a5adfSJaehoon Chung aligned_buf[i] = mci_readw(host, 14934e0a5adfSJaehoon Chung DATA(host->data_offset)); 149434b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 149534b664a2SJames Hogan memcpy(buf, aligned_buf, len); 149634b664a2SJames Hogan buf += len; 149734b664a2SJames Hogan cnt -= len; 149834b664a2SJames Hogan } 149934b664a2SJames Hogan } else 150034b664a2SJames Hogan #endif 150134b664a2SJames Hogan { 150234b664a2SJames Hogan u16 *pdata = buf; 150334b664a2SJames Hogan for (; cnt >= 2; cnt -= 2) 15044e0a5adfSJaehoon Chung *pdata++ = mci_readw(host, DATA(host->data_offset)); 150534b664a2SJames Hogan buf = pdata; 150634b664a2SJames Hogan } 150734b664a2SJames Hogan if (cnt) { 15084e0a5adfSJaehoon Chung host->part_buf16 = mci_readw(host, DATA(host->data_offset)); 150934b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1510f95f3850SWill Newton } 1511f95f3850SWill Newton } 1512f95f3850SWill Newton 1513f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) 1514f95f3850SWill Newton { 1515cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1516cfbeb59cSMarkos Chandras int init_cnt = cnt; 1517cfbeb59cSMarkos Chandras 151834b664a2SJames Hogan /* try and push anything in the part_buf */ 151934b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 152034b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 152134b664a2SJames Hogan buf += len; 152234b664a2SJames Hogan cnt -= len; 1523cfbeb59cSMarkos Chandras if (host->part_buf_count == 4) { 15244e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 15254e0a5adfSJaehoon Chung host->part_buf32); 152634b664a2SJames Hogan host->part_buf_count = 0; 152734b664a2SJames Hogan } 152834b664a2SJames Hogan } 152934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 153034b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 153134b664a2SJames Hogan while (cnt >= 4) { 153234b664a2SJames Hogan u32 aligned_buf[32]; 153334b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 153434b664a2SJames Hogan int items = len >> 2; 153534b664a2SJames Hogan int i; 153634b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 153734b664a2SJames Hogan memcpy(aligned_buf, buf, len); 153834b664a2SJames Hogan buf += len; 153934b664a2SJames Hogan cnt -= len; 154034b664a2SJames Hogan /* push data from aligned buffer into fifo */ 154134b664a2SJames Hogan for (i = 0; i < items; ++i) 15424e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 15434e0a5adfSJaehoon Chung aligned_buf[i]); 154434b664a2SJames Hogan } 154534b664a2SJames Hogan } else 154634b664a2SJames Hogan #endif 154734b664a2SJames Hogan { 154834b664a2SJames Hogan u32 *pdata = buf; 154934b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 15504e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), *pdata++); 155134b664a2SJames Hogan buf = pdata; 155234b664a2SJames Hogan } 155334b664a2SJames Hogan /* put anything remaining in the part_buf */ 155434b664a2SJames Hogan if (cnt) { 155534b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1556cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1557cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1558cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 15594e0a5adfSJaehoon Chung mci_writel(host, DATA(host->data_offset), 15604e0a5adfSJaehoon Chung host->part_buf32); 1561f95f3850SWill Newton } 1562f95f3850SWill Newton } 1563f95f3850SWill Newton 1564f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) 1565f95f3850SWill Newton { 156634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 156734b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x3)) { 156834b664a2SJames Hogan while (cnt >= 4) { 156934b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 157034b664a2SJames Hogan u32 aligned_buf[32]; 157134b664a2SJames Hogan int len = min(cnt & -4, (int)sizeof(aligned_buf)); 157234b664a2SJames Hogan int items = len >> 2; 157334b664a2SJames Hogan int i; 157434b664a2SJames Hogan for (i = 0; i < items; ++i) 15754e0a5adfSJaehoon Chung aligned_buf[i] = mci_readl(host, 15764e0a5adfSJaehoon Chung DATA(host->data_offset)); 157734b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 157834b664a2SJames Hogan memcpy(buf, aligned_buf, len); 157934b664a2SJames Hogan buf += len; 158034b664a2SJames Hogan cnt -= len; 158134b664a2SJames Hogan } 158234b664a2SJames Hogan } else 158334b664a2SJames Hogan #endif 158434b664a2SJames Hogan { 158534b664a2SJames Hogan u32 *pdata = buf; 158634b664a2SJames Hogan for (; cnt >= 4; cnt -= 4) 15874e0a5adfSJaehoon Chung *pdata++ = mci_readl(host, DATA(host->data_offset)); 158834b664a2SJames Hogan buf = pdata; 158934b664a2SJames Hogan } 159034b664a2SJames Hogan if (cnt) { 15914e0a5adfSJaehoon Chung host->part_buf32 = mci_readl(host, DATA(host->data_offset)); 159234b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 1593f95f3850SWill Newton } 1594f95f3850SWill Newton } 1595f95f3850SWill Newton 1596f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) 1597f95f3850SWill Newton { 1598cfbeb59cSMarkos Chandras struct mmc_data *data = host->data; 1599cfbeb59cSMarkos Chandras int init_cnt = cnt; 1600cfbeb59cSMarkos Chandras 160134b664a2SJames Hogan /* try and push anything in the part_buf */ 160234b664a2SJames Hogan if (unlikely(host->part_buf_count)) { 160334b664a2SJames Hogan int len = dw_mci_push_part_bytes(host, buf, cnt); 160434b664a2SJames Hogan buf += len; 160534b664a2SJames Hogan cnt -= len; 1606c09fbd74SSeungwon Jeon 1607cfbeb59cSMarkos Chandras if (host->part_buf_count == 8) { 1608c09fbd74SSeungwon Jeon mci_writeq(host, DATA(host->data_offset), 16094e0a5adfSJaehoon Chung host->part_buf); 161034b664a2SJames Hogan host->part_buf_count = 0; 161134b664a2SJames Hogan } 161234b664a2SJames Hogan } 161334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 161434b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 161534b664a2SJames Hogan while (cnt >= 8) { 161634b664a2SJames Hogan u64 aligned_buf[16]; 161734b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 161834b664a2SJames Hogan int items = len >> 3; 161934b664a2SJames Hogan int i; 162034b664a2SJames Hogan /* memcpy from input buffer into aligned buffer */ 162134b664a2SJames Hogan memcpy(aligned_buf, buf, len); 162234b664a2SJames Hogan buf += len; 162334b664a2SJames Hogan cnt -= len; 162434b664a2SJames Hogan /* push data from aligned buffer into fifo */ 162534b664a2SJames Hogan for (i = 0; i < items; ++i) 16264e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 16274e0a5adfSJaehoon Chung aligned_buf[i]); 162834b664a2SJames Hogan } 162934b664a2SJames Hogan } else 163034b664a2SJames Hogan #endif 163134b664a2SJames Hogan { 163234b664a2SJames Hogan u64 *pdata = buf; 163334b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 16344e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), *pdata++); 163534b664a2SJames Hogan buf = pdata; 163634b664a2SJames Hogan } 163734b664a2SJames Hogan /* put anything remaining in the part_buf */ 163834b664a2SJames Hogan if (cnt) { 163934b664a2SJames Hogan dw_mci_set_part_bytes(host, buf, cnt); 1640cfbeb59cSMarkos Chandras /* Push data if we have reached the expected data length */ 1641cfbeb59cSMarkos Chandras if ((data->bytes_xfered + init_cnt) == 1642cfbeb59cSMarkos Chandras (data->blksz * data->blocks)) 16434e0a5adfSJaehoon Chung mci_writeq(host, DATA(host->data_offset), 16444e0a5adfSJaehoon Chung host->part_buf); 1645f95f3850SWill Newton } 1646f95f3850SWill Newton } 1647f95f3850SWill Newton 1648f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) 1649f95f3850SWill Newton { 165034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 165134b664a2SJames Hogan if (unlikely((unsigned long)buf & 0x7)) { 165234b664a2SJames Hogan while (cnt >= 8) { 165334b664a2SJames Hogan /* pull data from fifo into aligned buffer */ 165434b664a2SJames Hogan u64 aligned_buf[16]; 165534b664a2SJames Hogan int len = min(cnt & -8, (int)sizeof(aligned_buf)); 165634b664a2SJames Hogan int items = len >> 3; 165734b664a2SJames Hogan int i; 165834b664a2SJames Hogan for (i = 0; i < items; ++i) 16594e0a5adfSJaehoon Chung aligned_buf[i] = mci_readq(host, 16604e0a5adfSJaehoon Chung DATA(host->data_offset)); 166134b664a2SJames Hogan /* memcpy from aligned buffer into output buffer */ 166234b664a2SJames Hogan memcpy(buf, aligned_buf, len); 166334b664a2SJames Hogan buf += len; 166434b664a2SJames Hogan cnt -= len; 1665f95f3850SWill Newton } 166634b664a2SJames Hogan } else 166734b664a2SJames Hogan #endif 166834b664a2SJames Hogan { 166934b664a2SJames Hogan u64 *pdata = buf; 167034b664a2SJames Hogan for (; cnt >= 8; cnt -= 8) 16714e0a5adfSJaehoon Chung *pdata++ = mci_readq(host, DATA(host->data_offset)); 167234b664a2SJames Hogan buf = pdata; 167334b664a2SJames Hogan } 167434b664a2SJames Hogan if (cnt) { 16754e0a5adfSJaehoon Chung host->part_buf = mci_readq(host, DATA(host->data_offset)); 167634b664a2SJames Hogan dw_mci_pull_final_bytes(host, buf, cnt); 167734b664a2SJames Hogan } 167834b664a2SJames Hogan } 167934b664a2SJames Hogan 168034b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) 168134b664a2SJames Hogan { 168234b664a2SJames Hogan int len; 168334b664a2SJames Hogan 168434b664a2SJames Hogan /* get remaining partial bytes */ 168534b664a2SJames Hogan len = dw_mci_pull_part_bytes(host, buf, cnt); 168634b664a2SJames Hogan if (unlikely(len == cnt)) 168734b664a2SJames Hogan return; 168834b664a2SJames Hogan buf += len; 168934b664a2SJames Hogan cnt -= len; 169034b664a2SJames Hogan 169134b664a2SJames Hogan /* get the rest of the data */ 169234b664a2SJames Hogan host->pull_data(host, buf, cnt); 1693f95f3850SWill Newton } 1694f95f3850SWill Newton 169587a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) 1696f95f3850SWill Newton { 1697f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1698f9c2a0dcSSeungwon Jeon void *buf; 1699f9c2a0dcSSeungwon Jeon unsigned int offset; 1700f95f3850SWill Newton struct mmc_data *data = host->data; 1701f95f3850SWill Newton int shift = host->data_shift; 1702f95f3850SWill Newton u32 status; 17033e4b0d8bSMarkos Chandras unsigned int len; 1704f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 1705f95f3850SWill Newton 1706f95f3850SWill Newton do { 1707f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1708f9c2a0dcSSeungwon Jeon goto done; 1709f95f3850SWill Newton 17104225fc85SImre Deak host->sg = sg_miter->piter.sg; 1711f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 1712f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 1713f9c2a0dcSSeungwon Jeon offset = 0; 1714f9c2a0dcSSeungwon Jeon 1715f9c2a0dcSSeungwon Jeon do { 1716f9c2a0dcSSeungwon Jeon fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS)) 1717f9c2a0dcSSeungwon Jeon << shift) + host->part_buf_count; 1718f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 1719f9c2a0dcSSeungwon Jeon if (!len) 1720f9c2a0dcSSeungwon Jeon break; 1721f9c2a0dcSSeungwon Jeon dw_mci_pull_data(host, (void *)(buf + offset), len); 17223e4b0d8bSMarkos Chandras data->bytes_xfered += len; 1723f95f3850SWill Newton offset += len; 1724f9c2a0dcSSeungwon Jeon remain -= len; 1725f9c2a0dcSSeungwon Jeon } while (remain); 1726f95f3850SWill Newton 1727e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 1728f95f3850SWill Newton status = mci_readl(host, MINTSTS); 1729f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 173087a74d39SKyoungil Kim /* if the RXDR is ready read again */ 173187a74d39SKyoungil Kim } while ((status & SDMMC_INT_RXDR) || 173287a74d39SKyoungil Kim (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); 1733f9c2a0dcSSeungwon Jeon 1734f9c2a0dcSSeungwon Jeon if (!remain) { 1735f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1736f9c2a0dcSSeungwon Jeon goto done; 1737f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 1738f9c2a0dcSSeungwon Jeon } 1739f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1740f95f3850SWill Newton return; 1741f95f3850SWill Newton 1742f95f3850SWill Newton done: 1743f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1744f9c2a0dcSSeungwon Jeon host->sg = NULL; 1745f95f3850SWill Newton smp_wmb(); 1746f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1747f95f3850SWill Newton } 1748f95f3850SWill Newton 1749f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host) 1750f95f3850SWill Newton { 1751f9c2a0dcSSeungwon Jeon struct sg_mapping_iter *sg_miter = &host->sg_miter; 1752f9c2a0dcSSeungwon Jeon void *buf; 1753f9c2a0dcSSeungwon Jeon unsigned int offset; 1754f95f3850SWill Newton struct mmc_data *data = host->data; 1755f95f3850SWill Newton int shift = host->data_shift; 1756f95f3850SWill Newton u32 status; 17573e4b0d8bSMarkos Chandras unsigned int len; 1758f9c2a0dcSSeungwon Jeon unsigned int fifo_depth = host->fifo_depth; 1759f9c2a0dcSSeungwon Jeon unsigned int remain, fcnt; 1760f95f3850SWill Newton 1761f95f3850SWill Newton do { 1762f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1763f9c2a0dcSSeungwon Jeon goto done; 1764f95f3850SWill Newton 17654225fc85SImre Deak host->sg = sg_miter->piter.sg; 1766f9c2a0dcSSeungwon Jeon buf = sg_miter->addr; 1767f9c2a0dcSSeungwon Jeon remain = sg_miter->length; 1768f9c2a0dcSSeungwon Jeon offset = 0; 1769f9c2a0dcSSeungwon Jeon 1770f9c2a0dcSSeungwon Jeon do { 1771f9c2a0dcSSeungwon Jeon fcnt = ((fifo_depth - 1772f9c2a0dcSSeungwon Jeon SDMMC_GET_FCNT(mci_readl(host, STATUS))) 1773f9c2a0dcSSeungwon Jeon << shift) - host->part_buf_count; 1774f9c2a0dcSSeungwon Jeon len = min(remain, fcnt); 1775f9c2a0dcSSeungwon Jeon if (!len) 1776f9c2a0dcSSeungwon Jeon break; 1777f9c2a0dcSSeungwon Jeon host->push_data(host, (void *)(buf + offset), len); 17783e4b0d8bSMarkos Chandras data->bytes_xfered += len; 1779f95f3850SWill Newton offset += len; 1780f9c2a0dcSSeungwon Jeon remain -= len; 1781f9c2a0dcSSeungwon Jeon } while (remain); 1782f95f3850SWill Newton 1783e74f3a9cSSeungwon Jeon sg_miter->consumed = offset; 1784f95f3850SWill Newton status = mci_readl(host, MINTSTS); 1785f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 1786f95f3850SWill Newton } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 1787f9c2a0dcSSeungwon Jeon 1788f9c2a0dcSSeungwon Jeon if (!remain) { 1789f9c2a0dcSSeungwon Jeon if (!sg_miter_next(sg_miter)) 1790f9c2a0dcSSeungwon Jeon goto done; 1791f9c2a0dcSSeungwon Jeon sg_miter->consumed = 0; 1792f9c2a0dcSSeungwon Jeon } 1793f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1794f95f3850SWill Newton return; 1795f95f3850SWill Newton 1796f95f3850SWill Newton done: 1797f9c2a0dcSSeungwon Jeon sg_miter_stop(sg_miter); 1798f9c2a0dcSSeungwon Jeon host->sg = NULL; 1799f95f3850SWill Newton smp_wmb(); 1800f95f3850SWill Newton set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1801f95f3850SWill Newton } 1802f95f3850SWill Newton 1803f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) 1804f95f3850SWill Newton { 1805f95f3850SWill Newton if (!host->cmd_status) 1806f95f3850SWill Newton host->cmd_status = status; 1807f95f3850SWill Newton 1808f95f3850SWill Newton smp_wmb(); 1809f95f3850SWill Newton 1810f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 1811f95f3850SWill Newton tasklet_schedule(&host->tasklet); 1812f95f3850SWill Newton } 1813f95f3850SWill Newton 1814f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) 1815f95f3850SWill Newton { 1816f95f3850SWill Newton struct dw_mci *host = dev_id; 1817182c9081SSeungwon Jeon u32 pending; 18181a5c8e1fSShashidhar Hiremath int i; 1819f95f3850SWill Newton 1820f95f3850SWill Newton pending = mci_readl(host, MINTSTS); /* read-only mask reg */ 1821f95f3850SWill Newton 1822f95f3850SWill Newton /* 1823f95f3850SWill Newton * DTO fix - version 2.10a and below, and only if internal DMA 1824f95f3850SWill Newton * is configured. 1825f95f3850SWill Newton */ 1826f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { 1827f95f3850SWill Newton if (!pending && 1828f95f3850SWill Newton ((mci_readl(host, STATUS) >> 17) & 0x1fff)) 1829f95f3850SWill Newton pending |= SDMMC_INT_DATA_OVER; 1830f95f3850SWill Newton } 1831f95f3850SWill Newton 1832476d79f1SDoug Anderson if (pending) { 1833f95f3850SWill Newton if (pending & DW_MCI_CMD_ERROR_FLAGS) { 1834f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); 1835182c9081SSeungwon Jeon host->cmd_status = pending; 1836f95f3850SWill Newton smp_wmb(); 1837f95f3850SWill Newton set_bit(EVENT_CMD_COMPLETE, &host->pending_events); 1838f95f3850SWill Newton } 1839f95f3850SWill Newton 1840f95f3850SWill Newton if (pending & DW_MCI_DATA_ERROR_FLAGS) { 1841f95f3850SWill Newton /* if there is an error report DATA_ERROR */ 1842f95f3850SWill Newton mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); 1843182c9081SSeungwon Jeon host->data_status = pending; 1844f95f3850SWill Newton smp_wmb(); 1845f95f3850SWill Newton set_bit(EVENT_DATA_ERROR, &host->pending_events); 1846f95f3850SWill Newton tasklet_schedule(&host->tasklet); 1847f95f3850SWill Newton } 1848f95f3850SWill Newton 1849f95f3850SWill Newton if (pending & SDMMC_INT_DATA_OVER) { 1850f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); 1851f95f3850SWill Newton if (!host->data_status) 1852182c9081SSeungwon Jeon host->data_status = pending; 1853f95f3850SWill Newton smp_wmb(); 1854f95f3850SWill Newton if (host->dir_status == DW_MCI_RECV_STATUS) { 1855f95f3850SWill Newton if (host->sg != NULL) 185687a74d39SKyoungil Kim dw_mci_read_data_pio(host, true); 1857f95f3850SWill Newton } 1858f95f3850SWill Newton set_bit(EVENT_DATA_COMPLETE, &host->pending_events); 1859f95f3850SWill Newton tasklet_schedule(&host->tasklet); 1860f95f3850SWill Newton } 1861f95f3850SWill Newton 1862f95f3850SWill Newton if (pending & SDMMC_INT_RXDR) { 1863f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 1864b40af3aaSJames Hogan if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) 186587a74d39SKyoungil Kim dw_mci_read_data_pio(host, false); 1866f95f3850SWill Newton } 1867f95f3850SWill Newton 1868f95f3850SWill Newton if (pending & SDMMC_INT_TXDR) { 1869f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 1870b40af3aaSJames Hogan if (host->dir_status == DW_MCI_SEND_STATUS && host->sg) 1871f95f3850SWill Newton dw_mci_write_data_pio(host); 1872f95f3850SWill Newton } 1873f95f3850SWill Newton 1874f95f3850SWill Newton if (pending & SDMMC_INT_CMD_DONE) { 1875f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); 1876182c9081SSeungwon Jeon dw_mci_cmd_interrupt(host, pending); 1877f95f3850SWill Newton } 1878f95f3850SWill Newton 1879f95f3850SWill Newton if (pending & SDMMC_INT_CD) { 1880f95f3850SWill Newton mci_writel(host, RINTSTS, SDMMC_INT_CD); 188195dcc2cbSThomas Abraham queue_work(host->card_workqueue, &host->card_work); 1882f95f3850SWill Newton } 1883f95f3850SWill Newton 18841a5c8e1fSShashidhar Hiremath /* Handle SDIO Interrupts */ 18851a5c8e1fSShashidhar Hiremath for (i = 0; i < host->num_slots; i++) { 18861a5c8e1fSShashidhar Hiremath struct dw_mci_slot *slot = host->slot[i]; 18871a5c8e1fSShashidhar Hiremath if (pending & SDMMC_INT_SDIO(i)) { 18881a5c8e1fSShashidhar Hiremath mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); 18891a5c8e1fSShashidhar Hiremath mmc_signal_sdio_irq(slot->mmc); 18901a5c8e1fSShashidhar Hiremath } 18911a5c8e1fSShashidhar Hiremath } 18921a5c8e1fSShashidhar Hiremath 18931fb5f68aSMarkos Chandras } 1894f95f3850SWill Newton 1895f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 1896f95f3850SWill Newton /* Handle DMA interrupts */ 1897f95f3850SWill Newton pending = mci_readl(host, IDSTS); 1898f95f3850SWill Newton if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { 1899f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); 1900f95f3850SWill Newton mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); 1901f95f3850SWill Newton host->dma_ops->complete(host); 1902f95f3850SWill Newton } 1903f95f3850SWill Newton #endif 1904f95f3850SWill Newton 1905f95f3850SWill Newton return IRQ_HANDLED; 1906f95f3850SWill Newton } 1907f95f3850SWill Newton 19081791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work) 1909f95f3850SWill Newton { 19101791b13eSJames Hogan struct dw_mci *host = container_of(work, struct dw_mci, card_work); 1911f95f3850SWill Newton int i; 1912f95f3850SWill Newton 1913f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 1914f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 1915f95f3850SWill Newton struct mmc_host *mmc = slot->mmc; 1916f95f3850SWill Newton struct mmc_request *mrq; 1917f95f3850SWill Newton int present; 1918f95f3850SWill Newton 1919f95f3850SWill Newton present = dw_mci_get_cd(mmc); 1920f95f3850SWill Newton while (present != slot->last_detect_state) { 1921f95f3850SWill Newton dev_dbg(&slot->mmc->class_dev, "card %s\n", 1922f95f3850SWill Newton present ? "inserted" : "removed"); 1923f95f3850SWill Newton 19241791b13eSJames Hogan spin_lock_bh(&host->lock); 19251791b13eSJames Hogan 1926f95f3850SWill Newton /* Card change detected */ 1927f95f3850SWill Newton slot->last_detect_state = present; 1928f95f3850SWill Newton 19291791b13eSJames Hogan /* Mark card as present if applicable */ 19301791b13eSJames Hogan if (present != 0) 1931f95f3850SWill Newton set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1932f95f3850SWill Newton 1933f95f3850SWill Newton /* Clean up queue if present */ 1934f95f3850SWill Newton mrq = slot->mrq; 1935f95f3850SWill Newton if (mrq) { 1936f95f3850SWill Newton if (mrq == host->mrq) { 1937f95f3850SWill Newton host->data = NULL; 1938f95f3850SWill Newton host->cmd = NULL; 1939f95f3850SWill Newton 1940f95f3850SWill Newton switch (host->state) { 1941f95f3850SWill Newton case STATE_IDLE: 1942f95f3850SWill Newton break; 1943f95f3850SWill Newton case STATE_SENDING_CMD: 1944f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1945f95f3850SWill Newton if (!mrq->data) 1946f95f3850SWill Newton break; 1947f95f3850SWill Newton /* fall through */ 1948f95f3850SWill Newton case STATE_SENDING_DATA: 1949f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 1950f95f3850SWill Newton dw_mci_stop_dma(host); 1951f95f3850SWill Newton break; 1952f95f3850SWill Newton case STATE_DATA_BUSY: 1953f95f3850SWill Newton case STATE_DATA_ERROR: 1954f95f3850SWill Newton if (mrq->data->error == -EINPROGRESS) 1955f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 1956f95f3850SWill Newton /* fall through */ 1957f95f3850SWill Newton case STATE_SENDING_STOP: 195890c2143aSSeungwon Jeon if (mrq->stop) 1959f95f3850SWill Newton mrq->stop->error = -ENOMEDIUM; 1960f95f3850SWill Newton break; 1961f95f3850SWill Newton } 1962f95f3850SWill Newton 1963f95f3850SWill Newton dw_mci_request_end(host, mrq); 1964f95f3850SWill Newton } else { 1965f95f3850SWill Newton list_del(&slot->queue_node); 1966f95f3850SWill Newton mrq->cmd->error = -ENOMEDIUM; 1967f95f3850SWill Newton if (mrq->data) 1968f95f3850SWill Newton mrq->data->error = -ENOMEDIUM; 1969f95f3850SWill Newton if (mrq->stop) 1970f95f3850SWill Newton mrq->stop->error = -ENOMEDIUM; 1971f95f3850SWill Newton 1972f95f3850SWill Newton spin_unlock(&host->lock); 1973f95f3850SWill Newton mmc_request_done(slot->mmc, mrq); 1974f95f3850SWill Newton spin_lock(&host->lock); 1975f95f3850SWill Newton } 1976f95f3850SWill Newton } 1977f95f3850SWill Newton 1978f95f3850SWill Newton /* Power down slot */ 1979f95f3850SWill Newton if (present == 0) { 1980f95f3850SWill Newton clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 1981f95f3850SWill Newton 198231bff450SSeungwon Jeon /* Clear down the FIFO */ 198331bff450SSeungwon Jeon dw_mci_fifo_reset(host); 1984f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 1985*5ce9d961SSeungwon Jeon dw_mci_idmac_reset(host); 1986f95f3850SWill Newton #endif 1987f95f3850SWill Newton 1988f95f3850SWill Newton } 1989f95f3850SWill Newton 19901791b13eSJames Hogan spin_unlock_bh(&host->lock); 19911791b13eSJames Hogan 1992f95f3850SWill Newton present = dw_mci_get_cd(mmc); 1993f95f3850SWill Newton } 1994f95f3850SWill Newton 1995f95f3850SWill Newton mmc_detect_change(slot->mmc, 1996f95f3850SWill Newton msecs_to_jiffies(host->pdata->detect_delay_ms)); 1997f95f3850SWill Newton } 1998f95f3850SWill Newton } 1999f95f3850SWill Newton 2000c91eab4bSThomas Abraham #ifdef CONFIG_OF 2001c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */ 2002c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 2003c91eab4bSThomas Abraham { 2004c91eab4bSThomas Abraham struct device_node *np; 2005c91eab4bSThomas Abraham const __be32 *addr; 2006c91eab4bSThomas Abraham int len; 2007c91eab4bSThomas Abraham 2008c91eab4bSThomas Abraham if (!dev || !dev->of_node) 2009c91eab4bSThomas Abraham return NULL; 2010c91eab4bSThomas Abraham 2011c91eab4bSThomas Abraham for_each_child_of_node(dev->of_node, np) { 2012c91eab4bSThomas Abraham addr = of_get_property(np, "reg", &len); 2013c91eab4bSThomas Abraham if (!addr || (len < sizeof(int))) 2014c91eab4bSThomas Abraham continue; 2015c91eab4bSThomas Abraham if (be32_to_cpup(addr) == slot) 2016c91eab4bSThomas Abraham return np; 2017c91eab4bSThomas Abraham } 2018c91eab4bSThomas Abraham return NULL; 2019c91eab4bSThomas Abraham } 2020c91eab4bSThomas Abraham 2021a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks { 2022a70aaa64SDoug Anderson char *quirk; 2023a70aaa64SDoug Anderson int id; 2024a70aaa64SDoug Anderson } of_slot_quirks[] = { 2025a70aaa64SDoug Anderson { 2026a70aaa64SDoug Anderson .quirk = "disable-wp", 2027a70aaa64SDoug Anderson .id = DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT, 2028a70aaa64SDoug Anderson }, 2029a70aaa64SDoug Anderson }; 2030a70aaa64SDoug Anderson 2031a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2032a70aaa64SDoug Anderson { 2033a70aaa64SDoug Anderson struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 2034a70aaa64SDoug Anderson int quirks = 0; 2035a70aaa64SDoug Anderson int idx; 2036a70aaa64SDoug Anderson 2037a70aaa64SDoug Anderson /* get quirks */ 2038a70aaa64SDoug Anderson for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++) 2039a70aaa64SDoug Anderson if (of_get_property(np, of_slot_quirks[idx].quirk, NULL)) 2040a70aaa64SDoug Anderson quirks |= of_slot_quirks[idx].id; 2041a70aaa64SDoug Anderson 2042a70aaa64SDoug Anderson return quirks; 2043a70aaa64SDoug Anderson } 2044a70aaa64SDoug Anderson 2045c91eab4bSThomas Abraham /* find out bus-width for a given slot */ 2046c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) 2047c91eab4bSThomas Abraham { 2048c91eab4bSThomas Abraham struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 2049c91eab4bSThomas Abraham u32 bus_wd = 1; 2050c91eab4bSThomas Abraham 2051c91eab4bSThomas Abraham if (!np) 2052c91eab4bSThomas Abraham return 1; 2053c91eab4bSThomas Abraham 2054c91eab4bSThomas Abraham if (of_property_read_u32(np, "bus-width", &bus_wd)) 2055c91eab4bSThomas Abraham dev_err(dev, "bus-width property not found, assuming width" 2056c91eab4bSThomas Abraham " as 1\n"); 2057c91eab4bSThomas Abraham return bus_wd; 2058c91eab4bSThomas Abraham } 205955a6ceb2SDoug Anderson 206055a6ceb2SDoug Anderson /* find the write protect gpio for a given slot; or -1 if none specified */ 206155a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) 206255a6ceb2SDoug Anderson { 206355a6ceb2SDoug Anderson struct device_node *np = dw_mci_of_find_slot_node(dev, slot); 206455a6ceb2SDoug Anderson int gpio; 206555a6ceb2SDoug Anderson 206655a6ceb2SDoug Anderson if (!np) 206755a6ceb2SDoug Anderson return -EINVAL; 206855a6ceb2SDoug Anderson 206955a6ceb2SDoug Anderson gpio = of_get_named_gpio(np, "wp-gpios", 0); 207055a6ceb2SDoug Anderson 207155a6ceb2SDoug Anderson /* Having a missing entry is valid; return silently */ 207255a6ceb2SDoug Anderson if (!gpio_is_valid(gpio)) 207355a6ceb2SDoug Anderson return -EINVAL; 207455a6ceb2SDoug Anderson 207555a6ceb2SDoug Anderson if (devm_gpio_request(dev, gpio, "dw-mci-wp")) { 207655a6ceb2SDoug Anderson dev_warn(dev, "gpio [%d] request failed\n", gpio); 207755a6ceb2SDoug Anderson return -EINVAL; 207855a6ceb2SDoug Anderson } 207955a6ceb2SDoug Anderson 208055a6ceb2SDoug Anderson return gpio; 208155a6ceb2SDoug Anderson } 2082c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2083a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) 2084a70aaa64SDoug Anderson { 2085a70aaa64SDoug Anderson return 0; 2086a70aaa64SDoug Anderson } 2087c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot) 2088c91eab4bSThomas Abraham { 2089c91eab4bSThomas Abraham return 1; 2090c91eab4bSThomas Abraham } 2091c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) 2092c91eab4bSThomas Abraham { 2093c91eab4bSThomas Abraham return NULL; 2094c91eab4bSThomas Abraham } 209555a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot) 209655a6ceb2SDoug Anderson { 209755a6ceb2SDoug Anderson return -EINVAL; 209855a6ceb2SDoug Anderson } 2099c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2100c91eab4bSThomas Abraham 210136c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) 2102f95f3850SWill Newton { 2103f95f3850SWill Newton struct mmc_host *mmc; 2104f95f3850SWill Newton struct dw_mci_slot *slot; 2105e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2106800d78bfSThomas Abraham int ctrl_id, ret; 21071f44a2a5SSeungwon Jeon u32 freq[2]; 2108c91eab4bSThomas Abraham u8 bus_width; 2109f95f3850SWill Newton 21104a90920cSThomas Abraham mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); 2111f95f3850SWill Newton if (!mmc) 2112f95f3850SWill Newton return -ENOMEM; 2113f95f3850SWill Newton 2114f95f3850SWill Newton slot = mmc_priv(mmc); 2115f95f3850SWill Newton slot->id = id; 2116f95f3850SWill Newton slot->mmc = mmc; 2117f95f3850SWill Newton slot->host = host; 2118c91eab4bSThomas Abraham host->slot[id] = slot; 2119f95f3850SWill Newton 2120a70aaa64SDoug Anderson slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id); 2121a70aaa64SDoug Anderson 2122f95f3850SWill Newton mmc->ops = &dw_mci_ops; 21231f44a2a5SSeungwon Jeon if (of_property_read_u32_array(host->dev->of_node, 21241f44a2a5SSeungwon Jeon "clock-freq-min-max", freq, 2)) { 21251f44a2a5SSeungwon Jeon mmc->f_min = DW_MCI_FREQ_MIN; 21261f44a2a5SSeungwon Jeon mmc->f_max = DW_MCI_FREQ_MAX; 21271f44a2a5SSeungwon Jeon } else { 21281f44a2a5SSeungwon Jeon mmc->f_min = freq[0]; 21291f44a2a5SSeungwon Jeon mmc->f_max = freq[1]; 21301f44a2a5SSeungwon Jeon } 2131f95f3850SWill Newton 2132f95f3850SWill Newton if (host->pdata->get_ocr) 2133f95f3850SWill Newton mmc->ocr_avail = host->pdata->get_ocr(id); 2134f95f3850SWill Newton else 2135f95f3850SWill Newton mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 2136f95f3850SWill Newton 2137f95f3850SWill Newton /* 2138f95f3850SWill Newton * Start with slot power disabled, it will be enabled when a card 2139f95f3850SWill Newton * is detected. 2140f95f3850SWill Newton */ 2141f95f3850SWill Newton if (host->pdata->setpower) 2142f95f3850SWill Newton host->pdata->setpower(id, 0); 2143f95f3850SWill Newton 2144fc3d7720SJaehoon Chung if (host->pdata->caps) 2145fc3d7720SJaehoon Chung mmc->caps = host->pdata->caps; 2146fc3d7720SJaehoon Chung 2147ab269128SAbhilash Kesavan if (host->pdata->pm_caps) 2148ab269128SAbhilash Kesavan mmc->pm_caps = host->pdata->pm_caps; 2149ab269128SAbhilash Kesavan 2150800d78bfSThomas Abraham if (host->dev->of_node) { 2151800d78bfSThomas Abraham ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); 2152800d78bfSThomas Abraham if (ctrl_id < 0) 2153800d78bfSThomas Abraham ctrl_id = 0; 2154800d78bfSThomas Abraham } else { 2155800d78bfSThomas Abraham ctrl_id = to_platform_device(host->dev)->id; 2156800d78bfSThomas Abraham } 2157cb27a843SJames Hogan if (drv_data && drv_data->caps) 2158cb27a843SJames Hogan mmc->caps |= drv_data->caps[ctrl_id]; 2159800d78bfSThomas Abraham 21604f408cc6SSeungwon Jeon if (host->pdata->caps2) 21614f408cc6SSeungwon Jeon mmc->caps2 = host->pdata->caps2; 21624f408cc6SSeungwon Jeon 2163f95f3850SWill Newton if (host->pdata->get_bus_wd) 2164c91eab4bSThomas Abraham bus_width = host->pdata->get_bus_wd(slot->id); 2165c91eab4bSThomas Abraham else if (host->dev->of_node) 2166c91eab4bSThomas Abraham bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id); 2167c91eab4bSThomas Abraham else 2168c91eab4bSThomas Abraham bus_width = 1; 2169c91eab4bSThomas Abraham 2170c91eab4bSThomas Abraham switch (bus_width) { 2171c91eab4bSThomas Abraham case 8: 2172c91eab4bSThomas Abraham mmc->caps |= MMC_CAP_8_BIT_DATA; 2173c91eab4bSThomas Abraham case 4: 2174f95f3850SWill Newton mmc->caps |= MMC_CAP_4_BIT_DATA; 2175c91eab4bSThomas Abraham } 2176f95f3850SWill Newton 2177f95f3850SWill Newton if (host->pdata->blk_settings) { 2178f95f3850SWill Newton mmc->max_segs = host->pdata->blk_settings->max_segs; 2179f95f3850SWill Newton mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; 2180f95f3850SWill Newton mmc->max_blk_count = host->pdata->blk_settings->max_blk_count; 2181f95f3850SWill Newton mmc->max_req_size = host->pdata->blk_settings->max_req_size; 2182f95f3850SWill Newton mmc->max_seg_size = host->pdata->blk_settings->max_seg_size; 2183f95f3850SWill Newton } else { 2184f95f3850SWill Newton /* Useful defaults if platform data is unset. */ 2185a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC 2186a39e5746SJaehoon Chung mmc->max_segs = host->ring_size; 2187a39e5746SJaehoon Chung mmc->max_blk_size = 65536; 2188a39e5746SJaehoon Chung mmc->max_blk_count = host->ring_size; 2189a39e5746SJaehoon Chung mmc->max_seg_size = 0x1000; 2190a39e5746SJaehoon Chung mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; 2191a39e5746SJaehoon Chung #else 2192f95f3850SWill Newton mmc->max_segs = 64; 2193f95f3850SWill Newton mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ 2194f95f3850SWill Newton mmc->max_blk_count = 512; 2195f95f3850SWill Newton mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 2196f95f3850SWill Newton mmc->max_seg_size = mmc->max_req_size; 2197f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */ 2198a39e5746SJaehoon Chung } 2199f95f3850SWill Newton 2200f95f3850SWill Newton if (dw_mci_get_cd(mmc)) 2201f95f3850SWill Newton set_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2202f95f3850SWill Newton else 2203f95f3850SWill Newton clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); 2204f95f3850SWill Newton 220555a6ceb2SDoug Anderson slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); 220655a6ceb2SDoug Anderson 22070cea529dSJaehoon Chung ret = mmc_add_host(mmc); 22080cea529dSJaehoon Chung if (ret) 22090cea529dSJaehoon Chung goto err_setup_bus; 2210f95f3850SWill Newton 2211f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS) 2212f95f3850SWill Newton dw_mci_init_debugfs(slot); 2213f95f3850SWill Newton #endif 2214f95f3850SWill Newton 2215f95f3850SWill Newton /* Card initially undetected */ 2216f95f3850SWill Newton slot->last_detect_state = 0; 2217f95f3850SWill Newton 2218f95f3850SWill Newton return 0; 2219800d78bfSThomas Abraham 2220800d78bfSThomas Abraham err_setup_bus: 2221800d78bfSThomas Abraham mmc_free_host(mmc); 2222800d78bfSThomas Abraham return -EINVAL; 2223f95f3850SWill Newton } 2224f95f3850SWill Newton 2225f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) 2226f95f3850SWill Newton { 2227f95f3850SWill Newton /* Shutdown detect IRQ */ 2228f95f3850SWill Newton if (slot->host->pdata->exit) 2229f95f3850SWill Newton slot->host->pdata->exit(id); 2230f95f3850SWill Newton 2231f95f3850SWill Newton /* Debugfs stuff is cleaned up by mmc core */ 2232f95f3850SWill Newton mmc_remove_host(slot->mmc); 2233f95f3850SWill Newton slot->host->slot[id] = NULL; 2234f95f3850SWill Newton mmc_free_host(slot->mmc); 2235f95f3850SWill Newton } 2236f95f3850SWill Newton 2237f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host) 2238f95f3850SWill Newton { 2239f95f3850SWill Newton /* Alloc memory for sg translation */ 2240780f22afSSeungwon Jeon host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, 2241f95f3850SWill Newton &host->sg_dma, GFP_KERNEL); 2242f95f3850SWill Newton if (!host->sg_cpu) { 22434a90920cSThomas Abraham dev_err(host->dev, "%s: could not alloc DMA memory\n", 2244f95f3850SWill Newton __func__); 2245f95f3850SWill Newton goto no_dma; 2246f95f3850SWill Newton } 2247f95f3850SWill Newton 2248f95f3850SWill Newton /* Determine which DMA interface to use */ 2249f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC 2250f95f3850SWill Newton host->dma_ops = &dw_mci_idmac_ops; 225100956ea3SSeungwon Jeon dev_info(host->dev, "Using internal DMA controller.\n"); 2252f95f3850SWill Newton #endif 2253f95f3850SWill Newton 2254f95f3850SWill Newton if (!host->dma_ops) 2255f95f3850SWill Newton goto no_dma; 2256f95f3850SWill Newton 2257e1631f98SJaehoon Chung if (host->dma_ops->init && host->dma_ops->start && 2258e1631f98SJaehoon Chung host->dma_ops->stop && host->dma_ops->cleanup) { 2259f95f3850SWill Newton if (host->dma_ops->init(host)) { 22604a90920cSThomas Abraham dev_err(host->dev, "%s: Unable to initialize " 2261f95f3850SWill Newton "DMA Controller.\n", __func__); 2262f95f3850SWill Newton goto no_dma; 2263f95f3850SWill Newton } 2264f95f3850SWill Newton } else { 22654a90920cSThomas Abraham dev_err(host->dev, "DMA initialization not found.\n"); 2266f95f3850SWill Newton goto no_dma; 2267f95f3850SWill Newton } 2268f95f3850SWill Newton 2269f95f3850SWill Newton host->use_dma = 1; 2270f95f3850SWill Newton return; 2271f95f3850SWill Newton 2272f95f3850SWill Newton no_dma: 22734a90920cSThomas Abraham dev_info(host->dev, "Using PIO mode.\n"); 2274f95f3850SWill Newton host->use_dma = 0; 2275f95f3850SWill Newton return; 2276f95f3850SWill Newton } 2277f95f3850SWill Newton 227831bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset) 2279f95f3850SWill Newton { 2280f95f3850SWill Newton unsigned long timeout = jiffies + msecs_to_jiffies(500); 228131bff450SSeungwon Jeon u32 ctrl; 2282f95f3850SWill Newton 228331bff450SSeungwon Jeon ctrl = mci_readl(host, CTRL); 228431bff450SSeungwon Jeon ctrl |= reset; 228531bff450SSeungwon Jeon mci_writel(host, CTRL, ctrl); 2286f95f3850SWill Newton 2287f95f3850SWill Newton /* wait till resets clear */ 2288f95f3850SWill Newton do { 2289f95f3850SWill Newton ctrl = mci_readl(host, CTRL); 229031bff450SSeungwon Jeon if (!(ctrl & reset)) 2291f95f3850SWill Newton return true; 2292f95f3850SWill Newton } while (time_before(jiffies, timeout)); 2293f95f3850SWill Newton 229431bff450SSeungwon Jeon dev_err(host->dev, 229531bff450SSeungwon Jeon "Timeout resetting block (ctrl reset %#x)\n", 229631bff450SSeungwon Jeon ctrl & reset); 2297f95f3850SWill Newton 2298f95f3850SWill Newton return false; 2299f95f3850SWill Newton } 2300f95f3850SWill Newton 230131bff450SSeungwon Jeon static inline bool dw_mci_fifo_reset(struct dw_mci *host) 230231bff450SSeungwon Jeon { 230331bff450SSeungwon Jeon /* 230431bff450SSeungwon Jeon * Reseting generates a block interrupt, hence setting 230531bff450SSeungwon Jeon * the scatter-gather pointer to NULL. 230631bff450SSeungwon Jeon */ 230731bff450SSeungwon Jeon if (host->sg) { 230831bff450SSeungwon Jeon sg_miter_stop(&host->sg_miter); 230931bff450SSeungwon Jeon host->sg = NULL; 231031bff450SSeungwon Jeon } 231131bff450SSeungwon Jeon 231231bff450SSeungwon Jeon return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET); 231331bff450SSeungwon Jeon } 231431bff450SSeungwon Jeon 231531bff450SSeungwon Jeon static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host) 231631bff450SSeungwon Jeon { 231731bff450SSeungwon Jeon return dw_mci_ctrl_reset(host, 231831bff450SSeungwon Jeon SDMMC_CTRL_FIFO_RESET | 231931bff450SSeungwon Jeon SDMMC_CTRL_RESET | 232031bff450SSeungwon Jeon SDMMC_CTRL_DMA_RESET); 232131bff450SSeungwon Jeon } 232231bff450SSeungwon Jeon 2323c91eab4bSThomas Abraham #ifdef CONFIG_OF 2324c91eab4bSThomas Abraham static struct dw_mci_of_quirks { 2325c91eab4bSThomas Abraham char *quirk; 2326c91eab4bSThomas Abraham int id; 2327c91eab4bSThomas Abraham } of_quirks[] = { 2328c91eab4bSThomas Abraham { 2329c91eab4bSThomas Abraham .quirk = "broken-cd", 2330c91eab4bSThomas Abraham .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, 2331c91eab4bSThomas Abraham }, 2332c91eab4bSThomas Abraham }; 2333c91eab4bSThomas Abraham 2334c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2335c91eab4bSThomas Abraham { 2336c91eab4bSThomas Abraham struct dw_mci_board *pdata; 2337c91eab4bSThomas Abraham struct device *dev = host->dev; 2338c91eab4bSThomas Abraham struct device_node *np = dev->of_node; 2339e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 2340800d78bfSThomas Abraham int idx, ret; 23413c6d89eaSDoug Anderson u32 clock_frequency; 2342c91eab4bSThomas Abraham 2343c91eab4bSThomas Abraham pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2344c91eab4bSThomas Abraham if (!pdata) { 2345c91eab4bSThomas Abraham dev_err(dev, "could not allocate memory for pdata\n"); 2346c91eab4bSThomas Abraham return ERR_PTR(-ENOMEM); 2347c91eab4bSThomas Abraham } 2348c91eab4bSThomas Abraham 2349c91eab4bSThomas Abraham /* find out number of slots supported */ 2350c91eab4bSThomas Abraham if (of_property_read_u32(dev->of_node, "num-slots", 2351c91eab4bSThomas Abraham &pdata->num_slots)) { 2352c91eab4bSThomas Abraham dev_info(dev, "num-slots property not found, " 2353c91eab4bSThomas Abraham "assuming 1 slot is available\n"); 2354c91eab4bSThomas Abraham pdata->num_slots = 1; 2355c91eab4bSThomas Abraham } 2356c91eab4bSThomas Abraham 2357c91eab4bSThomas Abraham /* get quirks */ 2358c91eab4bSThomas Abraham for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) 2359c91eab4bSThomas Abraham if (of_get_property(np, of_quirks[idx].quirk, NULL)) 2360c91eab4bSThomas Abraham pdata->quirks |= of_quirks[idx].id; 2361c91eab4bSThomas Abraham 2362c91eab4bSThomas Abraham if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) 2363c91eab4bSThomas Abraham dev_info(dev, "fifo-depth property not found, using " 2364c91eab4bSThomas Abraham "value of FIFOTH register as default\n"); 2365c91eab4bSThomas Abraham 2366c91eab4bSThomas Abraham of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); 2367c91eab4bSThomas Abraham 23683c6d89eaSDoug Anderson if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) 23693c6d89eaSDoug Anderson pdata->bus_hz = clock_frequency; 23703c6d89eaSDoug Anderson 2371cb27a843SJames Hogan if (drv_data && drv_data->parse_dt) { 2372cb27a843SJames Hogan ret = drv_data->parse_dt(host); 2373800d78bfSThomas Abraham if (ret) 2374800d78bfSThomas Abraham return ERR_PTR(ret); 2375800d78bfSThomas Abraham } 2376800d78bfSThomas Abraham 2377ab269128SAbhilash Kesavan if (of_find_property(np, "keep-power-in-suspend", NULL)) 2378ab269128SAbhilash Kesavan pdata->pm_caps |= MMC_PM_KEEP_POWER; 2379ab269128SAbhilash Kesavan 2380ab269128SAbhilash Kesavan if (of_find_property(np, "enable-sdio-wakeup", NULL)) 2381ab269128SAbhilash Kesavan pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; 2382ab269128SAbhilash Kesavan 238310b49841SSeungwon Jeon if (of_find_property(np, "supports-highspeed", NULL)) 238410b49841SSeungwon Jeon pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; 238510b49841SSeungwon Jeon 23865dd63f52SSeungwon Jeon if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL)) 23875dd63f52SSeungwon Jeon pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR; 23885dd63f52SSeungwon Jeon 23895dd63f52SSeungwon Jeon if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL)) 23905dd63f52SSeungwon Jeon pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR; 23915dd63f52SSeungwon Jeon 2392c91eab4bSThomas Abraham return pdata; 2393c91eab4bSThomas Abraham } 2394c91eab4bSThomas Abraham 2395c91eab4bSThomas Abraham #else /* CONFIG_OF */ 2396c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) 2397c91eab4bSThomas Abraham { 2398c91eab4bSThomas Abraham return ERR_PTR(-EINVAL); 2399c91eab4bSThomas Abraham } 2400c91eab4bSThomas Abraham #endif /* CONFIG_OF */ 2401c91eab4bSThomas Abraham 240262ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host) 2403f95f3850SWill Newton { 2404e95baf13SArnd Bergmann const struct dw_mci_drv_data *drv_data = host->drv_data; 240562ca8034SShashidhar Hiremath int width, i, ret = 0; 2406f95f3850SWill Newton u32 fifo_size; 24071c2215b7SThomas Abraham int init_slots = 0; 2408f95f3850SWill Newton 2409c91eab4bSThomas Abraham if (!host->pdata) { 2410c91eab4bSThomas Abraham host->pdata = dw_mci_parse_dt(host); 2411c91eab4bSThomas Abraham if (IS_ERR(host->pdata)) { 2412c91eab4bSThomas Abraham dev_err(host->dev, "platform data not available\n"); 2413c91eab4bSThomas Abraham return -EINVAL; 2414c91eab4bSThomas Abraham } 2415f95f3850SWill Newton } 2416f95f3850SWill Newton 241762ca8034SShashidhar Hiremath if (!host->pdata->select_slot && host->pdata->num_slots > 1) { 24184a90920cSThomas Abraham dev_err(host->dev, 2419f95f3850SWill Newton "Platform data must supply select_slot function\n"); 242062ca8034SShashidhar Hiremath return -ENODEV; 2421f95f3850SWill Newton } 2422f95f3850SWill Newton 2423780f22afSSeungwon Jeon host->biu_clk = devm_clk_get(host->dev, "biu"); 2424f90a0612SThomas Abraham if (IS_ERR(host->biu_clk)) { 2425f90a0612SThomas Abraham dev_dbg(host->dev, "biu clock not available\n"); 2426f90a0612SThomas Abraham } else { 2427f90a0612SThomas Abraham ret = clk_prepare_enable(host->biu_clk); 2428f90a0612SThomas Abraham if (ret) { 2429f90a0612SThomas Abraham dev_err(host->dev, "failed to enable biu clock\n"); 2430f90a0612SThomas Abraham return ret; 2431f90a0612SThomas Abraham } 2432f95f3850SWill Newton } 2433f95f3850SWill Newton 2434780f22afSSeungwon Jeon host->ciu_clk = devm_clk_get(host->dev, "ciu"); 2435f90a0612SThomas Abraham if (IS_ERR(host->ciu_clk)) { 2436f90a0612SThomas Abraham dev_dbg(host->dev, "ciu clock not available\n"); 24373c6d89eaSDoug Anderson host->bus_hz = host->pdata->bus_hz; 2438f90a0612SThomas Abraham } else { 2439f90a0612SThomas Abraham ret = clk_prepare_enable(host->ciu_clk); 2440f90a0612SThomas Abraham if (ret) { 2441f90a0612SThomas Abraham dev_err(host->dev, "failed to enable ciu clock\n"); 2442f90a0612SThomas Abraham goto err_clk_biu; 2443f90a0612SThomas Abraham } 2444f90a0612SThomas Abraham 24453c6d89eaSDoug Anderson if (host->pdata->bus_hz) { 24463c6d89eaSDoug Anderson ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); 24473c6d89eaSDoug Anderson if (ret) 24483c6d89eaSDoug Anderson dev_warn(host->dev, 24493c6d89eaSDoug Anderson "Unable to set bus rate to %ul\n", 24503c6d89eaSDoug Anderson host->pdata->bus_hz); 24513c6d89eaSDoug Anderson } 2452f90a0612SThomas Abraham host->bus_hz = clk_get_rate(host->ciu_clk); 24533c6d89eaSDoug Anderson } 2454f90a0612SThomas Abraham 2455002f0d5cSYuvaraj Kumar C D if (drv_data && drv_data->init) { 2456002f0d5cSYuvaraj Kumar C D ret = drv_data->init(host); 2457002f0d5cSYuvaraj Kumar C D if (ret) { 2458002f0d5cSYuvaraj Kumar C D dev_err(host->dev, 2459002f0d5cSYuvaraj Kumar C D "implementation specific init failed\n"); 2460002f0d5cSYuvaraj Kumar C D goto err_clk_ciu; 2461002f0d5cSYuvaraj Kumar C D } 2462002f0d5cSYuvaraj Kumar C D } 2463002f0d5cSYuvaraj Kumar C D 2464cb27a843SJames Hogan if (drv_data && drv_data->setup_clock) { 2465cb27a843SJames Hogan ret = drv_data->setup_clock(host); 2466800d78bfSThomas Abraham if (ret) { 2467800d78bfSThomas Abraham dev_err(host->dev, 2468800d78bfSThomas Abraham "implementation specific clock setup failed\n"); 2469800d78bfSThomas Abraham goto err_clk_ciu; 2470800d78bfSThomas Abraham } 2471800d78bfSThomas Abraham } 2472800d78bfSThomas Abraham 2473a55d6ff0SMark Brown host->vmmc = devm_regulator_get_optional(host->dev, "vmmc"); 2474870556a3SDoug Anderson if (IS_ERR(host->vmmc)) { 2475870556a3SDoug Anderson ret = PTR_ERR(host->vmmc); 2476870556a3SDoug Anderson if (ret == -EPROBE_DEFER) 2477870556a3SDoug Anderson goto err_clk_ciu; 2478870556a3SDoug Anderson 2479870556a3SDoug Anderson dev_info(host->dev, "no vmmc regulator found: %d\n", ret); 2480870556a3SDoug Anderson host->vmmc = NULL; 2481870556a3SDoug Anderson } else { 2482870556a3SDoug Anderson ret = regulator_enable(host->vmmc); 2483870556a3SDoug Anderson if (ret) { 2484870556a3SDoug Anderson if (ret != -EPROBE_DEFER) 2485870556a3SDoug Anderson dev_err(host->dev, 2486870556a3SDoug Anderson "regulator_enable fail: %d\n", ret); 2487870556a3SDoug Anderson goto err_clk_ciu; 2488870556a3SDoug Anderson } 2489870556a3SDoug Anderson } 2490870556a3SDoug Anderson 2491f90a0612SThomas Abraham if (!host->bus_hz) { 2492f90a0612SThomas Abraham dev_err(host->dev, 2493f90a0612SThomas Abraham "Platform data must supply bus speed\n"); 2494f90a0612SThomas Abraham ret = -ENODEV; 2495870556a3SDoug Anderson goto err_regulator; 2496f90a0612SThomas Abraham } 2497f90a0612SThomas Abraham 249862ca8034SShashidhar Hiremath host->quirks = host->pdata->quirks; 2499f95f3850SWill Newton 2500f95f3850SWill Newton spin_lock_init(&host->lock); 2501f95f3850SWill Newton INIT_LIST_HEAD(&host->queue); 2502f95f3850SWill Newton 2503f95f3850SWill Newton /* 2504f95f3850SWill Newton * Get the host data width - this assumes that HCON has been set with 2505f95f3850SWill Newton * the correct values. 2506f95f3850SWill Newton */ 2507f95f3850SWill Newton i = (mci_readl(host, HCON) >> 7) & 0x7; 2508f95f3850SWill Newton if (!i) { 2509f95f3850SWill Newton host->push_data = dw_mci_push_data16; 2510f95f3850SWill Newton host->pull_data = dw_mci_pull_data16; 2511f95f3850SWill Newton width = 16; 2512f95f3850SWill Newton host->data_shift = 1; 2513f95f3850SWill Newton } else if (i == 2) { 2514f95f3850SWill Newton host->push_data = dw_mci_push_data64; 2515f95f3850SWill Newton host->pull_data = dw_mci_pull_data64; 2516f95f3850SWill Newton width = 64; 2517f95f3850SWill Newton host->data_shift = 3; 2518f95f3850SWill Newton } else { 2519f95f3850SWill Newton /* Check for a reserved value, and warn if it is */ 2520f95f3850SWill Newton WARN((i != 1), 2521f95f3850SWill Newton "HCON reports a reserved host data width!\n" 2522f95f3850SWill Newton "Defaulting to 32-bit access.\n"); 2523f95f3850SWill Newton host->push_data = dw_mci_push_data32; 2524f95f3850SWill Newton host->pull_data = dw_mci_pull_data32; 2525f95f3850SWill Newton width = 32; 2526f95f3850SWill Newton host->data_shift = 2; 2527f95f3850SWill Newton } 2528f95f3850SWill Newton 2529f95f3850SWill Newton /* Reset all blocks */ 253031bff450SSeungwon Jeon if (!dw_mci_ctrl_all_reset(host)) 2531141a712aSSeungwon Jeon return -ENODEV; 2532141a712aSSeungwon Jeon 2533141a712aSSeungwon Jeon host->dma_ops = host->pdata->dma_ops; 2534141a712aSSeungwon Jeon dw_mci_init_dma(host); 2535f95f3850SWill Newton 2536f95f3850SWill Newton /* Clear the interrupts for the host controller */ 2537f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2538f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2539f95f3850SWill Newton 2540f95f3850SWill Newton /* Put in max timeout */ 2541f95f3850SWill Newton mci_writel(host, TMOUT, 0xFFFFFFFF); 2542f95f3850SWill Newton 2543f95f3850SWill Newton /* 2544f95f3850SWill Newton * FIFO threshold settings RxMark = fifo_size / 2 - 1, 2545f95f3850SWill Newton * Tx Mark = fifo_size / 2 DMA Size = 8 2546f95f3850SWill Newton */ 2547b86d8253SJames Hogan if (!host->pdata->fifo_depth) { 2548b86d8253SJames Hogan /* 2549b86d8253SJames Hogan * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may 2550b86d8253SJames Hogan * have been overwritten by the bootloader, just like we're 2551b86d8253SJames Hogan * about to do, so if you know the value for your hardware, you 2552b86d8253SJames Hogan * should put it in the platform data. 2553b86d8253SJames Hogan */ 2554f95f3850SWill Newton fifo_size = mci_readl(host, FIFOTH); 25558234e869SJaehoon Chung fifo_size = 1 + ((fifo_size >> 16) & 0xfff); 2556b86d8253SJames Hogan } else { 2557b86d8253SJames Hogan fifo_size = host->pdata->fifo_depth; 2558b86d8253SJames Hogan } 2559b86d8253SJames Hogan host->fifo_depth = fifo_size; 256052426899SSeungwon Jeon host->fifoth_val = 256152426899SSeungwon Jeon SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2); 2562e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 2563f95f3850SWill Newton 2564f95f3850SWill Newton /* disable clock to CIU */ 2565f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2566f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2567f95f3850SWill Newton 256863008768SJames Hogan /* 256963008768SJames Hogan * In 2.40a spec, Data offset is changed. 257063008768SJames Hogan * Need to check the version-id and set data-offset for DATA register. 257163008768SJames Hogan */ 257263008768SJames Hogan host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); 257363008768SJames Hogan dev_info(host->dev, "Version ID is %04x\n", host->verid); 257463008768SJames Hogan 257563008768SJames Hogan if (host->verid < DW_MMC_240A) 257663008768SJames Hogan host->data_offset = DATA_OFFSET; 257763008768SJames Hogan else 257863008768SJames Hogan host->data_offset = DATA_240A_OFFSET; 257963008768SJames Hogan 2580f95f3850SWill Newton tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 258195dcc2cbSThomas Abraham host->card_workqueue = alloc_workqueue("dw-mci-card", 25821791b13eSJames Hogan WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); 2583ef7aef9aSWei Yongjun if (!host->card_workqueue) { 2584ef7aef9aSWei Yongjun ret = -ENOMEM; 25851791b13eSJames Hogan goto err_dmaunmap; 2586ef7aef9aSWei Yongjun } 25871791b13eSJames Hogan INIT_WORK(&host->card_work, dw_mci_work_routine_card); 2588780f22afSSeungwon Jeon ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, 2589780f22afSSeungwon Jeon host->irq_flags, "dw-mci", host); 2590f95f3850SWill Newton if (ret) 25911791b13eSJames Hogan goto err_workqueue; 2592f95f3850SWill Newton 2593f95f3850SWill Newton if (host->pdata->num_slots) 2594f95f3850SWill Newton host->num_slots = host->pdata->num_slots; 2595f95f3850SWill Newton else 2596f95f3850SWill Newton host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; 2597f95f3850SWill Newton 25982da1d7f2SYuvaraj CD /* 25992da1d7f2SYuvaraj CD * Enable interrupts for command done, data over, data empty, card det, 26002da1d7f2SYuvaraj CD * receive ready and error such as transmit, receive timeout, crc error 26012da1d7f2SYuvaraj CD */ 26022da1d7f2SYuvaraj CD mci_writel(host, RINTSTS, 0xFFFFFFFF); 26032da1d7f2SYuvaraj CD mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 26042da1d7f2SYuvaraj CD SDMMC_INT_TXDR | SDMMC_INT_RXDR | 26052da1d7f2SYuvaraj CD DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 26062da1d7f2SYuvaraj CD mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ 26072da1d7f2SYuvaraj CD 26082da1d7f2SYuvaraj CD dev_info(host->dev, "DW MMC controller at irq %d, " 26092da1d7f2SYuvaraj CD "%d bit host data width, " 26102da1d7f2SYuvaraj CD "%u deep fifo\n", 26112da1d7f2SYuvaraj CD host->irq, width, fifo_size); 26122da1d7f2SYuvaraj CD 2613f95f3850SWill Newton /* We need at least one slot to succeed */ 2614f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2615f95f3850SWill Newton ret = dw_mci_init_slot(host, i); 26161c2215b7SThomas Abraham if (ret) 26171c2215b7SThomas Abraham dev_dbg(host->dev, "slot %d init failed\n", i); 26181c2215b7SThomas Abraham else 26191c2215b7SThomas Abraham init_slots++; 2620f95f3850SWill Newton } 26211c2215b7SThomas Abraham 26221c2215b7SThomas Abraham if (init_slots) { 26231c2215b7SThomas Abraham dev_info(host->dev, "%d slots initialized\n", init_slots); 26241c2215b7SThomas Abraham } else { 26251c2215b7SThomas Abraham dev_dbg(host->dev, "attempted to initialize %d slots, " 26261c2215b7SThomas Abraham "but failed on all\n", host->num_slots); 2627780f22afSSeungwon Jeon goto err_workqueue; 2628f95f3850SWill Newton } 2629f95f3850SWill Newton 2630f95f3850SWill Newton if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) 26314a90920cSThomas Abraham dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); 2632f95f3850SWill Newton 2633f95f3850SWill Newton return 0; 2634f95f3850SWill Newton 26351791b13eSJames Hogan err_workqueue: 263695dcc2cbSThomas Abraham destroy_workqueue(host->card_workqueue); 26371791b13eSJames Hogan 2638f95f3850SWill Newton err_dmaunmap: 2639f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2640f95f3850SWill Newton host->dma_ops->exit(host); 2641f95f3850SWill Newton 2642870556a3SDoug Anderson err_regulator: 2643780f22afSSeungwon Jeon if (host->vmmc) 2644c07946a3SJaehoon Chung regulator_disable(host->vmmc); 2645f90a0612SThomas Abraham 2646f90a0612SThomas Abraham err_clk_ciu: 2647780f22afSSeungwon Jeon if (!IS_ERR(host->ciu_clk)) 2648f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2649780f22afSSeungwon Jeon 2650f90a0612SThomas Abraham err_clk_biu: 2651780f22afSSeungwon Jeon if (!IS_ERR(host->biu_clk)) 2652f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2653780f22afSSeungwon Jeon 2654f95f3850SWill Newton return ret; 2655f95f3850SWill Newton } 265662ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe); 2657f95f3850SWill Newton 265862ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host) 2659f95f3850SWill Newton { 2660f95f3850SWill Newton int i; 2661f95f3850SWill Newton 2662f95f3850SWill Newton mci_writel(host, RINTSTS, 0xFFFFFFFF); 2663f95f3850SWill Newton mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */ 2664f95f3850SWill Newton 2665f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 26664a90920cSThomas Abraham dev_dbg(host->dev, "remove slot %d\n", i); 2667f95f3850SWill Newton if (host->slot[i]) 2668f95f3850SWill Newton dw_mci_cleanup_slot(host->slot[i], i); 2669f95f3850SWill Newton } 2670f95f3850SWill Newton 2671f95f3850SWill Newton /* disable clock to CIU */ 2672f95f3850SWill Newton mci_writel(host, CLKENA, 0); 2673f95f3850SWill Newton mci_writel(host, CLKSRC, 0); 2674f95f3850SWill Newton 267595dcc2cbSThomas Abraham destroy_workqueue(host->card_workqueue); 2676f95f3850SWill Newton 2677f95f3850SWill Newton if (host->use_dma && host->dma_ops->exit) 2678f95f3850SWill Newton host->dma_ops->exit(host); 2679f95f3850SWill Newton 2680780f22afSSeungwon Jeon if (host->vmmc) 2681c07946a3SJaehoon Chung regulator_disable(host->vmmc); 2682c07946a3SJaehoon Chung 2683f90a0612SThomas Abraham if (!IS_ERR(host->ciu_clk)) 2684f90a0612SThomas Abraham clk_disable_unprepare(host->ciu_clk); 2685780f22afSSeungwon Jeon 2686f90a0612SThomas Abraham if (!IS_ERR(host->biu_clk)) 2687f90a0612SThomas Abraham clk_disable_unprepare(host->biu_clk); 2688f95f3850SWill Newton } 268962ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove); 269062ca8034SShashidhar Hiremath 269162ca8034SShashidhar Hiremath 2692f95f3850SWill Newton 26936fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP 2694f95f3850SWill Newton /* 2695f95f3850SWill Newton * TODO: we should probably disable the clock to the card in the suspend path. 2696f95f3850SWill Newton */ 269762ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host) 2698f95f3850SWill Newton { 269962ca8034SShashidhar Hiremath int i, ret = 0; 2700f95f3850SWill Newton 2701f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2702f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 2703f95f3850SWill Newton if (!slot) 2704f95f3850SWill Newton continue; 2705f95f3850SWill Newton ret = mmc_suspend_host(slot->mmc); 2706f95f3850SWill Newton if (ret < 0) { 2707f95f3850SWill Newton while (--i >= 0) { 2708f95f3850SWill Newton slot = host->slot[i]; 2709f95f3850SWill Newton if (slot) 2710f95f3850SWill Newton mmc_resume_host(host->slot[i]->mmc); 2711f95f3850SWill Newton } 2712f95f3850SWill Newton return ret; 2713f95f3850SWill Newton } 2714f95f3850SWill Newton } 2715f95f3850SWill Newton 2716c07946a3SJaehoon Chung if (host->vmmc) 2717c07946a3SJaehoon Chung regulator_disable(host->vmmc); 2718c07946a3SJaehoon Chung 2719f95f3850SWill Newton return 0; 2720f95f3850SWill Newton } 272162ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend); 2722f95f3850SWill Newton 272362ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host) 2724f95f3850SWill Newton { 2725f95f3850SWill Newton int i, ret; 2726f95f3850SWill Newton 2727f2f942ceSSachin Kamat if (host->vmmc) { 2728f2f942ceSSachin Kamat ret = regulator_enable(host->vmmc); 2729f2f942ceSSachin Kamat if (ret) { 2730f2f942ceSSachin Kamat dev_err(host->dev, 2731f2f942ceSSachin Kamat "failed to enable regulator: %d\n", ret); 2732f2f942ceSSachin Kamat return ret; 2733f2f942ceSSachin Kamat } 2734f2f942ceSSachin Kamat } 27351d6c4e0aSJaehoon Chung 273631bff450SSeungwon Jeon if (!dw_mci_ctrl_all_reset(host)) { 2737e61cf118SJaehoon Chung ret = -ENODEV; 2738e61cf118SJaehoon Chung return ret; 2739e61cf118SJaehoon Chung } 2740e61cf118SJaehoon Chung 27413bfe619dSJonathan Kliegman if (host->use_dma && host->dma_ops->init) 2742141a712aSSeungwon Jeon host->dma_ops->init(host); 2743141a712aSSeungwon Jeon 274452426899SSeungwon Jeon /* 274552426899SSeungwon Jeon * Restore the initial value at FIFOTH register 274652426899SSeungwon Jeon * And Invalidate the prev_blksz with zero 274752426899SSeungwon Jeon */ 2748e61cf118SJaehoon Chung mci_writel(host, FIFOTH, host->fifoth_val); 274952426899SSeungwon Jeon host->prev_blksz = 0; 2750e61cf118SJaehoon Chung 27512eb2944fSDoug Anderson /* Put in max timeout */ 27522eb2944fSDoug Anderson mci_writel(host, TMOUT, 0xFFFFFFFF); 27532eb2944fSDoug Anderson 2754e61cf118SJaehoon Chung mci_writel(host, RINTSTS, 0xFFFFFFFF); 2755e61cf118SJaehoon Chung mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | 2756e61cf118SJaehoon Chung SDMMC_INT_TXDR | SDMMC_INT_RXDR | 2757e61cf118SJaehoon Chung DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); 2758e61cf118SJaehoon Chung mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); 2759e61cf118SJaehoon Chung 2760f95f3850SWill Newton for (i = 0; i < host->num_slots; i++) { 2761f95f3850SWill Newton struct dw_mci_slot *slot = host->slot[i]; 2762f95f3850SWill Newton if (!slot) 2763f95f3850SWill Newton continue; 2764ab269128SAbhilash Kesavan if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { 2765ab269128SAbhilash Kesavan dw_mci_set_ios(slot->mmc, &slot->mmc->ios); 2766ab269128SAbhilash Kesavan dw_mci_setup_bus(slot, true); 2767ab269128SAbhilash Kesavan } 2768ab269128SAbhilash Kesavan 2769f95f3850SWill Newton ret = mmc_resume_host(host->slot[i]->mmc); 2770f95f3850SWill Newton if (ret < 0) 2771f95f3850SWill Newton return ret; 2772f95f3850SWill Newton } 2773f95f3850SWill Newton return 0; 2774f95f3850SWill Newton } 277562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume); 27766fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */ 27776fe8890dSJaehoon Chung 2778f95f3850SWill Newton static int __init dw_mci_init(void) 2779f95f3850SWill Newton { 27808e1c4e4dSSachin Kamat pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); 278162ca8034SShashidhar Hiremath return 0; 2782f95f3850SWill Newton } 2783f95f3850SWill Newton 2784f95f3850SWill Newton static void __exit dw_mci_exit(void) 2785f95f3850SWill Newton { 2786f95f3850SWill Newton } 2787f95f3850SWill Newton 2788f95f3850SWill Newton module_init(dw_mci_init); 2789f95f3850SWill Newton module_exit(dw_mci_exit); 2790f95f3850SWill Newton 2791f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); 2792f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam"); 2793f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd"); 2794f95f3850SWill Newton MODULE_LICENSE("GPL v2"); 2795