Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: mmci: Add qcom dml support to the driver.

On Qualcomm APQ8064 SOCs, SD card controller has an additional glue
called DML (Data Mover Local/Lite) to assist dma transfers.
This hardware needs to be setup before any dma transfer is requested.
DML itself is not a DMA engine, its just a gule between the SD card
controller and dma controller.

Most of this code has been ported from qualcomm's 3.4 kernel.

This patch adds the code necessary to intialize the hardware and setup
before doing any dma transfers.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Srinivas Kandagatla and committed by
Ulf Hansson
9cb15142 221414db

+237 -1
+11
drivers/mmc/host/Kconfig
··· 14 14 15 15 If unsure, say N. 16 16 17 + config MMC_QCOM_DML 18 + tristate "Qualcomm Data Mover for SD Card Controller" 19 + depends on MMC_ARMMMCI && QCOM_BAM_DMA 20 + default y 21 + help 22 + This selects the Qualcomm Data Mover lite/local on SD Card controller. 23 + This option will enable the dma to work correctly, if you are using 24 + Qcom SOCs and MMC, you would probably need this option to get DMA working. 25 + 26 + if unsure, say N. 27 + 17 28 config MMC_PXA 18 29 tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" 19 30 depends on ARCH_PXA
+1
drivers/mmc/host/Makefile
··· 3 3 # 4 4 5 5 obj-$(CONFIG_MMC_ARMMMCI) += mmci.o 6 + obj-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o 6 7 obj-$(CONFIG_MMC_PXA) += pxamci.o 7 8 obj-$(CONFIG_MMC_MXC) += mxcmmc.o 8 9 obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
+17 -1
drivers/mmc/host/mmci.c
··· 43 43 #include <asm/sizes.h> 44 44 45 45 #include "mmci.h" 46 + #include "mmci_qcom_dml.h" 46 47 47 48 #define DRIVER_NAME "mmci-pl18x" 48 49 ··· 75 74 * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply 76 75 * @explicit_mclk_control: enable explicit mclk control in driver. 77 76 * @qcom_fifo: enables qcom specific fifo pio read logic. 77 + * @qcom_dml: enables qcom specific dma glue for dma transfers. 78 78 * @reversed_irq_handling: handle data irq before cmd irq. 79 79 */ 80 80 struct variant_data { ··· 100 98 bool pwrreg_nopower; 101 99 bool explicit_mclk_control; 102 100 bool qcom_fifo; 101 + bool qcom_dml; 103 102 bool reversed_irq_handling; 104 103 }; 105 104 ··· 211 208 .f_max = 208000000, 212 209 .explicit_mclk_control = true, 213 210 .qcom_fifo = true, 211 + .qcom_dml = true, 214 212 }; 215 213 216 214 static int mmci_card_busy(struct mmc_host *mmc) ··· 425 421 { 426 422 const char *rxname, *txname; 427 423 dma_cap_mask_t mask; 424 + struct variant_data *variant = host->variant; 428 425 429 426 host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); 430 427 host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); ··· 476 471 if (max_seg_size < host->mmc->max_seg_size) 477 472 host->mmc->max_seg_size = max_seg_size; 478 473 } 474 + 475 + if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel) 476 + if (dml_hw_init(host, host->mmc->parent->of_node)) 477 + variant->qcom_dml = false; 479 478 } 480 479 481 480 /* ··· 581 572 struct dma_async_tx_descriptor *desc; 582 573 enum dma_data_direction buffer_dirn; 583 574 int nr_sg; 575 + unsigned long flags = DMA_CTRL_ACK; 584 576 585 577 if (data->flags & MMC_DATA_READ) { 586 578 conf.direction = DMA_DEV_TO_MEM; ··· 606 596 if (nr_sg == 0) 607 597 return -EINVAL; 608 598 599 + if (host->variant->qcom_dml) 600 + flags |= DMA_PREP_INTERRUPT; 601 + 609 602 dmaengine_slave_config(chan, &conf); 610 603 desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg, 611 - conf.direction, DMA_CTRL_ACK); 604 + conf.direction, flags); 612 605 if (!desc) 613 606 goto unmap_exit; 614 607 ··· 659 646 data->sg_len, data->blksz, data->blocks, data->flags); 660 647 dmaengine_submit(host->dma_desc_current); 661 648 dma_async_issue_pending(host->dma_current); 649 + 650 + if (host->variant->qcom_dml) 651 + dml_start_xfer(host, data); 662 652 663 653 datactrl |= MCI_DPSM_DMAENABLE; 664 654
+177
drivers/mmc/host/mmci_qcom_dml.c
··· 1 + /* 2 + * 3 + * Copyright (c) 2011, The Linux Foundation. All rights reserved. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 and 7 + * only version 2 as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + */ 15 + #include <linux/of.h> 16 + #include <linux/of_dma.h> 17 + #include <linux/bitops.h> 18 + #include <linux/mmc/host.h> 19 + #include <linux/mmc/card.h> 20 + #include "mmci.h" 21 + 22 + /* Registers */ 23 + #define DML_CONFIG 0x00 24 + #define PRODUCER_CRCI_MSK GENMASK(1, 0) 25 + #define PRODUCER_CRCI_DISABLE 0 26 + #define PRODUCER_CRCI_X_SEL BIT(0) 27 + #define PRODUCER_CRCI_Y_SEL BIT(1) 28 + #define CONSUMER_CRCI_MSK GENMASK(3, 2) 29 + #define CONSUMER_CRCI_DISABLE 0 30 + #define CONSUMER_CRCI_X_SEL BIT(2) 31 + #define CONSUMER_CRCI_Y_SEL BIT(3) 32 + #define PRODUCER_TRANS_END_EN BIT(4) 33 + #define BYPASS BIT(16) 34 + #define DIRECT_MODE BIT(17) 35 + #define INFINITE_CONS_TRANS BIT(18) 36 + 37 + #define DML_SW_RESET 0x08 38 + #define DML_PRODUCER_START 0x0c 39 + #define DML_CONSUMER_START 0x10 40 + #define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14 41 + #define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18 42 + #define DML_PIPE_ID 0x1c 43 + #define PRODUCER_PIPE_ID_SHFT 0 44 + #define PRODUCER_PIPE_ID_MSK GENMASK(4, 0) 45 + #define CONSUMER_PIPE_ID_SHFT 16 46 + #define CONSUMER_PIPE_ID_MSK GENMASK(20, 16) 47 + 48 + #define DML_PRODUCER_BAM_BLOCK_SIZE 0x24 49 + #define DML_PRODUCER_BAM_TRANS_SIZE 0x28 50 + 51 + /* other definitions */ 52 + #define PRODUCER_PIPE_LOGICAL_SIZE 4096 53 + #define CONSUMER_PIPE_LOGICAL_SIZE 4096 54 + 55 + #define DML_OFFSET 0x800 56 + 57 + void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) 58 + { 59 + u32 config; 60 + void __iomem *base = host->base + DML_OFFSET; 61 + 62 + if (data->flags & MMC_DATA_READ) { 63 + /* Read operation: configure DML for producer operation */ 64 + /* Set producer CRCI-x and disable consumer CRCI */ 65 + config = readl_relaxed(base + DML_CONFIG); 66 + config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL; 67 + config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE; 68 + writel_relaxed(config, base + DML_CONFIG); 69 + 70 + /* Set the Producer BAM block size */ 71 + writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE); 72 + 73 + /* Set Producer BAM Transaction size */ 74 + writel_relaxed(data->blocks * data->blksz, 75 + base + DML_PRODUCER_BAM_TRANS_SIZE); 76 + /* Set Producer Transaction End bit */ 77 + config = readl_relaxed(base + DML_CONFIG); 78 + config |= PRODUCER_TRANS_END_EN; 79 + writel_relaxed(config, base + DML_CONFIG); 80 + /* Trigger producer */ 81 + writel_relaxed(1, base + DML_PRODUCER_START); 82 + } else { 83 + /* Write operation: configure DML for consumer operation */ 84 + /* Set consumer CRCI-x and disable producer CRCI*/ 85 + config = readl_relaxed(base + DML_CONFIG); 86 + config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL; 87 + config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE; 88 + writel_relaxed(config, base + DML_CONFIG); 89 + /* Clear Producer Transaction End bit */ 90 + config = readl_relaxed(base + DML_CONFIG); 91 + config &= ~PRODUCER_TRANS_END_EN; 92 + writel_relaxed(config, base + DML_CONFIG); 93 + /* Trigger consumer */ 94 + writel_relaxed(1, base + DML_CONSUMER_START); 95 + } 96 + 97 + /* make sure the dml is configured before dma is triggered */ 98 + wmb(); 99 + } 100 + 101 + static int of_get_dml_pipe_index(struct device_node *np, const char *name) 102 + { 103 + int index; 104 + struct of_phandle_args dma_spec; 105 + 106 + index = of_property_match_string(np, "dma-names", name); 107 + 108 + if (index < 0) 109 + return -ENODEV; 110 + 111 + if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index, 112 + &dma_spec)) 113 + return -ENODEV; 114 + 115 + if (dma_spec.args_count) 116 + return dma_spec.args[0]; 117 + 118 + return -ENODEV; 119 + } 120 + 121 + /* Initialize the dml hardware connected to SD Card controller */ 122 + int dml_hw_init(struct mmci_host *host, struct device_node *np) 123 + { 124 + u32 config; 125 + void __iomem *base; 126 + int consumer_id, producer_id; 127 + 128 + consumer_id = of_get_dml_pipe_index(np, "tx"); 129 + producer_id = of_get_dml_pipe_index(np, "rx"); 130 + 131 + if (producer_id < 0 || consumer_id < 0) 132 + return -ENODEV; 133 + 134 + base = host->base + DML_OFFSET; 135 + 136 + /* Reset the DML block */ 137 + writel_relaxed(1, base + DML_SW_RESET); 138 + 139 + /* Disable the producer and consumer CRCI */ 140 + config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE); 141 + /* 142 + * Disable the bypass mode. Bypass mode will only be used 143 + * if data transfer is to happen in PIO mode and don't 144 + * want the BAM interface to connect with SDCC-DML. 145 + */ 146 + config &= ~BYPASS; 147 + /* 148 + * Disable direct mode as we don't DML to MASTER the AHB bus. 149 + * BAM connected with DML should MASTER the AHB bus. 150 + */ 151 + config &= ~DIRECT_MODE; 152 + /* 153 + * Disable infinite mode transfer as we won't be doing any 154 + * infinite size data transfers. All data transfer will be 155 + * of finite data size. 156 + */ 157 + config &= ~INFINITE_CONS_TRANS; 158 + writel_relaxed(config, base + DML_CONFIG); 159 + 160 + /* 161 + * Initialize the logical BAM pipe size for producer 162 + * and consumer. 163 + */ 164 + writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE, 165 + base + DML_PRODUCER_PIPE_LOGICAL_SIZE); 166 + writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE, 167 + base + DML_CONSUMER_PIPE_LOGICAL_SIZE); 168 + 169 + /* Initialize Producer/consumer pipe id */ 170 + writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT), 171 + base + DML_PIPE_ID); 172 + 173 + /* Make sure dml intialization is finished */ 174 + mb(); 175 + 176 + return 0; 177 + }
+31
drivers/mmc/host/mmci_qcom_dml.h
··· 1 + /* 2 + * 3 + * Copyright (c) 2011, The Linux Foundation. All rights reserved. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 and 7 + * only version 2 as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + */ 15 + #ifndef __MMC_QCOM_DML_H__ 16 + #define __MMC_QCOM_DML_H__ 17 + 18 + #ifdef CONFIG_MMC_QCOM_DML 19 + int dml_hw_init(struct mmci_host *host, struct device_node *np); 20 + void dml_start_xfer(struct mmci_host *host, struct mmc_data *data); 21 + #else 22 + static inline int dml_hw_init(struct mmci_host *host, struct device_node *np) 23 + { 24 + return -ENOSYS; 25 + } 26 + static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) 27 + { 28 + } 29 + #endif /* CONFIG_MMC_QCOM_DML */ 30 + 31 + #endif /* __MMC_QCOM_DML_H__ */