root/arch/mips/kernel/jazzdma.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vdma_init
  2. vdma_alloc
  3. vdma_free
  4. vdma_remap
  5. vdma_phys2log
  6. vdma_log2phys
  7. vdma_pgtbl_init
  8. vdma_stats
  9. vdma_enable
  10. vdma_disable
  11. vdma_set_mode
  12. vdma_set_addr
  13. vdma_set_count
  14. vdma_get_residue

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

/* [previous][next][first][last][top][bottom][index][help] */