1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Direct Memory Access U-Class Simulation driver 4 * 5 * Copyright (C) 2018 Texas Instruments Incorporated <www.ti.com> 6 * 7 * Author: Grygorii Strashko <grygorii.strashko@ti.com> 8 */ 9 10 #include <common.h> 11 #include <dm.h> 12 #include <dm/read.h> 13 #include <dma-uclass.h> 14 #include <dt-structs.h> 15 #include <errno.h> 16 17 #define SANDBOX_DMA_CH_CNT 3 18 #define SANDBOX_DMA_BUF_SIZE 1024 19 20 struct sandbox_dma_chan { 21 struct sandbox_dma_dev *ud; 22 char name[20]; 23 u32 id; 24 enum dma_direction dir; 25 bool in_use; 26 bool enabled; 27 }; 28 29 struct sandbox_dma_dev { 30 struct device *dev; 31 u32 ch_count; 32 struct sandbox_dma_chan channels[SANDBOX_DMA_CH_CNT]; 33 uchar buf[SANDBOX_DMA_BUF_SIZE]; 34 uchar *buf_rx; 35 size_t data_len; 36 u32 meta; 37 }; 38 39 static int sandbox_dma_transfer(struct udevice *dev, int direction, 40 void *dst, void *src, size_t len) 41 { 42 memcpy(dst, src, len); 43 44 return 0; 45 } 46 47 static int sandbox_dma_of_xlate(struct dma *dma, 48 struct ofnode_phandle_args *args) 49 { 50 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 51 struct sandbox_dma_chan *uc; 52 53 debug("%s(dma id=%u)\n", __func__, args->args[0]); 54 55 if (args->args[0] >= SANDBOX_DMA_CH_CNT) 56 return -EINVAL; 57 58 dma->id = args->args[0]; 59 60 uc = &ud->channels[dma->id]; 61 62 if (dma->id == 1) 63 uc->dir = DMA_MEM_TO_DEV; 64 else if (dma->id == 2) 65 uc->dir = DMA_DEV_TO_MEM; 66 else 67 uc->dir = DMA_MEM_TO_MEM; 68 debug("%s(dma id=%lu dir=%d)\n", __func__, dma->id, uc->dir); 69 70 return 0; 71 } 72 73 static int sandbox_dma_request(struct dma *dma) 74 { 75 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 76 struct sandbox_dma_chan *uc; 77 78 if (dma->id >= SANDBOX_DMA_CH_CNT) 79 return -EINVAL; 80 81 uc = &ud->channels[dma->id]; 82 if (uc->in_use) 83 return -EBUSY; 84 85 uc->in_use = true; 86 debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); 87 88 return 0; 89 } 90 91 static int sandbox_dma_free(struct dma *dma) 92 { 93 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 94 struct sandbox_dma_chan *uc; 95 96 if (dma->id >= SANDBOX_DMA_CH_CNT) 97 return -EINVAL; 98 99 uc = &ud->channels[dma->id]; 100 if (!uc->in_use) 101 return -EINVAL; 102 103 uc->in_use = false; 104 ud->buf_rx = NULL; 105 ud->data_len = 0; 106 debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); 107 108 return 0; 109 } 110 111 static int sandbox_dma_enable(struct dma *dma) 112 { 113 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 114 struct sandbox_dma_chan *uc; 115 116 if (dma->id >= SANDBOX_DMA_CH_CNT) 117 return -EINVAL; 118 119 uc = &ud->channels[dma->id]; 120 if (!uc->in_use) 121 return -EINVAL; 122 if (uc->enabled) 123 return -EINVAL; 124 125 uc->enabled = true; 126 debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); 127 128 return 0; 129 } 130 131 static int sandbox_dma_disable(struct dma *dma) 132 { 133 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 134 struct sandbox_dma_chan *uc; 135 136 if (dma->id >= SANDBOX_DMA_CH_CNT) 137 return -EINVAL; 138 139 uc = &ud->channels[dma->id]; 140 if (!uc->in_use) 141 return -EINVAL; 142 if (!uc->enabled) 143 return -EINVAL; 144 145 uc->enabled = false; 146 debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); 147 148 return 0; 149 } 150 151 static int sandbox_dma_send(struct dma *dma, 152 void *src, size_t len, void *metadata) 153 { 154 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 155 struct sandbox_dma_chan *uc; 156 157 if (dma->id >= SANDBOX_DMA_CH_CNT) 158 return -EINVAL; 159 if (!src || !metadata) 160 return -EINVAL; 161 162 debug("%s(dma id=%lu)\n", __func__, dma->id); 163 164 uc = &ud->channels[dma->id]; 165 if (uc->dir != DMA_MEM_TO_DEV) 166 return -EINVAL; 167 if (!uc->in_use) 168 return -EINVAL; 169 if (!uc->enabled) 170 return -EINVAL; 171 if (len >= SANDBOX_DMA_BUF_SIZE) 172 return -EINVAL; 173 174 memcpy(ud->buf, src, len); 175 ud->data_len = len; 176 ud->meta = *((u32 *)metadata); 177 178 debug("%s(dma id=%lu len=%zu meta=%08x)\n", 179 __func__, dma->id, len, ud->meta); 180 181 return 0; 182 } 183 184 static int sandbox_dma_receive(struct dma *dma, void **dst, void *metadata) 185 { 186 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 187 struct sandbox_dma_chan *uc; 188 189 if (dma->id >= SANDBOX_DMA_CH_CNT) 190 return -EINVAL; 191 if (!dst || !metadata) 192 return -EINVAL; 193 194 uc = &ud->channels[dma->id]; 195 if (uc->dir != DMA_DEV_TO_MEM) 196 return -EINVAL; 197 if (!uc->in_use) 198 return -EINVAL; 199 if (!uc->enabled) 200 return -EINVAL; 201 if (!ud->data_len) 202 return 0; 203 204 if (ud->buf_rx) { 205 memcpy(ud->buf_rx, ud->buf, ud->data_len); 206 *dst = ud->buf_rx; 207 } else { 208 memcpy(*dst, ud->buf, ud->data_len); 209 } 210 211 *((u32 *)metadata) = ud->meta; 212 213 debug("%s(dma id=%lu len=%zu meta=%08x %p)\n", 214 __func__, dma->id, ud->data_len, ud->meta, *dst); 215 216 return ud->data_len; 217 } 218 219 static int sandbox_dma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) 220 { 221 struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); 222 223 ud->buf_rx = dst; 224 225 return 0; 226 } 227 228 static const struct dma_ops sandbox_dma_ops = { 229 .transfer = sandbox_dma_transfer, 230 .of_xlate = sandbox_dma_of_xlate, 231 .request = sandbox_dma_request, 232 .free = sandbox_dma_free, 233 .enable = sandbox_dma_enable, 234 .disable = sandbox_dma_disable, 235 .send = sandbox_dma_send, 236 .receive = sandbox_dma_receive, 237 .prepare_rcv_buf = sandbox_dma_prepare_rcv_buf, 238 }; 239 240 static int sandbox_dma_probe(struct udevice *dev) 241 { 242 struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); 243 struct sandbox_dma_dev *ud = dev_get_priv(dev); 244 int i, ret = 0; 245 246 uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM | 247 DMA_SUPPORTS_MEM_TO_DEV | 248 DMA_SUPPORTS_DEV_TO_MEM; 249 250 ud->ch_count = SANDBOX_DMA_CH_CNT; 251 ud->buf_rx = NULL; 252 ud->meta = 0; 253 ud->data_len = 0; 254 255 pr_err("Number of channels: %u\n", ud->ch_count); 256 257 for (i = 0; i < ud->ch_count; i++) { 258 struct sandbox_dma_chan *uc = &ud->channels[i]; 259 260 uc->ud = ud; 261 uc->id = i; 262 sprintf(uc->name, "DMA chan%d\n", i); 263 uc->in_use = false; 264 uc->enabled = false; 265 } 266 267 return ret; 268 } 269 270 static const struct udevice_id sandbox_dma_ids[] = { 271 { .compatible = "sandbox,dma" }, 272 { } 273 }; 274 275 U_BOOT_DRIVER(sandbox_dma) = { 276 .name = "sandbox-dma", 277 .id = UCLASS_DMA, 278 .of_match = sandbox_dma_ids, 279 .ops = &sandbox_dma_ops, 280 .probe = sandbox_dma_probe, 281 .priv_auto_alloc_size = sizeof(struct sandbox_dma_dev), 282 }; 283