/* This function checks if parameters are appropriate for DMA, and if they are, it sets up for DMA. If return value is false, caller may use PIO for this transfer. If return value is true, caller must issue a DMA ATA command and then call ata_dma_finish(). */ bool ata_dma_setup(void *addr, unsigned long bytes, bool write) { /* Require cacheline alignment for reads to prevent interference. */ if (!write && ((unsigned long)addr & 15)) return false; /* Writes only need to be word-aligned, but by default DMA * is not used for writing as it appears to be slower. */ #ifdef ATA_DMA_WRITES if (write && ((unsigned long)addr & 3)) return false; #else if (write) return false; #endif #if ATA_MAX_UDMA > 2 if (dma_needs_boost && !dma_boosted) { cpu_boost(true); dma_boosted = true; } #endif if (write) { /* If unflushed, old data may be written to disk */ commit_dcache(); } else { /* Invalidate cache because new data may be present in RAM */ commit_discard_dcache(); } /* Clear pending interrupts so ata_dma_finish() can wait for an interrupt from this transfer */ IDE0_CFG |= IDE_CFG_INTRQ; IDE_DMA_CONTROL |= 2; IDE_DMA_LENGTH = bytes - 4; #if !defined(BOOTLOADER) || defined (HAVE_BOOTLOADER_USB_MODE) if ((unsigned long)addr < DRAM_START) /* Rockbox remaps DRAM to start at 0 */ IDE_DMA_ADDR = (unsigned long)addr + DRAM_START; else #endif IDE_DMA_ADDR = (unsigned long)addr; if (write) IDE_DMA_CONTROL &= ~IDE_DMA_CONTROL_READ; else IDE_DMA_CONTROL |= IDE_DMA_CONTROL_READ; IDE0_CFG |= 0x8000; return true; }
static void dma_lcd_copy_buffer_rect(int x, int y, int width, int height) { char *dst, *src; /* Image buffer A is 4KW, every pixel is one Word */ /* lines is maximum number of lines we can transfer in single run */ int lines = 4096/width; if (lines > height) lines = height; /* Set source and destination addresses */ dst = (char*)(FRAME + LCD_WIDTH*y + x); src = (char*)(FBADDR(x,y)); /* Flush cache to memory */ commit_dcache(); /* Addresses are relative to start of SDRAM */ src -= CONFIG_SDRAM_START; dst -= CONFIG_SDRAM_START; /* Enable Image Buffer clock */ bitset16(&IO_CLK_MOD1, CLK_MOD1_IMGBUF); /* Use Image Buffer A for DMA */ COP_BUF_MUX0 = (COP_BUF_MUX0 & 0xFFF0) | 0x0003; /* Setup buffer offsets and transfer width/height */ COP_BUF_LOFST = width; COP_DMA_XNUM = width; COP_DMA_YNUM = lines; /* DMA: No byte SWAP, no transformation, data bus shift down 0 bit */ COP_IMG_MODE &= 0xC0; /* Set the start address of buffer */ COP_BUF_ADDR = 0x0000; /* Setup SDRAM stride */ COP_SDEM_LOFST = LCD_WIDTH; do { int addr; addr = (int)src; addr >>= 1; /* Addresses are in 16-bit words */ /* Setup the registers to initiate the read from SDRAM */ COP_SDEM_ADDRH = addr >> 16; COP_SDEM_ADDRL = addr & 0xFFFF; /* Set direction and start */ COP_DMA_CTRL = 0x0001; COP_DMA_CTRL |= 0x0002; /* Wait for read to finish */ while (COP_DMA_CTRL & 0x02) {}; addr = (int)dst; addr >>= 1; COP_SDEM_ADDRH = addr >> 16; COP_SDEM_ADDRL = addr & 0xFFFF; /* Set direction and start transfer */ COP_DMA_CTRL = 0x0000; COP_DMA_CTRL |= 0x0002; /* Wait for the transfer to complete */ while (COP_DMA_CTRL & 0x02) {}; /* Decrease height, update pointers */ src += (LCD_WIDTH << 1)*lines; dst += (LCD_WIDTH << 1)*lines; height -= lines; if (height < lines) { lines = height; COP_DMA_YNUM = height; } } while (height > 0); /* Disable Image Buffer clock */ bitclr16(&IO_CLK_MOD1, CLK_MOD1_IMGBUF); }