linux/arch/arm/mach-omap1/dma.c
<<
>>
Prefs
   1/*
   2 * OMAP1/OMAP7xx - specific DMA driver
   3 *
   4 * Copyright (C) 2003 - 2008 Nokia Corporation
   5 * Author: Juha Yrjölä <juha.yrjola@nokia.com>
   6 * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
   7 * Graphics DMA and LCD DMA graphics tranformations
   8 * by Imre Deak <imre.deak@nokia.com>
   9 * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
  10 * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
  11 *
  12 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
  13 * Converted DMA library into platform driver
  14 *                   - G, Manjunath Kondaiah <manjugk@ti.com>
  15 *
  16 * This program is free software; you can redistribute it and/or modify
  17 * it under the terms of the GNU General Public License version 2 as
  18 * published by the Free Software Foundation.
  19 */
  20
  21#include <linux/err.h>
  22#include <linux/slab.h>
  23#include <linux/module.h>
  24#include <linux/init.h>
  25#include <linux/device.h>
  26#include <linux/io.h>
  27#include <linux/dma-mapping.h>
  28#include <linux/omap-dma.h>
  29#include <mach/tc.h>
  30
  31#include <mach/irqs.h>
  32
  33#include "dma.h"
  34
  35#define OMAP1_DMA_BASE                  (0xfffed800)
  36#define OMAP1_LOGICAL_DMA_CH_COUNT      17
  37#define OMAP1_DMA_STRIDE                0x40
  38
  39static u32 errata;
  40static u32 enable_1510_mode;
  41static u8 dma_stride;
  42static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end;
  43
  44static u16 reg_map[] = {
  45        [GCR]           = 0x400,
  46        [GSCR]          = 0x404,
  47        [GRST1]         = 0x408,
  48        [HW_ID]         = 0x442,
  49        [PCH2_ID]       = 0x444,
  50        [PCH0_ID]       = 0x446,
  51        [PCH1_ID]       = 0x448,
  52        [PCHG_ID]       = 0x44a,
  53        [PCHD_ID]       = 0x44c,
  54        [CAPS_0]        = 0x44e,
  55        [CAPS_1]        = 0x452,
  56        [CAPS_2]        = 0x456,
  57        [CAPS_3]        = 0x458,
  58        [CAPS_4]        = 0x45a,
  59        [PCH2_SR]       = 0x460,
  60        [PCH0_SR]       = 0x480,
  61        [PCH1_SR]       = 0x482,
  62        [PCHD_SR]       = 0x4c0,
  63
  64        /* Common Registers */
  65        [CSDP]          = 0x00,
  66        [CCR]           = 0x02,
  67        [CICR]          = 0x04,
  68        [CSR]           = 0x06,
  69        [CEN]           = 0x10,
  70        [CFN]           = 0x12,
  71        [CSFI]          = 0x14,
  72        [CSEI]          = 0x16,
  73        [CPC]           = 0x18, /* 15xx only */
  74        [CSAC]          = 0x18,
  75        [CDAC]          = 0x1a,
  76        [CDEI]          = 0x1c,
  77        [CDFI]          = 0x1e,
  78        [CLNK_CTRL]     = 0x28,
  79
  80        /* Channel specific register offsets */
  81        [CSSA]          = 0x08,
  82        [CDSA]          = 0x0c,
  83        [COLOR]         = 0x20,
  84        [CCR2]          = 0x24,
  85        [LCH_CTRL]      = 0x2a,
  86};
  87
  88static struct resource res[] __initdata = {
  89        [0] = {
  90                .start  = OMAP1_DMA_BASE,
  91                .end    = OMAP1_DMA_BASE + SZ_2K - 1,
  92                .flags  = IORESOURCE_MEM,
  93        },
  94        [1] = {
  95                .name   = "0",
  96                .start  = INT_DMA_CH0_6,
  97                .flags  = IORESOURCE_IRQ,
  98        },
  99        [2] = {
 100                .name   = "1",
 101                .start  = INT_DMA_CH1_7,
 102                .flags  = IORESOURCE_IRQ,
 103        },
 104        [3] = {
 105                .name   = "2",
 106                .start  = INT_DMA_CH2_8,
 107                .flags  = IORESOURCE_IRQ,
 108        },
 109        [4] = {
 110                .name   = "3",
 111                .start  = INT_DMA_CH3,
 112                .flags  = IORESOURCE_IRQ,
 113        },
 114        [5] = {
 115                .name   = "4",
 116                .start  = INT_DMA_CH4,
 117                .flags  = IORESOURCE_IRQ,
 118        },
 119        [6] = {
 120                .name   = "5",
 121                .start  = INT_DMA_CH5,
 122                .flags  = IORESOURCE_IRQ,
 123        },
 124        /* Handled in lcd_dma.c */
 125        [7] = {
 126                .name   = "6",
 127                .start  = INT_1610_DMA_CH6,
 128                .flags  = IORESOURCE_IRQ,
 129        },
 130        /* irq's for omap16xx and omap7xx */
 131        [8] = {
 132                .name   = "7",
 133                .start  = INT_1610_DMA_CH7,
 134                .flags  = IORESOURCE_IRQ,
 135        },
 136        [9] = {
 137                .name   = "8",
 138                .start  = INT_1610_DMA_CH8,
 139                .flags  = IORESOURCE_IRQ,
 140        },
 141        [10] = {
 142                .name  = "9",
 143                .start = INT_1610_DMA_CH9,
 144                .flags = IORESOURCE_IRQ,
 145        },
 146        [11] = {
 147                .name  = "10",
 148                .start = INT_1610_DMA_CH10,
 149                .flags = IORESOURCE_IRQ,
 150        },
 151        [12] = {
 152                .name  = "11",
 153                .start = INT_1610_DMA_CH11,
 154                .flags = IORESOURCE_IRQ,
 155        },
 156        [13] = {
 157                .name  = "12",
 158                .start = INT_1610_DMA_CH12,
 159                .flags = IORESOURCE_IRQ,
 160        },
 161        [14] = {
 162                .name  = "13",
 163                .start = INT_1610_DMA_CH13,
 164                .flags = IORESOURCE_IRQ,
 165        },
 166        [15] = {
 167                .name  = "14",
 168                .start = INT_1610_DMA_CH14,
 169                .flags = IORESOURCE_IRQ,
 170        },
 171        [16] = {
 172                .name  = "15",
 173                .start = INT_1610_DMA_CH15,
 174                .flags = IORESOURCE_IRQ,
 175        },
 176        [17] = {
 177                .name  = "16",
 178                .start = INT_DMA_LCD,
 179                .flags = IORESOURCE_IRQ,
 180        },
 181};
 182
 183static void __iomem *dma_base;
 184static inline void dma_write(u32 val, int reg, int lch)
 185{
 186        u8  stride;
 187        u32 offset;
 188
 189        stride = (reg >= dma_common_ch_start) ? dma_stride : 0;
 190        offset = reg_map[reg] + (stride * lch);
 191
 192        __raw_writew(val, dma_base + offset);
 193        if ((reg > CLNK_CTRL && reg < CCEN) ||
 194                        (reg > PCHD_ID && reg < CAPS_2)) {
 195                u32 offset2 = reg_map[reg] + 2 + (stride * lch);
 196                __raw_writew(val >> 16, dma_base + offset2);
 197        }
 198}
 199
 200static inline u32 dma_read(int reg, int lch)
 201{
 202        u8 stride;
 203        u32 offset, val;
 204
 205        stride = (reg >= dma_common_ch_start) ? dma_stride : 0;
 206        offset = reg_map[reg] + (stride * lch);
 207
 208        val = __raw_readw(dma_base + offset);
 209        if ((reg > CLNK_CTRL && reg < CCEN) ||
 210                        (reg > PCHD_ID && reg < CAPS_2)) {
 211                u16 upper;
 212                u32 offset2 = reg_map[reg] + 2 + (stride * lch);
 213                upper = __raw_readw(dma_base + offset2);
 214                val |= (upper << 16);
 215        }
 216        return val;
 217}
 218
 219static void omap1_clear_lch_regs(int lch)
 220{
 221        int i = dma_common_ch_start;
 222
 223        for (; i <= dma_common_ch_end; i += 1)
 224                dma_write(0, i, lch);
 225}
 226
 227static void omap1_clear_dma(int lch)
 228{
 229        u32 l;
 230
 231        l = dma_read(CCR, lch);
 232        l &= ~OMAP_DMA_CCR_EN;
 233        dma_write(l, CCR, lch);
 234
 235        /* Clear pending interrupts */
 236        l = dma_read(CSR, lch);
 237}
 238
 239static void omap1_show_dma_caps(void)
 240{
 241        if (enable_1510_mode) {
 242                printk(KERN_INFO "DMA support for OMAP15xx initialized\n");
 243        } else {
 244                u16 w;
 245                printk(KERN_INFO "OMAP DMA hardware version %d\n",
 246                                                        dma_read(HW_ID, 0));
 247                printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
 248                        dma_read(CAPS_0, 0), dma_read(CAPS_1, 0),
 249                        dma_read(CAPS_2, 0), dma_read(CAPS_3, 0),
 250                        dma_read(CAPS_4, 0));
 251
 252                /* Disable OMAP 3.0/3.1 compatibility mode. */
 253                w = dma_read(GSCR, 0);
 254                w |= 1 << 3;
 255                dma_write(w, GSCR, 0);
 256        }
 257        return;
 258}
 259
 260static u32 configure_dma_errata(void)
 261{
 262
 263        /*
 264         * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is
 265         * read before the DMA controller finished disabling the channel.
 266         */
 267        if (!cpu_is_omap15xx())
 268                SET_DMA_ERRATA(DMA_ERRATA_3_3);
 269
 270        return errata;
 271}
 272
 273static const struct platform_device_info omap_dma_dev_info = {
 274        .name = "omap-dma-engine",
 275        .id = -1,
 276        .dma_mask = DMA_BIT_MASK(32),
 277};
 278
 279static int __init omap1_system_dma_init(void)
 280{
 281        struct omap_system_dma_plat_info        *p;
 282        struct omap_dma_dev_attr                *d;
 283        struct platform_device                  *pdev, *dma_pdev;
 284        int ret;
 285
 286        pdev = platform_device_alloc("omap_dma_system", 0);
 287        if (!pdev) {
 288                pr_err("%s: Unable to device alloc for dma\n",
 289                        __func__);
 290                return -ENOMEM;
 291        }
 292
 293        dma_base = ioremap(res[0].start, resource_size(&res[0]));
 294        if (!dma_base) {
 295                pr_err("%s: Unable to ioremap\n", __func__);
 296                ret = -ENODEV;
 297                goto exit_device_put;
 298        }
 299
 300        ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
 301        if (ret) {
 302                dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
 303                        __func__, pdev->name, pdev->id);
 304                goto exit_iounmap;
 305        }
 306
 307        p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL);
 308        if (!p) {
 309                dev_err(&pdev->dev, "%s: Unable to allocate 'p' for %s\n",
 310                        __func__, pdev->name);
 311                ret = -ENOMEM;
 312                goto exit_iounmap;
 313        }
 314
 315        d = kzalloc(sizeof(struct omap_dma_dev_attr), GFP_KERNEL);
 316        if (!d) {
 317                dev_err(&pdev->dev, "%s: Unable to allocate 'd' for %s\n",
 318                        __func__, pdev->name);
 319                ret = -ENOMEM;
 320                goto exit_release_p;
 321        }
 322
 323        d->lch_count            = OMAP1_LOGICAL_DMA_CH_COUNT;
 324
 325        /* Valid attributes for omap1 plus processors */
 326        if (cpu_is_omap15xx())
 327                d->dev_caps = ENABLE_1510_MODE;
 328        enable_1510_mode = d->dev_caps & ENABLE_1510_MODE;
 329
 330        if (cpu_is_omap16xx())
 331                d->dev_caps = ENABLE_16XX_MODE;
 332
 333        d->dev_caps             |= SRC_PORT;
 334        d->dev_caps             |= DST_PORT;
 335        d->dev_caps             |= SRC_INDEX;
 336        d->dev_caps             |= DST_INDEX;
 337        d->dev_caps             |= IS_BURST_ONLY4;
 338        d->dev_caps             |= CLEAR_CSR_ON_READ;
 339        d->dev_caps             |= IS_WORD_16;
 340
 341
 342        d->chan = kzalloc(sizeof(struct omap_dma_lch) *
 343                                        (d->lch_count), GFP_KERNEL);
 344        if (!d->chan) {
 345                dev_err(&pdev->dev,
 346                        "%s: Memory allocation failed for d->chan!\n",
 347                        __func__);
 348                ret = -ENOMEM;
 349                goto exit_release_d;
 350        }
 351
 352        if (cpu_is_omap15xx())
 353                d->chan_count = 9;
 354        else if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
 355                if (!(d->dev_caps & ENABLE_1510_MODE))
 356                        d->chan_count = 16;
 357                else
 358                        d->chan_count = 9;
 359        }
 360
 361        p->dma_attr = d;
 362
 363        p->show_dma_caps        = omap1_show_dma_caps;
 364        p->clear_lch_regs       = omap1_clear_lch_regs;
 365        p->clear_dma            = omap1_clear_dma;
 366        p->dma_write            = dma_write;
 367        p->dma_read             = dma_read;
 368        p->disable_irq_lch      = NULL;
 369
 370        p->errata = configure_dma_errata();
 371
 372        ret = platform_device_add_data(pdev, p, sizeof(*p));
 373        if (ret) {
 374                dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
 375                        __func__, pdev->name, pdev->id);
 376                goto exit_release_chan;
 377        }
 378
 379        ret = platform_device_add(pdev);
 380        if (ret) {
 381                dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
 382                        __func__, pdev->name, pdev->id);
 383                goto exit_release_chan;
 384        }
 385
 386        dma_stride              = OMAP1_DMA_STRIDE;
 387        dma_common_ch_start     = CPC;
 388        dma_common_ch_end       = COLOR;
 389
 390        dma_pdev = platform_device_register_full(&omap_dma_dev_info);
 391        if (IS_ERR(dma_pdev)) {
 392                ret = PTR_ERR(dma_pdev);
 393                goto exit_release_pdev;
 394        }
 395
 396        return ret;
 397
 398exit_release_pdev:
 399        platform_device_del(pdev);
 400exit_release_chan:
 401        kfree(d->chan);
 402exit_release_d:
 403        kfree(d);
 404exit_release_p:
 405        kfree(p);
 406exit_iounmap:
 407        iounmap(dma_base);
 408exit_device_put:
 409        platform_device_put(pdev);
 410
 411        return ret;
 412}
 413arch_initcall(omap1_system_dma_init);
 414