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 <asm/mipsregs.h>
  18#include <asm/jazz.h>
  19#include <asm/io.h>
  20#include <asm/uaccess.h>
  21#include <asm/dma.h>
  22#include <asm/jazzdma.h>
  23#include <asm/pgtable.h>
  24
  25/*
  26 * Set this to one to enable additional vdma debug code.
  27 */
  28#define CONF_DEBUG_VDMA 0
  29
  30static VDMA_PGTBL_ENTRY *pgtbl;
  31
  32static DEFINE_SPINLOCK(vdma_lock);
  33
  34/*
  35 * Debug stuff
  36 */
  37#define vdma_debug     ((CONF_DEBUG_VDMA) ? debuglvl : 0)
  38
  39static int debuglvl = 3;
  40
  41/*
  42 * Initialize the pagetable with a one-to-one mapping of
  43 * the first 16 Mbytes of main memory and declare all
  44 * entries to be unused. Using this method will at least
  45 * allow some early device driver operations to work.
  46 */
  47static inline void vdma_pgtbl_init(void)
  48{
  49        unsigned long paddr = 0;
  50        int i;
  51
  52        for (i = 0; i < VDMA_PGTBL_ENTRIES; i++) {
  53                pgtbl[i].frame = paddr;
  54                pgtbl[i].owner = VDMA_PAGE_EMPTY;
  55                paddr += VDMA_PAGESIZE;
  56        }
  57}
  58
  59/*
  60 * Initialize the Jazz R4030 dma controller
  61 */
  62static int __init vdma_init(void)
  63{
  64        /*
  65         * Allocate 32k of memory for DMA page tables.  This needs to be page
  66         * aligned and should be uncached to avoid cache flushing after every
  67         * update.
  68         */
  69        pgtbl = (VDMA_PGTBL_ENTRY *)__get_free_pages(GFP_KERNEL | GFP_DMA,
  70                                                    get_order(VDMA_PGTBL_SIZE));
  71        if (!pgtbl)
  72                BUG();
  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 (pgtbl[i].owner == laddr && i < VDMA_PGTBL_ENTRIES) {
 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, npages;
 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        npages = pages =
 232            (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
 233        first = laddr >> 12;
 234        if (vdma_debug)
 235                printk("vdma_remap: first=%x, pages=%x\n", first, pages);
 236        if (first + pages > VDMA_PGTBL_ENTRIES) {
 237                if (vdma_debug)
 238                        printk("vdma_alloc: Invalid size: %08lx\n", size);
 239                return -EINVAL;
 240        }
 241
 242        paddr &= ~(VDMA_PAGESIZE - 1);
 243        while (pages > 0 && first < VDMA_PGTBL_ENTRIES) {
 244                if (pgtbl[first].owner != laddr) {
 245                        if (vdma_debug)
 246                                printk("Trying to remap other's pages.\n");
 247                        return -EPERM;  /* not owner */
 248                }
 249                pgtbl[first].frame = paddr;
 250                paddr += VDMA_PAGESIZE;
 251                first++;
 252                pages--;
 253        }
 254
 255        /*
 256         * Update translation table
 257         */
 258        r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0);
 259
 260        if (vdma_debug > 2) {
 261                int i;
 262                pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1;
 263                first = laddr >> 12;
 264                printk("LADDR: ");
 265                for (i = first; i < first + pages; i++)
 266                        printk("%08x ", i << 12);
 267                printk("\nPADDR: ");
 268                for (i = first; i < first + pages; i++)
 269                        printk("%08x ", pgtbl[i].frame);
 270                printk("\nOWNER: ");
 271                for (i = first; i < first + pages; i++)
 272                        printk("%08x ", pgtbl[i].owner);
 273                printk("\n");
 274        }
 275
 276        return 0;
 277}
 278
 279/*
 280 * Translate a physical address to a logical address.
 281 * This will return the logical address of the first
 282 * match.
 283 */
 284unsigned long vdma_phys2log(unsigned long paddr)
 285{
 286        int i;
 287        int frame;
 288
 289        frame = paddr & ~(VDMA_PAGESIZE - 1);
 290
 291        for (i = 0; i < VDMA_PGTBL_ENTRIES; i++) {
 292                if (pgtbl[i].frame == frame)
 293                        break;
 294        }
 295
 296        if (i == VDMA_PGTBL_ENTRIES)
 297                return ~0UL;
 298
 299        return (i << 12) + (paddr & (VDMA_PAGESIZE - 1));
 300}
 301
 302EXPORT_SYMBOL(vdma_phys2log);
 303
 304/*
 305 * Translate a logical DMA address to a physical address
 306 */
 307unsigned long vdma_log2phys(unsigned long laddr)
 308{
 309        return pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE - 1));
 310}
 311
 312EXPORT_SYMBOL(vdma_log2phys);
 313
 314/*
 315 * Print DMA statistics
 316 */
 317void vdma_stats(void)
 318{
 319        int i;
 320
 321        printk("vdma_stats: CONFIG: %08x\n",
 322               r4030_read_reg32(JAZZ_R4030_CONFIG));
 323        printk("R4030 translation table base: %08x\n",
 324               r4030_read_reg32(JAZZ_R4030_TRSTBL_BASE));
 325        printk("R4030 translation table limit: %08x\n",
 326               r4030_read_reg32(JAZZ_R4030_TRSTBL_LIM));
 327        printk("vdma_stats: INV_ADDR: %08x\n",
 328               r4030_read_reg32(JAZZ_R4030_INV_ADDR));
 329        printk("vdma_stats: R_FAIL_ADDR: %08x\n",
 330               r4030_read_reg32(JAZZ_R4030_R_FAIL_ADDR));
 331        printk("vdma_stats: M_FAIL_ADDR: %08x\n",
 332               r4030_read_reg32(JAZZ_R4030_M_FAIL_ADDR));
 333        printk("vdma_stats: IRQ_SOURCE: %08x\n",
 334               r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE));
 335        printk("vdma_stats: I386_ERROR: %08x\n",
 336               r4030_read_reg32(JAZZ_R4030_I386_ERROR));
 337        printk("vdma_chnl_modes:   ");
 338        for (i = 0; i < 8; i++)
 339                printk("%04x ",
 340                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_MODE +
 341                                                   (i << 5)));
 342        printk("\n");
 343        printk("vdma_chnl_enables: ");
 344        for (i = 0; i < 8; i++)
 345                printk("%04x ",
 346                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 347                                                   (i << 5)));
 348        printk("\n");
 349}
 350
 351/*
 352 * DMA transfer functions
 353 */
 354
 355/*
 356 * Enable a DMA channel. Also clear any error conditions.
 357 */
 358void vdma_enable(int channel)
 359{
 360        int status;
 361
 362        if (vdma_debug)
 363                printk("vdma_enable: channel %d\n", channel);
 364
 365        /*
 366         * Check error conditions first
 367         */
 368        status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5));
 369        if (status & 0x400)
 370                printk("VDMA: Channel %d: Address error!\n", channel);
 371        if (status & 0x200)
 372                printk("VDMA: Channel %d: Memory error!\n", channel);
 373
 374        /*
 375         * Clear all interrupt flags
 376         */
 377        r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 378                          r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 379                                           (channel << 5)) | R4030_TC_INTR
 380                          | R4030_MEM_INTR | R4030_ADDR_INTR);
 381
 382        /*
 383         * Enable the desired channel
 384         */
 385        r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 386                          r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 387                                           (channel << 5)) |
 388                          R4030_CHNL_ENABLE);
 389}
 390
 391EXPORT_SYMBOL(vdma_enable);
 392
 393/*
 394 * Disable a DMA channel
 395 */
 396void vdma_disable(int channel)
 397{
 398        if (vdma_debug) {
 399                int status =
 400                    r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 401                                     (channel << 5));
 402
 403                printk("vdma_disable: channel %d\n", channel);
 404                printk("VDMA: channel %d status: %04x (%s) mode: "
 405                       "%02x addr: %06x count: %06x\n",
 406                       channel, status,
 407                       ((status & 0x600) ? "ERROR" : "OK"),
 408                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_MODE +
 409                                                   (channel << 5)),
 410                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_ADDR +
 411                                                   (channel << 5)),
 412                       (unsigned) r4030_read_reg32(JAZZ_R4030_CHNL_COUNT +
 413                                                   (channel << 5)));
 414        }
 415
 416        r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 417                          r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 418                                           (channel << 5)) &
 419                          ~R4030_CHNL_ENABLE);
 420
 421        /*
 422         * After disabling a DMA channel a remote bus register should be
 423         * read to ensure that the current DMA acknowledge cycle is completed.
 424         */
 425        *((volatile unsigned int *) JAZZ_DUMMY_DEVICE);
 426}
 427
 428EXPORT_SYMBOL(vdma_disable);
 429
 430/*
 431 * Set DMA mode. This function accepts the mode values used
 432 * to set a PC-style DMA controller. For the SCSI and FDC
 433 * channels, we also set the default modes each time we're
 434 * called.
 435 * NOTE: The FAST and BURST dma modes are supported by the
 436 * R4030 Rev. 2 and PICA chipsets only. I leave them disabled
 437 * for now.
 438 */
 439void vdma_set_mode(int channel, int mode)
 440{
 441        if (vdma_debug)
 442                printk("vdma_set_mode: channel %d, mode 0x%x\n", channel,
 443                       mode);
 444
 445        switch (channel) {
 446        case JAZZ_SCSI_DMA:     /* scsi */
 447                r4030_write_reg32(JAZZ_R4030_CHNL_MODE + (channel << 5),
 448/*                        R4030_MODE_FAST | */
 449/*                        R4030_MODE_BURST | */
 450                                  R4030_MODE_INTR_EN |
 451                                  R4030_MODE_WIDTH_16 |
 452                                  R4030_MODE_ATIME_80);
 453                break;
 454
 455        case JAZZ_FLOPPY_DMA:   /* floppy */
 456                r4030_write_reg32(JAZZ_R4030_CHNL_MODE + (channel << 5),
 457/*                        R4030_MODE_FAST | */
 458/*                        R4030_MODE_BURST | */
 459                                  R4030_MODE_INTR_EN |
 460                                  R4030_MODE_WIDTH_8 |
 461                                  R4030_MODE_ATIME_120);
 462                break;
 463
 464        case JAZZ_AUDIOL_DMA:
 465        case JAZZ_AUDIOR_DMA:
 466                printk("VDMA: Audio DMA not supported yet.\n");
 467                break;
 468
 469        default:
 470                printk
 471                    ("VDMA: vdma_set_mode() called with unsupported channel %d!\n",
 472                     channel);
 473        }
 474
 475        switch (mode) {
 476        case DMA_MODE_READ:
 477                r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 478                                  r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 479                                                   (channel << 5)) &
 480                                  ~R4030_CHNL_WRITE);
 481                break;
 482
 483        case DMA_MODE_WRITE:
 484                r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5),
 485                                  r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE +
 486                                                   (channel << 5)) |
 487                                  R4030_CHNL_WRITE);
 488                break;
 489
 490        default:
 491                printk
 492                    ("VDMA: vdma_set_mode() called with unknown dma mode 0x%x\n",
 493                     mode);
 494        }
 495}
 496
 497EXPORT_SYMBOL(vdma_set_mode);
 498
 499/*
 500 * Set Transfer Address
 501 */
 502void vdma_set_addr(int channel, long addr)
 503{
 504        if (vdma_debug)
 505                printk("vdma_set_addr: channel %d, addr %lx\n", channel,
 506                       addr);
 507
 508        r4030_write_reg32(JAZZ_R4030_CHNL_ADDR + (channel << 5), addr);
 509}
 510
 511EXPORT_SYMBOL(vdma_set_addr);
 512
 513/*
 514 * Set Transfer Count
 515 */
 516void vdma_set_count(int channel, int count)
 517{
 518        if (vdma_debug)
 519                printk("vdma_set_count: channel %d, count %08x\n", channel,
 520                       (unsigned) count);
 521
 522        r4030_write_reg32(JAZZ_R4030_CHNL_COUNT + (channel << 5), count);
 523}
 524
 525EXPORT_SYMBOL(vdma_set_count);
 526
 527/*
 528 * Get Residual
 529 */
 530int vdma_get_residue(int channel)
 531{
 532        int residual;
 533
 534        residual = r4030_read_reg32(JAZZ_R4030_CHNL_COUNT + (channel << 5));
 535
 536        if (vdma_debug)
 537                printk("vdma_get_residual: channel %d: residual=%d\n",
 538                       channel, residual);
 539
 540        return residual;
 541}
 542
 543/*
 544 * Get DMA channel enable register
 545 */
 546int vdma_get_enable(int channel)
 547{
 548        int enable;
 549
 550        enable = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE + (channel << 5));
 551
 552        if (vdma_debug)
 553                printk("vdma_get_enable: channel %d: enable=%d\n", channel,
 554                       enable);
 555
 556        return enable;
 557}
 558
 559arch_initcall(vdma_init);
 560