1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (c) 2011, The Linux Foundation. All rights reserved. 5 */ 6 #include <linux/of.h> 7 #include <linux/of_dma.h> 8 #include <linux/bitops.h> 9 #include <linux/mmc/host.h> 10 #include <linux/mmc/card.h> 11 #include "mmci.h" 12 13 /* Registers */ 14 #define DML_CONFIG 0x00 15 #define PRODUCER_CRCI_MSK GENMASK(1, 0) 16 #define PRODUCER_CRCI_DISABLE 0 17 #define PRODUCER_CRCI_X_SEL BIT(0) 18 #define PRODUCER_CRCI_Y_SEL BIT(1) 19 #define CONSUMER_CRCI_MSK GENMASK(3, 2) 20 #define CONSUMER_CRCI_DISABLE 0 21 #define CONSUMER_CRCI_X_SEL BIT(2) 22 #define CONSUMER_CRCI_Y_SEL BIT(3) 23 #define PRODUCER_TRANS_END_EN BIT(4) 24 #define BYPASS BIT(16) 25 #define DIRECT_MODE BIT(17) 26 #define INFINITE_CONS_TRANS BIT(18) 27 28 #define DML_SW_RESET 0x08 29 #define DML_PRODUCER_START 0x0c 30 #define DML_CONSUMER_START 0x10 31 #define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14 32 #define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18 33 #define DML_PIPE_ID 0x1c 34 #define PRODUCER_PIPE_ID_SHFT 0 35 #define PRODUCER_PIPE_ID_MSK GENMASK(4, 0) 36 #define CONSUMER_PIPE_ID_SHFT 16 37 #define CONSUMER_PIPE_ID_MSK GENMASK(20, 16) 38 39 #define DML_PRODUCER_BAM_BLOCK_SIZE 0x24 40 #define DML_PRODUCER_BAM_TRANS_SIZE 0x28 41 42 /* other definitions */ 43 #define PRODUCER_PIPE_LOGICAL_SIZE 4096 44 #define CONSUMER_PIPE_LOGICAL_SIZE 4096 45 46 #define DML_OFFSET 0x800 47 48 static int qcom_dma_start(struct mmci_host *host, unsigned int *datactrl) 49 { 50 u32 config; 51 void __iomem *base = host->base + DML_OFFSET; 52 struct mmc_data *data = host->data; 53 int ret = mmci_dmae_start(host, datactrl); 54 55 if (ret) 56 return ret; 57 58 if (data->flags & MMC_DATA_READ) { 59 /* Read operation: configure DML for producer operation */ 60 /* Set producer CRCI-x and disable consumer CRCI */ 61 config = readl_relaxed(base + DML_CONFIG); 62 config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL; 63 config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE; 64 writel_relaxed(config, base + DML_CONFIG); 65 66 /* Set the Producer BAM block size */ 67 writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE); 68 69 /* Set Producer BAM Transaction size */ 70 writel_relaxed(data->blocks * data->blksz, 71 base + DML_PRODUCER_BAM_TRANS_SIZE); 72 /* Set Producer Transaction End bit */ 73 config = readl_relaxed(base + DML_CONFIG); 74 config |= PRODUCER_TRANS_END_EN; 75 writel_relaxed(config, base + DML_CONFIG); 76 /* Trigger producer */ 77 writel_relaxed(1, base + DML_PRODUCER_START); 78 } else { 79 /* Write operation: configure DML for consumer operation */ 80 /* Set consumer CRCI-x and disable producer CRCI*/ 81 config = readl_relaxed(base + DML_CONFIG); 82 config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL; 83 config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE; 84 writel_relaxed(config, base + DML_CONFIG); 85 /* Clear Producer Transaction End bit */ 86 config = readl_relaxed(base + DML_CONFIG); 87 config &= ~PRODUCER_TRANS_END_EN; 88 writel_relaxed(config, base + DML_CONFIG); 89 /* Trigger consumer */ 90 writel_relaxed(1, base + DML_CONSUMER_START); 91 } 92 93 /* make sure the dml is configured before dma is triggered */ 94 wmb(); 95 return 0; 96 } 97 98 static int of_get_dml_pipe_index(struct device_node *np, const char *name) 99 { 100 int index; 101 struct of_phandle_args dma_spec; 102 103 index = of_property_match_string(np, "dma-names", name); 104 105 if (index < 0) 106 return -ENODEV; 107 108 if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index, 109 &dma_spec)) 110 return -ENODEV; 111 112 of_node_put(dma_spec.np); 113 if (dma_spec.args_count) 114 return dma_spec.args[0]; 115 116 return -ENODEV; 117 } 118 119 /* Initialize the dml hardware connected to SD Card controller */ 120 static int qcom_dma_setup(struct mmci_host *host) 121 { 122 u32 config; 123 void __iomem *base; 124 int consumer_id, producer_id; 125 struct device_node *np = host->mmc->parent->of_node; 126 127 if (mmci_dmae_setup(host)) 128 return -EINVAL; 129 130 consumer_id = of_get_dml_pipe_index(np, "tx"); 131 producer_id = of_get_dml_pipe_index(np, "rx"); 132 133 if (producer_id < 0 || consumer_id < 0) { 134 mmci_dmae_release(host); 135 return -EINVAL; 136 } 137 138 base = host->base + DML_OFFSET; 139 140 /* Reset the DML block */ 141 writel_relaxed(1, base + DML_SW_RESET); 142 143 /* Disable the producer and consumer CRCI */ 144 config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE); 145 /* 146 * Disable the bypass mode. Bypass mode will only be used 147 * if data transfer is to happen in PIO mode and don't 148 * want the BAM interface to connect with SDCC-DML. 149 */ 150 config &= ~BYPASS; 151 /* 152 * Disable direct mode as we don't DML to MASTER the AHB bus. 153 * BAM connected with DML should MASTER the AHB bus. 154 */ 155 config &= ~DIRECT_MODE; 156 /* 157 * Disable infinite mode transfer as we won't be doing any 158 * infinite size data transfers. All data transfer will be 159 * of finite data size. 160 */ 161 config &= ~INFINITE_CONS_TRANS; 162 writel_relaxed(config, base + DML_CONFIG); 163 164 /* 165 * Initialize the logical BAM pipe size for producer 166 * and consumer. 167 */ 168 writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE, 169 base + DML_PRODUCER_PIPE_LOGICAL_SIZE); 170 writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE, 171 base + DML_CONSUMER_PIPE_LOGICAL_SIZE); 172 173 /* Initialize Producer/consumer pipe id */ 174 writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT), 175 base + DML_PIPE_ID); 176 177 /* Make sure dml initialization is finished */ 178 mb(); 179 180 return 0; 181 } 182 183 static u32 qcom_get_dctrl_cfg(struct mmci_host *host) 184 { 185 return MCI_DPSM_ENABLE | (host->data->blksz << 4); 186 } 187 188 static struct mmci_host_ops qcom_variant_ops = { 189 .prep_data = mmci_dmae_prep_data, 190 .unprep_data = mmci_dmae_unprep_data, 191 .get_datactrl_cfg = qcom_get_dctrl_cfg, 192 .get_next_data = mmci_dmae_get_next_data, 193 .dma_setup = qcom_dma_setup, 194 .dma_release = mmci_dmae_release, 195 .dma_start = qcom_dma_start, 196 .dma_finalize = mmci_dmae_finalize, 197 .dma_error = mmci_dmae_error, 198 }; 199 200 void qcom_variant_init(struct mmci_host *host) 201 { 202 host->ops = &qcom_variant_ops; 203 } 204