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/dmaengine.h>
  29#include <linux/omap-dma.h>
  30#include <mach/tc.h>
  31
  32#include "soc.h"
  33
  34#define OMAP1_DMA_BASE                  (0xfffed800)
  35
  36static u32 enable_1510_mode;
  37
  38static const struct omap_dma_reg reg_map[] = {
  39        [GCR]           = { 0x0400, 0x00, OMAP_DMA_REG_16BIT },
  40        [GSCR]          = { 0x0404, 0x00, OMAP_DMA_REG_16BIT },
  41        [GRST1]         = { 0x0408, 0x00, OMAP_DMA_REG_16BIT },
  42        [HW_ID]         = { 0x0442, 0x00, OMAP_DMA_REG_16BIT },
  43        [PCH2_ID]       = { 0x0444, 0x00, OMAP_DMA_REG_16BIT },
  44        [PCH0_ID]       = { 0x0446, 0x00, OMAP_DMA_REG_16BIT },
  45        [PCH1_ID]       = { 0x0448, 0x00, OMAP_DMA_REG_16BIT },
  46        [PCHG_ID]       = { 0x044a, 0x00, OMAP_DMA_REG_16BIT },
  47        [PCHD_ID]       = { 0x044c, 0x00, OMAP_DMA_REG_16BIT },
  48        [CAPS_0]        = { 0x044e, 0x00, OMAP_DMA_REG_2X16BIT },
  49        [CAPS_1]        = { 0x0452, 0x00, OMAP_DMA_REG_2X16BIT },
  50        [CAPS_2]        = { 0x0456, 0x00, OMAP_DMA_REG_16BIT },
  51        [CAPS_3]        = { 0x0458, 0x00, OMAP_DMA_REG_16BIT },
  52        [CAPS_4]        = { 0x045a, 0x00, OMAP_DMA_REG_16BIT },
  53        [PCH2_SR]       = { 0x0460, 0x00, OMAP_DMA_REG_16BIT },
  54        [PCH0_SR]       = { 0x0480, 0x00, OMAP_DMA_REG_16BIT },
  55        [PCH1_SR]       = { 0x0482, 0x00, OMAP_DMA_REG_16BIT },
  56        [PCHD_SR]       = { 0x04c0, 0x00, OMAP_DMA_REG_16BIT },
  57
  58        /* Common Registers */
  59        [CSDP]          = { 0x0000, 0x40, OMAP_DMA_REG_16BIT },
  60        [CCR]           = { 0x0002, 0x40, OMAP_DMA_REG_16BIT },
  61        [CICR]          = { 0x0004, 0x40, OMAP_DMA_REG_16BIT },
  62        [CSR]           = { 0x0006, 0x40, OMAP_DMA_REG_16BIT },
  63        [CEN]           = { 0x0010, 0x40, OMAP_DMA_REG_16BIT },
  64        [CFN]           = { 0x0012, 0x40, OMAP_DMA_REG_16BIT },
  65        [CSFI]          = { 0x0014, 0x40, OMAP_DMA_REG_16BIT },
  66        [CSEI]          = { 0x0016, 0x40, OMAP_DMA_REG_16BIT },
  67        [CPC]           = { 0x0018, 0x40, OMAP_DMA_REG_16BIT }, /* 15xx only */
  68        [CSAC]          = { 0x0018, 0x40, OMAP_DMA_REG_16BIT },
  69        [CDAC]          = { 0x001a, 0x40, OMAP_DMA_REG_16BIT },
  70        [CDEI]          = { 0x001c, 0x40, OMAP_DMA_REG_16BIT },
  71        [CDFI]          = { 0x001e, 0x40, OMAP_DMA_REG_16BIT },
  72        [CLNK_CTRL]     = { 0x0028, 0x40, OMAP_DMA_REG_16BIT },
  73
  74        /* Channel specific register offsets */
  75        [CSSA]          = { 0x0008, 0x40, OMAP_DMA_REG_2X16BIT },
  76        [CDSA]          = { 0x000c, 0x40, OMAP_DMA_REG_2X16BIT },
  77        [COLOR]         = { 0x0020, 0x40, OMAP_DMA_REG_2X16BIT },
  78        [CCR2]          = { 0x0024, 0x40, OMAP_DMA_REG_16BIT },
  79        [LCH_CTRL]      = { 0x002a, 0x40, OMAP_DMA_REG_16BIT },
  80};
  81
  82static struct resource res[] __initdata = {
  83        [0] = {
  84                .start  = OMAP1_DMA_BASE,
  85                .end    = OMAP1_DMA_BASE + SZ_2K - 1,
  86                .flags  = IORESOURCE_MEM,
  87        },
  88        [1] = {
  89                .name   = "0",
  90                .start  = INT_DMA_CH0_6,
  91                .flags  = IORESOURCE_IRQ,
  92        },
  93        [2] = {
  94                .name   = "1",
  95                .start  = INT_DMA_CH1_7,
  96                .flags  = IORESOURCE_IRQ,
  97        },
  98        [3] = {
  99                .name   = "2",
 100                .start  = INT_DMA_CH2_8,
 101                .flags  = IORESOURCE_IRQ,
 102        },
 103        [4] = {
 104                .name   = "3",
 105                .start  = INT_DMA_CH3,
 106                .flags  = IORESOURCE_IRQ,
 107        },
 108        [5] = {
 109                .name   = "4",
 110                .start  = INT_DMA_CH4,
 111                .flags  = IORESOURCE_IRQ,
 112        },
 113        [6] = {
 114                .name   = "5",
 115                .start  = INT_DMA_CH5,
 116                .flags  = IORESOURCE_IRQ,
 117        },
 118        /* Handled in lcd_dma.c */
 119        [7] = {
 120                .name   = "6",
 121                .start  = INT_1610_DMA_CH6,
 122                .flags  = IORESOURCE_IRQ,
 123        },
 124        /* irq's for omap16xx and omap7xx */
 125        [8] = {
 126                .name   = "7",
 127                .start  = INT_1610_DMA_CH7,
 128                .flags  = IORESOURCE_IRQ,
 129        },
 130        [9] = {
 131                .name   = "8",
 132                .start  = INT_1610_DMA_CH8,
 133                .flags  = IORESOURCE_IRQ,
 134        },
 135        [10] = {
 136                .name  = "9",
 137                .start = INT_1610_DMA_CH9,
 138                .flags = IORESOURCE_IRQ,
 139        },
 140        [11] = {
 141                .name  = "10",
 142                .start = INT_1610_DMA_CH10,
 143                .flags = IORESOURCE_IRQ,
 144        },
 145        [12] = {
 146                .name  = "11",
 147                .start = INT_1610_DMA_CH11,
 148                .flags = IORESOURCE_IRQ,
 149        },
 150        [13] = {
 151                .name  = "12",
 152                .start = INT_1610_DMA_CH12,
 153                .flags = IORESOURCE_IRQ,
 154        },
 155        [14] = {
 156                .name  = "13",
 157                .start = INT_1610_DMA_CH13,
 158                .flags = IORESOURCE_IRQ,
 159        },
 160        [15] = {
 161                .name  = "14",
 162                .start = INT_1610_DMA_CH14,
 163                .flags = IORESOURCE_IRQ,
 164        },
 165        [16] = {
 166                .name  = "15",
 167                .start = INT_1610_DMA_CH15,
 168                .flags = IORESOURCE_IRQ,
 169        },
 170        [17] = {
 171                .name  = "16",
 172                .start = INT_DMA_LCD,
 173                .flags = IORESOURCE_IRQ,
 174        },
 175};
 176
 177static void __iomem *dma_base;
 178static inline void dma_write(u32 val, int reg, int lch)
 179{
 180        void __iomem *addr = dma_base;
 181
 182        addr += reg_map[reg].offset;
 183        addr += reg_map[reg].stride * lch;
 184
 185        __raw_writew(val, addr);
 186        if (reg_map[reg].type == OMAP_DMA_REG_2X16BIT)
 187                __raw_writew(val >> 16, addr + 2);
 188}
 189
 190static inline u32 dma_read(int reg, int lch)
 191{
 192        void __iomem *addr = dma_base;
 193        uint32_t val;
 194
 195        addr += reg_map[reg].offset;
 196        addr += reg_map[reg].stride * lch;
 197
 198        val = __raw_readw(addr);
 199        if (reg_map[reg].type == OMAP_DMA_REG_2X16BIT)
 200                val |= __raw_readw(addr + 2) << 16;
 201
 202        return val;
 203}
 204
 205static void omap1_clear_lch_regs(int lch)
 206{
 207        int i;
 208
 209        for (i = CPC; i <= COLOR; i += 1)
 210                dma_write(0, i, lch);
 211}
 212
 213static void omap1_clear_dma(int lch)
 214{
 215        u32 l;
 216
 217        l = dma_read(CCR, lch);
 218        l &= ~OMAP_DMA_CCR_EN;
 219        dma_write(l, CCR, lch);
 220
 221        /* Clear pending interrupts */
 222        l = dma_read(CSR, lch);
 223}
 224
 225static void omap1_show_dma_caps(void)
 226{
 227        if (enable_1510_mode) {
 228                printk(KERN_INFO "DMA support for OMAP15xx initialized\n");
 229        } else {
 230                u16 w;
 231                printk(KERN_INFO "OMAP DMA hardware version %d\n",
 232                                                        dma_read(HW_ID, 0));
 233                printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
 234                        dma_read(CAPS_0, 0), dma_read(CAPS_1, 0),
 235                        dma_read(CAPS_2, 0), dma_read(CAPS_3, 0),
 236                        dma_read(CAPS_4, 0));
 237
 238                /* Disable OMAP 3.0/3.1 compatibility mode. */
 239                w = dma_read(GSCR, 0);
 240                w |= 1 << 3;
 241                dma_write(w, GSCR, 0);
 242        }
 243}
 244
 245static unsigned configure_dma_errata(void)
 246{
 247        unsigned errata = 0;
 248
 249        /*
 250         * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is
 251         * read before the DMA controller finished disabling the channel.
 252         */
 253        if (!cpu_is_omap15xx())
 254                SET_DMA_ERRATA(DMA_ERRATA_3_3);
 255
 256        return errata;
 257}
 258
 259static const struct platform_device_info omap_dma_dev_info = {
 260        .name = "omap-dma-engine",
 261        .id = -1,
 262        .dma_mask = DMA_BIT_MASK(32),
 263        .res = res,
 264        .num_res = 1,
 265};
 266
 267/* OMAP730, OMAP850 */
 268static const struct dma_slave_map omap7xx_sdma_map[] = {
 269        { "omap-mcbsp.1", "tx", SDMA_FILTER_PARAM(8) },
 270        { "omap-mcbsp.1", "rx", SDMA_FILTER_PARAM(9) },
 271        { "omap-mcbsp.2", "tx", SDMA_FILTER_PARAM(10) },
 272        { "omap-mcbsp.2", "rx", SDMA_FILTER_PARAM(11) },
 273        { "mmci-omap.0", "tx", SDMA_FILTER_PARAM(21) },
 274        { "mmci-omap.0", "rx", SDMA_FILTER_PARAM(22) },
 275        { "omap_udc", "rx0", SDMA_FILTER_PARAM(26) },
 276        { "omap_udc", "rx1", SDMA_FILTER_PARAM(27) },
 277        { "omap_udc", "rx2", SDMA_FILTER_PARAM(28) },
 278        { "omap_udc", "tx0", SDMA_FILTER_PARAM(29) },
 279        { "omap_udc", "tx1", SDMA_FILTER_PARAM(30) },
 280        { "omap_udc", "tx2", SDMA_FILTER_PARAM(31) },
 281};
 282
 283/* OMAP1510, OMAP1610*/
 284static const struct dma_slave_map omap1xxx_sdma_map[] = {
 285        { "omap-mcbsp.1", "tx", SDMA_FILTER_PARAM(8) },
 286        { "omap-mcbsp.1", "rx", SDMA_FILTER_PARAM(9) },
 287        { "omap-mcbsp.3", "tx", SDMA_FILTER_PARAM(10) },
 288        { "omap-mcbsp.3", "rx", SDMA_FILTER_PARAM(11) },
 289        { "omap-mcbsp.2", "tx", SDMA_FILTER_PARAM(16) },
 290        { "omap-mcbsp.2", "rx", SDMA_FILTER_PARAM(17) },
 291        { "mmci-omap.0", "tx", SDMA_FILTER_PARAM(21) },
 292        { "mmci-omap.0", "rx", SDMA_FILTER_PARAM(22) },
 293        { "omap_udc", "rx0", SDMA_FILTER_PARAM(26) },
 294        { "omap_udc", "rx1", SDMA_FILTER_PARAM(27) },
 295        { "omap_udc", "rx2", SDMA_FILTER_PARAM(28) },
 296        { "omap_udc", "tx0", SDMA_FILTER_PARAM(29) },
 297        { "omap_udc", "tx1", SDMA_FILTER_PARAM(30) },
 298        { "omap_udc", "tx2", SDMA_FILTER_PARAM(31) },
 299        { "mmci-omap.1", "tx", SDMA_FILTER_PARAM(54) },
 300        { "mmci-omap.1", "rx", SDMA_FILTER_PARAM(55) },
 301};
 302
 303static struct omap_system_dma_plat_info dma_plat_info __initdata = {
 304        .reg_map        = reg_map,
 305        .channel_stride = 0x40,
 306        .show_dma_caps  = omap1_show_dma_caps,
 307        .clear_lch_regs = omap1_clear_lch_regs,
 308        .clear_dma      = omap1_clear_dma,
 309        .dma_write      = dma_write,
 310        .dma_read       = dma_read,
 311};
 312
 313static int __init omap1_system_dma_init(void)
 314{
 315        struct omap_system_dma_plat_info        p;
 316        struct omap_dma_dev_attr                *d;
 317        struct platform_device                  *pdev, *dma_pdev;
 318        int ret;
 319
 320        pdev = platform_device_alloc("omap_dma_system", 0);
 321        if (!pdev) {
 322                pr_err("%s: Unable to device alloc for dma\n",
 323                        __func__);
 324                return -ENOMEM;
 325        }
 326
 327        dma_base = ioremap(res[0].start, resource_size(&res[0]));
 328        if (!dma_base) {
 329                pr_err("%s: Unable to ioremap\n", __func__);
 330                ret = -ENODEV;
 331                goto exit_device_put;
 332        }
 333
 334        ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
 335        if (ret) {
 336                dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
 337                        __func__, pdev->name, pdev->id);
 338                goto exit_iounmap;
 339        }
 340
 341        d = kzalloc(sizeof(*d), GFP_KERNEL);
 342        if (!d) {
 343                ret = -ENOMEM;
 344                goto exit_iounmap;
 345        }
 346
 347        /* Valid attributes for omap1 plus processors */
 348        if (cpu_is_omap15xx())
 349                d->dev_caps = ENABLE_1510_MODE;
 350        enable_1510_mode = d->dev_caps & ENABLE_1510_MODE;
 351
 352        if (cpu_is_omap16xx())
 353                d->dev_caps = ENABLE_16XX_MODE;
 354
 355        d->dev_caps             |= SRC_PORT;
 356        d->dev_caps             |= DST_PORT;
 357        d->dev_caps             |= SRC_INDEX;
 358        d->dev_caps             |= DST_INDEX;
 359        d->dev_caps             |= IS_BURST_ONLY4;
 360        d->dev_caps             |= CLEAR_CSR_ON_READ;
 361        d->dev_caps             |= IS_WORD_16;
 362
 363        /* available logical channels */
 364        if (cpu_is_omap15xx()) {
 365                d->lch_count = 9;
 366        } else {
 367                if (d->dev_caps & ENABLE_1510_MODE)
 368                        d->lch_count = 9;
 369                else
 370                        d->lch_count = 16;
 371        }
 372
 373        p = dma_plat_info;
 374        p.dma_attr = d;
 375        p.errata = configure_dma_errata();
 376
 377        if (cpu_is_omap7xx()) {
 378                p.slave_map = omap7xx_sdma_map;
 379                p.slavecnt = ARRAY_SIZE(omap7xx_sdma_map);
 380        } else {
 381                p.slave_map = omap1xxx_sdma_map;
 382                p.slavecnt = ARRAY_SIZE(omap1xxx_sdma_map);
 383        }
 384
 385        ret = platform_device_add_data(pdev, &p, sizeof(p));
 386        if (ret) {
 387                dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
 388                        __func__, pdev->name, pdev->id);
 389                goto exit_release_d;
 390        }
 391
 392        ret = platform_device_add(pdev);
 393        if (ret) {
 394                dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
 395                        __func__, pdev->name, pdev->id);
 396                goto exit_release_d;
 397        }
 398
 399        dma_pdev = platform_device_register_full(&omap_dma_dev_info);
 400        if (IS_ERR(dma_pdev)) {
 401                ret = PTR_ERR(dma_pdev);
 402                goto exit_release_pdev;
 403        }
 404
 405        return ret;
 406
 407exit_release_pdev:
 408        platform_device_del(pdev);
 409exit_release_d:
 410        kfree(d);
 411exit_iounmap:
 412        iounmap(dma_base);
 413exit_device_put:
 414        platform_device_put(pdev);
 415
 416        return ret;
 417}
 418arch_initcall(omap1_system_dma_init);
 419