11b66e94eSJonas Jensen /* 21b66e94eSJonas Jensen * MOXA ART MMC host driver. 31b66e94eSJonas Jensen * 41b66e94eSJonas Jensen * Copyright (C) 2014 Jonas Jensen 51b66e94eSJonas Jensen * 61b66e94eSJonas Jensen * Jonas Jensen <jonas.jensen@gmail.com> 71b66e94eSJonas Jensen * 81b66e94eSJonas Jensen * Based on code from 91b66e94eSJonas Jensen * Moxa Technologies Co., Ltd. <www.moxa.com> 101b66e94eSJonas Jensen * 111b66e94eSJonas Jensen * This file is licensed under the terms of the GNU General Public 121b66e94eSJonas Jensen * License version 2. This program is licensed "as is" without any 131b66e94eSJonas Jensen * warranty of any kind, whether express or implied. 141b66e94eSJonas Jensen */ 151b66e94eSJonas Jensen 161b66e94eSJonas Jensen #include <linux/module.h> 171b66e94eSJonas Jensen #include <linux/init.h> 181b66e94eSJonas Jensen #include <linux/platform_device.h> 191b66e94eSJonas Jensen #include <linux/delay.h> 203981c516SArnd Bergmann #include <linux/errno.h> 211b66e94eSJonas Jensen #include <linux/interrupt.h> 221b66e94eSJonas Jensen #include <linux/blkdev.h> 231b66e94eSJonas Jensen #include <linux/dma-mapping.h> 241b66e94eSJonas Jensen #include <linux/dmaengine.h> 251b66e94eSJonas Jensen #include <linux/mmc/host.h> 261b66e94eSJonas Jensen #include <linux/mmc/sd.h> 271b66e94eSJonas Jensen #include <linux/sched.h> 281b66e94eSJonas Jensen #include <linux/io.h> 291b66e94eSJonas Jensen #include <linux/of_address.h> 301b66e94eSJonas Jensen #include <linux/of_irq.h> 311b66e94eSJonas Jensen #include <linux/clk.h> 321b66e94eSJonas Jensen #include <linux/bitops.h> 331b66e94eSJonas Jensen #include <linux/of_dma.h> 341b66e94eSJonas Jensen #include <linux/spinlock.h> 351b66e94eSJonas Jensen 361b66e94eSJonas Jensen #define REG_COMMAND 0 371b66e94eSJonas Jensen #define REG_ARGUMENT 4 381b66e94eSJonas Jensen #define REG_RESPONSE0 8 391b66e94eSJonas Jensen #define REG_RESPONSE1 12 401b66e94eSJonas Jensen #define REG_RESPONSE2 16 411b66e94eSJonas Jensen #define REG_RESPONSE3 20 421b66e94eSJonas Jensen #define REG_RESPONSE_COMMAND 24 431b66e94eSJonas Jensen #define REG_DATA_CONTROL 28 441b66e94eSJonas Jensen #define REG_DATA_TIMER 32 451b66e94eSJonas Jensen #define REG_DATA_LENGTH 36 461b66e94eSJonas Jensen #define REG_STATUS 40 471b66e94eSJonas Jensen #define REG_CLEAR 44 481b66e94eSJonas Jensen #define REG_INTERRUPT_MASK 48 491b66e94eSJonas Jensen #define REG_POWER_CONTROL 52 501b66e94eSJonas Jensen #define REG_CLOCK_CONTROL 56 511b66e94eSJonas Jensen #define REG_BUS_WIDTH 60 521b66e94eSJonas Jensen #define REG_DATA_WINDOW 64 531b66e94eSJonas Jensen #define REG_FEATURE 68 541b66e94eSJonas Jensen #define REG_REVISION 72 551b66e94eSJonas Jensen 561b66e94eSJonas Jensen /* REG_COMMAND */ 571b66e94eSJonas Jensen #define CMD_SDC_RESET BIT(10) 581b66e94eSJonas Jensen #define CMD_EN BIT(9) 591b66e94eSJonas Jensen #define CMD_APP_CMD BIT(8) 601b66e94eSJonas Jensen #define CMD_LONG_RSP BIT(7) 611b66e94eSJonas Jensen #define CMD_NEED_RSP BIT(6) 621b66e94eSJonas Jensen #define CMD_IDX_MASK 0x3f 631b66e94eSJonas Jensen 641b66e94eSJonas Jensen /* REG_RESPONSE_COMMAND */ 651b66e94eSJonas Jensen #define RSP_CMD_APP BIT(6) 661b66e94eSJonas Jensen #define RSP_CMD_IDX_MASK 0x3f 671b66e94eSJonas Jensen 681b66e94eSJonas Jensen /* REG_DATA_CONTROL */ 691b66e94eSJonas Jensen #define DCR_DATA_FIFO_RESET BIT(8) 701b66e94eSJonas Jensen #define DCR_DATA_THRES BIT(7) 711b66e94eSJonas Jensen #define DCR_DATA_EN BIT(6) 721b66e94eSJonas Jensen #define DCR_DMA_EN BIT(5) 731b66e94eSJonas Jensen #define DCR_DATA_WRITE BIT(4) 741b66e94eSJonas Jensen #define DCR_BLK_SIZE 0x0f 751b66e94eSJonas Jensen 761b66e94eSJonas Jensen /* REG_DATA_LENGTH */ 771b66e94eSJonas Jensen #define DATA_LEN_MASK 0xffffff 781b66e94eSJonas Jensen 791b66e94eSJonas Jensen /* REG_STATUS */ 801b66e94eSJonas Jensen #define WRITE_PROT BIT(12) 811b66e94eSJonas Jensen #define CARD_DETECT BIT(11) 821b66e94eSJonas Jensen /* 1-10 below can be sent to either registers, interrupt or clear. */ 831b66e94eSJonas Jensen #define CARD_CHANGE BIT(10) 841b66e94eSJonas Jensen #define FIFO_ORUN BIT(9) 851b66e94eSJonas Jensen #define FIFO_URUN BIT(8) 861b66e94eSJonas Jensen #define DATA_END BIT(7) 871b66e94eSJonas Jensen #define CMD_SENT BIT(6) 881b66e94eSJonas Jensen #define DATA_CRC_OK BIT(5) 891b66e94eSJonas Jensen #define RSP_CRC_OK BIT(4) 901b66e94eSJonas Jensen #define DATA_TIMEOUT BIT(3) 911b66e94eSJonas Jensen #define RSP_TIMEOUT BIT(2) 921b66e94eSJonas Jensen #define DATA_CRC_FAIL BIT(1) 931b66e94eSJonas Jensen #define RSP_CRC_FAIL BIT(0) 941b66e94eSJonas Jensen 951b66e94eSJonas Jensen #define MASK_RSP (RSP_TIMEOUT | RSP_CRC_FAIL | \ 961b66e94eSJonas Jensen RSP_CRC_OK | CARD_DETECT | CMD_SENT) 971b66e94eSJonas Jensen 981b66e94eSJonas Jensen #define MASK_DATA (DATA_CRC_OK | DATA_END | \ 991b66e94eSJonas Jensen DATA_CRC_FAIL | DATA_TIMEOUT) 1001b66e94eSJonas Jensen 1011b66e94eSJonas Jensen #define MASK_INTR_PIO (FIFO_URUN | FIFO_ORUN | CARD_CHANGE) 1021b66e94eSJonas Jensen 1031b66e94eSJonas Jensen /* REG_POWER_CONTROL */ 1041b66e94eSJonas Jensen #define SD_POWER_ON BIT(4) 1051b66e94eSJonas Jensen #define SD_POWER_MASK 0x0f 1061b66e94eSJonas Jensen 1071b66e94eSJonas Jensen /* REG_CLOCK_CONTROL */ 1081b66e94eSJonas Jensen #define CLK_HISPD BIT(9) 1091b66e94eSJonas Jensen #define CLK_OFF BIT(8) 1101b66e94eSJonas Jensen #define CLK_SD BIT(7) 1111b66e94eSJonas Jensen #define CLK_DIV_MASK 0x7f 1121b66e94eSJonas Jensen 1131b66e94eSJonas Jensen /* REG_BUS_WIDTH */ 1141b66e94eSJonas Jensen #define BUS_WIDTH_8 BIT(2) 1151b66e94eSJonas Jensen #define BUS_WIDTH_4 BIT(1) 1161b66e94eSJonas Jensen #define BUS_WIDTH_1 BIT(0) 1171b66e94eSJonas Jensen 1181b66e94eSJonas Jensen #define MMC_VDD_360 23 1191b66e94eSJonas Jensen #define MIN_POWER (MMC_VDD_360 - SD_POWER_MASK) 1201b66e94eSJonas Jensen #define MAX_RETRIES 500000 1211b66e94eSJonas Jensen 1221b66e94eSJonas Jensen struct moxart_host { 1231b66e94eSJonas Jensen spinlock_t lock; 1241b66e94eSJonas Jensen 1251b66e94eSJonas Jensen void __iomem *base; 1261b66e94eSJonas Jensen 1271b66e94eSJonas Jensen phys_addr_t reg_phys; 1281b66e94eSJonas Jensen 1291b66e94eSJonas Jensen struct dma_chan *dma_chan_tx; 1301b66e94eSJonas Jensen struct dma_chan *dma_chan_rx; 1311b66e94eSJonas Jensen struct dma_async_tx_descriptor *tx_desc; 1321b66e94eSJonas Jensen struct mmc_host *mmc; 1331b66e94eSJonas Jensen struct mmc_request *mrq; 1341b66e94eSJonas Jensen struct scatterlist *cur_sg; 1351b66e94eSJonas Jensen struct completion dma_complete; 1361b66e94eSJonas Jensen struct completion pio_complete; 1371b66e94eSJonas Jensen 1381b66e94eSJonas Jensen u32 num_sg; 1391b66e94eSJonas Jensen u32 data_remain; 1401b66e94eSJonas Jensen u32 data_len; 1411b66e94eSJonas Jensen u32 fifo_width; 1421b66e94eSJonas Jensen u32 timeout; 1431b66e94eSJonas Jensen u32 rate; 1441b66e94eSJonas Jensen 1451b66e94eSJonas Jensen long sysclk; 1461b66e94eSJonas Jensen 1471b66e94eSJonas Jensen bool have_dma; 1481b66e94eSJonas Jensen bool is_removed; 1491b66e94eSJonas Jensen }; 1501b66e94eSJonas Jensen 1511b66e94eSJonas Jensen static inline void moxart_init_sg(struct moxart_host *host, 1521b66e94eSJonas Jensen struct mmc_data *data) 1531b66e94eSJonas Jensen { 1541b66e94eSJonas Jensen host->cur_sg = data->sg; 1551b66e94eSJonas Jensen host->num_sg = data->sg_len; 1561b66e94eSJonas Jensen host->data_remain = host->cur_sg->length; 1571b66e94eSJonas Jensen 1581b66e94eSJonas Jensen if (host->data_remain > host->data_len) 1591b66e94eSJonas Jensen host->data_remain = host->data_len; 1601b66e94eSJonas Jensen } 1611b66e94eSJonas Jensen 1621b66e94eSJonas Jensen static inline int moxart_next_sg(struct moxart_host *host) 1631b66e94eSJonas Jensen { 1641b66e94eSJonas Jensen int remain; 1651b66e94eSJonas Jensen struct mmc_data *data = host->mrq->cmd->data; 1661b66e94eSJonas Jensen 1671b66e94eSJonas Jensen host->cur_sg++; 1681b66e94eSJonas Jensen host->num_sg--; 1691b66e94eSJonas Jensen 1701b66e94eSJonas Jensen if (host->num_sg > 0) { 1711b66e94eSJonas Jensen host->data_remain = host->cur_sg->length; 1721b66e94eSJonas Jensen remain = host->data_len - data->bytes_xfered; 1731b66e94eSJonas Jensen if (remain > 0 && remain < host->data_remain) 1741b66e94eSJonas Jensen host->data_remain = remain; 1751b66e94eSJonas Jensen } 1761b66e94eSJonas Jensen 1771b66e94eSJonas Jensen return host->num_sg; 1781b66e94eSJonas Jensen } 1791b66e94eSJonas Jensen 1801b66e94eSJonas Jensen static int moxart_wait_for_status(struct moxart_host *host, 1811b66e94eSJonas Jensen u32 mask, u32 *status) 1821b66e94eSJonas Jensen { 1831b66e94eSJonas Jensen int ret = -ETIMEDOUT; 1841b66e94eSJonas Jensen u32 i; 1851b66e94eSJonas Jensen 1861b66e94eSJonas Jensen for (i = 0; i < MAX_RETRIES; i++) { 1871b66e94eSJonas Jensen *status = readl(host->base + REG_STATUS); 1881b66e94eSJonas Jensen if (!(*status & mask)) { 1891b66e94eSJonas Jensen udelay(5); 1901b66e94eSJonas Jensen continue; 1911b66e94eSJonas Jensen } 1921b66e94eSJonas Jensen writel(*status & mask, host->base + REG_CLEAR); 1931b66e94eSJonas Jensen ret = 0; 1941b66e94eSJonas Jensen break; 1951b66e94eSJonas Jensen } 1961b66e94eSJonas Jensen 1971b66e94eSJonas Jensen if (ret) 1981b66e94eSJonas Jensen dev_err(mmc_dev(host->mmc), "timed out waiting for status\n"); 1991b66e94eSJonas Jensen 2001b66e94eSJonas Jensen return ret; 2011b66e94eSJonas Jensen } 2021b66e94eSJonas Jensen 2031b66e94eSJonas Jensen 2041b66e94eSJonas Jensen static void moxart_send_command(struct moxart_host *host, 2051b66e94eSJonas Jensen struct mmc_command *cmd) 2061b66e94eSJonas Jensen { 2071b66e94eSJonas Jensen u32 status, cmdctrl; 2081b66e94eSJonas Jensen 2091b66e94eSJonas Jensen writel(RSP_TIMEOUT | RSP_CRC_OK | 2101b66e94eSJonas Jensen RSP_CRC_FAIL | CMD_SENT, host->base + REG_CLEAR); 2111b66e94eSJonas Jensen writel(cmd->arg, host->base + REG_ARGUMENT); 2121b66e94eSJonas Jensen 2131b66e94eSJonas Jensen cmdctrl = cmd->opcode & CMD_IDX_MASK; 2141b66e94eSJonas Jensen if (cmdctrl == SD_APP_SET_BUS_WIDTH || cmdctrl == SD_APP_OP_COND || 2151b66e94eSJonas Jensen cmdctrl == SD_APP_SEND_SCR || cmdctrl == SD_APP_SD_STATUS || 2161b66e94eSJonas Jensen cmdctrl == SD_APP_SEND_NUM_WR_BLKS) 2171b66e94eSJonas Jensen cmdctrl |= CMD_APP_CMD; 2181b66e94eSJonas Jensen 2191b66e94eSJonas Jensen if (cmd->flags & MMC_RSP_PRESENT) 2201b66e94eSJonas Jensen cmdctrl |= CMD_NEED_RSP; 2211b66e94eSJonas Jensen 2221b66e94eSJonas Jensen if (cmd->flags & MMC_RSP_136) 2231b66e94eSJonas Jensen cmdctrl |= CMD_LONG_RSP; 2241b66e94eSJonas Jensen 2251b66e94eSJonas Jensen writel(cmdctrl | CMD_EN, host->base + REG_COMMAND); 2261b66e94eSJonas Jensen 2271b66e94eSJonas Jensen if (moxart_wait_for_status(host, MASK_RSP, &status) == -ETIMEDOUT) 2281b66e94eSJonas Jensen cmd->error = -ETIMEDOUT; 2291b66e94eSJonas Jensen 2301b66e94eSJonas Jensen if (status & RSP_TIMEOUT) { 2311b66e94eSJonas Jensen cmd->error = -ETIMEDOUT; 2321b66e94eSJonas Jensen return; 2331b66e94eSJonas Jensen } 2341b66e94eSJonas Jensen if (status & RSP_CRC_FAIL) { 2351b66e94eSJonas Jensen cmd->error = -EIO; 2361b66e94eSJonas Jensen return; 2371b66e94eSJonas Jensen } 2381b66e94eSJonas Jensen if (status & RSP_CRC_OK) { 2391b66e94eSJonas Jensen if (cmd->flags & MMC_RSP_136) { 2401b66e94eSJonas Jensen cmd->resp[3] = readl(host->base + REG_RESPONSE0); 2411b66e94eSJonas Jensen cmd->resp[2] = readl(host->base + REG_RESPONSE1); 2421b66e94eSJonas Jensen cmd->resp[1] = readl(host->base + REG_RESPONSE2); 2431b66e94eSJonas Jensen cmd->resp[0] = readl(host->base + REG_RESPONSE3); 2441b66e94eSJonas Jensen } else { 2451b66e94eSJonas Jensen cmd->resp[0] = readl(host->base + REG_RESPONSE0); 2461b66e94eSJonas Jensen } 2471b66e94eSJonas Jensen } 2481b66e94eSJonas Jensen } 2491b66e94eSJonas Jensen 2501b66e94eSJonas Jensen static void moxart_dma_complete(void *param) 2511b66e94eSJonas Jensen { 2521b66e94eSJonas Jensen struct moxart_host *host = param; 2531b66e94eSJonas Jensen 2541b66e94eSJonas Jensen complete(&host->dma_complete); 2551b66e94eSJonas Jensen } 2561b66e94eSJonas Jensen 2571b66e94eSJonas Jensen static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host) 2581b66e94eSJonas Jensen { 259feeef096SHeiner Kallweit u32 len, dir_slave; 26041f469caSNicholas Mc Guire long dma_time; 2611b66e94eSJonas Jensen struct dma_async_tx_descriptor *desc = NULL; 2621b66e94eSJonas Jensen struct dma_chan *dma_chan; 2631b66e94eSJonas Jensen 2641b66e94eSJonas Jensen if (host->data_len == data->bytes_xfered) 2651b66e94eSJonas Jensen return; 2661b66e94eSJonas Jensen 2671b66e94eSJonas Jensen if (data->flags & MMC_DATA_WRITE) { 2681b66e94eSJonas Jensen dma_chan = host->dma_chan_tx; 2691b66e94eSJonas Jensen dir_slave = DMA_MEM_TO_DEV; 2701b66e94eSJonas Jensen } else { 2711b66e94eSJonas Jensen dma_chan = host->dma_chan_rx; 2721b66e94eSJonas Jensen dir_slave = DMA_DEV_TO_MEM; 2731b66e94eSJonas Jensen } 2741b66e94eSJonas Jensen 2751b66e94eSJonas Jensen len = dma_map_sg(dma_chan->device->dev, data->sg, 276feeef096SHeiner Kallweit data->sg_len, mmc_get_dma_dir(data)); 2771b66e94eSJonas Jensen 2781b66e94eSJonas Jensen if (len > 0) { 2791b66e94eSJonas Jensen desc = dmaengine_prep_slave_sg(dma_chan, data->sg, 2801b66e94eSJonas Jensen len, dir_slave, 2811b66e94eSJonas Jensen DMA_PREP_INTERRUPT | 2821b66e94eSJonas Jensen DMA_CTRL_ACK); 2831b66e94eSJonas Jensen } else { 2841b66e94eSJonas Jensen dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n"); 2851b66e94eSJonas Jensen } 2861b66e94eSJonas Jensen 2871b66e94eSJonas Jensen if (desc) { 2881b66e94eSJonas Jensen host->tx_desc = desc; 2891b66e94eSJonas Jensen desc->callback = moxart_dma_complete; 2901b66e94eSJonas Jensen desc->callback_param = host; 2911b66e94eSJonas Jensen dmaengine_submit(desc); 2921b66e94eSJonas Jensen dma_async_issue_pending(dma_chan); 2931b66e94eSJonas Jensen } 2941b66e94eSJonas Jensen 2951b66e94eSJonas Jensen data->bytes_xfered += host->data_remain; 2961b66e94eSJonas Jensen 2971b66e94eSJonas Jensen dma_time = wait_for_completion_interruptible_timeout( 2981b66e94eSJonas Jensen &host->dma_complete, host->timeout); 2991b66e94eSJonas Jensen 3001b66e94eSJonas Jensen dma_unmap_sg(dma_chan->device->dev, 3011b66e94eSJonas Jensen data->sg, data->sg_len, 302feeef096SHeiner Kallweit mmc_get_dma_dir(data)); 3031b66e94eSJonas Jensen } 3041b66e94eSJonas Jensen 3051b66e94eSJonas Jensen 3061b66e94eSJonas Jensen static void moxart_transfer_pio(struct moxart_host *host) 3071b66e94eSJonas Jensen { 3081b66e94eSJonas Jensen struct mmc_data *data = host->mrq->cmd->data; 3091b66e94eSJonas Jensen u32 *sgp, len = 0, remain, status; 3101b66e94eSJonas Jensen 3111b66e94eSJonas Jensen if (host->data_len == data->bytes_xfered) 3121b66e94eSJonas Jensen return; 3131b66e94eSJonas Jensen 3141b66e94eSJonas Jensen sgp = sg_virt(host->cur_sg); 3151b66e94eSJonas Jensen remain = host->data_remain; 3161b66e94eSJonas Jensen 3171b66e94eSJonas Jensen if (data->flags & MMC_DATA_WRITE) { 3181b66e94eSJonas Jensen while (remain > 0) { 3191b66e94eSJonas Jensen if (moxart_wait_for_status(host, FIFO_URUN, &status) 3201b66e94eSJonas Jensen == -ETIMEDOUT) { 3211b66e94eSJonas Jensen data->error = -ETIMEDOUT; 3221b66e94eSJonas Jensen complete(&host->pio_complete); 3231b66e94eSJonas Jensen return; 3241b66e94eSJonas Jensen } 3251b66e94eSJonas Jensen for (len = 0; len < remain && len < host->fifo_width;) { 3261b66e94eSJonas Jensen iowrite32(*sgp, host->base + REG_DATA_WINDOW); 3271b66e94eSJonas Jensen sgp++; 3281b66e94eSJonas Jensen len += 4; 3291b66e94eSJonas Jensen } 3301b66e94eSJonas Jensen remain -= len; 3311b66e94eSJonas Jensen } 3321b66e94eSJonas Jensen 3331b66e94eSJonas Jensen } else { 3341b66e94eSJonas Jensen while (remain > 0) { 3351b66e94eSJonas Jensen if (moxart_wait_for_status(host, FIFO_ORUN, &status) 3361b66e94eSJonas Jensen == -ETIMEDOUT) { 3371b66e94eSJonas Jensen data->error = -ETIMEDOUT; 3381b66e94eSJonas Jensen complete(&host->pio_complete); 3391b66e94eSJonas Jensen return; 3401b66e94eSJonas Jensen } 3411b66e94eSJonas Jensen for (len = 0; len < remain && len < host->fifo_width;) { 3421b66e94eSJonas Jensen /* SCR data must be read in big endian. */ 3431b66e94eSJonas Jensen if (data->mrq->cmd->opcode == SD_APP_SEND_SCR) 3441b66e94eSJonas Jensen *sgp = ioread32be(host->base + 3451b66e94eSJonas Jensen REG_DATA_WINDOW); 3461b66e94eSJonas Jensen else 3471b66e94eSJonas Jensen *sgp = ioread32(host->base + 3481b66e94eSJonas Jensen REG_DATA_WINDOW); 3491b66e94eSJonas Jensen sgp++; 3501b66e94eSJonas Jensen len += 4; 3511b66e94eSJonas Jensen } 3521b66e94eSJonas Jensen remain -= len; 3531b66e94eSJonas Jensen } 3541b66e94eSJonas Jensen } 3551b66e94eSJonas Jensen 3561b66e94eSJonas Jensen data->bytes_xfered += host->data_remain - remain; 3571b66e94eSJonas Jensen host->data_remain = remain; 3581b66e94eSJonas Jensen 3591b66e94eSJonas Jensen if (host->data_len != data->bytes_xfered) 3601b66e94eSJonas Jensen moxart_next_sg(host); 3611b66e94eSJonas Jensen else 3621b66e94eSJonas Jensen complete(&host->pio_complete); 3631b66e94eSJonas Jensen } 3641b66e94eSJonas Jensen 3651b66e94eSJonas Jensen static void moxart_prepare_data(struct moxart_host *host) 3661b66e94eSJonas Jensen { 3671b66e94eSJonas Jensen struct mmc_data *data = host->mrq->cmd->data; 3681b66e94eSJonas Jensen u32 datactrl; 3691b66e94eSJonas Jensen int blksz_bits; 3701b66e94eSJonas Jensen 3711b66e94eSJonas Jensen if (!data) 3721b66e94eSJonas Jensen return; 3731b66e94eSJonas Jensen 3741b66e94eSJonas Jensen host->data_len = data->blocks * data->blksz; 3751b66e94eSJonas Jensen blksz_bits = ffs(data->blksz) - 1; 3761b66e94eSJonas Jensen BUG_ON(1 << blksz_bits != data->blksz); 3771b66e94eSJonas Jensen 3781b66e94eSJonas Jensen moxart_init_sg(host, data); 3791b66e94eSJonas Jensen 3801b66e94eSJonas Jensen datactrl = DCR_DATA_EN | (blksz_bits & DCR_BLK_SIZE); 3811b66e94eSJonas Jensen 3821b66e94eSJonas Jensen if (data->flags & MMC_DATA_WRITE) 3831b66e94eSJonas Jensen datactrl |= DCR_DATA_WRITE; 3841b66e94eSJonas Jensen 3851b66e94eSJonas Jensen if ((host->data_len > host->fifo_width) && host->have_dma) 3861b66e94eSJonas Jensen datactrl |= DCR_DMA_EN; 3871b66e94eSJonas Jensen 3881b66e94eSJonas Jensen writel(DCR_DATA_FIFO_RESET, host->base + REG_DATA_CONTROL); 3891b66e94eSJonas Jensen writel(MASK_DATA | FIFO_URUN | FIFO_ORUN, host->base + REG_CLEAR); 3901b66e94eSJonas Jensen writel(host->rate, host->base + REG_DATA_TIMER); 3911b66e94eSJonas Jensen writel(host->data_len, host->base + REG_DATA_LENGTH); 3921b66e94eSJonas Jensen writel(datactrl, host->base + REG_DATA_CONTROL); 3931b66e94eSJonas Jensen } 3941b66e94eSJonas Jensen 3951b66e94eSJonas Jensen static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq) 3961b66e94eSJonas Jensen { 3971b66e94eSJonas Jensen struct moxart_host *host = mmc_priv(mmc); 39841f469caSNicholas Mc Guire long pio_time; 39941f469caSNicholas Mc Guire unsigned long flags; 4001b66e94eSJonas Jensen u32 status; 4011b66e94eSJonas Jensen 4021b66e94eSJonas Jensen spin_lock_irqsave(&host->lock, flags); 4031b66e94eSJonas Jensen 4041b66e94eSJonas Jensen init_completion(&host->dma_complete); 4051b66e94eSJonas Jensen init_completion(&host->pio_complete); 4061b66e94eSJonas Jensen 4071b66e94eSJonas Jensen host->mrq = mrq; 4081b66e94eSJonas Jensen 4091b66e94eSJonas Jensen if (readl(host->base + REG_STATUS) & CARD_DETECT) { 4101b66e94eSJonas Jensen mrq->cmd->error = -ETIMEDOUT; 4111b66e94eSJonas Jensen goto request_done; 4121b66e94eSJonas Jensen } 4131b66e94eSJonas Jensen 4141b66e94eSJonas Jensen moxart_prepare_data(host); 4151b66e94eSJonas Jensen moxart_send_command(host, host->mrq->cmd); 4161b66e94eSJonas Jensen 4171b66e94eSJonas Jensen if (mrq->cmd->data) { 4181b66e94eSJonas Jensen if ((host->data_len > host->fifo_width) && host->have_dma) { 4191b66e94eSJonas Jensen 4201b66e94eSJonas Jensen writel(CARD_CHANGE, host->base + REG_INTERRUPT_MASK); 4211b66e94eSJonas Jensen 4221b66e94eSJonas Jensen spin_unlock_irqrestore(&host->lock, flags); 4231b66e94eSJonas Jensen 4241b66e94eSJonas Jensen moxart_transfer_dma(mrq->cmd->data, host); 4251b66e94eSJonas Jensen 4261b66e94eSJonas Jensen spin_lock_irqsave(&host->lock, flags); 4271b66e94eSJonas Jensen } else { 4281b66e94eSJonas Jensen 4291b66e94eSJonas Jensen writel(MASK_INTR_PIO, host->base + REG_INTERRUPT_MASK); 4301b66e94eSJonas Jensen 4311b66e94eSJonas Jensen spin_unlock_irqrestore(&host->lock, flags); 4321b66e94eSJonas Jensen 4331b66e94eSJonas Jensen /* PIO transfers start from interrupt. */ 4341b66e94eSJonas Jensen pio_time = wait_for_completion_interruptible_timeout( 4351b66e94eSJonas Jensen &host->pio_complete, host->timeout); 4361b66e94eSJonas Jensen 4371b66e94eSJonas Jensen spin_lock_irqsave(&host->lock, flags); 4381b66e94eSJonas Jensen } 4391b66e94eSJonas Jensen 4401b66e94eSJonas Jensen if (host->is_removed) { 4411b66e94eSJonas Jensen dev_err(mmc_dev(host->mmc), "card removed\n"); 4421b66e94eSJonas Jensen mrq->cmd->error = -ETIMEDOUT; 4431b66e94eSJonas Jensen goto request_done; 4441b66e94eSJonas Jensen } 4451b66e94eSJonas Jensen 4461b66e94eSJonas Jensen if (moxart_wait_for_status(host, MASK_DATA, &status) 4471b66e94eSJonas Jensen == -ETIMEDOUT) { 4481b66e94eSJonas Jensen mrq->cmd->data->error = -ETIMEDOUT; 4491b66e94eSJonas Jensen goto request_done; 4501b66e94eSJonas Jensen } 4511b66e94eSJonas Jensen 4521b66e94eSJonas Jensen if (status & DATA_CRC_FAIL) 4531b66e94eSJonas Jensen mrq->cmd->data->error = -ETIMEDOUT; 4541b66e94eSJonas Jensen 4551b66e94eSJonas Jensen if (mrq->cmd->data->stop) 4561b66e94eSJonas Jensen moxart_send_command(host, mrq->cmd->data->stop); 4571b66e94eSJonas Jensen } 4581b66e94eSJonas Jensen 4591b66e94eSJonas Jensen request_done: 4601b66e94eSJonas Jensen spin_unlock_irqrestore(&host->lock, flags); 4611b66e94eSJonas Jensen mmc_request_done(host->mmc, mrq); 4621b66e94eSJonas Jensen } 4631b66e94eSJonas Jensen 4641b66e94eSJonas Jensen static irqreturn_t moxart_irq(int irq, void *devid) 4651b66e94eSJonas Jensen { 4661b66e94eSJonas Jensen struct moxart_host *host = (struct moxart_host *)devid; 4671b66e94eSJonas Jensen u32 status; 4681b66e94eSJonas Jensen unsigned long flags; 4691b66e94eSJonas Jensen 4701b66e94eSJonas Jensen spin_lock_irqsave(&host->lock, flags); 4711b66e94eSJonas Jensen 4721b66e94eSJonas Jensen status = readl(host->base + REG_STATUS); 4731b66e94eSJonas Jensen if (status & CARD_CHANGE) { 4741b66e94eSJonas Jensen host->is_removed = status & CARD_DETECT; 4751b66e94eSJonas Jensen if (host->is_removed && host->have_dma) { 4761b66e94eSJonas Jensen dmaengine_terminate_all(host->dma_chan_tx); 4771b66e94eSJonas Jensen dmaengine_terminate_all(host->dma_chan_rx); 4781b66e94eSJonas Jensen } 4791b66e94eSJonas Jensen host->mrq = NULL; 4801b66e94eSJonas Jensen writel(MASK_INTR_PIO, host->base + REG_CLEAR); 4811b66e94eSJonas Jensen writel(CARD_CHANGE, host->base + REG_INTERRUPT_MASK); 4821b66e94eSJonas Jensen mmc_detect_change(host->mmc, 0); 4831b66e94eSJonas Jensen } 4841b66e94eSJonas Jensen if (status & (FIFO_ORUN | FIFO_URUN) && host->mrq) 4851b66e94eSJonas Jensen moxart_transfer_pio(host); 4861b66e94eSJonas Jensen 4871b66e94eSJonas Jensen spin_unlock_irqrestore(&host->lock, flags); 4881b66e94eSJonas Jensen 4891b66e94eSJonas Jensen return IRQ_HANDLED; 4901b66e94eSJonas Jensen } 4911b66e94eSJonas Jensen 4921b66e94eSJonas Jensen static void moxart_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 4931b66e94eSJonas Jensen { 4941b66e94eSJonas Jensen struct moxart_host *host = mmc_priv(mmc); 4951b66e94eSJonas Jensen unsigned long flags; 4961b66e94eSJonas Jensen u8 power, div; 4971b66e94eSJonas Jensen u32 ctrl; 4981b66e94eSJonas Jensen 4991b66e94eSJonas Jensen spin_lock_irqsave(&host->lock, flags); 5001b66e94eSJonas Jensen 5011b66e94eSJonas Jensen if (ios->clock) { 5021b66e94eSJonas Jensen for (div = 0; div < CLK_DIV_MASK; ++div) { 5031b66e94eSJonas Jensen if (ios->clock >= host->sysclk / (2 * (div + 1))) 5041b66e94eSJonas Jensen break; 5051b66e94eSJonas Jensen } 5061b66e94eSJonas Jensen ctrl = CLK_SD | div; 5071b66e94eSJonas Jensen host->rate = host->sysclk / (2 * (div + 1)); 5081b66e94eSJonas Jensen if (host->rate > host->sysclk) 5091b66e94eSJonas Jensen ctrl |= CLK_HISPD; 5101b66e94eSJonas Jensen writel(ctrl, host->base + REG_CLOCK_CONTROL); 5111b66e94eSJonas Jensen } 5121b66e94eSJonas Jensen 5131b66e94eSJonas Jensen if (ios->power_mode == MMC_POWER_OFF) { 5141b66e94eSJonas Jensen writel(readl(host->base + REG_POWER_CONTROL) & ~SD_POWER_ON, 5151b66e94eSJonas Jensen host->base + REG_POWER_CONTROL); 5161b66e94eSJonas Jensen } else { 5171b66e94eSJonas Jensen if (ios->vdd < MIN_POWER) 5181b66e94eSJonas Jensen power = 0; 5191b66e94eSJonas Jensen else 5201b66e94eSJonas Jensen power = ios->vdd - MIN_POWER; 5211b66e94eSJonas Jensen 5221b66e94eSJonas Jensen writel(SD_POWER_ON | (u32) power, 5231b66e94eSJonas Jensen host->base + REG_POWER_CONTROL); 5241b66e94eSJonas Jensen } 5251b66e94eSJonas Jensen 5261b66e94eSJonas Jensen switch (ios->bus_width) { 5271b66e94eSJonas Jensen case MMC_BUS_WIDTH_4: 5281b66e94eSJonas Jensen writel(BUS_WIDTH_4, host->base + REG_BUS_WIDTH); 5291b66e94eSJonas Jensen break; 5301b66e94eSJonas Jensen case MMC_BUS_WIDTH_8: 5311b66e94eSJonas Jensen writel(BUS_WIDTH_8, host->base + REG_BUS_WIDTH); 5321b66e94eSJonas Jensen break; 5331b66e94eSJonas Jensen default: 5341b66e94eSJonas Jensen writel(BUS_WIDTH_1, host->base + REG_BUS_WIDTH); 5351b66e94eSJonas Jensen break; 5361b66e94eSJonas Jensen } 5371b66e94eSJonas Jensen 5381b66e94eSJonas Jensen spin_unlock_irqrestore(&host->lock, flags); 5391b66e94eSJonas Jensen } 5401b66e94eSJonas Jensen 5411b66e94eSJonas Jensen 5421b66e94eSJonas Jensen static int moxart_get_ro(struct mmc_host *mmc) 5431b66e94eSJonas Jensen { 5441b66e94eSJonas Jensen struct moxart_host *host = mmc_priv(mmc); 5451b66e94eSJonas Jensen 5461b66e94eSJonas Jensen return !!(readl(host->base + REG_STATUS) & WRITE_PROT); 5471b66e94eSJonas Jensen } 5481b66e94eSJonas Jensen 549bc860c20SJulia Lawall static const struct mmc_host_ops moxart_ops = { 5501b66e94eSJonas Jensen .request = moxart_request, 5511b66e94eSJonas Jensen .set_ios = moxart_set_ios, 5521b66e94eSJonas Jensen .get_ro = moxart_get_ro, 5531b66e94eSJonas Jensen }; 5541b66e94eSJonas Jensen 5551b66e94eSJonas Jensen static int moxart_probe(struct platform_device *pdev) 5561b66e94eSJonas Jensen { 5571b66e94eSJonas Jensen struct device *dev = &pdev->dev; 5581b66e94eSJonas Jensen struct device_node *node = dev->of_node; 5591b66e94eSJonas Jensen struct resource res_mmc; 5601b66e94eSJonas Jensen struct mmc_host *mmc; 5611b66e94eSJonas Jensen struct moxart_host *host = NULL; 5621b66e94eSJonas Jensen struct dma_slave_config cfg; 5631b66e94eSJonas Jensen struct clk *clk; 5641b66e94eSJonas Jensen void __iomem *reg_mmc; 5651b66e94eSJonas Jensen int irq, ret; 5661b66e94eSJonas Jensen u32 i; 5671b66e94eSJonas Jensen 5681b66e94eSJonas Jensen mmc = mmc_alloc_host(sizeof(struct moxart_host), dev); 5691b66e94eSJonas Jensen if (!mmc) { 5701b66e94eSJonas Jensen dev_err(dev, "mmc_alloc_host failed\n"); 5711b66e94eSJonas Jensen ret = -ENOMEM; 5721b66e94eSJonas Jensen goto out; 5731b66e94eSJonas Jensen } 5741b66e94eSJonas Jensen 5751b66e94eSJonas Jensen ret = of_address_to_resource(node, 0, &res_mmc); 5761b66e94eSJonas Jensen if (ret) { 5771b66e94eSJonas Jensen dev_err(dev, "of_address_to_resource failed\n"); 5781b66e94eSJonas Jensen goto out; 5791b66e94eSJonas Jensen } 5801b66e94eSJonas Jensen 5811b66e94eSJonas Jensen irq = irq_of_parse_and_map(node, 0); 5821b66e94eSJonas Jensen if (irq <= 0) { 5831b66e94eSJonas Jensen dev_err(dev, "irq_of_parse_and_map failed\n"); 5841b66e94eSJonas Jensen ret = -EINVAL; 5851b66e94eSJonas Jensen goto out; 5861b66e94eSJonas Jensen } 5871b66e94eSJonas Jensen 5883981c516SArnd Bergmann clk = devm_clk_get(dev, NULL); 5891b66e94eSJonas Jensen if (IS_ERR(clk)) { 5901b66e94eSJonas Jensen ret = PTR_ERR(clk); 5911b66e94eSJonas Jensen goto out; 5921b66e94eSJonas Jensen } 5931b66e94eSJonas Jensen 5941b66e94eSJonas Jensen reg_mmc = devm_ioremap_resource(dev, &res_mmc); 5951b66e94eSJonas Jensen if (IS_ERR(reg_mmc)) { 5961b66e94eSJonas Jensen ret = PTR_ERR(reg_mmc); 5971b66e94eSJonas Jensen goto out; 5981b66e94eSJonas Jensen } 5991b66e94eSJonas Jensen 6006d2b4218SUlf Hansson ret = mmc_of_parse(mmc); 6016d2b4218SUlf Hansson if (ret) 6026d2b4218SUlf Hansson goto out; 6031b66e94eSJonas Jensen 6041b66e94eSJonas Jensen host = mmc_priv(mmc); 6051b66e94eSJonas Jensen host->mmc = mmc; 6061b66e94eSJonas Jensen host->base = reg_mmc; 6071b66e94eSJonas Jensen host->reg_phys = res_mmc.start; 6081b66e94eSJonas Jensen host->timeout = msecs_to_jiffies(1000); 6091b66e94eSJonas Jensen host->sysclk = clk_get_rate(clk); 6101b66e94eSJonas Jensen host->fifo_width = readl(host->base + REG_FEATURE) << 2; 6113981c516SArnd Bergmann host->dma_chan_tx = dma_request_slave_channel_reason(dev, "tx"); 6123981c516SArnd Bergmann host->dma_chan_rx = dma_request_slave_channel_reason(dev, "rx"); 6131b66e94eSJonas Jensen 6141b66e94eSJonas Jensen spin_lock_init(&host->lock); 6151b66e94eSJonas Jensen 6161b66e94eSJonas Jensen mmc->ops = &moxart_ops; 6171b66e94eSJonas Jensen mmc->f_max = DIV_ROUND_CLOSEST(host->sysclk, 2); 6181b66e94eSJonas Jensen mmc->f_min = DIV_ROUND_CLOSEST(host->sysclk, CLK_DIV_MASK * 2); 6191b66e94eSJonas Jensen mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */ 6201b66e94eSJonas Jensen 6211b66e94eSJonas Jensen if (IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { 6223981c516SArnd Bergmann if (PTR_ERR(host->dma_chan_tx) == -EPROBE_DEFER || 6233981c516SArnd Bergmann PTR_ERR(host->dma_chan_rx) == -EPROBE_DEFER) { 6243981c516SArnd Bergmann ret = -EPROBE_DEFER; 6253981c516SArnd Bergmann goto out; 6263981c516SArnd Bergmann } 6271b66e94eSJonas Jensen dev_dbg(dev, "PIO mode transfer enabled\n"); 6281b66e94eSJonas Jensen host->have_dma = false; 6291b66e94eSJonas Jensen } else { 6301b66e94eSJonas Jensen dev_dbg(dev, "DMA channels found (%p,%p)\n", 6311b66e94eSJonas Jensen host->dma_chan_tx, host->dma_chan_rx); 6321b66e94eSJonas Jensen host->have_dma = true; 6331b66e94eSJonas Jensen 6341b66e94eSJonas Jensen cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 6351b66e94eSJonas Jensen cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 6361b66e94eSJonas Jensen 6371b66e94eSJonas Jensen cfg.direction = DMA_MEM_TO_DEV; 6381b66e94eSJonas Jensen cfg.src_addr = 0; 6391b66e94eSJonas Jensen cfg.dst_addr = host->reg_phys + REG_DATA_WINDOW; 6401b66e94eSJonas Jensen dmaengine_slave_config(host->dma_chan_tx, &cfg); 6411b66e94eSJonas Jensen 6421b66e94eSJonas Jensen cfg.direction = DMA_DEV_TO_MEM; 6431b66e94eSJonas Jensen cfg.src_addr = host->reg_phys + REG_DATA_WINDOW; 6441b66e94eSJonas Jensen cfg.dst_addr = 0; 6451b66e94eSJonas Jensen dmaengine_slave_config(host->dma_chan_rx, &cfg); 6461b66e94eSJonas Jensen } 6471b66e94eSJonas Jensen 6481b66e94eSJonas Jensen switch ((readl(host->base + REG_BUS_WIDTH) >> 3) & 3) { 6491b66e94eSJonas Jensen case 1: 6501b66e94eSJonas Jensen mmc->caps |= MMC_CAP_4_BIT_DATA; 6511b66e94eSJonas Jensen break; 6521b66e94eSJonas Jensen case 2: 6531b66e94eSJonas Jensen mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; 6541b66e94eSJonas Jensen break; 6551b66e94eSJonas Jensen default: 6561b66e94eSJonas Jensen break; 6571b66e94eSJonas Jensen } 6581b66e94eSJonas Jensen 6591b66e94eSJonas Jensen writel(0, host->base + REG_INTERRUPT_MASK); 6601b66e94eSJonas Jensen 6611b66e94eSJonas Jensen writel(CMD_SDC_RESET, host->base + REG_COMMAND); 6621b66e94eSJonas Jensen for (i = 0; i < MAX_RETRIES; i++) { 6631b66e94eSJonas Jensen if (!(readl(host->base + REG_COMMAND) & CMD_SDC_RESET)) 6641b66e94eSJonas Jensen break; 6651b66e94eSJonas Jensen udelay(5); 6661b66e94eSJonas Jensen } 6671b66e94eSJonas Jensen 6681b66e94eSJonas Jensen ret = devm_request_irq(dev, irq, moxart_irq, 0, "moxart-mmc", host); 6691b66e94eSJonas Jensen if (ret) 6701b66e94eSJonas Jensen goto out; 6711b66e94eSJonas Jensen 6721b66e94eSJonas Jensen dev_set_drvdata(dev, mmc); 6731b66e94eSJonas Jensen mmc_add_host(mmc); 6741b66e94eSJonas Jensen 6751b66e94eSJonas Jensen dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n", irq, host->fifo_width); 6761b66e94eSJonas Jensen 6771b66e94eSJonas Jensen return 0; 6781b66e94eSJonas Jensen 6791b66e94eSJonas Jensen out: 6801b66e94eSJonas Jensen if (mmc) 6811b66e94eSJonas Jensen mmc_free_host(mmc); 6821b66e94eSJonas Jensen return ret; 6831b66e94eSJonas Jensen } 6841b66e94eSJonas Jensen 6851b66e94eSJonas Jensen static int moxart_remove(struct platform_device *pdev) 6861b66e94eSJonas Jensen { 6871b66e94eSJonas Jensen struct mmc_host *mmc = dev_get_drvdata(&pdev->dev); 6881b66e94eSJonas Jensen struct moxart_host *host = mmc_priv(mmc); 6891b66e94eSJonas Jensen 6901b66e94eSJonas Jensen dev_set_drvdata(&pdev->dev, NULL); 6911b66e94eSJonas Jensen 6921b66e94eSJonas Jensen if (mmc) { 6931b66e94eSJonas Jensen if (!IS_ERR(host->dma_chan_tx)) 6941b66e94eSJonas Jensen dma_release_channel(host->dma_chan_tx); 6951b66e94eSJonas Jensen if (!IS_ERR(host->dma_chan_rx)) 6961b66e94eSJonas Jensen dma_release_channel(host->dma_chan_rx); 6971b66e94eSJonas Jensen mmc_remove_host(mmc); 6981b66e94eSJonas Jensen mmc_free_host(mmc); 6991b66e94eSJonas Jensen 7001b66e94eSJonas Jensen writel(0, host->base + REG_INTERRUPT_MASK); 7011b66e94eSJonas Jensen writel(0, host->base + REG_POWER_CONTROL); 7021b66e94eSJonas Jensen writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF, 7031b66e94eSJonas Jensen host->base + REG_CLOCK_CONTROL); 7041b66e94eSJonas Jensen } 7051b66e94eSJonas Jensen return 0; 7061b66e94eSJonas Jensen } 7071b66e94eSJonas Jensen 7081b66e94eSJonas Jensen static const struct of_device_id moxart_mmc_match[] = { 7091b66e94eSJonas Jensen { .compatible = "moxa,moxart-mmc" }, 7101b66e94eSJonas Jensen { .compatible = "faraday,ftsdc010" }, 7111b66e94eSJonas Jensen { } 7121b66e94eSJonas Jensen }; 71377452353SLuis de Bethencourt MODULE_DEVICE_TABLE(of, moxart_mmc_match); 7141b66e94eSJonas Jensen 7151b66e94eSJonas Jensen static struct platform_driver moxart_mmc_driver = { 7161b66e94eSJonas Jensen .probe = moxart_probe, 7171b66e94eSJonas Jensen .remove = moxart_remove, 7181b66e94eSJonas Jensen .driver = { 7191b66e94eSJonas Jensen .name = "mmc-moxart", 7201b66e94eSJonas Jensen .of_match_table = moxart_mmc_match, 7211b66e94eSJonas Jensen }, 7221b66e94eSJonas Jensen }; 7231b66e94eSJonas Jensen module_platform_driver(moxart_mmc_driver); 7241b66e94eSJonas Jensen 7251b66e94eSJonas Jensen MODULE_ALIAS("platform:mmc-moxart"); 7261b66e94eSJonas Jensen MODULE_DESCRIPTION("MOXA ART MMC driver"); 7271b66e94eSJonas Jensen MODULE_LICENSE("GPL v2"); 7281b66e94eSJonas Jensen MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); 729