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