linux/drivers/dma/sh/sudmac.c
<<
>>
Prefs
   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 shdma_chan *schan;
 299        int i;
 300
 301        shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
 302                BUG_ON(!schan);
 303
 304                shdma_chan_remove(schan);
 305        }
 306}
 307
 308static dma_addr_t sudmac_slave_addr(struct shdma_chan *schan)
 309{
 310        /* SUDMAC doesn't need the address */
 311        return 0;
 312}
 313
 314static struct shdma_desc *sudmac_embedded_desc(void *buf, int i)
 315{
 316        return &((struct sudmac_desc *)buf)[i].shdma_desc;
 317}
 318
 319static const struct shdma_ops sudmac_shdma_ops = {
 320        .desc_completed = sudmac_desc_completed,
 321        .halt_channel = sudmac_halt,
 322        .channel_busy = sudmac_channel_busy,
 323        .slave_addr = sudmac_slave_addr,
 324        .desc_setup = sudmac_desc_setup,
 325        .set_slave = sudmac_set_slave,
 326        .setup_xfer = sudmac_setup_xfer,
 327        .start_xfer = sudmac_start_xfer,
 328        .embedded_desc = sudmac_embedded_desc,
 329        .chan_irq = sudmac_chan_irq,
 330        .get_partial = sudmac_get_partial,
 331};
 332
 333static int sudmac_probe(struct platform_device *pdev)
 334{
 335        struct sudmac_pdata *pdata = dev_get_platdata(&pdev->dev);
 336        int err, i;
 337        struct sudmac_device *su_dev;
 338        struct dma_device *dma_dev;
 339        struct resource *chan, *irq_res;
 340
 341        /* get platform data */
 342        if (!pdata)
 343                return -ENODEV;
 344
 345        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 346        if (!irq_res)
 347                return -ENODEV;
 348
 349        err = -ENOMEM;
 350        su_dev = devm_kzalloc(&pdev->dev, sizeof(struct sudmac_device),
 351                              GFP_KERNEL);
 352        if (!su_dev) {
 353                dev_err(&pdev->dev, "Not enough memory\n");
 354                return err;
 355        }
 356
 357        dma_dev = &su_dev->shdma_dev.dma_dev;
 358
 359        chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 360        su_dev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
 361        if (IS_ERR(su_dev->chan_reg))
 362                return PTR_ERR(su_dev->chan_reg);
 363
 364        dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
 365
 366        su_dev->shdma_dev.ops = &sudmac_shdma_ops;
 367        su_dev->shdma_dev.desc_size = sizeof(struct sudmac_desc);
 368        err = shdma_init(&pdev->dev, &su_dev->shdma_dev, pdata->channel_num);
 369        if (err < 0)
 370                return err;
 371
 372        /* platform data */
 373        su_dev->pdata = dev_get_platdata(&pdev->dev);
 374
 375        platform_set_drvdata(pdev, su_dev);
 376
 377        /* Create DMA Channel */
 378        for (i = 0; i < pdata->channel_num; i++) {
 379                err = sudmac_chan_probe(su_dev, i, irq_res->start, IRQF_SHARED);
 380                if (err)
 381                        goto chan_probe_err;
 382        }
 383
 384        err = dma_async_device_register(&su_dev->shdma_dev.dma_dev);
 385        if (err < 0)
 386                goto chan_probe_err;
 387
 388        return err;
 389
 390chan_probe_err:
 391        sudmac_chan_remove(su_dev);
 392
 393        shdma_cleanup(&su_dev->shdma_dev);
 394
 395        return err;
 396}
 397
 398static int sudmac_remove(struct platform_device *pdev)
 399{
 400        struct sudmac_device *su_dev = platform_get_drvdata(pdev);
 401        struct dma_device *dma_dev = &su_dev->shdma_dev.dma_dev;
 402
 403        dma_async_device_unregister(dma_dev);
 404        sudmac_chan_remove(su_dev);
 405        shdma_cleanup(&su_dev->shdma_dev);
 406
 407        return 0;
 408}
 409
 410static struct platform_driver sudmac_driver = {
 411        .driver         = {
 412                .name   = SUDMAC_DRV_NAME,
 413        },
 414        .probe          = sudmac_probe,
 415        .remove         = sudmac_remove,
 416};
 417module_platform_driver(sudmac_driver);
 418
 419MODULE_AUTHOR("Yoshihiro Shimoda");
 420MODULE_DESCRIPTION("Renesas SUDMAC driver");
 421MODULE_LICENSE("GPL v2");
 422MODULE_ALIAS("platform:" SUDMAC_DRV_NAME);
 423