forked from len0rd/rockbox
Sansa AMS: Use DMA for SD transfers (read and write)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19211 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
d7e4e54bcb
commit
c1f90b1881
6 changed files with 293 additions and 119 deletions
|
@ -343,6 +343,7 @@ target/arm/as3525/kernel-as3525.c
|
||||||
target/arm/as3525/ata_sd_as3525.c
|
target/arm/as3525/ata_sd_as3525.c
|
||||||
target/arm/as3525/power-as3525.c
|
target/arm/as3525/power-as3525.c
|
||||||
target/arm/as3525/usb-as3525.c
|
target/arm/as3525/usb-as3525.c
|
||||||
|
target/arm/as3525/dma-pl081.c
|
||||||
#ifndef BOOTLOADER
|
#ifndef BOOTLOADER
|
||||||
target/arm/adc-as3514.c
|
target/arm/adc-as3514.c
|
||||||
target/arm/as3525/pcm-as3525.c
|
target/arm/as3525/pcm-as3525.c
|
||||||
|
|
77
firmware/export/pl081.h
Normal file
77
firmware/export/pl081.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright © 2008 Rafaël Carré
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Note: since the base address is not specified, you need to define DMAC_BASE
|
||||||
|
* before including this file */
|
||||||
|
|
||||||
|
/* ARM PrimeCell PL081 Single Master DMA controller */
|
||||||
|
|
||||||
|
#define DMAC_INT_STATUS (*(volatile unsigned long*)(DMAC_BASE+0x000))
|
||||||
|
#define DMAC_INT_TC_STATUS (*(volatile unsigned long*)(DMAC_BASE+0x004))
|
||||||
|
#define DMAC_INT_TC_CLEAR (*(volatile unsigned long*)(DMAC_BASE+0x008))
|
||||||
|
#define DMAC_INT_ERROR_STATUS (*(volatile unsigned long*)(DMAC_BASE+0x00C))
|
||||||
|
#define DMAC_INT_ERR_CLEAR (*(volatile unsigned long*)(DMAC_BASE+0x010))
|
||||||
|
#define DMAC_RAW_INT_TC_STATUS (*(volatile unsigned long*)(DMAC_BASE+0x014))
|
||||||
|
#define DMAC_RAW_INT_ERROR_STATUS (*(volatile unsigned long*)(DMAC_BASE+0x018))
|
||||||
|
#define DMAC_ENBLD_CHANS (*(volatile unsigned long*)(DMAC_BASE+0x01C))
|
||||||
|
#define DMAC_SOFT_B_REQ (*(volatile unsigned long*)(DMAC_BASE+0x020))
|
||||||
|
#define DMAC_SOFT_S_REQ (*(volatile unsigned long*)(DMAC_BASE+0x024))
|
||||||
|
#define DMAC_SOFT_LB_REQ (*(volatile unsigned long*)(DMAC_BASE+0x028))
|
||||||
|
#define DMAC_SOFT_LS_REQ (*(volatile unsigned long*)(DMAC_BASE+0x02C))
|
||||||
|
#define DMAC_CONFIGURATION (*(volatile unsigned long*)(DMAC_BASE+0x030))
|
||||||
|
#define DMAC_SYNC (*(volatile unsigned long*)(DMAC_BASE+0x034))
|
||||||
|
|
||||||
|
/* Channel registers (0 & 1) */
|
||||||
|
#define DMAC_CH_SRC_ADDR(c) (*(volatile unsigned long*)(DMAC_BASE+0x100+(0x20*c)))
|
||||||
|
#define DMAC_CH_DST_ADDR(c) (*(volatile unsigned long*)(DMAC_BASE+0x104+(0x20*c)))
|
||||||
|
#define DMAC_CH_LLI(c) (*(volatile unsigned long*)(DMAC_BASE+0x108+(0x20*c)))
|
||||||
|
#define DMAC_CH_CONTROL(c) (*(volatile unsigned long*)(DMAC_BASE+0x10C+(0x20*c)))
|
||||||
|
#define DMAC_CH_CONFIGURATION(c) (*(volatile unsigned long*)(DMAC_BASE+0x110+(0x20*c)))
|
||||||
|
|
||||||
|
/* Test registers */
|
||||||
|
#define DMAC_ITCR (*(volatile unsigned long*)(DMAC_BASE+0x500))
|
||||||
|
#define DMAC_ITOP1 (*(volatile unsigned long*)(DMAC_BASE+0x504))
|
||||||
|
#define DMAC_ITOP2 (*(volatile unsigned long*)(DMAC_BASE+0x508))
|
||||||
|
#define DMAC_ITOP3 (*(volatile unsigned long*)(DMAC_BASE+0x50C))
|
||||||
|
|
||||||
|
/* Flow controllers */
|
||||||
|
|
||||||
|
/* Controller is DMAC */
|
||||||
|
#define DMAC_FLOWCTRL_DMAC_MEM_TO_MEM 0
|
||||||
|
#define DMAC_FLOWCTRL_DMAC_MEM_TO_PERI 1
|
||||||
|
#define DMAC_FLOWCTRL_DMAC_PERI_TO_MEM 2
|
||||||
|
#define DMAC_FLOWCTRL_DMAC_PERI_TO_PERI 3
|
||||||
|
|
||||||
|
/* Controller is peripheral */
|
||||||
|
#define DMAC_FLOWCTRL_SRC_PERI_PERI_TO_PERI 4
|
||||||
|
#define DMAC_FLOWCTRL_PERI_MEM_TO_PERI 5
|
||||||
|
#define DMAC_FLOWCTRL_PERI_PERI_TO_MEM 6
|
||||||
|
#define DMAC_FLOWCTRL_DST_PERI_PERI_TO_PERI 7
|
||||||
|
|
||||||
|
/* Transfer request sizes */
|
||||||
|
#define DMA_S1 0
|
||||||
|
#define DMA_S4 1
|
||||||
|
#define DMA_S8 2
|
||||||
|
#define DMA_S16 3
|
||||||
|
#define DMA_S32 4
|
||||||
|
#define DMA_S64 5
|
||||||
|
#define DMA_S128 6
|
||||||
|
#define DMA_S256 7
|
|
@ -32,7 +32,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "as3525.h"
|
#include "as3525.h"
|
||||||
#include "pl180.h"
|
#include "pl180.h" /* SD controller */
|
||||||
|
#include "pl081.h" /* DMA controller */
|
||||||
|
#include "dma-target.h" /* DMA request lines */
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "stdbool.h"
|
#include "stdbool.h"
|
||||||
#include "ata_idle_notify.h"
|
#include "ata_idle_notify.h"
|
||||||
|
@ -71,8 +73,8 @@
|
||||||
|
|
||||||
#define MCI_FIFO(i) ((unsigned long *) (pl180_base[i]+0x80))
|
#define MCI_FIFO(i) ((unsigned long *) (pl180_base[i]+0x80))
|
||||||
/* volumes */
|
/* volumes */
|
||||||
#define NAND_AS3525 0 /* embedded SD card */
|
#define INTERNAL_AS3525 0 /* embedded SD card */
|
||||||
#define SD_AS3525 1 /* SD slot if present */
|
#define SD_SLOT_AS3525 1 /* SD slot if present */
|
||||||
|
|
||||||
static const int pl180_base[NUM_VOLUMES] = {
|
static const int pl180_base[NUM_VOLUMES] = {
|
||||||
NAND_FLASH_BASE
|
NAND_FLASH_BASE
|
||||||
|
@ -81,6 +83,7 @@ static const int pl180_base[NUM_VOLUMES] = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* TODO : BLOCK_SIZE != SECTOR_SIZE ? */
|
||||||
#define BLOCK_SIZE 512
|
#define BLOCK_SIZE 512
|
||||||
#define SECTOR_SIZE 512
|
#define SECTOR_SIZE 512
|
||||||
|
|
||||||
|
@ -389,8 +392,8 @@ int sd_init(void)
|
||||||
CGU_PERI |= CGU_MCI_CLOCK_ENABLE;
|
CGU_PERI |= CGU_MCI_CLOCK_ENABLE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
init_pl180_controller(NAND_AS3525);
|
init_pl180_controller(INTERNAL_AS3525);
|
||||||
ret = sd_init_card(NAND_AS3525);
|
ret = sd_init_card(INTERNAL_AS3525);
|
||||||
if(ret < 0)
|
if(ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -398,8 +401,8 @@ int sd_init(void)
|
||||||
CCU_IO &= ~8; /* bits 3:2 = 01, xpd is SD interface */
|
CCU_IO &= ~8; /* bits 3:2 = 01, xpd is SD interface */
|
||||||
CCU_IO |= 4;
|
CCU_IO |= 4;
|
||||||
|
|
||||||
init_pl180_controller(SD_AS3525);
|
init_pl180_controller(SD_SLOT_AS3525);
|
||||||
sd_init_card(SD_AS3525);
|
sd_init_card(SD_SLOT_AS3525);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
queue_init(&sd_queue, true);
|
queue_init(&sd_queue, true);
|
||||||
|
@ -441,40 +444,6 @@ bool sd_present(IF_MV_NONVOID(int drive))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf)
|
|
||||||
{
|
|
||||||
(void)start;
|
|
||||||
(void)count;
|
|
||||||
(void)buf;
|
|
||||||
return -1; /* TODO */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sd_poll_status(const int drive, unsigned int trigger, long timeout)
|
|
||||||
{
|
|
||||||
long t = current_tick;
|
|
||||||
//int my_next_yield =0;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
while (((status = MCI_STATUS(drive)) & trigger) == 0)
|
|
||||||
{
|
|
||||||
long time = current_tick;
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (TIME_AFTER(time, my_next_yield))
|
|
||||||
{
|
|
||||||
long ty = current_tick;
|
|
||||||
yield();
|
|
||||||
timeout += current_tick - ty;
|
|
||||||
my_next_yield = ty + MIN_YIELD_PERIOD;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (TIME_AFTER(time, t + timeout))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sd_wait_for_state(const int drive, unsigned int state)
|
static int sd_wait_for_state(const int drive, unsigned int state)
|
||||||
{
|
{
|
||||||
unsigned int response = 0;
|
unsigned int response = 0;
|
||||||
|
@ -484,7 +453,7 @@ static int sd_wait_for_state(const int drive, unsigned int state)
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
long us;
|
long tick;
|
||||||
|
|
||||||
if(!send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca,
|
if(!send_cmd(drive, SD_SEND_STATUS, card_info[drive].rca,
|
||||||
MCI_RESP|MCI_ARG, &response))
|
MCI_RESP|MCI_ARG, &response))
|
||||||
|
@ -496,35 +465,30 @@ static int sd_wait_for_state(const int drive, unsigned int state)
|
||||||
if(TIME_AFTER(current_tick, t + timeout))
|
if(TIME_AFTER(current_tick, t + timeout))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
us = current_tick;
|
if (TIME_AFTER((tick = current_tick), next_yield))
|
||||||
if (TIME_AFTER(us, next_yield))
|
|
||||||
{
|
{
|
||||||
yield();
|
yield();
|
||||||
timeout += current_tick - us;
|
timeout += current_tick - tick;
|
||||||
next_yield = us + MIN_YIELD_PERIOD;
|
next_yield = tick + MIN_YIELD_PERIOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int incount,
|
static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
|
||||||
void* inbuf)
|
int count, void* buf, bool write)
|
||||||
{
|
{
|
||||||
#ifndef HAVE_MULTIVOLUME
|
#ifndef HAVE_MULTIVOLUME
|
||||||
const int drive = 0;
|
const int drive = 0;
|
||||||
#endif
|
#endif
|
||||||
int ret;
|
int ret;
|
||||||
unsigned char *buf_end, *buf = inbuf;
|
|
||||||
int remaining = incount;
|
|
||||||
const unsigned long *fifo_base = MCI_FIFO(drive);
|
|
||||||
|
|
||||||
/* skip SanDisk OF */
|
/* skip SanDisk OF */
|
||||||
if (drive == NAND_AS3525)
|
if (drive == INTERNAL_AS3525)
|
||||||
#if defined(SANSA_E200V2) || defined(SANSA_FUZE)
|
#if defined(SANSA_E200V2) || defined(SANSA_FUZE)
|
||||||
start += 61440;
|
start += 61440;
|
||||||
#else
|
#else
|
||||||
start += 20480;
|
start += 20480;
|
||||||
#endif
|
#endif
|
||||||
/* TODO: Add DMA support. */
|
|
||||||
|
|
||||||
mutex_lock(&sd_mtx);
|
mutex_lock(&sd_mtx);
|
||||||
|
|
||||||
|
@ -533,15 +497,15 @@ int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int incount,
|
||||||
{
|
{
|
||||||
/* no external sd-card inserted */
|
/* no external sd-card inserted */
|
||||||
ret = -88;
|
ret = -88;
|
||||||
goto sd_read_error;
|
goto sd_transfer_error;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (card_info[drive].initialized < 0)
|
if (card_info[drive].initialized < 0)
|
||||||
{
|
{
|
||||||
ret = card_info[drive].initialized;
|
ret = card_info[drive].initialized;
|
||||||
panicf("card not initalised");
|
panicf("card not initialised");
|
||||||
goto sd_read_error;
|
goto sd_transfer_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_disk_activity = current_tick;
|
last_disk_activity = current_tick;
|
||||||
|
@ -550,109 +514,103 @@ int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int incount,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
panicf("wait for state failed");
|
panicf("wait for state failed");
|
||||||
goto sd_read_error;
|
goto sd_transfer_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
disable_irq(); /* FIXME: data transfer is too slow and error prone when
|
while(count)
|
||||||
* interrupts are enabled */
|
|
||||||
|
|
||||||
while(remaining)
|
|
||||||
{
|
{
|
||||||
/* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH
|
/* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH
|
||||||
* register, so we have to transfer maximum 127 sectors at a time. */
|
* register, so we have to transfer maximum 127 sectors at a time. */
|
||||||
int transfer = (remaining >= 128) ? 127 : remaining; /* sectors */
|
unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */
|
||||||
|
const int cmd =
|
||||||
|
write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK;
|
||||||
|
|
||||||
if(card_info[drive].ocr & (1<<30) ) /* SDHC */
|
if(card_info[drive].ocr & (1<<30) ) /* SDHC */
|
||||||
ret = send_cmd(drive, SD_READ_MULTIPLE_BLOCK, start, MCI_ARG, NULL);
|
ret = send_cmd(drive, cmd, start, MCI_ARG, NULL);
|
||||||
else
|
else
|
||||||
ret = send_cmd(drive, SD_READ_MULTIPLE_BLOCK, start * BLOCK_SIZE,
|
ret = send_cmd(drive, cmd, start * BLOCK_SIZE,
|
||||||
MCI_ARG, NULL);
|
MCI_ARG, NULL);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
panicf("read multiple blocks failed");
|
panicf("transfer multiple blocks failed");
|
||||||
goto sd_read_error;
|
goto sd_transfer_error;
|
||||||
}
|
}
|
||||||
/* TODO: Don't assume BLOCK_SIZE == SECTOR_SIZE */
|
|
||||||
|
|
||||||
|
if(write)
|
||||||
|
dma_enable_channel(0, buf, MCI_FIFO(drive),
|
||||||
|
(drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
|
||||||
|
DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8);
|
||||||
|
else
|
||||||
|
dma_enable_channel(0, MCI_FIFO(drive), buf,
|
||||||
|
(drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
|
||||||
|
DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8);
|
||||||
|
|
||||||
MCI_DATA_TIMER(drive) = 0x1000000; /* FIXME: arbitrary */
|
MCI_DATA_TIMER(drive) = 0x1000000; /* FIXME: arbitrary */
|
||||||
MCI_DATA_LENGTH(drive) = transfer * card_info[drive].block_size;
|
MCI_DATA_LENGTH(drive) = transfer * card_info[drive].block_size;
|
||||||
MCI_DATA_CTRL(drive) = (1<<0) /* enable */ |
|
MCI_DATA_CTRL(drive) = (1<<0) /* enable */ |
|
||||||
(1<<1) /* from card to controller */ |
|
(!write<<1) /* transfer direction */ |
|
||||||
|
(1<<3) /* DMA */ |
|
||||||
(9<<4) /* 2^9 = 512 */ ;
|
(9<<4) /* 2^9 = 512 */ ;
|
||||||
|
|
||||||
buf_end = buf + transfer * card_info[drive].block_size;
|
while(!dma_finished)
|
||||||
|
yield();
|
||||||
|
|
||||||
while(buf < buf_end)
|
buf += transfer * SECTOR_SIZE;
|
||||||
{
|
|
||||||
/* Wait for the FIFO to be half full */
|
|
||||||
const int trigger = MCI_RX_FIFO_HALF_FULL|MCI_RX_FIFO_FULL;
|
|
||||||
int controller_status = sd_poll_status(drive, trigger, 100);
|
|
||||||
|
|
||||||
controller_status &= ~(MCI_RX_ACTIVE|MCI_RX_DATA_AVAIL|
|
|
||||||
MCI_DATA_BLOCK_END|MCI_DATA_END);
|
|
||||||
|
|
||||||
if(!controller_status || (controller_status & ~trigger))
|
|
||||||
panicf("incorrect status 0x%x", controller_status & ~trigger);
|
|
||||||
|
|
||||||
if(((intptr_t)buf & 3) == 0)
|
|
||||||
{ /* aligned destination buffer */
|
|
||||||
asm volatile(
|
|
||||||
"ldmia %2, {r0-r7} \n" /* load 8 * 4 bytes */
|
|
||||||
"stmia %1!, {r0-r7} \n" /* store 8 * 4 bytes */
|
|
||||||
:"=r"(buf) /* output */
|
|
||||||
:"r"(buf), "r"(fifo_base) /* input */
|
|
||||||
:"r0","r1","r2","r3","r4","r5","r6","r7" /* clobbers */
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ /* non aligned destination buffer */
|
|
||||||
int tmp[8];
|
|
||||||
asm volatile(
|
|
||||||
"ldmia %1, {r0-r7} \n" /* load 8 * 4 bytes */
|
|
||||||
"stmia %0, {r0-r7} \n" /* store 8 * 4 bytes */
|
|
||||||
:/* no output */
|
|
||||||
:"r"(tmp), "r"(fifo_base) /* input */
|
|
||||||
:"r0","r1","r2","r3","r4","r5","r6","r7" /* clobbers */
|
|
||||||
);
|
|
||||||
memcpy(buf, tmp, 32);
|
|
||||||
buf = &buf[32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remaining -= transfer;
|
|
||||||
start += transfer;
|
start += transfer;
|
||||||
|
count -= transfer;
|
||||||
last_disk_activity = current_tick;
|
last_disk_activity = current_tick;
|
||||||
|
|
||||||
if(!send_cmd(drive, SD_STOP_TRANSMISSION, 0, MCI_NO_FLAGS, NULL))
|
if(!send_cmd(drive, SD_STOP_TRANSMISSION, 0, MCI_NO_FLAGS, NULL))
|
||||||
{
|
{
|
||||||
ret = -666;
|
ret = -666;
|
||||||
panicf("STOP TRANSMISSION failed");
|
panicf("STOP TRANSMISSION failed");
|
||||||
goto sd_read_error;
|
goto sd_transfer_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sd_wait_for_state(drive, SD_TRAN);
|
ret = sd_wait_for_state(drive, SD_TRAN);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
panicf(" wait for state TRAN failed");
|
panicf(" wait for state TRAN failed");
|
||||||
goto sd_read_error;
|
goto sd_transfer_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
mutex_unlock(&sd_mtx);
|
mutex_unlock(&sd_mtx);
|
||||||
|
|
||||||
enable_irq();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
sd_read_error:
|
sd_transfer_error:
|
||||||
panicf("read error : %d",ret);
|
panicf("transfer error : %d",ret);
|
||||||
card_info[drive].initialized = 0;
|
card_info[drive].initialized = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sd_read_sectors(IF_MV2(int drive,) unsigned long start, int count,
|
||||||
|
void* buf)
|
||||||
|
{
|
||||||
|
return sd_transfer_sectors(IF_MV2(drive,) start, count, buf, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sd_write_sectors(IF_MV2(int drive,) unsigned long start, int count,
|
||||||
|
const void* buf)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef BOOTLOADER /* we don't need write support in bootloader */
|
||||||
|
#ifdef HAVE_MULTIVOLUME
|
||||||
|
(void) drive;
|
||||||
|
#endif
|
||||||
|
(void) start;
|
||||||
|
(void) count;
|
||||||
|
(void) buf;
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
return sd_transfer_sectors(IF_MV2(drive,) start, count, (void*)buf, true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef BOOTLOADER
|
#ifndef BOOTLOADER
|
||||||
void sd_sleep(void)
|
void sd_sleep(void)
|
||||||
{
|
{
|
||||||
|
|
96
firmware/target/arm/as3525/dma-pl081.c
Normal file
96
firmware/target/arm/as3525/dma-pl081.c
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright © 2008 Rafaël Carré
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "as3525.h"
|
||||||
|
#include "pl081.h"
|
||||||
|
#include "dma-target.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "panic.h"
|
||||||
|
|
||||||
|
volatile bool dma_finished;
|
||||||
|
|
||||||
|
void dma_init(void)
|
||||||
|
{
|
||||||
|
/* Enable DMA controller */
|
||||||
|
CGU_PERI |= CGU_DMA_CLOCK_ENABLE;
|
||||||
|
DMAC_CONFIGURATION |= (1<<0);
|
||||||
|
DMAC_SYNC = 0;
|
||||||
|
VIC_INT_ENABLE |= INTERRUPT_DMAC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_enable_channel(int channel, void *src, void *dst, int peri,
|
||||||
|
int flow_controller, bool src_inc, bool dst_inc,
|
||||||
|
size_t size, int nwords)
|
||||||
|
{
|
||||||
|
int control = 0;
|
||||||
|
|
||||||
|
DMAC_CH_SRC_ADDR(channel) = (int)src;
|
||||||
|
DMAC_CH_DST_ADDR(channel) = (int)dst;
|
||||||
|
|
||||||
|
DMAC_CH_LLI(channel) = 0; /* we use contigous memory, so don't use the LLI */
|
||||||
|
|
||||||
|
/* specify address increment */
|
||||||
|
if(src_inc)
|
||||||
|
control |= (1<<26);
|
||||||
|
|
||||||
|
if(dst_inc)
|
||||||
|
control |= (1<<27);
|
||||||
|
|
||||||
|
/* OF use transfers of 4 * 32 bits words on memory, i2sin, i2sout */
|
||||||
|
/* OF use transfers of 8 * 32 bits words on SD */
|
||||||
|
|
||||||
|
control |= (2<<21) | (2<<18); /* dst/src width = word, 32bit */
|
||||||
|
control |= (nwords<<15) | (nwords<<12); /* dst/src size */
|
||||||
|
control |= (size & 0x7ff); /* transfer size */
|
||||||
|
|
||||||
|
control |= (1<<31); /* current LLI is expected to trigger terminal count interrupt */
|
||||||
|
|
||||||
|
DMAC_CH_CONTROL(channel) = control;
|
||||||
|
|
||||||
|
dma_finished = false;
|
||||||
|
|
||||||
|
/* only needed if DMAC and Peripheral do not run at the same clock speed */
|
||||||
|
DMAC_SYNC |= (1<<peri);
|
||||||
|
|
||||||
|
/* we set the same peripheral as source and destination because we always
|
||||||
|
* use memory-to-peripheral or peripheral-to-memory transfers */
|
||||||
|
DMAC_CH_CONFIGURATION(channel) =
|
||||||
|
(flow_controller<<11) /* flow controller is peripheral */
|
||||||
|
| (1<<15) /* terminal count interrupt mask */
|
||||||
|
| (1<<14) /* interrupt error mask */
|
||||||
|
| (peri<<6) /* dst peripheral */
|
||||||
|
| (peri<<1) /* src peripheral */
|
||||||
|
| (1<<0) /* enable channel */
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* isr */
|
||||||
|
void INT_DMAC(void)
|
||||||
|
{
|
||||||
|
int channel = (DMAC_INT_STATUS & (1<<0)) ? 0 : 1;
|
||||||
|
|
||||||
|
if(DMAC_INT_ERROR_STATUS & (1<<channel))
|
||||||
|
panicf("DMA error, channel %d", channel);
|
||||||
|
|
||||||
|
DMAC_INT_TC_CLEAR |= (1<<channel); /* clear terminal count interrupt */
|
||||||
|
|
||||||
|
dma_finished = true; /* TODO : use struct wakeup ? */
|
||||||
|
}
|
39
firmware/target/arm/as3525/dma-target.h
Normal file
39
firmware/target/arm/as3525/dma-target.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright © 2008 Rafaël Carré
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* DMA request lines (16 max): not specified in AS3525 datasheet, but common to
|
||||||
|
* all AS3525 based models (made by SanDisk) supported by rockbox. */
|
||||||
|
|
||||||
|
#define DMA_PERI_SD_SLOT 2
|
||||||
|
#define DMA_PERI_I2SOUT 3
|
||||||
|
#define DMA_PERI_I2SIN 4
|
||||||
|
#define DMA_PERI_SD 5 /* embedded storage */
|
||||||
|
#define DMA_PERI_DBOP 8
|
||||||
|
|
||||||
|
void dma_init(void);
|
||||||
|
void dma_enable_channel(int channel, void *src, void *dst, int peri,
|
||||||
|
int flow_controller, bool src_inc, bool dst_inc,
|
||||||
|
size_t size, int nwords);
|
||||||
|
|
||||||
|
extern volatile bool dma_finished;
|
|
@ -24,6 +24,7 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "ascodec-target.h"
|
#include "ascodec-target.h"
|
||||||
|
#include "dma-target.h"
|
||||||
|
|
||||||
#define default_interrupt(name) \
|
#define default_interrupt(name) \
|
||||||
extern __attribute__((weak,alias("UIRQ"))) void name (void)
|
extern __attribute__((weak,alias("UIRQ"))) void name (void)
|
||||||
|
@ -220,9 +221,6 @@ void system_init(void)
|
||||||
CGU_PROC = (3<<2)|0x01; /* fclk = PLLA*5/8 = 240 MHz */
|
CGU_PROC = (3<<2)|0x01; /* fclk = PLLA*5/8 = 240 MHz */
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"mrs r0, cpsr \n"
|
|
||||||
"orr r0, r0, #0x80 \n" /* disable interrupts */
|
|
||||||
"msr cpsr, r0 \n"
|
|
||||||
"mov r0, #0 \n"
|
"mov r0, #0 \n"
|
||||||
"mcr p15, 0, r0, c7, c7 \n" /* invalidate icache & dcache */
|
"mcr p15, 0, r0, c7, c7 \n" /* invalidate icache & dcache */
|
||||||
"mrc p15, 0, r0, c1, c0 \n" /* control register */
|
"mrc p15, 0, r0, c1, c0 \n" /* control register */
|
||||||
|
@ -239,15 +237,20 @@ void system_init(void)
|
||||||
CGU_PERI |= CGU_TIMERIF_CLOCK_ENABLE;
|
CGU_PERI |= CGU_TIMERIF_CLOCK_ENABLE;
|
||||||
|
|
||||||
/* enable VIC */
|
/* enable VIC */
|
||||||
|
VIC_INT_ENABLE = 0; /* disable all interrupt lines */
|
||||||
CGU_PERI |= CGU_VIC_CLOCK_ENABLE;
|
CGU_PERI |= CGU_VIC_CLOCK_ENABLE;
|
||||||
VIC_INT_SELECT = 0; /* only IRQ, no FIQ */
|
VIC_INT_SELECT = 0; /* only IRQ, no FIQ */
|
||||||
|
|
||||||
|
enable_irq();
|
||||||
#else
|
#else
|
||||||
/* disable fast hardware power-off, to use power button normally */
|
/* Disable fast hardware power-off, to use power button normally
|
||||||
|
* We don't need the power button in the bootloader. */
|
||||||
ascodec_init();
|
ascodec_init();
|
||||||
ascodec_write(AS3514_CVDD_DCDC3, ascodec_read(AS3514_CVDD_DCDC3) & (1<<2));
|
ascodec_write(AS3514_CVDD_DCDC3, ascodec_read(AS3514_CVDD_DCDC3) & (1<<2));
|
||||||
|
|
||||||
#endif /* BOOTLOADER */
|
#endif /* BOOTLOADER */
|
||||||
|
|
||||||
|
dma_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void system_reboot(void)
|
void system_reboot(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue