sudmac.c revision 830c863987aa26c2133241b61fe22bf466ccb7cc
1/* 2 * Renesas SUDMAC support 3 * 4 * Copyright (C) 2013 Renesas Solutions Corp. 5 * 6 * based on drivers/dma/sh/shdma.c: 7 * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de> 8 * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com> 9 * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved. 10 * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. 11 * 12 * This is free software; you can redistribute it and/or modify 13 * it under the terms of version 2 of the GNU General Public License as 14 * published by the Free Software Foundation. 15 */ 16 17#include <linux/dmaengine.h> 18#include <linux/err.h> 19#include <linux/init.h> 20#include <linux/interrupt.h> 21#include <linux/module.h> 22#include <linux/platform_device.h> 23#include <linux/slab.h> 24#include <linux/sudmac.h> 25 26struct sudmac_chan { 27 struct shdma_chan shdma_chan; 28 void __iomem *base; 29 char dev_id[16]; /* unique name per DMAC of channel */ 30 31 u32 offset; /* for CFG, BA, BBC, CA, CBC, DEN */ 32 u32 cfg; 33 u32 dint_end_bit; 34}; 35 36struct sudmac_device { 37 struct shdma_dev shdma_dev; 38 struct sudmac_pdata *pdata; 39 void __iomem *chan_reg; 40}; 41 42struct sudmac_regs { 43 u32 base_addr; 44 u32 base_byte_count; 45}; 46 47struct sudmac_desc { 48 struct sudmac_regs hw; 49 struct shdma_desc shdma_desc; 50}; 51 52#define to_chan(schan) container_of(schan, struct sudmac_chan, shdma_chan) 53#define to_desc(sdesc) container_of(sdesc, struct sudmac_desc, shdma_desc) 54#define to_sdev(sc) container_of(sc->shdma_chan.dma_chan.device, \ 55 struct sudmac_device, shdma_dev.dma_dev) 56 57/* SUDMAC register */ 58#define SUDMAC_CH0CFG 0x00 59#define SUDMAC_CH0BA 0x10 60#define SUDMAC_CH0BBC 0x18 61#define SUDMAC_CH0CA 0x20 62#define SUDMAC_CH0CBC 0x28 63#define SUDMAC_CH0DEN 0x30 64#define SUDMAC_DSTSCLR 0x38 65#define SUDMAC_DBUFCTRL 0x3C 66#define SUDMAC_DINTCTRL 0x40 67#define SUDMAC_DINTSTS 0x44 68#define SUDMAC_DINTSTSCLR 0x48 69#define SUDMAC_CH0SHCTRL 0x50 70 71/* Definitions for the sudmac_channel.config */ 72#define SUDMAC_SENDBUFM 0x1000 /* b12: Transmit Buffer Mode */ 73#define SUDMAC_RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */ 74#define SUDMAC_LBA_WAIT 0x0030 /* b5-4: Local Bus Access Wait */ 75 76/* Definitions for the sudmac_channel.dint_end_bit */ 77#define SUDMAC_CH1ENDE 0x0002 /* b1: Ch1 DMA Transfer End Int Enable */ 78#define SUDMAC_CH0ENDE 0x0001 /* b0: Ch0 DMA Transfer End Int Enable */ 79 80#define SUDMAC_DRV_NAME "sudmac" 81 82static void sudmac_writel(struct sudmac_chan *sc, u32 data, u32 reg) 83{ 84 iowrite32(data, sc->base + reg); 85} 86 87static u32 sudmac_readl(struct sudmac_chan *sc, u32 reg) 88{ 89 return ioread32(sc->base + reg); 90} 91 92static bool sudmac_is_busy(struct sudmac_chan *sc) 93{ 94 u32 den = sudmac_readl(sc, SUDMAC_CH0DEN + sc->offset); 95 96 if (den) 97 return true; /* working */ 98 99 return false; /* waiting */ 100} 101 102static void sudmac_set_reg(struct sudmac_chan *sc, struct sudmac_regs *hw, 103 struct shdma_desc *sdesc) 104{ 105 sudmac_writel(sc, sc->cfg, SUDMAC_CH0CFG + sc->offset); 106 sudmac_writel(sc, hw->base_addr, SUDMAC_CH0BA + sc->offset); 107 sudmac_writel(sc, hw->base_byte_count, SUDMAC_CH0BBC + sc->offset); 108} 109 110static void sudmac_start(struct sudmac_chan *sc) 111{ 112 u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL); 113 114 sudmac_writel(sc, dintctrl | sc->dint_end_bit, SUDMAC_DINTCTRL); 115 sudmac_writel(sc, 1, SUDMAC_CH0DEN + sc->offset); 116} 117 118static void sudmac_start_xfer(struct shdma_chan *schan, 119 struct shdma_desc *sdesc) 120{ 121 struct sudmac_chan *sc = to_chan(schan); 122 struct sudmac_desc *sd = to_desc(sdesc); 123 124 sudmac_set_reg(sc, &sd->hw, sdesc); 125 sudmac_start(sc); 126} 127 128static bool sudmac_channel_busy(struct shdma_chan *schan) 129{ 130 struct sudmac_chan *sc = to_chan(schan); 131 132 return sudmac_is_busy(sc); 133} 134 135static void sudmac_setup_xfer(struct shdma_chan *schan, int slave_id) 136{ 137} 138 139static const struct sudmac_slave_config *sudmac_find_slave( 140 struct sudmac_chan *sc, int slave_id) 141{ 142 struct sudmac_device *sdev = to_sdev(sc); 143 struct sudmac_pdata *pdata = sdev->pdata; 144 const struct sudmac_slave_config *cfg; 145 int i; 146 147 for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) 148 if (cfg->slave_id == slave_id) 149 return cfg; 150 151 return NULL; 152} 153 154static int sudmac_set_slave(struct shdma_chan *schan, int slave_id, 155 dma_addr_t slave_addr, bool try) 156{ 157 struct sudmac_chan *sc = to_chan(schan); 158 const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id); 159 160 if (!cfg) 161 return -ENODEV; 162 163 return 0; 164} 165 166static inline void sudmac_dma_halt(struct sudmac_chan *sc) 167{ 168 u32 dintctrl = sudmac_readl(sc, SUDMAC_DINTCTRL); 169 170 sudmac_writel(sc, 0, SUDMAC_CH0DEN + sc->offset); 171 sudmac_writel(sc, dintctrl & ~sc->dint_end_bit, SUDMAC_DINTCTRL); 172 sudmac_writel(sc, sc->dint_end_bit, SUDMAC_DINTSTSCLR); 173} 174 175static int sudmac_desc_setup(struct shdma_chan *schan, 176 struct shdma_desc *sdesc, 177 dma_addr_t src, dma_addr_t dst, size_t *len) 178{ 179 struct sudmac_chan *sc = to_chan(schan); 180 struct sudmac_desc *sd = to_desc(sdesc); 181 182 dev_dbg(sc->shdma_chan.dev, "%s: src=%pad, dst=%pad, len=%zu\n", 183 __func__, &src, &dst, *len); 184 185 if (*len > schan->max_xfer_len) 186 *len = schan->max_xfer_len; 187 188 if (dst) 189 sd->hw.base_addr = dst; 190 else if (src) 191 sd->hw.base_addr = src; 192 sd->hw.base_byte_count = *len; 193 194 return 0; 195} 196 197static void sudmac_halt(struct shdma_chan *schan) 198{ 199 struct sudmac_chan *sc = to_chan(schan); 200 201 sudmac_dma_halt(sc); 202} 203 204static bool sudmac_chan_irq(struct shdma_chan *schan, int irq) 205{ 206 struct sudmac_chan *sc = to_chan(schan); 207 u32 dintsts = sudmac_readl(sc, SUDMAC_DINTSTS); 208 209 if (!(dintsts & sc->dint_end_bit)) 210 return false; 211 212 /* DMA stop */ 213 sudmac_dma_halt(sc); 214 215 return true; 216} 217 218static size_t sudmac_get_partial(struct shdma_chan *schan, 219 struct shdma_desc *sdesc) 220{ 221 struct sudmac_chan *sc = to_chan(schan); 222 struct sudmac_desc *sd = to_desc(sdesc); 223 u32 current_byte_count = sudmac_readl(sc, SUDMAC_CH0CBC + sc->offset); 224 225 return sd->hw.base_byte_count - current_byte_count; 226} 227 228static bool sudmac_desc_completed(struct shdma_chan *schan, 229 struct shdma_desc *sdesc) 230{ 231 struct sudmac_chan *sc = to_chan(schan); 232 struct sudmac_desc *sd = to_desc(sdesc); 233 u32 current_addr = sudmac_readl(sc, SUDMAC_CH0CA + sc->offset); 234 235 return sd->hw.base_addr + sd->hw.base_byte_count == current_addr; 236} 237 238static int sudmac_chan_probe(struct sudmac_device *su_dev, int id, int irq, 239 unsigned long flags) 240{ 241 struct shdma_dev *sdev = &su_dev->shdma_dev; 242 struct platform_device *pdev = to_platform_device(sdev->dma_dev.dev); 243 struct sudmac_chan *sc; 244 struct shdma_chan *schan; 245 int err; 246 247 sc = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_chan), GFP_KERNEL); 248 if (!sc) { 249 dev_err(sdev->dma_dev.dev, 250 "No free memory for allocating dma channels!\n"); 251 return -ENOMEM; 252 } 253 254 schan = &sc->shdma_chan; 255 schan->max_xfer_len = 64 * 1024 * 1024 - 1; 256 257 shdma_chan_probe(sdev, schan, id); 258 259 sc->base = su_dev->chan_reg; 260 261 /* get platform_data */ 262 sc->offset = su_dev->pdata->channel->offset; 263 if (su_dev->pdata->channel->config & SUDMAC_TX_BUFFER_MODE) 264 sc->cfg |= SUDMAC_SENDBUFM; 265 if (su_dev->pdata->channel->config & SUDMAC_RX_END_MODE) 266 sc->cfg |= SUDMAC_RCVENDM; 267 sc->cfg |= (su_dev->pdata->channel->wait << 4) & SUDMAC_LBA_WAIT; 268 269 if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH0) 270 sc->dint_end_bit |= SUDMAC_CH0ENDE; 271 if (su_dev->pdata->channel->dint_end_bit & SUDMAC_DMA_BIT_CH1) 272 sc->dint_end_bit |= SUDMAC_CH1ENDE; 273 274 /* set up channel irq */ 275 if (pdev->id >= 0) 276 snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d.%d", 277 pdev->id, id); 278 else 279 snprintf(sc->dev_id, sizeof(sc->dev_id), "sudmac%d", id); 280 281 err = shdma_request_irq(schan, irq, flags, sc->dev_id); 282 if (err) { 283 dev_err(sdev->dma_dev.dev, 284 "DMA channel %d request_irq failed %d\n", id, err); 285 goto err_no_irq; 286 } 287 288 return 0; 289 290err_no_irq: 291 /* remove from dmaengine device node */ 292 shdma_chan_remove(schan); 293 return err; 294} 295 296static void sudmac_chan_remove(struct sudmac_device *su_dev) 297{ 298 struct dma_device *dma_dev = &su_dev->shdma_dev.dma_dev; 299 struct shdma_chan *schan; 300 int i; 301 302 shdma_for_each_chan(schan, &su_dev->shdma_dev, i) { 303 BUG_ON(!schan); 304 305 shdma_chan_remove(schan); 306 } 307 dma_dev->chancnt = 0; 308} 309 310static dma_addr_t sudmac_slave_addr(struct shdma_chan *schan) 311{ 312 /* SUDMAC doesn't need the address */ 313 return 0; 314} 315 316static struct shdma_desc *sudmac_embedded_desc(void *buf, int i) 317{ 318 return &((struct sudmac_desc *)buf)[i].shdma_desc; 319} 320 321static const struct shdma_ops sudmac_shdma_ops = { 322 .desc_completed = sudmac_desc_completed, 323 .halt_channel = sudmac_halt, 324 .channel_busy = sudmac_channel_busy, 325 .slave_addr = sudmac_slave_addr, 326 .desc_setup = sudmac_desc_setup, 327 .set_slave = sudmac_set_slave, 328 .setup_xfer = sudmac_setup_xfer, 329 .start_xfer = sudmac_start_xfer, 330 .embedded_desc = sudmac_embedded_desc, 331 .chan_irq = sudmac_chan_irq, 332 .get_partial = sudmac_get_partial, 333}; 334 335static int sudmac_probe(struct platform_device *pdev) 336{ 337 struct sudmac_pdata *pdata = dev_get_platdata(&pdev->dev); 338 int err, i; 339 struct sudmac_device *su_dev; 340 struct dma_device *dma_dev; 341 struct resource *chan, *irq_res; 342 343 /* get platform data */ 344 if (!pdata) 345 return -ENODEV; 346 347 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 348 if (!irq_res) 349 return -ENODEV; 350 351 err = -ENOMEM; 352 su_dev = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_device), 353 GFP_KERNEL); 354 if (!su_dev) { 355 dev_err(&pdev->dev, "Not enough memory\n"); 356 return err; 357 } 358 359 dma_dev = &su_dev->shdma_dev.dma_dev; 360 361 chan = platform_get_resource(pdev, IORESOURCE_MEM, 0); 362 su_dev->chan_reg = devm_ioremap_resource(&pdev->dev, chan); 363 if (IS_ERR(su_dev->chan_reg)) 364 return PTR_ERR(su_dev->chan_reg); 365 366 dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); 367 368 su_dev->shdma_dev.ops = &sudmac_shdma_ops; 369 su_dev->shdma_dev.desc_size = sizeof(struct sudmac_desc); 370 err = shdma_init(&pdev->dev, &su_dev->shdma_dev, pdata->channel_num); 371 if (err < 0) 372 return err; 373 374 /* platform data */ 375 su_dev->pdata = dev_get_platdata(&pdev->dev); 376 377 platform_set_drvdata(pdev, su_dev); 378 379 /* Create DMA Channel */ 380 for (i = 0; i < pdata->channel_num; i++) { 381 err = sudmac_chan_probe(su_dev, i, irq_res->start, IRQF_SHARED); 382 if (err) 383 goto chan_probe_err; 384 } 385 386 err = dma_async_device_register(&su_dev->shdma_dev.dma_dev); 387 if (err < 0) 388 goto chan_probe_err; 389 390 return err; 391 392chan_probe_err: 393 sudmac_chan_remove(su_dev); 394 395 shdma_cleanup(&su_dev->shdma_dev); 396 397 return err; 398} 399 400static int sudmac_remove(struct platform_device *pdev) 401{ 402 struct sudmac_device *su_dev = platform_get_drvdata(pdev); 403 struct dma_device *dma_dev = &su_dev->shdma_dev.dma_dev; 404 405 dma_async_device_unregister(dma_dev); 406 sudmac_chan_remove(su_dev); 407 shdma_cleanup(&su_dev->shdma_dev); 408 409 return 0; 410} 411 412static struct platform_driver sudmac_driver = { 413 .driver = { 414 .owner = THIS_MODULE, 415 .name = SUDMAC_DRV_NAME, 416 }, 417 .probe = sudmac_probe, 418 .remove = sudmac_remove, 419}; 420module_platform_driver(sudmac_driver); 421 422MODULE_AUTHOR("Yoshihiro Shimoda"); 423MODULE_DESCRIPTION("Renesas SUDMAC driver"); 424MODULE_LICENSE("GPL v2"); 425MODULE_ALIAS("platform:" SUDMAC_DRV_NAME); 426