linux/arch/mips/jazz/jazzdma.c
<<
>>
Prefs
   1/*
   2 * Mips Jazz DMA controller support
   3 * Copyright (C) 1995, 1996 by Andreas Busse
   4 *
   5 * NOTE: Some of the argument checking could be removed when
   6 * things have settled down. Also, instead of returning 0xffffffff
   7 * on failure of vdma_alloc() one could leave page #0 unused
   8 * and return the more usual NULL pointer as logical address.
   9 */
  10#include <linux/kernel.h>
  11#include <linux/init.h>
  12#include <linux/module.h>
  13#include <linux/errno.h>
  14#include <linux/mm.h>
  15#include <linux/bootmem.h>
  16#include <linux/spinlock.h>
  17#include <linux/gfp.h>
  18#include <asm/mipsregs.h>
  19#include <asm/jazz.h>
  20#include <asm/io.h>
  21#include <asm/uaccess.h>
  22#include <asm/dma.h>
  23#include <asm/jazzdma.h>
  24#include <asm/pgtable.h>
  25
  26/*
  27 * Set this to one to enable additional vdma debug code.
  28 */
  29#define CONF_DEBUG_VDMA 0
  30
  31static VDMA_PGTBL_ENTRY *pgtbl;
  32
  33static DEFINE_SPINLOCK(vdma_lock);
  34
  35/*
  36 * Debug stuff
  37 */
  38#define vdma_debug     ((CONF_DEBUG_VDMA) ? debuglvl : 0)
  39
  40static int debuglvl = 3;
  41
  42/*
  43 * Initialize the pagetable with a one-to-one mapping of
  44 * the first 16 Mbytes of main memory and declare all
  45 * entries to be unused. Using this method will at least
  46 * allow some early device driver operations to work.
  47 */
  48static inline void vdma_pgtbl_init(void)
  49{
  50        unsigned long paddr = 0;
  51        int i;
  52
  53        for (i = 0; i < VDMA_PGTBL_ENTRIES; i++) {
  54                pgtbl[i].frame = paddr;
  55                pgtbl[i].owner = VDMA_PAGE_EMPTY;
  56                paddr += VDMA_PAGESIZE;
  57        }
  58}
  59
  60/*
  61 * Initialize the Jazz R4030 dma controller
  62 */
  63static int __init vdma_init(void)
  64{
  65        /*
  66         * Allocate 32k of memory for DMA page tables.  This needs to be page
  67         * aligned and should be uncached to avoid cache flushing after every
  68         * update.
  69         */
  70        pgtbl = (VDMA_PGTBL_ENTRY *)__get_free_pages(GFP_KERNEL | GFP_DMA,
  71                                                    get_order(VDMA_PGTBL_SIZE));
  72        BUG_ON(!pgtbl);
  73        dma_cache_wback_inv((unsigned long)pgtbl, VDMA_PGTBL_SIZE);
  74        pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl);
  75
  76        /*
  77         * Clear the R4030 translation table
  78         */
  79        vdma_pgtbl_init();
  80
  81        r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, CPHYSADDR(pgtbl));
  82        r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM, VDMA_PGTBL_SIZE);
  83        r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
  84
  85        printk(KERN_INFO "VDMA: R4030 DMA pagetables initialized.\n");
  86        return 0;
  87}
  88
  89/*
  90 * Allocate DMA pagetables using a simple first-fit algorithm
  91 */
  92unsigned long vdma_alloc(unsigned long paddr, unsigned long size)
  93{
  94        int first, last, pages, frame, i;
  95        unsigned long laddr, flags;
  96
  97        /* check arguments */
  98
  99        if (paddr > 0x1fffffff) {
 100                if (vdma_debug)
 101                        printk("vdma_alloc: Invalid physical address: %08lx\n",
 102                               paddr);
 103                return VDMA_ERROR;      /* invalid physical address */
 104        }
 105        if (size > 0x400000 || size == 0) {
 106                if (vdma_debug)
 107                        printk("vdma_alloc: Invalid size: %08lx\n", size);
 108                return VDMA_ERROR;      /* invalid physical address */
 109        }
 110
 111        spin_lock_irqsave(&vdma_lock, flags);
 112        /*
 113         * Find free chunk
 114         */
 115        pages = VDMA_PAGE(paddr + size) - VDMA_PAGE(paddr) + 1;
 116        first = 0;
 117        while (1) {
 118                while (pgtbl[first].owner != VDMA_PAGE_EMPTY &&
 119                       first < VDMA_PGTBL_ENTRIES) first++;
 120                if (first + pages > VDMA_PGTBL_ENTRIES) {       /* nothing free */
 121                        spin_unlock_irqrestore(&vdma_lock, flags);
 122                        return VDMA_ERROR;
 123                }
 124
 125                last = first + 1;
 126                while (pgtbl[last].owner == VDMA_PAGE_EMPTY
 127                       && last - first < pages)
 128                        last++;
 129
 130                if (last - first == pages)
 131                        break;  /* found */
 132                first = last + 1;
 133        }
 134
 135        /*
 136         * Mark pages as allocated
 137         */
 138        laddr = (first << 12) + (paddr & (VDMA_PAGESIZE - 1));
 139        frame = paddr & ~(VDMA_PAGESIZE - 1);
 140
 141        for (i = first; i < last; i++) {
 142                pgtbl[i].frame = frame;
 143                pgtbl[i].owner = laddr;
 144                frame += VDMA_PAGESIZE;
 145        }
 146
 147        /*
 148         * Update translation table and return logical start address
 149         */
 150        r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
 151
 152        if (vdma_debug > 1)
 153                printk("vdma_alloc: Allocated %d pages starting from %08lx\n",
 154                     pages, laddr);
 155
 156        if (vdma_debug > 2) {
 157                printk("LADDR: ");
 158                for (i = first; i < last; i++)
 159                        printk("%08x ", i << 12);
 160                printk("\nPADDR: ");
 161                for (i = first; i < last; i++)
 162                        printk("%08x ", pgtbl[i].frame);
 163                printk("\nOWNER: ");
 164                for (i = first; i < last; i++)
 165                        printk("%08x ", pgtbl[i].owner);
 166                printk("\n");
 167        }
 168
 169        spin_unlock_irqrestore(&vdma_lock, flags);
 170
 171        return laddr;
 172}
 173
 174EXPORT_SYMBOL(vdma_alloc);
 175
 176/*
 177 * Free previously allocated dma translation pages
 178 * Note that this does NOT change the translation table,
 179 * it just marks the free'd pages as unused!
 180 */
 181int vdma_free(unsigned long laddr)
 182{
 183        int i;
 184
 185        i = laddr >> 12;
 186
 187        if (pgtbl[i].owner != laddr) {
 188                printk
 189                    ("vdma_free: trying to free other's dma pages, laddr=%8lx\n",
 190                     laddr);
 191                return -1;
 192        }
 193
 194        while (i < VDMA_PGTBL_ENTRIES && pgtbl[i].owner == laddr) {
 195                pgtbl[i].owner = VDMA_PAGE_EMPTY;
 196                i++;
 197        }
 198
 199        if (vdma_debug > 1)
 200                printk("vdma_free: freed %ld pages starting from %08lx\n",
 201                       i - (laddr >> 12), laddr);
 202
 203        return 0;
 204}
 205
 206EXPORT_SYMBOL(vdma_free);
 207
 208/*
 209 * Map certain page(s) to another physical address.
 210 * Caller must have allocated the page(s) before.
 211 */
 212int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size)
 213{
 214        int first, pages;
 215
 216        if (laddr > 0xffffff) {
 217                if (vdma_debug)
 218                        printk
 219                            ("vdma_map: Invalid logical address: %08lx\n",
 220                             laddr);
 221                return -EINVAL; /* invalid logical address */
 222        }
 223        if (paddr > 0x1fffffff) {
 224                if (vdma_debug)
 225                        printk
 226                            ("vdma_map: Invalid physical address: %08lx\n",
 227                             paddr);
 228                return -EINVAL; /* invalid physical address */
 229        }
 230
 231        pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
 232        first = laddr >> 12;
 233        if (vdma_debug)
 234                printk("vdma_remap: first=%x, pages=%x\n", first, pages);
 235        if (first + pages > VDMA_PGTBL_ENTRIES) {
 236                if (vdma_debug)
 237                        printk("vdma_alloc: Invalid size: %08lx\n", size);
 238                return -EINVAL;
 239        }
 240
 241        paddr &= ~(VDMA_PAGESIZE - 1);
 242        while (pages > 0 && first < VDMA_PGTBL_ENTRIES) {
 243                if (pgtbl[first].owner != laddr) {
 244                        if (vdma_debug)
 245                                printk("Trying to remap other's pages.\n");
 246                        return -EPERM;  /* not owner */
 247                }
 248                pgtbl[first].frame = paddr;
 249                paddr += VDMA_PAGESIZE;
 250                first++;
 251                pages--;
 252        }
 253
 254        /*
 255         * Update translation table
 256         */
 257        r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
 258
 259        if (vdma_debug > 2) {
 260                int i;
 261                pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
 262                first = laddr >> 12;
 263                printk("LADDR: ");
 264                for (i = first; i < first + pages; i++)
 265                        printk("%08x ", i << 12);
 266                printk("\nPADDR: ");
 267                for (i = first; i < first + pages; i++)
 268                        printk("%08x ", pgtbl[i].frame);
 269                printk("\nOWNER: ");
 270                for (i = first; i < first + pages; i++)
 271                        printk("%08x ", pgtbl[i].owner);
 272                printk("\n");
 273        }
 274
 275        return 0;
 276}
 277
 278/*
 279 * Translate a physical address to a logical address.
 280 * This will return the logical address of the first
 281 * match.
 282 */
 283unsigned long vdma_phys2log(unsigned long paddr)
 284{
 285        int i;
 286        int frame;
 287
 288        frame = paddr & ~(VDMA_PAGESIZE - 1);
 289
 290        for (i = 0; i < VDMA_PGTBL_ENTRIES; i++) {
 291                if (pgtbl[i].frame == frame)
 292                        break;
 293        }
 294
 295        if (i == VDMA_PGTBL_ENTRIES)
 296                return ~0UL;
 297
 298        return (i << 12) + (paddr & (VDMA_PAGESIZE - 1));
 299}
 300
 301EXPORT_SYMBOL(vdma_phys2log);
 302
 303/*
 304 * Translate a logical DMA address to a physical address
 305 */
 306unsigned long vdma_log2phys(unsigned long laddr)
 307{
 308        return pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE - 1));
 309}
 310
 311EXPORT_SYMBOL(vdma_log2phys);
 312
 313/*
 314 * Print DMA statistics
 315 */
 316void vdma_stats(void)
 317{
 318        int i;
 319
 320        printk("vdma_stats: CONFIG: %08x\n",
 321               r4030_read_reg32(JAZZ_R4030_CONFIG));
 322        printk("R4030 translation table base: %08x\n",
 323               r4030_read_reg32(JAZZ_R4030_TRSTBL_BASE));
 324        printk("R4030 translation table limit: %08x\n",
 325               r4030_read_reg32(JAZZ_R4030_TRSTBL_LIM));
 326        printk("vdma_stats: INV_ADDR: %08x\n",
 327               r4030_read_reg32(JAZZ_R4030_INV_ADDR));
 328        printk("vdma_stats: R_FAIL_ADDR: %08x\n",
 329               r4030_read_reg32(JAZZ_R4030_R_FAIL_ADDR));
 330        printk("vdma_stats: M_FAIL_ADDR: %08x\n",
 331               r4030_read_reg32(JAZZ_R4030_M_FAIL_ADDR));
 332        printk("vdma_stats: IRQ_SOURCE: %08x\n",
 333               r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE));
 334        printk("vdma_stats: I386_ERROR: %08x\n",
 335               r4030_read_reg32(JAZZ_R4030_I386_ERROR));
 336        printk("vdma_chnl_modes:   ");
 337        for (i = 0; i < 8; i++)
 338                printk("%04x ",
 339                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_MODE +
 340                                                   (i << 5)));
 341        printk("\n");
 342        printk("vdma_chnl_enables: ");
 343        for (i = 0; i < 8; i++)
 344                printk("%04x ",
 345                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 346                                                   (i << 5)));
 347        printk("\n");
 348}
 349
 350/*
 351 * DMA transfer functions
 352 */
 353
 354/*
 355 * Enable a DMA channel. Also clear any error conditions.
 356 */
 357void vdma_enable(int channel)
 358{
 359        int status;
 360
 361        if (vdma_debug)
 362                printk("vdma_enable: channel %d\n", channel);
 363
 364        /*
 365         * Check error conditions first
 366         */
 367        status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5));
 368        if (status & 0x400)
 369                printk("VDMA: Channel %d: Address error!\n", channel);
 370        if (status & 0x200)
 371                printk("VDMA: Channel %d: Memory error!\n", channel);
 372
 373        /*
 374         * Clear all interrupt flags
 375         */
 376        r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 377                          r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 378                                           (channel << 5)) | R4030_TC_INTR
 379                          | R4030_MEM_INTR | R4030_ADDR_INTR);
 380
 381        /*
 382         * Enable the desired channel
 383         */
 384        r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 385                          r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 386                                           (channel << 5)) |
 387                          R4030_CHNL_ENABLE);
 388}
 389
 390EXPORT_SYMBOL(vdma_enable);
 391
 392/*
 393 * Disable a DMA channel
 394 */
 395void vdma_disable(int channel)
 396{
 397        if (vdma_debug) {
 398                int status =
 399                    r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 400                                     (channel << 5));
 401
 402                printk("vdma_disable: channel %d\n", channel);
 403                printk("VDMA: channel %d status: %04x (%s) mode: "
 404                       "%02x addr: %06x count: %06x\n",
 405                       channel, status,
 406                       ((status & 0x600) ? "ERROR" : "OK"),
 407                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_MODE +
 408                                                   (channel << 5)),
 409                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_ADDR +
 410                                                   (channel << 5)),
 411                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_COUNT +
 412                                                   (channel << 5)));
 413        }
 414
 415        r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 416                          r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 417                                           (channel << 5)) &
 418                          ~R4030_CHNL_ENABLE);
 419
 420        /*
 421         * After disabling a DMA channel a remote bus register should be
 422         * read to ensure that the current DMA acknowledge cycle is completed.
 423         */
 424        *((volatile unsigned int *) JAZZ_DUMMY_DEVICE);
 425}
 426
 427EXPORT_SYMBOL(vdma_disable);
 428
 429/*
 430 * Set DMA mode. This function accepts the mode values used
 431 * to set a PC-style DMA controller. For the SCSI and FDC
 432 * channels, we also set the default modes each time we're
 433 * called.
 434 * NOTE: The FAST and BURST dma modes are supported by the
 435 * R4030 Rev. 2 and PICA chipsets only. I leave them disabled
 436 * for now.
 437 */
 438void vdma_set_mode(int channel, int mode)
 439{
 440        if (vdma_debug)
 441                printk("vdma_set_mode: channel %d, mode 0x%x\n", channel,
 442                       mode);
 443
 444        switch (channel) {
 445        case JAZZ_SCSI_DMA:     /* scsi */
 446                r4030_write_reg32(JAZZ_R4030_CHNL_MODE + (channel << 5),
 447/*                        R4030_MODE_FAST | */
 448/*                        R4030_MODE_BURST | */
 449                                  R4030_MODE_INTR_EN |
 450                                  R4030_MODE_WIDTH_16 |
 451                                  R4030_MODE_ATIME_80);
 452                break;
 453
 454        case JAZZ_FLOPPY_DMA:   /* floppy */
 455                r4030_write_reg32(JAZZ_R4030_CHNL_MODE + (channel << 5),
 456/*                        R4030_MODE_FAST | */
 457/*                        R4030_MODE_BURST | */
 458                                  R4030_MODE_INTR_EN |
 459                                  R4030_MODE_WIDTH_8 |
 460                                  R4030_MODE_ATIME_120);
 461                break;
 462
 463        case JAZZ_AUDIOL_DMA:
 464        case JAZZ_AUDIOR_DMA:
 465                printk("VDMA: Audio DMA not supported yet.\n");
 466                break;
 467
 468        default:
 469                printk
 470                    ("VDMA: vdma_set_mode() called with unsupported channel %d!\n",
 471                     channel);
 472        }
 473
 474        switch (mode) {
 475        case DMA_MODE_READ:
 476                r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 477                                  r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 478                                                   (channel << 5)) &
 479                                  ~R4030_CHNL_WRITE);
 480                break;
 481
 482        case DMA_MODE_WRITE:
 483                r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 484                                  r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 485                                                   (channel << 5)) |
 486                                  R4030_CHNL_WRITE);
 487                break;
 488
 489        default:
 490                printk
 491                    ("VDMA: vdma_set_mode() called with unknown dma mode 0x%x\n",
 492                     mode);
 493        }
 494}
 495
 496EXPORT_SYMBOL(vdma_set_mode);
 497
 498/*
 499 * Set Transfer Address
 500 */
 501void vdma_set_addr(int channel, long addr)
 502{
 503        if (vdma_debug)
 504                printk("vdma_set_addr: channel %d, addr %lx\n", channel,
 505                       addr);
 506
 507        r4030_write_reg32(JAZZ_R4030_CHNL_ADDR + (channel << 5), addr);
 508}
 509
 510EXPORT_SYMBOL(vdma_set_addr);
 511
 512/*
 513 * Set Transfer Count
 514 */
 515void vdma_set_count(int channel, int count)
 516{
 517        if (vdma_debug)
 518                printk("vdma_set_count: channel %d, count %08x\n", channel,
 519                       (unsigned) count);
 520
 521        r4030_write_reg32(JAZZ_R4030_CHNL_COUNT + (channel << 5), count);
 522}
 523
 524EXPORT_SYMBOL(vdma_set_count);
 525
 526/*
 527 * Get Residual
 528 */
 529int vdma_get_residue(int channel)
 530{
 531        int residual;
 532
 533        residual = r4030_read_reg32(JAZZ_R4030_CHNL_COUNT + (channel << 5));
 534
 535        if (vdma_debug)
 536                printk("vdma_get_residual: channel %d: residual=%d\n",
 537                       channel, residual);
 538
 539        return residual;
 540}
 541
 542/*
 543 * Get DMA channel enable register
 544 */
 545int vdma_get_enable(int channel)
 546{
 547        int enable;
 548
 549        enable = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5));
 550
 551        if (vdma_debug)
 552                printk("vdma_get_enable: channel %d: enable=%d\n", channel,
 553                       enable);
 554
 555        return enable;
 556}
 557
 558arch_initcall(vdma_init);
 559