Gigabeat S: Implement an SDMA API and use it in the PCM driver. Some other miscellaneous adjustments to recording and PCM buffer to accomodate use of physical addresses and cache coherency.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19949 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
0222d0a5eb
commit
94537f954e
21 changed files with 3002 additions and 141 deletions
|
@ -1001,6 +1001,11 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
|
|||
/* Give 5ms clearance. */
|
||||
bufstart += NATIVE_FREQUENCY * 4 / 200;
|
||||
|
||||
#ifdef HAVE_PCM_DMA_ADDRESS
|
||||
/* Returned peak addresses are DMA addresses */
|
||||
bufend = pcm_dma_addr(bufend);
|
||||
#endif
|
||||
|
||||
/* Wrapped above? */
|
||||
if (bufstart >= bufend)
|
||||
bufstart -= pcmbuf_size;
|
||||
|
|
|
@ -1148,8 +1148,8 @@ static void pcmrec_init(void)
|
|||
|
||||
buffer = audio_get_recording_buffer(&rec_buffer_size);
|
||||
|
||||
/* Line align pcm_buffer 2^4=16 bytes */
|
||||
pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 4);
|
||||
/* Line align pcm_buffer 2^5=32 bytes */
|
||||
pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 5);
|
||||
enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE +
|
||||
PCM_MAX_FEED_SIZE, 2);
|
||||
/* Adjust available buffer for possible align advancement */
|
||||
|
|
|
@ -756,7 +756,6 @@ target/arm/imx31/gigabeat-s/avic-imx31.c
|
|||
target/arm/imx31/gigabeat-s/backlight-imx31.c
|
||||
target/arm/imx31/gigabeat-s/button-imx31.c
|
||||
target/arm/imx31/gigabeat-s/clkctl-imx31.c
|
||||
target/arm/imx31/gigabeat-s/dma_start.c
|
||||
target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/gpio-imx31.c
|
||||
target/arm/imx31/gigabeat-s/kernel-imx31.c
|
||||
|
@ -773,6 +772,7 @@ target/arm/imx31/gigabeat-s/system-imx31.c
|
|||
target/arm/imx31/gigabeat-s/usb-imx31.c
|
||||
target/arm/imx31/gigabeat-s/wmcodec-imx31.c
|
||||
#ifndef BOOTLOADER
|
||||
target/arm/imx31/sdma-imx31.c
|
||||
target/arm/imx31/gigabeat-s/audio-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
|
||||
|
|
|
@ -214,6 +214,8 @@
|
|||
/* Define this if you have adjustable CPU frequency */
|
||||
/* #define HAVE_ADJUSTABLE_CPU_FREQ */
|
||||
|
||||
#define HAVE_PCM_DMA_ADDRESS
|
||||
|
||||
#define BOOTFILE_EXT "gigabeat"
|
||||
#define BOOTFILE "rockbox." BOOTFILE_EXT
|
||||
#define BOOTDIR "/.rockbox"
|
||||
|
|
|
@ -118,6 +118,22 @@
|
|||
#define WDOG1_BASE_ADDR WDOG_BASE_ADDR
|
||||
#define CRM_MCU_BASE_ADDR CCM_BASE_ADDR
|
||||
|
||||
/* IIM */
|
||||
#define IIM_PREV (*(REG32_PTR_T)(IIM_BASE_ADDR + 0x20))
|
||||
#define IIM_PREV_SIG (0x1f << 3)
|
||||
#define IIM_PREV_SIG_IMX31 (0x01 << 3) /* i.MX31 */
|
||||
#define IIM_SREV (*(REG32_PTR_T)(IIM_BASE_ADDR + 0x24))
|
||||
#define IIM_SREV_SREV (0xff << 0)
|
||||
#define IIM_SREV_1_0 0x00 /* i.MX31/L 1.0, L38W */
|
||||
#define IIM_SREV_1_1 0x10 /* i.MX31 1.1, 2L38W */
|
||||
#define IIM_SREV_1_1L 0x11 /* i.MX31L 1.1, 2L38W */
|
||||
#define IIM_SREV_1_15 0x12 /* i.MX31 1.15, 2L38W/3L38W */
|
||||
#define IIM_SREV_1_15L 0x13 /* i.MX31L 1.15, 2L38W/3L38W */
|
||||
#define IIM_SREV_1_2 0x14 /* i.MX31 1.2, 3L38W, M45G */
|
||||
#define IIM_SREV_1_2L 0x15 /* i.MX31L 1.2, 3L38W, M45G */
|
||||
#define IIM_SREV_2_0_1 0x28 /* i.MX31 2.0/2.0.1, M91E */
|
||||
#define IIM_SREV_2_0_1L 0x29 /* i.MX31L 2.0/2.0.1, M91E */
|
||||
|
||||
/* IOMUXC */
|
||||
#define IOMUXC_(o) (*(REG32_PTR_T)(IOMUXC_BASE_ADDR+(o)))
|
||||
|
||||
|
@ -1618,6 +1634,141 @@
|
|||
#define EUARTUTS_RXFULL (1 << 3) // RxFIFO full
|
||||
#define EUARTUTS_SOFTRST (1 << 0) // Software reset
|
||||
|
||||
/* SDMA */
|
||||
#define SDMA_MC0PTR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x000))
|
||||
#define SDMA_INTR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x004))
|
||||
#define SDMA_STOP_STAT (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x008))
|
||||
#define SDMA_HSTART (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x00C))
|
||||
#define SDMA_EVTOVR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x010))
|
||||
#define SDMA_DSPOVR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x014))
|
||||
#define SDMA_HOSTOVR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x018))
|
||||
#define SDMA_EVTPEND (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x01C))
|
||||
#define SDMA_DSPENBL (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x020))
|
||||
#define SDMA_RESET (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x024))
|
||||
#define SDMA_EVTERR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x028))
|
||||
#define SDMA_INTRMSK (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x02C))
|
||||
#define SDMA_PSW (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x030))
|
||||
#define SDMA_EVTERRDBG (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x034))
|
||||
#define SDMA_CONFIG (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x038))
|
||||
#define SDMA_ONCE_ENB (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x040))
|
||||
#define SDMA_ONCE_DATA (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x044))
|
||||
#define SDMA_ONCE_INSTR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x048))
|
||||
#define SDMA_ONCE_STAT (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x04C))
|
||||
#define SDMA_ONCE_CMD (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x050))
|
||||
#define SDMA_EVT_MIRROR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x054))
|
||||
#define SDMA_ILLINSTADDR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x058))
|
||||
#define SDMA_CHN0ADDR (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x05C))
|
||||
#define SDMA_ONCE_RTB (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x060))
|
||||
#define SDMA_XTRIG_CONF1 (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x070))
|
||||
#define SDMA_XTRIG_CONF2 (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x074))
|
||||
|
||||
/* SDMA_CHNENBL: 0x080 - 0x0FC */
|
||||
#define SDMA_CHNENBL(n) (((REG32_PTR_T)(SDMA_BASE_ADDR + 0x080))[n]) /* 0..31 */
|
||||
|
||||
/* SDMA_CHNPRI: 0x100 - 0x17C */
|
||||
#define SDMA_CHNPRI(n) (((REG32_PTR_T)(SDMA_BASE_ADDR + 0x100))[n]) /* 0..31 */
|
||||
|
||||
#define SDMA_ONCE_COUNT (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x200))
|
||||
#define SDMA_ONCE_ECTL (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x204))
|
||||
#define SDMA_ONCE_EAA (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x208))
|
||||
#define SDMA_ONCE_EAB (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x20C))
|
||||
#define SDMA_ONCE_EAM (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x210))
|
||||
#define SDMA_ONCE_ED (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x214))
|
||||
#define SDMA_ONCE_EDM (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x218))
|
||||
#define SDMA_ONCE_PCMATCH (*(REG32_PTR_T)(SDMA_BASE_ADDR + 0x21C))
|
||||
|
||||
/* SDMA_RESET */
|
||||
#define SDMA_RESET_RESCHED (0x1 << 1)
|
||||
#define SDMA_RESET_RESET (0x1 << 0)
|
||||
|
||||
/* SDMA_PSW */
|
||||
#define SDMA_PSW_NCP (0x7 << 13)
|
||||
#define SDMA_PSW_NCR (0x1f << 8)
|
||||
#define SDMA_PSW_CCP (0x7 << 5)
|
||||
#define SDMA_PSW_CCR (0x1f << 0)
|
||||
|
||||
/* SDMA_CONFIG */
|
||||
#define SDMA_CONFIG_DSPDMA (0x1 << 12)
|
||||
#define SDMA_CONFIG_RTDOBS (0x1 << 11)
|
||||
#define SDMA_CONFIG_ACR (0x1 << 4)
|
||||
#define SDMA_CONFIG_CSM (0x3 << 0)
|
||||
#define SDMA_CONFIG_CSM_STATIC (0x0 << 0)
|
||||
#define SDMA_CONFIG_CSM_DYNAMIC_LOW_POWER (0x1 << 0)
|
||||
#define SDMA_CONFIG_CSM_DYNAMIC_NO_LOOP (0x2 << 0)
|
||||
#define SDMA_CONFIG_CSM_DYNAMIC (0x3 << 0)
|
||||
|
||||
/* SDMA_ONCE_ENB */
|
||||
#define SDMA_ONCE_ENB_ENB (0x1 << 0)
|
||||
|
||||
/* SDMA_ONCE_STAT */
|
||||
#define SDMA_ONCE_STAT_PST (0xf << 12)
|
||||
#define SDMA_ONCE_STAT_PST_PROGRAM (0x0 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_DATA (0x1 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_CHANGE_OF_FLOW (0x2 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_CHANGE_OF_FLOW_IN_LOOP (0x3 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_DEBUG (0x4 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_FUNCTIONAL_UNIT (0x5 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_SLEEP (0x6 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_SAVE (0x7 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_PROGRAM_IN_SLEEP (0x8 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_DATA_IN_SLEEP (0x9 << 12)
|
||||
#define SDMA_ONCE_STAT_PST_CHANGE_OF_FLOW_IN_SLEEP (0xa << 12)
|
||||
#define SDMA_ONCE_STAT_PST_CHANGE_OF_FLOW_IN_LOOP_IN_SLEEP (0xb << 12)
|
||||
#define SDMA_ONCE_STAT_PST_DEBUG_IN_SLEEP (0xc << 12)
|
||||
#define SDMA_ONCE_STAT_PST_FUNCTIONAL_UNIT_IN_SLEEP (0xd << 12)
|
||||
#define SDMA_ONCE_STAT_PST_SLEEP_AFTER_RESET (0xe << 12)
|
||||
#define SDMA_ONCE_STAT_PST_RESTORE (0xf << 12)
|
||||
#define SDMA_ONCE_STAT_RCV (0x1 << 11)
|
||||
#define SDMA_ONCE_STAT_EDR (0x1 << 10)
|
||||
#define SDMA_ONCE_STAT_ODR (0x1 << 9)
|
||||
#define SDMA_ONCE_STAT_SWB (0x1 << 8)
|
||||
#define SDMA_ONCE_STAT_MST (0x1 << 7)
|
||||
#define SDMA_ONCE_STAT_ECDR (0x7 << 0)
|
||||
#define SDMA_ONCE_STAT_ECDR_MATCHED_ADDRA_COND (0x1 << 0)
|
||||
#define SDMA_ONCE_STAT_ECDR_MATCHED_ADDRB_COND (0x1 << 1)
|
||||
#define SDMA_ONCE_STAT_ECDR_MATCHED_DATA_COND (0x1 << 2)
|
||||
|
||||
/* SDMA_ONCE_CMD */
|
||||
#define SDMA_ONCE_CMD_RSTATUS 0x0
|
||||
#define SDMA_ONCE_CMD_DMOV 0x1
|
||||
#define SDMA_ONCE_CMD_EXEC_ONCE 0x2
|
||||
#define SDMA_ONCE_CMD_RUN_CORE 0x3
|
||||
#define SDMA_ONCE_CMD_EXEC_CORE 0x4
|
||||
#define SDMA_ONCE_CMD_DEBUG_RQST 0x5
|
||||
#define SDMA_ONCE_CMD_RBUFFER 0x6
|
||||
/* 7-15 reserved */
|
||||
|
||||
/* SDMA_CHN0ADDR */
|
||||
#define SDMA_CHN0ADDR_SMSZ (0x1 << 14)
|
||||
/* 13:0 = 0x0050 by default (std. boot code) */
|
||||
|
||||
/* SDMA_EVT_MIRROR */
|
||||
#define SDMA_EVT_MIRROR_EVENTS(n) (0x1 << (n))
|
||||
|
||||
/* SDMA_XTRIG_CONF1 */
|
||||
#define SDMA_XTRIG_CONF1_CNF3 (0x1 << 30)
|
||||
#define SDMA_XTRIG_CONF1_NUM3 (0x1f << 24)
|
||||
#define SDMA_XTRIG_CONF1_CNF2 (0x1 << 22)
|
||||
#define SDMA_XTRIG_CONF1_NUM2 (0x1f << 16)
|
||||
#define SDMA_XTRIG_CONF1_CNF1 (0x1 << 14)
|
||||
#define SDMA_XTRIG_CONF1_NUM1 (0x1f << 8)
|
||||
#define SDMA_XTRIG_CONF1_CNF0 (0x1 << 6)
|
||||
#define SDMA_XTRIG_CONF1_NUM0 (0x1f << 0)
|
||||
|
||||
/* SDMA_XTRIG_CONF2 */
|
||||
#define SDMA_XTRIG_CONF2_CNF7 (0x1 << 30)
|
||||
#define SDMA_XTRIG_CONF2_NUM7 (0x1f << 24)
|
||||
#define SDMA_XTRIG_CONF2_CNF6 (0x1 << 22)
|
||||
#define SDMA_XTRIG_CONF2_NUM6 (0x1f << 16)
|
||||
#define SDMA_XTRIG_CONF2_CNF5 (0x1 << 14)
|
||||
#define SDMA_XTRIG_CONF2_NUM5 (0x1f << 8)
|
||||
#define SDMA_XTRIG_CONF2_CNF4 (0x1 << 6)
|
||||
#define SDMA_XTRIG_CONF2_NUM4 (0x1f << 0)
|
||||
|
||||
/* SDMA_CHNENBL(n) */
|
||||
#define SDMA_CHNENBL_ENBL(n) (0x1 << (n))
|
||||
|
||||
|
||||
#define L2CC_ENABLED
|
||||
|
||||
/* Assuming 26MHz input clock */
|
||||
|
|
|
@ -90,6 +90,10 @@ extern unsigned long pcm_curr_sampr;
|
|||
extern unsigned long pcm_sampr;
|
||||
extern int pcm_fsel;
|
||||
|
||||
#ifdef HAVE_PCM_DMA_ADDRESS
|
||||
void * pcm_dma_addr(void *addr);
|
||||
#endif
|
||||
|
||||
/* the registered callback function to ask for more mp3 data */
|
||||
extern volatile pcm_more_callback_type pcm_callback_for_more;
|
||||
extern volatile bool pcm_playing;
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
* ==Playback/Recording==
|
||||
* Semi-private -
|
||||
* pcm_dma_apply_settings
|
||||
* pcm_dma_addr
|
||||
*
|
||||
* ==Recording==
|
||||
* Public -
|
||||
|
@ -65,7 +66,7 @@
|
|||
* pcm_rec_dma_stop
|
||||
* pcm_rec_dma_get_peak_buffer
|
||||
* Data Read/Written within TSP -
|
||||
* pcm_rec_peak_addr (R)
|
||||
* pcm_rec_peak_addr (R/W)
|
||||
* pcm_callback_more_ready (R)
|
||||
* pcm_recording (R)
|
||||
*
|
||||
|
|
|
@ -46,6 +46,10 @@ bool __dbg_hw_info(void)
|
|||
while (1)
|
||||
{
|
||||
line = 0;
|
||||
snprintf(buf, sizeof (buf), "Sys Rev Code: 0x%02X",
|
||||
iim_system_rev());
|
||||
lcd_puts(0, line++, buf); line++;
|
||||
|
||||
mpctl = CLKCTL_MPCTL;
|
||||
spctl = CLKCTL_SPCTL;
|
||||
upctl = CLKCTL_UPCTL;
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
#include "cpu.h"
|
||||
#include "clkctl-imx31.h"
|
||||
|
||||
unsigned int imx31_get_src_pll(void)
|
||||
{
|
||||
return (CLKCTL_PMCR0 & 0xC0000000) == 0 ? PLL_SERIAL : PLL_MCU;
|
||||
}
|
||||
|
||||
void imx31_clkctl_module_clock_gating(enum IMX31_CG_LIST cg,
|
||||
enum IMX31_CG_MODES mode)
|
||||
{
|
||||
|
@ -72,8 +77,8 @@ unsigned int imx31_clkctl_get_pll(enum IMX31_PLLS pll)
|
|||
|
||||
unsigned int imx31_clkctl_get_ipg_clk(void)
|
||||
{
|
||||
unsigned int pll = imx31_clkctl_get_pll((CLKCTL_PMCR0 & 0xC0000000) == 0 ?
|
||||
PLL_SERIAL : PLL_MCU);
|
||||
unsigned int pllnum = imx31_get_src_pll();
|
||||
unsigned int pll = imx31_clkctl_get_pll(pllnum);
|
||||
uint32_t reg = CLKCTL_PDR0;
|
||||
unsigned int max_pdf = ((reg >> 3) & 0x7) + 1;
|
||||
unsigned int ipg_pdf = ((reg >> 6) & 0x3) + 1;
|
||||
|
@ -81,6 +86,15 @@ unsigned int imx31_clkctl_get_ipg_clk(void)
|
|||
return pll / (max_pdf * ipg_pdf);
|
||||
}
|
||||
|
||||
unsigned int imx31_clkctl_get_ahb_clk(void)
|
||||
{
|
||||
unsigned int pllnum = imx31_get_src_pll();
|
||||
unsigned int pll = imx31_clkctl_get_pll(pllnum);
|
||||
unsigned int max_pdf = ((CLKCTL_PDR0 >> 3) & 0x7) + 1;
|
||||
|
||||
return pll / max_pdf;
|
||||
}
|
||||
|
||||
unsigned int imx31_clkctl_get_ata_clk(void)
|
||||
{
|
||||
return imx31_clkctl_get_ipg_clk();
|
||||
|
|
|
@ -105,6 +105,9 @@ unsigned int imx31_clkctl_get_pll(enum IMX31_PLLS pll);
|
|||
/* Return ipg_clk in HZ */
|
||||
unsigned int imx31_clkctl_get_ipg_clk(void);
|
||||
|
||||
/* Return ahb_clk in HZ */
|
||||
unsigned int imx31_clkctl_get_ahb_clk(void);
|
||||
|
||||
/* Return the ATA frequency in HZ */
|
||||
unsigned int imx31_clkctl_get_ata_clk(void);
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
void dma_start(const void* addr, size_t size) {
|
||||
(void) addr;
|
||||
(void) size;
|
||||
//TODO:
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include "spi-imx31.h"
|
||||
#include "mc13783.h"
|
||||
#include "clkctl-imx31.h"
|
||||
#include "sdma-imx31.h"
|
||||
#include "kernel.h"
|
||||
#include "thread.h"
|
||||
|
||||
|
@ -64,6 +65,9 @@ void tick_start(unsigned int interval_in_ms)
|
|||
|
||||
void kernel_device_init(void)
|
||||
{
|
||||
#ifndef BOOTLOADER
|
||||
sdma_init();
|
||||
#endif
|
||||
spi_init();
|
||||
mc13783_init();
|
||||
}
|
||||
|
|
|
@ -22,21 +22,12 @@
|
|||
#include "mmu-imx31.h"
|
||||
#include "mmu-arm.h"
|
||||
|
||||
void memory_init(void) {
|
||||
#if 0
|
||||
ttb_init();
|
||||
set_page_tables();
|
||||
enable_mmu();
|
||||
#endif
|
||||
unsigned long addr_virt_to_phys(unsigned long addr)
|
||||
{
|
||||
return addr | CSD0_BASE_ADDR;
|
||||
}
|
||||
|
||||
void set_page_tables() {
|
||||
#if 0
|
||||
map_section(0, 0, 0x1000, CACHE_NONE); /* map every memory region to itself */
|
||||
/*This pa *might* change*/
|
||||
map_section(0x80000000, 0, 64, CACHE_ALL); /* map RAM to 0 and enable caching for it */
|
||||
map_section((int)FRAME1, (int)FRAME1, 1, BUFFERED); /* enable buffered writing for the framebuffer */
|
||||
map_section((int)FRAME2, (int)FRAME2, 1, BUFFERED);
|
||||
#endif
|
||||
unsigned long addr_phys_to_virt(unsigned long addr)
|
||||
{
|
||||
return addr & ~CSD0_BASE_ADDR;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,5 +23,7 @@
|
|||
|
||||
void memory_init(void);
|
||||
void set_page_tables(void);
|
||||
unsigned long addr_virt_to_phys(unsigned long addr);
|
||||
unsigned long addr_phys_to_virt(unsigned long addr);
|
||||
|
||||
#endif /* MMU_IMX31_H */
|
||||
|
|
|
@ -23,78 +23,93 @@
|
|||
#include "kernel.h"
|
||||
#include "audio.h"
|
||||
#include "sound.h"
|
||||
#include "avic-imx31.h"
|
||||
#include "clkctl-imx31.h"
|
||||
#include "sdma-imx31.h"
|
||||
#include "mmu-imx31.h"
|
||||
|
||||
/* This isn't DMA-based at the moment and is handled like Portal Player but
|
||||
* will suffice for starters. */
|
||||
#define DMA_PLAY_CH_NUM 2
|
||||
#define DMA_REC_CH_NUM 1
|
||||
|
||||
static struct buffer_descriptor dma_play_bd DEVBSS_ATTR;
|
||||
static struct channel_descriptor dma_play_cd DEVBSS_ATTR;
|
||||
|
||||
struct dma_data
|
||||
{
|
||||
uint16_t *p;
|
||||
size_t size;
|
||||
int locked;
|
||||
int callback_pending; /* DMA interrupt happened while locked */
|
||||
int state;
|
||||
};
|
||||
|
||||
static struct dma_data dma_play_data =
|
||||
{
|
||||
/* Initialize to a locked, stopped state */
|
||||
.p = NULL,
|
||||
.size = 0,
|
||||
.locked = 0,
|
||||
.callback_pending = 0,
|
||||
.state = 0
|
||||
};
|
||||
|
||||
static void play_dma_callback(void)
|
||||
{
|
||||
unsigned char *start;
|
||||
size_t size;
|
||||
pcm_more_callback_type get_more = pcm_callback_for_more;
|
||||
|
||||
if (dma_play_data.locked)
|
||||
{
|
||||
/* Callback is locked out */
|
||||
dma_play_data.callback_pending = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_more == NULL || (get_more(&start, &size), size == 0))
|
||||
{
|
||||
/* Callback missing or no more DMA to do */
|
||||
pcm_play_dma_stop();
|
||||
pcm_play_dma_stopped_callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
start = (void*)(((unsigned long)start + 3) & ~3);
|
||||
size &= ~3;
|
||||
|
||||
/* Flush any pending cache writes */
|
||||
clean_dcache_range(start, size);
|
||||
dma_play_bd.buf_addr = (void *)addr_virt_to_phys((unsigned long)start);
|
||||
dma_play_bd.mode.count = size;
|
||||
dma_play_bd.mode.command = TRANSFER_16BIT;
|
||||
dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
|
||||
sdma_channel_run(DMA_PLAY_CH_NUM);
|
||||
}
|
||||
}
|
||||
|
||||
void pcm_play_lock(void)
|
||||
{
|
||||
if (++dma_play_data.locked == 1)
|
||||
{
|
||||
/* Atomically disable transmit interrupt */
|
||||
imx31_regclr32(&SSI_SIER1, SSI_SIER_TIE);
|
||||
}
|
||||
imx31_regclr32(&SSI_SIER1, SSI_SIER_TDMAE);
|
||||
}
|
||||
|
||||
void pcm_play_unlock(void)
|
||||
{
|
||||
if (--dma_play_data.locked == 0 && dma_play_data.state != 0)
|
||||
{
|
||||
/* Atomically enable transmit interrupt */
|
||||
imx31_regset32(&SSI_SIER1, SSI_SIER_TIE);
|
||||
}
|
||||
}
|
||||
bool pending = false;
|
||||
int oldstatus = disable_irq_save();
|
||||
|
||||
static void __attribute__((interrupt("IRQ"))) SSI1_HANDLER(void)
|
||||
{
|
||||
register pcm_more_callback_type get_more;
|
||||
|
||||
do
|
||||
{
|
||||
while (dma_play_data.size > 0)
|
||||
if (dma_play_data.callback_pending)
|
||||
{
|
||||
if (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SSI_STX0_1 = *dma_play_data.p++;
|
||||
SSI_STX0_1 = *dma_play_data.p++;
|
||||
dma_play_data.size -= 4;
|
||||
pending = true;
|
||||
dma_play_data.callback_pending = 0;
|
||||
}
|
||||
|
||||
/* p is empty, get some more data */
|
||||
get_more = pcm_callback_for_more;
|
||||
SSI_SIER1 |= SSI_SIER_TDMAE;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
if (get_more)
|
||||
{
|
||||
get_more((unsigned char **)&dma_play_data.p,
|
||||
&dma_play_data.size);
|
||||
}
|
||||
/* Should an interrupt be forced instead? The upper pcm layer can
|
||||
* call producer's callback in thread context so technically this is
|
||||
* acceptable. */
|
||||
if (pending)
|
||||
play_dma_callback();
|
||||
}
|
||||
while (dma_play_data.size > 0);
|
||||
|
||||
/* No more data, so disable the FIFO/interrupt */
|
||||
pcm_play_dma_stop();
|
||||
pcm_play_dma_stopped_callback();
|
||||
}
|
||||
|
||||
void pcm_dma_apply_settings(void)
|
||||
|
@ -104,6 +119,17 @@ void pcm_dma_apply_settings(void)
|
|||
|
||||
void pcm_play_dma_init(void)
|
||||
{
|
||||
/* Init channel information */
|
||||
dma_play_cd.bd_count = 1;
|
||||
dma_play_cd.callback = play_dma_callback;
|
||||
dma_play_cd.shp_addr = SDMA_PER_ADDR_SSI1_TX1;
|
||||
dma_play_cd.wml = SDMA_SSI_TXFIFO_WML*2;
|
||||
dma_play_cd.per_type = SDMA_PER_SSI;
|
||||
dma_play_cd.tran_type = SDMA_TRAN_EMI_2_PER;
|
||||
dma_play_cd.event_id1 = SDMA_REQ_SSI1_TX1;
|
||||
|
||||
sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd);
|
||||
|
||||
imx31_clkctl_module_clock_gating(CG_SSI1, CGM_ON_ALL);
|
||||
imx31_clkctl_module_clock_gating(CG_SSI2, CGM_ON_ALL);
|
||||
|
||||
|
@ -111,8 +137,8 @@ void pcm_play_dma_init(void)
|
|||
SSI_SCR2 &= ~SSI_SCR_SSIEN;
|
||||
SSI_SCR1 &= ~SSI_SCR_SSIEN;
|
||||
|
||||
SSI_SIER1 = SSI_SIER_TFE0; /* TX0 can issue an interrupt */
|
||||
SSI_SIER2 = SSI_SIER_RFF0; /* RX0 can issue an interrupt */
|
||||
SSI_SIER1 = 0;
|
||||
SSI_SIER2 = 0;
|
||||
|
||||
/* Set up audio mux */
|
||||
|
||||
|
@ -155,8 +181,9 @@ void pcm_play_dma_init(void)
|
|||
SSI_STCCR1 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
|
||||
SSI_STRCCR_PMw(4-1);
|
||||
|
||||
/* Transmit low watermark - 2 samples in FIFO */
|
||||
SSI_SFCSR1 = SSI_SFCSR_TFWM1w(1) | SSI_SFCSR_TFWM0w(2);
|
||||
/* Transmit low watermark */
|
||||
SSI_SFCSR1 = (SSI_SFCSR1 & ~SSI_SFCSR_TFWM0) |
|
||||
SSI_SFCSR_TFWM0w(8-SDMA_SSI_TXFIFO_WML);
|
||||
SSI_STMSK1 = 0;
|
||||
|
||||
/* SSI2 - provides MCLK to codec. Receives data from codec. */
|
||||
|
@ -186,8 +213,9 @@ void pcm_play_dma_init(void)
|
|||
SSI_SRCCR2 = SSI_STRCCR_WL16 | SSI_STRCCR_DCw(2-1) |
|
||||
SSI_STRCCR_PMw(4-1);
|
||||
|
||||
/* Receive high watermark - 6 samples in FIFO */
|
||||
SSI_SFCSR2 = SSI_SFCSR_RFWM1w(8) | SSI_SFCSR_RFWM0w(6);
|
||||
/* Receive high watermark */
|
||||
SSI_SFCSR2 = (SSI_SFCSR2 & ~SSI_SFCSR_RFWM0) |
|
||||
SSI_SFCSR_RFWM0w(SDMA_SSI_RXFIFO_WML);
|
||||
SSI_SRMSK2 = 0;
|
||||
|
||||
/* Enable SSI2 (codec clock) */
|
||||
|
@ -199,7 +227,6 @@ void pcm_play_dma_init(void)
|
|||
void pcm_postinit(void)
|
||||
{
|
||||
audiohw_postinit();
|
||||
avic_enable_int(SSI1, IRQ, 8, SSI1_HANDLER);
|
||||
}
|
||||
|
||||
static void play_start_pcm(void)
|
||||
|
@ -207,32 +234,23 @@ static void play_start_pcm(void)
|
|||
/* Stop transmission (if in progress) */
|
||||
SSI_SCR1 &= ~SSI_SCR_TE;
|
||||
|
||||
/* Enable interrupt on unlock */
|
||||
dma_play_data.state = 1;
|
||||
|
||||
/* Fill the FIFO or start when data is used up */
|
||||
SSI_SCR1 |= SSI_SCR_SSIEN; /* Enable SSI */
|
||||
SSI_STCR1 |= SSI_STCR_TFEN0; /* Enable TX FIFO */
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 6 || dma_play_data.size == 0)
|
||||
{
|
||||
SSI_SCR1 |= SSI_SCR_TE; /* Start transmitting */
|
||||
return;
|
||||
}
|
||||
dma_play_data.state = 1; /* Enable DMA requests on unlock */
|
||||
|
||||
SSI_STX0_1 = *dma_play_data.p++;
|
||||
SSI_STX0_1 = *dma_play_data.p++;
|
||||
dma_play_data.size -= 4;
|
||||
}
|
||||
/* Do prefill to prevent swapped channels (see TLSbo61214 in MCIMX31CE).
|
||||
* No actual solution was offered but this appears to work. */
|
||||
SSI_STX0_1 = 0;
|
||||
SSI_STX0_1 = 0;
|
||||
SSI_STX0_1 = 0;
|
||||
SSI_STX0_1 = 0;
|
||||
|
||||
SSI_SCR1 |= SSI_SCR_TE; /* Start transmitting */
|
||||
}
|
||||
|
||||
static void play_stop_pcm(void)
|
||||
{
|
||||
/* Disable interrupt */
|
||||
SSI_SIER1 &= ~SSI_SIER_TIE;
|
||||
|
||||
/* Wait for FIFO to empty */
|
||||
while (SSI_SFCSR_TFCNT0r(SSI_SFCSR1) > 0);
|
||||
|
||||
|
@ -240,135 +258,227 @@ static void play_stop_pcm(void)
|
|||
SSI_STCR1 &= ~SSI_STCR_TFEN0;
|
||||
SSI_SCR1 &= ~(SSI_SCR_TE | SSI_SCR_SSIEN);
|
||||
|
||||
/* Do not enable interrupt on unlock */
|
||||
/* Do not enable DMA requests on unlock */
|
||||
dma_play_data.state = 0;
|
||||
dma_play_data.callback_pending = 0;
|
||||
}
|
||||
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
dma_play_data.p = (void *)(((uintptr_t)addr + 3) & ~3);
|
||||
dma_play_data.size = (size & ~3);
|
||||
sdma_channel_stop(DMA_PLAY_CH_NUM);
|
||||
|
||||
/* Disable transmission */
|
||||
SSI_STCR1 &= ~SSI_STCR_TFEN0;
|
||||
SSI_SCR1 &= ~(SSI_SCR_TE | SSI_SCR_SSIEN);
|
||||
|
||||
addr = (void *)(((unsigned long)addr + 3) & ~3);
|
||||
size &= ~3;
|
||||
|
||||
clean_dcache_range(addr, size);
|
||||
dma_play_bd.buf_addr =
|
||||
(void *)addr_virt_to_phys((unsigned long)(void *)addr);
|
||||
dma_play_bd.mode.count = size;
|
||||
dma_play_bd.mode.command = TRANSFER_16BIT;
|
||||
dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
|
||||
|
||||
play_start_pcm();
|
||||
sdma_channel_start(DMA_PLAY_CH_NUM);
|
||||
}
|
||||
|
||||
void pcm_play_dma_stop(void)
|
||||
{
|
||||
sdma_channel_stop(DMA_PLAY_CH_NUM);
|
||||
play_stop_pcm();
|
||||
dma_play_data.size = 0;
|
||||
}
|
||||
|
||||
void pcm_play_dma_pause(bool pause)
|
||||
{
|
||||
if (pause)
|
||||
{
|
||||
sdma_channel_pause(DMA_PLAY_CH_NUM);
|
||||
play_stop_pcm();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t addr = (uint32_t)dma_play_data.p;
|
||||
dma_play_data.p = (void *)((addr + 2) & ~3);
|
||||
dma_play_data.size &= ~3;
|
||||
play_start_pcm();
|
||||
sdma_channel_run(DMA_PLAY_CH_NUM);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of bytes waiting - full L-R sample pairs only */
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
{
|
||||
return dma_play_data.size & ~3;
|
||||
static unsigned long dsa DEVBSS_ATTR;
|
||||
long offs, size;
|
||||
int oldstatus;
|
||||
|
||||
/* read burst dma source address register in channel context */
|
||||
sdma_read_words(&dsa, CHANNEL_CONTEXT_ADDR(DMA_PLAY_CH_NUM)+0x0b, 1);
|
||||
|
||||
oldstatus = disable_irq_save();
|
||||
offs = dsa - (unsigned long)dma_play_bd.buf_addr;
|
||||
size = dma_play_bd.mode.count;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
/* Be addresses are coherent (no buffer change during read) */
|
||||
if (offs >= 0 && offs < size)
|
||||
{
|
||||
return (size - offs) & ~3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a pointer to the samples and the number of them in *count */
|
||||
const void * pcm_play_dma_get_peak_buffer(int *count)
|
||||
{
|
||||
uint32_t addr = (uint32_t)dma_play_data.p;
|
||||
size_t cnt = dma_play_data.size;
|
||||
*count = cnt >> 2;
|
||||
return (void *)((addr + 2) & ~3);
|
||||
static unsigned long dsa DEVBSS_ATTR;
|
||||
unsigned long addr;
|
||||
long offs, size;
|
||||
int oldstatus;
|
||||
|
||||
/* read burst dma source address register in channel context */
|
||||
sdma_read_words(&dsa, CHANNEL_CONTEXT_ADDR(DMA_PLAY_CH_NUM)+0x0b, 1);
|
||||
|
||||
oldstatus = disable_irq_save();
|
||||
addr = dsa;
|
||||
offs = addr - (unsigned long)dma_play_bd.buf_addr;
|
||||
size = dma_play_bd.mode.count;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
/* Be addresses are coherent (no buffer change during read) */
|
||||
if (offs >= 0 && offs < size)
|
||||
{
|
||||
*count = (size - offs) >> 2;
|
||||
return (void *)((addr + 2) & ~3);
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * pcm_dma_addr(void *addr)
|
||||
{
|
||||
return (void *)addr_virt_to_phys((unsigned long)addr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_RECORDING
|
||||
static struct buffer_descriptor dma_rec_bd DEVBSS_ATTR;
|
||||
static struct channel_descriptor dma_rec_cd DEVBSS_ATTR;
|
||||
|
||||
static struct dma_data dma_rec_data =
|
||||
{
|
||||
/* Initialize to a locked, stopped state */
|
||||
.p = NULL,
|
||||
.size = 0,
|
||||
.locked = 0,
|
||||
.state = 0
|
||||
};
|
||||
|
||||
static void __attribute__((interrupt("IRQ"))) SSI2_HANDLER(void)
|
||||
static void rec_dma_callback(void)
|
||||
{
|
||||
register pcm_more_callback_type2 more_ready;
|
||||
pcm_more_callback_type2 more_ready;
|
||||
int status = 0;
|
||||
|
||||
while (dma_rec_data.size > 0)
|
||||
if (dma_rec_data.locked)
|
||||
{
|
||||
if (SSI_SFCSR_RFCNT0r(SSI_SFCSR2) < 2)
|
||||
return;
|
||||
|
||||
*dma_rec_data.p++ = SSI_SRX0_2;
|
||||
*dma_rec_data.p++ = SSI_SRX0_2;
|
||||
dma_rec_data.size -= 4;
|
||||
dma_rec_data.callback_pending = 1;
|
||||
return; /* Callback is locked out */
|
||||
}
|
||||
|
||||
if (dma_rec_bd.mode.status & BD_RROR)
|
||||
status = DMA_REC_ERROR_DMA;
|
||||
|
||||
more_ready = pcm_callback_more_ready;
|
||||
|
||||
if (more_ready == NULL || more_ready(0) < 0) {
|
||||
/* Finished recording */
|
||||
pcm_rec_dma_stop();
|
||||
pcm_rec_dma_stopped_callback();
|
||||
if (more_ready != NULL && more_ready(status) >= 0)
|
||||
{
|
||||
sdma_channel_run(DMA_REC_CH_NUM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finished recording */
|
||||
pcm_rec_dma_stop();
|
||||
pcm_rec_dma_stopped_callback();
|
||||
}
|
||||
|
||||
void pcm_rec_lock(void)
|
||||
{
|
||||
if (++dma_rec_data.locked == 1)
|
||||
{
|
||||
/* Atomically disable receive interrupt */
|
||||
imx31_regclr32(&SSI_SIER2, SSI_SIER_RIE);
|
||||
}
|
||||
imx31_regclr32(&SSI_SIER2, SSI_SIER_RDMAE);
|
||||
}
|
||||
|
||||
void pcm_rec_unlock(void)
|
||||
{
|
||||
if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
|
||||
{
|
||||
/* Atomically enable receive interrupt */
|
||||
imx31_regset32(&SSI_SIER2, SSI_SIER_RIE);
|
||||
bool pending = false;
|
||||
int oldstatus = disable_irq_save();
|
||||
|
||||
if (dma_rec_data.callback_pending)
|
||||
{
|
||||
pending = true;
|
||||
dma_rec_data.callback_pending = 0;
|
||||
}
|
||||
|
||||
SSI_SIER2 |= SSI_SIER_RDMAE;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
/* Should an interrupt be forced instead? The upper pcm layer can
|
||||
* call consumer's callback in thread context so technically this is
|
||||
* acceptable. */
|
||||
if (pending)
|
||||
rec_dma_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void pcm_record_more(void *start, size_t size)
|
||||
{
|
||||
pcm_rec_peak_addr = start; /* Start peaking at dest */
|
||||
dma_rec_data.p = start; /* Start of RX buffer */
|
||||
dma_rec_data.size = size; /* Bytes to transfer */
|
||||
start = (void *)(((unsigned long)start + 3) & ~3);
|
||||
size &= ~3;
|
||||
|
||||
/* Write back and invalidate - buffer must be coherent */
|
||||
invalidate_dcache_range(start, size);
|
||||
|
||||
start = (void *)addr_virt_to_phys((unsigned long)start);
|
||||
|
||||
pcm_rec_peak_addr = start;
|
||||
dma_rec_bd.buf_addr = start;
|
||||
dma_rec_bd.mode.count = size;
|
||||
dma_rec_bd.mode.command = TRANSFER_16BIT;
|
||||
dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
|
||||
}
|
||||
|
||||
void pcm_rec_dma_stop(void)
|
||||
{
|
||||
/* Stop receiving data */
|
||||
sdma_channel_stop(DMA_REC_CH_NUM);
|
||||
|
||||
imx31_regclr32(&SSI_SIER2, SSI_SIER_RDMAE);
|
||||
|
||||
SSI_SCR2 &= ~SSI_SCR_RE; /* Disable RX */
|
||||
SSI_SRCR2 &= ~SSI_SRCR_RFEN0; /* Disable RX FIFO */
|
||||
|
||||
dma_rec_data.state = 0;
|
||||
|
||||
avic_disable_int(SSI2);
|
||||
dma_rec_data.callback_pending = 0;
|
||||
}
|
||||
|
||||
void pcm_rec_dma_start(void *addr, size_t size)
|
||||
{
|
||||
pcm_rec_dma_stop();
|
||||
|
||||
addr = (void *)(((unsigned long)addr + 3) & ~3);
|
||||
size &= ~3;
|
||||
|
||||
invalidate_dcache_range(addr, size);
|
||||
|
||||
addr = (void *)addr_virt_to_phys((unsigned long)addr);
|
||||
pcm_rec_peak_addr = addr;
|
||||
dma_rec_data.p = addr;
|
||||
dma_rec_data.size = size;
|
||||
dma_rec_bd.buf_addr = addr;
|
||||
dma_rec_bd.mode.count = size;
|
||||
dma_rec_bd.mode.command = TRANSFER_16BIT;
|
||||
dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
|
||||
|
||||
dma_rec_data.state = 1;
|
||||
|
||||
avic_enable_int(SSI2, IRQ, 9, SSI2_HANDLER);
|
||||
|
||||
SSI_SRCR2 |= SSI_SRCR_RFEN0; /* Enable RX FIFO */
|
||||
|
||||
/* Ensure clear FIFO */
|
||||
|
@ -377,24 +487,58 @@ void pcm_rec_dma_start(void *addr, size_t size)
|
|||
|
||||
/* Enable receive */
|
||||
SSI_SCR2 |= SSI_SCR_RE;
|
||||
|
||||
sdma_channel_start(DMA_REC_CH_NUM);
|
||||
}
|
||||
|
||||
void pcm_rec_dma_close(void)
|
||||
{
|
||||
pcm_rec_dma_stop();
|
||||
sdma_channel_close(DMA_REC_CH_NUM);
|
||||
}
|
||||
|
||||
void pcm_rec_dma_init(void)
|
||||
{
|
||||
pcm_rec_dma_stop();
|
||||
|
||||
/* Init channel information */
|
||||
dma_rec_cd.bd_count = 1;
|
||||
dma_rec_cd.callback = rec_dma_callback;
|
||||
dma_rec_cd.shp_addr = SDMA_PER_ADDR_SSI2_RX1;
|
||||
dma_rec_cd.wml = SDMA_SSI_RXFIFO_WML*2;
|
||||
dma_rec_cd.per_type = SDMA_PER_SSI;
|
||||
dma_rec_cd.tran_type = SDMA_TRAN_PER_2_EMI;
|
||||
dma_rec_cd.event_id1 = SDMA_REQ_SSI2_RX1;
|
||||
|
||||
sdma_channel_init(DMA_REC_CH_NUM, &dma_rec_cd, &dma_rec_bd);
|
||||
}
|
||||
|
||||
const void * pcm_rec_dma_get_peak_buffer(int *count)
|
||||
{
|
||||
unsigned long addr = (uint32_t)pcm_rec_peak_addr;
|
||||
unsigned long end = (uint32_t)dma_rec_data.p;
|
||||
*count = (end >> 2) - (addr >> 2);
|
||||
return (void *)(addr & ~3);
|
||||
static unsigned long pda DEVBSS_ATTR;
|
||||
unsigned long buf, addr, end, bufend;
|
||||
int oldstatus;
|
||||
|
||||
/* read burst dma destination address register in channel context */
|
||||
sdma_read_words(&pda, CHANNEL_CONTEXT_ADDR(DMA_REC_CH_NUM)+0x0a, 1);
|
||||
|
||||
oldstatus = disable_irq_save();
|
||||
end = pda;
|
||||
buf = (unsigned long)dma_rec_bd.buf_addr;
|
||||
addr = (unsigned long)pcm_rec_peak_addr;
|
||||
bufend = buf + dma_rec_bd.mode.count;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
/* Be addresses are coherent (no buffer change during read) */
|
||||
if (addr >= buf && addr < bufend &&
|
||||
end >= buf && end < bufend)
|
||||
{
|
||||
*count = (end >> 2) - (addr >> 2);
|
||||
return (void *)(addr & ~3);
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* HAVE_RECORDING */
|
||||
|
|
|
@ -32,6 +32,28 @@
|
|||
#include "clkctl-imx31.h"
|
||||
#include "mc13783.h"
|
||||
|
||||
static unsigned long product_rev;
|
||||
static unsigned long system_rev;
|
||||
|
||||
/** IC revision info routines **/
|
||||
unsigned int iim_system_rev(void)
|
||||
{
|
||||
return system_rev & IIM_SREV_SREV;
|
||||
}
|
||||
|
||||
unsigned int iim_prod_rev(void)
|
||||
{
|
||||
return product_rev;
|
||||
}
|
||||
|
||||
static void iim_init(void)
|
||||
{
|
||||
/* Initialize the IC revision info (required by SDMA) */
|
||||
imx31_clkctl_module_clock_gating(CG_IIM, CGM_ON_ALL);
|
||||
product_rev = IIM_PREV;
|
||||
system_rev = IIM_SREV;
|
||||
}
|
||||
|
||||
/** Watchdog timer routines **/
|
||||
|
||||
/* Initialize the watchdog timer */
|
||||
|
@ -155,6 +177,8 @@ void system_init(void)
|
|||
/* MCR WFI enables wait mode */
|
||||
CLKCTL_CCMR &= ~(3 << 14);
|
||||
|
||||
iim_init();
|
||||
|
||||
imx31_regset32(&SDHC1_CLOCK_CONTROL, STOP_CLK);
|
||||
imx31_regset32(&SDHC2_CLOCK_CONTROL, STOP_CLK);
|
||||
imx31_regset32(&RNGA_CONTROL, RNGA_CONTROL_SLEEP);
|
||||
|
|
|
@ -43,6 +43,8 @@ void watchdog_service(void);
|
|||
void gpt_start(void);
|
||||
void gpt_stop(void);
|
||||
|
||||
unsigned int iim_system_rev(void);
|
||||
|
||||
/* Prepare for transition to firmware */
|
||||
void system_prepare_fw_start(void);
|
||||
void tick_stop(void);
|
||||
|
|
807
firmware/target/arm/imx31/sdma-imx31.c
Normal file
807
firmware/target/arm/imx31/sdma-imx31.c
Normal file
|
@ -0,0 +1,807 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 by Michael Sevakis
|
||||
*
|
||||
* 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 "config.h"
|
||||
#include "system.h"
|
||||
#include <string.h>
|
||||
#include "logf.h"
|
||||
#include "panic.h"
|
||||
#include "clkctl-imx31.h"
|
||||
#include "avic-imx31.h"
|
||||
#include "sdma_struct.h"
|
||||
#include "sdma-imx31.h"
|
||||
#include "sdma_script_code.h"
|
||||
#include "mmu-imx31.h"
|
||||
|
||||
/* Most of the code in here is based upon the Linux BSP provided by Freescale
|
||||
* Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. */
|
||||
|
||||
/* Cut down to bare bones essentials */
|
||||
|
||||
/* Script information that depends on system revision */
|
||||
static struct sdma_script_start_addrs script_info;
|
||||
/* Mask of channels with callback enabled */
|
||||
static unsigned long sdma_enabled_ints = 0;
|
||||
/* One channel control block per channel in physically mapped device RAM */
|
||||
static struct channel_control_block ccb_array[CH_NUM] DEVBSS_ATTR;
|
||||
/* Channel 0 (command channel) data */
|
||||
static struct buffer_descriptor_extd c0_buffer_desc DEVBSS_ATTR;
|
||||
|
||||
/* All SDMA channel interrupts are handled here.
|
||||
* Dispatches lower channel numbers first (prioritized by SDMA API callers
|
||||
* who specify the desired channel number).
|
||||
*/
|
||||
static void __attribute__((interrupt("IRQ"))) SDMA_HANDLER(void)
|
||||
{
|
||||
unsigned long pending = SDMA_INTR;
|
||||
|
||||
SDMA_INTR = pending; /* Ack all ints */
|
||||
pending &= sdma_enabled_ints; /* Only dispatch ints with callback */
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned int channel;
|
||||
|
||||
if (pending == 0)
|
||||
break; /* No bits set */
|
||||
|
||||
channel = find_first_set_bit(pending);
|
||||
|
||||
pending &= ~(1ul << channel);
|
||||
|
||||
/* Call callback (required if using an interrupt) */
|
||||
ccb_array[channel].channel_desc->callback();
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize script information based upon the system revision */
|
||||
static void init_script_info(void)
|
||||
{
|
||||
if (iim_system_rev() == IIM_SREV_1_0)
|
||||
{
|
||||
/* Channel script info */
|
||||
script_info.app_2_mcu_addr = app_2_mcu_ADDR_1;
|
||||
script_info.ap_2_ap_addr = ap_2_ap_ADDR_1;
|
||||
script_info.ap_2_bp_addr = -1;
|
||||
script_info.bp_2_ap_addr = -1;
|
||||
script_info.loopback_on_dsp_side_addr = -1;
|
||||
script_info.mcu_2_app_addr = mcu_2_app_ADDR_1;
|
||||
script_info.mcu_2_shp_addr = mcu_2_shp_ADDR_1;
|
||||
script_info.mcu_interrupt_only_addr = -1;
|
||||
script_info.shp_2_mcu_addr = shp_2_mcu_ADDR_1;
|
||||
script_info.uartsh_2_mcu_addr = uartsh_2_mcu_ADDR_1;
|
||||
script_info.uart_2_mcu_addr = uart_2_mcu_ADDR_1;
|
||||
script_info.dptc_dvfs_addr = dptc_dvfs_ADDR_1;
|
||||
script_info.firi_2_mcu_addr = firi_2_mcu_ADDR_1;
|
||||
script_info.firi_2_per_addr = -1;
|
||||
script_info.mshc_2_mcu_addr = mshc_2_mcu_ADDR_1;
|
||||
script_info.per_2_app_addr = -1;
|
||||
script_info.per_2_firi_addr = -1;
|
||||
script_info.per_2_shp_addr = -1;
|
||||
script_info.mcu_2_ata_addr = mcu_2_ata_ADDR_1;
|
||||
script_info.mcu_2_firi_addr = mcu_2_firi_ADDR_1;
|
||||
script_info.mcu_2_mshc_addr = mcu_2_mshc_ADDR_1;
|
||||
script_info.ata_2_mcu_addr = ata_2_mcu_ADDR_1;
|
||||
script_info.uartsh_2_per_addr = -1;
|
||||
script_info.shp_2_per_addr = -1;
|
||||
script_info.uart_2_per_addr = -1;
|
||||
script_info.app_2_per_addr = -1;
|
||||
/* Main code block info */
|
||||
script_info.ram_code_size = RAM_CODE_SIZE_1;
|
||||
script_info.ram_code_start_addr = RAM_CODE_START_ADDR_1;
|
||||
script_info.mcu_start_addr = (unsigned long)sdma_code_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Channel script info */
|
||||
script_info.app_2_mcu_addr = app_2_mcu_patched_ADDR_2;
|
||||
script_info.ap_2_ap_addr = ap_2_ap_ADDR_2;
|
||||
script_info.ap_2_bp_addr = ap_2_bp_ADDR_2;
|
||||
script_info.bp_2_ap_addr = bp_2_ap_ADDR_2;
|
||||
script_info.loopback_on_dsp_side_addr = -1;
|
||||
script_info.mcu_2_app_addr = mcu_2_app_ADDR_2;
|
||||
script_info.mcu_2_shp_addr = mcu_2_shp_patched_ADDR_2;
|
||||
script_info.mcu_interrupt_only_addr = -1;
|
||||
script_info.shp_2_mcu_addr = shp_2_mcu_patched_ADDR_2;
|
||||
script_info.uartsh_2_mcu_addr = uartsh_2_mcu_patched_ADDR_2;
|
||||
script_info.uart_2_mcu_addr = uart_2_mcu_patched_ADDR_2;
|
||||
script_info.dptc_dvfs_addr = -1;
|
||||
script_info.firi_2_mcu_addr = firi_2_mcu_ADDR_2;
|
||||
script_info.firi_2_per_addr = -1;
|
||||
script_info.mshc_2_mcu_addr = -1;
|
||||
script_info.per_2_app_addr = -1;
|
||||
script_info.per_2_firi_addr = -1;
|
||||
script_info.per_2_shp_addr = per_2_shp_ADDR_2;
|
||||
script_info.mcu_2_ata_addr = mcu_2_ata_ADDR_2;
|
||||
script_info.mcu_2_firi_addr = mcu_2_firi_ADDR_2;
|
||||
script_info.mcu_2_mshc_addr = -1;
|
||||
script_info.ata_2_mcu_addr = ata_2_mcu_ADDR_2;
|
||||
script_info.uartsh_2_per_addr = -1;
|
||||
script_info.shp_2_per_addr = shp_2_per_ADDR_2;
|
||||
script_info.uart_2_per_addr = -1;
|
||||
script_info.app_2_per_addr = -1;
|
||||
/* Main code block info */
|
||||
script_info.ram_code_size = RAM_CODE_SIZE_2;
|
||||
script_info.ram_code_start_addr = RAM_CODE_START_ADDR_2;
|
||||
script_info.mcu_start_addr = (unsigned long)sdma_code_2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return pc of SDMA script in SDMA halfword space according to peripheral
|
||||
* and transfer type */
|
||||
static unsigned long get_script_pc(unsigned int peripheral_type,
|
||||
unsigned int transfer_type)
|
||||
{
|
||||
unsigned long res = (unsigned short)-1;
|
||||
|
||||
switch (peripheral_type)
|
||||
{
|
||||
case SDMA_PER_MEMORY:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_EMI_2_INT:
|
||||
case SDMA_TRAN_EMI_2_EMI:
|
||||
case SDMA_TRAN_INT_2_EMI:
|
||||
res = script_info.ap_2_ap_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_PER_DSP:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_EMI_2_DSP:
|
||||
res = script_info.ap_2_bp_addr;
|
||||
break;
|
||||
case SDMA_TRAN_DSP_2_EMI:
|
||||
res = script_info.bp_2_ap_addr;
|
||||
break;
|
||||
case SDMA_TRAN_DSP_2_EMI_LOOP:
|
||||
res = script_info.loopback_on_dsp_side_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_DSP_LOOP:
|
||||
res = script_info.mcu_interrupt_only_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_PER_FIRI:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_INT:
|
||||
res = script_info.firi_2_per_addr;
|
||||
break;
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.firi_2_mcu_addr;
|
||||
break;
|
||||
case SDMA_TRAN_INT_2_PER:
|
||||
res = script_info.per_2_firi_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
res = script_info.mcu_2_firi_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_PER_UART:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_INT:
|
||||
res = script_info.uart_2_per_addr;
|
||||
break;
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.uart_2_mcu_addr;
|
||||
break;
|
||||
case SDMA_TRAN_INT_2_PER:
|
||||
res = script_info.per_2_app_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
res = script_info.mcu_2_app_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_PER_UART_SP:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_INT:
|
||||
res = script_info.uartsh_2_per_addr;
|
||||
break;
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.uartsh_2_mcu_addr;
|
||||
break;
|
||||
case SDMA_TRAN_INT_2_PER:
|
||||
res = script_info.per_2_shp_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
res = script_info.mcu_2_shp_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SDMA_PER_ATA:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.ata_2_mcu_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
res = script_info.mcu_2_ata_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDMA_PER_CSPI:
|
||||
case SDMA_PER_EXT:
|
||||
case SDMA_PER_SSI:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_INT:
|
||||
res = script_info.app_2_per_addr;
|
||||
break;
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.app_2_mcu_addr;
|
||||
break;
|
||||
case SDMA_TRAN_INT_2_PER:
|
||||
res = script_info.per_2_app_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
res = script_info.mcu_2_app_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_PER_MMC:
|
||||
case SDMA_PER_SDHC:
|
||||
#endif
|
||||
case SDMA_PER_SSI_SP:
|
||||
case SDMA_PER_CSPI_SP:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_INT:
|
||||
res = script_info.shp_2_per_addr;
|
||||
break;
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.shp_2_mcu_addr;
|
||||
break;
|
||||
case SDMA_TRAN_INT_2_PER:
|
||||
res = script_info.per_2_shp_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
res = script_info.mcu_2_shp_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case SDMA_PER_MSHC:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.mshc_2_mcu_addr;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
res = script_info.mcu_2_mshc_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case SDMA_PER_CCM:
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
res = script_info.dptc_dvfs_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == (unsigned short)-1)
|
||||
{
|
||||
logf("SDMA script not found\n");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned int get_config(unsigned int transfer_type)
|
||||
{
|
||||
unsigned int res = -1;
|
||||
|
||||
switch (transfer_type)
|
||||
{
|
||||
case SDMA_TRAN_PER_2_INT:
|
||||
case SDMA_TRAN_PER_2_EMI:
|
||||
case SDMA_TRAN_INT_2_PER:
|
||||
case SDMA_TRAN_EMI_2_PER:
|
||||
/*
|
||||
* Peripheral <------> Memory
|
||||
* evtOvr = 0 mcuOvr = 0 dspOvr = 1
|
||||
*/
|
||||
res = CH_OWNSHP_MCU | CH_OWNSHP_EVT;
|
||||
break;
|
||||
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_TRAN_DSP_2_PER:
|
||||
res = 0;
|
||||
break;
|
||||
case SDMA_TRAN_EMI_2_DSP:
|
||||
case SDMA_TRAN_INT_2_DSP:
|
||||
case SDMA_TRAN_DSP_2_INT:
|
||||
case SDMA_TRAN_DSP_2_EMI:
|
||||
case SDMA_TRAN_DSP_2_DSP:
|
||||
/*
|
||||
* DSP <-----------> Memory
|
||||
* evtOvr = 1 mcuOvr = 0 dspOvr = 0
|
||||
*/
|
||||
res = CH_OWNSHP_MCU | CH_OWNSHP_DSP;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SDMA_TRAN_EMI_2_INT:
|
||||
case SDMA_TRAN_EMI_2_EMI:
|
||||
case SDMA_TRAN_INT_2_INT:
|
||||
case SDMA_TRAN_INT_2_EMI:
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_TRAN_DSP_2_EMI_LOOP:
|
||||
case SDMA_TRAN_EMI_2_DSP_LOOP:
|
||||
#endif
|
||||
/* evtOvr = 1 mcuOvr = 0 dspOvr = 1 */
|
||||
res = CH_OWNSHP_MCU;
|
||||
break;
|
||||
|
||||
#if 0 /* Not using this */
|
||||
case SDMA_TRAN_PER_2_DSP:
|
||||
/* evtOvr = 0 mcuOvr = 1 dspOvr = 0 */
|
||||
res = CH_OWNSHP_DSP | CH_OWNSHP_EVT;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Fill the buffer descriptor with the values given in parameter.
|
||||
* Expects physical addresses. */
|
||||
static inline void set_buffer_descriptor(
|
||||
struct buffer_descriptor *bd_p,
|
||||
unsigned int command, /* C0_* command or transfer size */
|
||||
unsigned int status, /* BD_* flags */
|
||||
unsigned int count, /* Size of buffer to transfer */
|
||||
void *buf_addr, /* Buffer to transfer */
|
||||
void *buf_addr_ext)
|
||||
{
|
||||
bd_p->mode.command = command;
|
||||
bd_p->mode.status = status;
|
||||
bd_p->mode.count = count;
|
||||
bd_p->buf_addr = buf_addr;
|
||||
if (status & BD_EXTD)
|
||||
((struct buffer_descriptor_extd *)bd_p)->buf_addr_ext = buf_addr_ext;
|
||||
}
|
||||
|
||||
/* Configure channel ownership */
|
||||
static void set_channel_ownership(unsigned int channel, unsigned int config)
|
||||
{
|
||||
unsigned long bit = 1ul << channel;
|
||||
|
||||
/* DSP side */
|
||||
#if 0 /* Not using this */
|
||||
imx31_regmod32(&SDMA_DSPOVR, (config & CH_OWNSHP_DSP) ? 0 : bit, bit);
|
||||
#endif
|
||||
/* Event */
|
||||
imx31_regmod32(&SDMA_EVTOVR, (config & CH_OWNSHP_EVT) ? 0 : bit, bit);
|
||||
/* MCU side */
|
||||
imx31_regmod32(&SDMA_HOSTOVR, (config & CH_OWNSHP_MCU) ? 0 : bit, bit);
|
||||
}
|
||||
|
||||
static bool setup_channel(struct channel_control_block *ccb_p)
|
||||
{
|
||||
static struct context_data context_buffer DEVBSS_ATTR;
|
||||
struct channel_descriptor *cd_p;
|
||||
unsigned int channel_cfg;
|
||||
unsigned int channel;
|
||||
unsigned long pc;
|
||||
|
||||
memset(&context_buffer, 0x00, sizeof (context_buffer));
|
||||
|
||||
channel = ccb_p - ccb_array;
|
||||
cd_p = ccb_p->channel_desc;
|
||||
|
||||
/* Obtain script start address for perihperal and transfer type */
|
||||
pc = get_script_pc(cd_p->per_type, cd_p->tran_type);
|
||||
|
||||
if (pc == (unsigned short)-1)
|
||||
return false; /* Failed to find a script */
|
||||
|
||||
context_buffer.channel_state.pc = pc;
|
||||
|
||||
if (cd_p->per_type != SDMA_PER_MEMORY && cd_p->per_type != SDMA_PER_DSP)
|
||||
{
|
||||
/* Set peripheral DMA request mask for this channel */
|
||||
context_buffer.event_mask1 = 1ul << cd_p->event_id1;
|
||||
|
||||
if (cd_p->per_type == SDMA_PER_ATA)
|
||||
{
|
||||
/* ATA has two */
|
||||
context_buffer.event_mask2 = 1ul << cd_p->event_id2;
|
||||
}
|
||||
|
||||
context_buffer.shp_addr = cd_p->shp_addr;
|
||||
context_buffer.wml = cd_p->wml;
|
||||
}
|
||||
else
|
||||
{
|
||||
context_buffer.wml = SDMA_PER_ADDR_SDRAM;
|
||||
}
|
||||
|
||||
/* Send channel context to SDMA core */
|
||||
clean_dcache_range(&context_buffer, sizeof (context_buffer));
|
||||
sdma_write_words((unsigned long *)&context_buffer,
|
||||
CHANNEL_CONTEXT_ADDR(channel),
|
||||
sizeof (context_buffer)/4);
|
||||
|
||||
if (cd_p->is_setup != 0)
|
||||
return true; /* No more to do */
|
||||
|
||||
/* Obtain channel ownership configuration */
|
||||
channel_cfg = get_config(cd_p->tran_type);
|
||||
|
||||
if (channel_cfg == (unsigned int)-1)
|
||||
return false;
|
||||
|
||||
/* Set who owns it and thus can activate it */
|
||||
set_channel_ownership(channel, channel_cfg);
|
||||
|
||||
if (channel_cfg & CH_OWNSHP_EVT)
|
||||
{
|
||||
/* Set event ID to channel activation bitmapping */
|
||||
imx31_regset32(&SDMA_CHNENBL(cd_p->event_id1), 1ul << channel);
|
||||
|
||||
if (cd_p->per_type == SDMA_PER_ATA)
|
||||
{
|
||||
/* ATA has two */
|
||||
imx31_regset32(&SDMA_CHNENBL(cd_p->event_id2), 1ul << channel);
|
||||
}
|
||||
}
|
||||
|
||||
cd_p->is_setup = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Public routines **/
|
||||
void sdma_init(void)
|
||||
{
|
||||
imx31_clkctl_module_clock_gating(CG_SDMA, CGM_ON_RUN_WAIT);
|
||||
int i;
|
||||
unsigned long acr;
|
||||
|
||||
/* Reset the controller */
|
||||
SDMA_RESET |= SDMA_RESET_RESET;
|
||||
while (SDMA_RESET & SDMA_RESET_RESET);
|
||||
|
||||
init_script_info();
|
||||
|
||||
/* No channel enabled, all priorities 0 */
|
||||
for (i = 0; i < CH_NUM; i++)
|
||||
{
|
||||
SDMA_CHNENBL(i) = 0;
|
||||
SDMA_CHNPRI(i) = 0;
|
||||
}
|
||||
|
||||
/* Ensure no ints pending */
|
||||
SDMA_INTR = 0xffffffff;
|
||||
|
||||
/* Nobody owns any channel (yet) */
|
||||
SDMA_HOSTOVR = 0xffffffff;
|
||||
SDMA_DSPOVR = 0xffffffff;
|
||||
SDMA_EVTOVR = 0xffffffff;
|
||||
|
||||
SDMA_MC0PTR = 0x00000000;
|
||||
|
||||
/* 32-word channel contexts, use default bootscript address */
|
||||
SDMA_CHN0ADDR = SDMA_CHN0ADDR_SMSZ | 0x0050;
|
||||
|
||||
avic_enable_int(SDMA, IRQ, 8, SDMA_HANDLER);
|
||||
|
||||
/* SDMA core must run at the proper frequency based upon the AHB/IPG ratio */
|
||||
acr = (imx31_clkctl_get_ahb_clk() / imx31_clkctl_get_ipg_clk()) < 2 ?
|
||||
SDMA_CONFIG_ACR : 0;
|
||||
|
||||
/* No dsp, no debug
|
||||
* Static context switching - TLSbo86520L SW Workaround for SDMA Chnl0
|
||||
* access issue */
|
||||
SDMA_CONFIG = acr;
|
||||
|
||||
/* Tell SDMA where the host channel table is */
|
||||
SDMA_MC0PTR = (unsigned long)ccb_array;
|
||||
|
||||
ccb_array[0].status.opened_init = 1;
|
||||
ccb_array[0].curr_bd_ptr = &c0_buffer_desc.bd;
|
||||
ccb_array[0].base_bd_ptr = &c0_buffer_desc.bd;
|
||||
ccb_array[0].channel_desc = NULL; /* No channel descriptor */
|
||||
|
||||
/* Command channel owned by AP */
|
||||
set_channel_ownership(0, CH_OWNSHP_MCU);
|
||||
|
||||
sdma_channel_set_priority(0, 1);
|
||||
|
||||
/* Load SDMA script code */
|
||||
set_buffer_descriptor(&c0_buffer_desc.bd,
|
||||
C0_SETPM,
|
||||
BD_DONE | BD_WRAP | BD_EXTD,
|
||||
script_info.ram_code_size,
|
||||
(void *)addr_virt_to_phys(script_info.mcu_start_addr),
|
||||
(void *)(unsigned long)script_info.ram_code_start_addr);
|
||||
|
||||
SDMA_HSTART = 1ul;
|
||||
sdma_channel_wait_nonblocking(0);
|
||||
|
||||
/* No dsp, no debug, dynamic context switching */
|
||||
SDMA_CONFIG = acr | SDMA_CONFIG_CSM_DYNAMIC;
|
||||
}
|
||||
|
||||
/* Busy wait for a channel to complete */
|
||||
void sdma_channel_wait_nonblocking(unsigned int channel)
|
||||
{
|
||||
unsigned long mask;
|
||||
|
||||
if (channel >= CH_NUM)
|
||||
return;
|
||||
|
||||
if (ccb_array[channel].status.opened_init == 0)
|
||||
return;
|
||||
|
||||
mask = 1ul << channel;
|
||||
while (SDMA_STOP_STAT & mask);
|
||||
}
|
||||
|
||||
/* Set a new channel priority */
|
||||
void sdma_channel_set_priority(unsigned int channel, unsigned int priority)
|
||||
{
|
||||
if (channel >= CH_NUM || priority > MAX_CH_PRIORITY)
|
||||
return;
|
||||
|
||||
if (ccb_array[channel].status.opened_init == 0)
|
||||
return;
|
||||
|
||||
SDMA_CHNPRI(channel) = priority;
|
||||
}
|
||||
|
||||
/* Start a channel cold - resets execution to start of script */
|
||||
void sdma_channel_start(unsigned int channel)
|
||||
{
|
||||
struct channel_control_block *ccb_p;
|
||||
|
||||
if (channel == 0 || channel >= CH_NUM)
|
||||
return;
|
||||
|
||||
ccb_p = &ccb_array[channel];
|
||||
|
||||
if (ccb_p->status.opened_init == 0)
|
||||
return;
|
||||
|
||||
if (!setup_channel(ccb_p))
|
||||
return;
|
||||
|
||||
SDMA_HSTART = 1ul << channel;
|
||||
}
|
||||
|
||||
/* Resume or start execution on a channel */
|
||||
void sdma_channel_run(unsigned int channel)
|
||||
{
|
||||
if (channel == 0 || channel >= CH_NUM)
|
||||
return;
|
||||
|
||||
if (ccb_array[channel].status.opened_init == 0)
|
||||
return;
|
||||
|
||||
SDMA_HSTART = 1ul << channel;
|
||||
}
|
||||
|
||||
/* Pause a running channel - can be resumed */
|
||||
void sdma_channel_pause(unsigned int channel)
|
||||
{
|
||||
if (channel == 0 || channel >= CH_NUM)
|
||||
return;
|
||||
|
||||
if (ccb_array[channel].status.opened_init == 0)
|
||||
return;
|
||||
|
||||
SDMA_STOP_STAT = 1ul << channel;
|
||||
}
|
||||
|
||||
/* Stop a channel from executing - cannot be resumed */
|
||||
void sdma_channel_stop(unsigned int channel)
|
||||
{
|
||||
struct channel_control_block *ccb_p;
|
||||
unsigned long chmsk;
|
||||
unsigned long intmsk;
|
||||
int oldstatus;
|
||||
int i;
|
||||
|
||||
if (channel == 0 || channel >= CH_NUM)
|
||||
return;
|
||||
|
||||
ccb_p = &ccb_array[channel];
|
||||
|
||||
if (ccb_p->status.opened_init == 0)
|
||||
return;
|
||||
|
||||
chmsk = 1ul << channel;
|
||||
|
||||
/* Lock callback */
|
||||
oldstatus = disable_irq_save();
|
||||
intmsk = sdma_enabled_ints;
|
||||
sdma_enabled_ints &= ~chmsk;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
/* Stop execution */
|
||||
for (i = ccb_p->channel_desc->bd_count - 1; i >= 0; i--)
|
||||
ccb_p->base_bd_ptr[i].mode.status &= ~BD_DONE;
|
||||
|
||||
SDMA_STOP_STAT = chmsk;
|
||||
while (SDMA_STOP_STAT & chmsk);
|
||||
|
||||
/* Unlock callback if it was set */
|
||||
if (intmsk & chmsk)
|
||||
imx31_regset32(&sdma_enabled_ints, chmsk);
|
||||
|
||||
logf("SDMA ch closed: %d", channel);
|
||||
}
|
||||
|
||||
bool sdma_channel_init(unsigned int channel,
|
||||
struct channel_descriptor *cd_p,
|
||||
struct buffer_descriptor *base_bd_p)
|
||||
{
|
||||
struct channel_control_block *ccb_p;
|
||||
|
||||
if (channel == 0 || channel >= CH_NUM ||
|
||||
cd_p == NULL || base_bd_p == NULL)
|
||||
return false;
|
||||
|
||||
ccb_p = &ccb_array[channel];
|
||||
|
||||
/* If initialized already, should close first then init. */
|
||||
if (ccb_p->status.opened_init != 0)
|
||||
return false;
|
||||
|
||||
/* Initialize channel control block. */
|
||||
ccb_p->curr_bd_ptr = base_bd_p;
|
||||
ccb_p->base_bd_ptr = base_bd_p;
|
||||
ccb_p->channel_desc = cd_p;
|
||||
ccb_p->status.error = 0;
|
||||
ccb_p->status.opened_init = 1;
|
||||
ccb_p->status.state_direction = 0;
|
||||
ccb_p->status.execute = 0;
|
||||
|
||||
/* Finish any channel descriptor inits. */
|
||||
cd_p->ccb_ptr = ccb_p;
|
||||
cd_p->is_setup = 0;
|
||||
|
||||
/* Do an initial setup now. */
|
||||
if (!setup_channel(ccb_p))
|
||||
{
|
||||
logf("SDMA ch init failed: %d", channel);
|
||||
cd_p->ccb_ptr = NULL;
|
||||
memset(ccb_p, 0x00, sizeof (struct channel_control_block));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Enable interrupt if a callback is specified. */
|
||||
if (cd_p->callback != NULL)
|
||||
imx31_regset32(&sdma_enabled_ints, 1ul << channel);
|
||||
|
||||
/* Minimum schedulable = 1 */
|
||||
sdma_channel_set_priority(channel, 1);
|
||||
|
||||
logf("SDMA ch initialized: %d", channel);
|
||||
return true;
|
||||
}
|
||||
|
||||
void sdma_channel_close(unsigned int channel)
|
||||
{
|
||||
struct channel_control_block *ccb_p;
|
||||
int i;
|
||||
|
||||
if (channel == 0 || channel >= CH_NUM)
|
||||
return;
|
||||
|
||||
ccb_p = &ccb_array[channel];
|
||||
|
||||
/* Block callbacks (if not initialized, it won't be set). */
|
||||
imx31_regclr32(&sdma_enabled_ints, 1ul << channel);
|
||||
|
||||
if (ccb_p->status.opened_init == 0)
|
||||
return;
|
||||
|
||||
/* Stop the channel if running */
|
||||
for (i = ccb_p->channel_desc->bd_count - 1; i >= 0; i--)
|
||||
ccb_p->base_bd_ptr[i].mode.status &= ~BD_DONE;
|
||||
|
||||
sdma_channel_stop(channel);
|
||||
|
||||
/* No ownership */
|
||||
set_channel_ownership(channel, 0);
|
||||
|
||||
/* Cannot schedule it again */
|
||||
sdma_channel_set_priority(channel, 0);
|
||||
|
||||
/* Reset channel control block entry */
|
||||
memset(ccb_p, 0x00, sizeof (struct channel_control_block));
|
||||
}
|
||||
|
||||
/* Write 32-bit words to SDMA core memory. Host endian->SDMA endian. */
|
||||
void sdma_write_words(const unsigned long *buf, unsigned long start, int count)
|
||||
{
|
||||
/* Setup buffer descriptor with channel 0 command */
|
||||
set_buffer_descriptor(&c0_buffer_desc.bd,
|
||||
C0_SETDM,
|
||||
BD_DONE | BD_WRAP | BD_EXTD,
|
||||
count,
|
||||
(void *)addr_virt_to_phys((unsigned long)buf),
|
||||
(void *)start);
|
||||
|
||||
SDMA_HSTART = 1ul;
|
||||
sdma_channel_wait_nonblocking(0);
|
||||
}
|
||||
|
||||
/* Read 32-bit words from SDMA core memory. SDMA endian->host endian. */
|
||||
void sdma_read_words(unsigned long *buf, unsigned long start, int count)
|
||||
{
|
||||
/* Setup buffer descriptor with channel 0 command */
|
||||
set_buffer_descriptor(&c0_buffer_desc.bd,
|
||||
C0_GETDM,
|
||||
BD_DONE | BD_WRAP | BD_EXTD,
|
||||
count,
|
||||
(void *)addr_virt_to_phys((unsigned long)buf),
|
||||
(void *)start);
|
||||
|
||||
SDMA_HSTART = 1ul;
|
||||
sdma_channel_wait_nonblocking(0);
|
||||
}
|
225
firmware/target/arm/imx31/sdma-imx31.h
Normal file
225
firmware/target/arm/imx31/sdma-imx31.h
Normal file
|
@ -0,0 +1,225 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 by Michael Sevakis
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef SDMA_IMX31_H
|
||||
#define SDMA_IMX31_H
|
||||
|
||||
/* Much of the code in here is based upon the Linux BSP provided by Freescale
|
||||
* Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. */
|
||||
|
||||
/* Peripheral and transfer type - used to select the proper SDMA channel
|
||||
* script to execute. */
|
||||
enum SDMA_PERIPHERAL_TYPE
|
||||
{
|
||||
__SDMA_PER_FIRST = -1,
|
||||
SDMA_PER_MEMORY,
|
||||
SDMA_PER_DSP,
|
||||
SDMA_PER_FIRI,
|
||||
SDMA_PER_UART,
|
||||
SDMA_PER_UART_SP, /* Shared */
|
||||
SDMA_PER_ATA,
|
||||
SDMA_PER_CSPI,
|
||||
SDMA_PER_EXT,
|
||||
SDMA_PER_SSI,
|
||||
SDMA_PER_SSI_SP, /* Shared */
|
||||
SDMA_PER_MMC,
|
||||
SDMA_PER_SDHC,
|
||||
SDMA_PER_CSPI_SP, /* Shared */
|
||||
SDMA_PER_MSHC,
|
||||
SDMA_PER_MSHC_SP, /* Shared */
|
||||
SDMA_PER_CCM,
|
||||
SDMA_PER_ASRC,
|
||||
SDMA_PER_ESAI,
|
||||
SDMA_PER_SIM,
|
||||
SDMA_PER_SPDIF,
|
||||
SDMA_PER_IPU_MEMORY,
|
||||
};
|
||||
|
||||
enum SDMA_TRANSFER_TYPE
|
||||
{
|
||||
__SDMA_TRAN_FIRST = -1,
|
||||
SDMA_TRAN_INT_2_INT,
|
||||
SDMA_TRAN_EMI_2_INT,
|
||||
SDMA_TRAN_EMI_2_EMI,
|
||||
SDMA_TRAN_INT_2_EMI,
|
||||
|
||||
SDMA_TRAN_INT_2_DSP,
|
||||
SDMA_TRAN_DSP_2_INT,
|
||||
SDMA_TRAN_DSP_2_DSP,
|
||||
SDMA_TRAN_DSP_2_PER,
|
||||
SDMA_TRAN_PER_2_DSP,
|
||||
SDMA_TRAN_EMI_2_DSP,
|
||||
SDMA_TRAN_DSP_2_EMI,
|
||||
SDMA_TRAN_DSP_2_EMI_LOOP,
|
||||
SDMA_TRAN_EMI_2_DSP_LOOP,
|
||||
|
||||
SDMA_TRAN_PER_2_INT,
|
||||
SDMA_TRAN_PER_2_EMI,
|
||||
SDMA_TRAN_INT_2_PER,
|
||||
SDMA_TRAN_EMI_2_PER,
|
||||
};
|
||||
|
||||
/* 2.3 - Smart Direct Memory Access (SDMA) Events, Table 2-5 */
|
||||
/* These are indexes into the SDMA_CHNENBL register array (each a bitmask
|
||||
* determining which channels are triggered by requests). */
|
||||
enum SDMA_REQUEST_TYPE
|
||||
{
|
||||
SDMA_REQ_EXT0 = 0, /* Extern DMA request from MCU1_0 */
|
||||
SDMA_REQ_CCM = 1, /* DVFS/DPTC event (ccm_dvfs_sdma_int) */
|
||||
SDMA_REQ_ATA_TX_END = 2, /* ata_txfer_end_alarm (event_id) */
|
||||
SDMA_REQ_ATA_TX = 3, /* ata_tx_fifo_alarm (event_id2) */
|
||||
SDMA_REQ_ATA_RX = 4, /* ata_rcv_fifo_alarm (event_id2) */
|
||||
SDMA_REQ_SIM = 5, /* */
|
||||
SDMA_REQ_CSPI2_RX = 6, /* DMA Rx request */
|
||||
SDMA_REQ_CSPI2_TX = 7, /* DMA Tx request */
|
||||
SDMA_REQ_CSPI1_RX = 8, /* DMA Rx request of CSPI */
|
||||
SDMA_REQ_UART3_RX = 8, /* DMA Rx request RxFIFO of UART3 */
|
||||
SDMA_REQ_CSPI1_TX = 9, /* DMA Tx request of CSPI */
|
||||
SDMA_REQ_UART3_TX = 9, /* DMA Tx request TxFIFO of UART3 */
|
||||
SDMA_REQ_CSPI3_RX = 10, /* RxFIFO or CSPI3 Rx request */
|
||||
SDMA_REQ_UART5_RX = 10, /* RxFIFO or CSPI3 Rx request */
|
||||
SDMA_REQ_CSPI3_TX = 11, /* TxFIFO or CSPI3 Tx request */
|
||||
SDMA_REQ_UART5_TX = 11, /* TxFIFO or CSPI3 Tx request */
|
||||
SDMA_REQ_UART4_RX = 12, /* RxFIFO */
|
||||
SDMA_REQ_UART4_TX = 13, /* TxFIFO */
|
||||
SDMA_REQ_EXT2 = 14, /* External DMA request from MCU1_2 or from
|
||||
MBX (Graphic accelerator) */
|
||||
SDMA_REQ_EXT1 = 15, /* External request from MCU1_1 */
|
||||
SDMA_REQ_FIRI_RX = 16, /* DMA request of FIR's receiver FIFO
|
||||
controlled by the pgp_firi signal
|
||||
from the IOMUXC PGP register */
|
||||
SDMA_REQ_UART2_RX = 16, /* RxFIFO of UART2 */
|
||||
SDMA_REQ_FIRI_TX = 17, /* DMA request of FIR's transmitter
|
||||
FIFO controled by the pgp_firi signal
|
||||
the IOMUXC PGP register */
|
||||
SDMA_REQ_UART2_TX = 17, /* TxFIFO of UART2 */
|
||||
SDMA_REQ_UART1_RX = 18, /* RxFIFO */
|
||||
SDMA_REQ_UART1_TX = 19, /* TxFIFO */
|
||||
SDMA_REQ_MMC1 = 20, /* MMC DMA request */
|
||||
SDMA_REQ_SDHC1 = 20, /* SDHC1 DMA request */
|
||||
SDMA_REQ_MSHC1 = 20, /* MSHC1 DMA request */
|
||||
SDMA_REQ_MMC2 = 21, /* MMC DMA request */
|
||||
SDMA_REQ_SDHC2 = 21, /* SDHC2 DMA request */
|
||||
SDMA_REQ_MSHC2 = 21, /* MSHC2 DMA request */
|
||||
SDMA_REQ_SSI2_RX2 = 22, /* SSI #2 receive 2 DMA request (SRX1_2) */
|
||||
SDMA_REQ_SSI2_TX2 = 23, /* SSI #2 transmit 2 DMA request (STX1_2) */
|
||||
SDMA_REQ_SSI2_RX1 = 24, /* SSI #2 receive 1 DMA request (SRX0_2) */
|
||||
SDMA_REQ_SSI2_TX1 = 25, /* SSI #2 transmit 1 DMA request (STX0_2) */
|
||||
SDMA_REQ_SSI1_RX2 = 26, /* SSI #1 receive 2 DMA request (SRX1_1) */
|
||||
SDMA_REQ_SSI1_TX2 = 27, /* SSI #1 transmit 2 DMA request (STX1_1) */
|
||||
SDMA_REQ_SSI1_RX1 = 28, /* SSI #1 receive 1 DMA request (SRX1_0) */
|
||||
SDMA_REQ_SSI1_TX1 = 29, /* SSI #1 transmit 1 DMA request (STX1_0) */
|
||||
SDMA_REQ_NFC = 30, /* NAND-flash controller */
|
||||
SDMA_REQ_IPU = 31, /* IPU source (defaults to IPU at reset) */
|
||||
SDMA_REQ_ECT = 31, /* ECT source */
|
||||
};
|
||||
|
||||
/* Addresses for peripheral DMA transfers */
|
||||
enum SDMA_PER_ADDR
|
||||
{
|
||||
SDMA_PER_ADDR_SDRAM = SDRAM_BASE_ADDR, /* memory */
|
||||
SDMA_PER_ADDR_CCM = CCM_BASE_ADDR+0x00, /* CCMR */
|
||||
/* ATA */
|
||||
SDMA_PER_ADDR_ATA_TX = ATA_DMA_BASE_ADDR+0x18,
|
||||
SDMA_PER_ADDR_ATA_RX = ATA_DMA_BASE_ADDR,
|
||||
#if 0
|
||||
SDMA_PER_ADDR_ATA_TX16 =
|
||||
SDMA_PER_ADDR_ATA_RX16 =
|
||||
#endif
|
||||
#if 0
|
||||
SDMA_PER_ADDR_SIM =
|
||||
#endif
|
||||
/* CSPI2 */
|
||||
SDMA_PER_ADDR_CSPI2_RX = CSPI2_BASE_ADDR+0x00, /* RXDATA2 */
|
||||
SDMA_PER_ADDR_CSPI2_TX = CSPI2_BASE_ADDR+0x04, /* TXDATA2 */
|
||||
/* CSPI1 */
|
||||
SDMA_PER_ADDR_CSPI1_RX = CSPI1_BASE_ADDR+0x00, /* RXDATA1 */
|
||||
SDMA_PER_ADDR_CSPI1_TX = CSPI1_BASE_ADDR+0x04, /* TXDATA1 */
|
||||
/* UART3 */
|
||||
SDMA_PER_ADDR_UART3_RX = UART3_BASE_ADDR+0x00, /* URXD3 */
|
||||
SDMA_PER_ADDR_UART3_TX = UART3_BASE_ADDR+0x40, /* UTXD3 */
|
||||
/* CSPI3 */
|
||||
SDMA_PER_ADDR_CSPI3_RX = CSPI3_BASE_ADDR+0x00, /* RXDATA3 */
|
||||
SDMA_PER_ADDR_CSPI3_TX = CSPI3_BASE_ADDR+0x04, /* TXDATA3 */
|
||||
/* UART5 */
|
||||
SDMA_PER_ADDR_UART5_RX = UART5_BASE_ADDR+0x00, /* URXD5 */
|
||||
SDMA_PER_ADDR_UART5_TX = UART5_BASE_ADDR+0x40, /* UTXD5 */
|
||||
/* UART4 */
|
||||
SDMA_PER_ADDR_UART4_RX = UART4_BASE_ADDR+0x00, /* URXD4 */
|
||||
SDMA_PER_ADDR_UART4_TX = UART4_BASE_ADDR+0x40, /* UTXD4 */
|
||||
/* FIRI */
|
||||
SDMA_PER_ADDR_FIRI_RX = FIRI_BASE_ADDR+0x18, /* Receiver FIFO */
|
||||
SDMA_PER_ADDR_FIRI_TX = FIRI_BASE_ADDR+0x14, /* Transmitter FIFO */
|
||||
/* UART2 */
|
||||
SDMA_PER_ADDR_UART2_RX = UART2_BASE_ADDR+0x00, /* URXD2 */
|
||||
SDMA_PER_ADDR_UART2_TX = UART2_BASE_ADDR+0x40, /* UTXD2 */
|
||||
/* UART1 */
|
||||
SDMA_PER_ADDR_UART1_RX = UART1_BASE_ADDR+0x00, /* URXD1 */
|
||||
SDMA_PER_ADDR_UART1_TX = UART1_BASE_ADDR+0x40, /* UTXD1 */
|
||||
SDMA_PER_ADDR_MMC_SDHC1 = MMC_SDHC1_BASE_ADDR+0x38, /* BUFFER_ACCESS */
|
||||
SDMA_PER_ADDR_MMC_SDHC2 = MMC_SDHC2_BASE_ADDR+0x38, /* BUFFER_ACCESS */
|
||||
#if 0
|
||||
SDMA_PER_ADDR_MSHC1 =
|
||||
SDMA_PER_ADDR_MSHC2 =
|
||||
#endif
|
||||
/* SSI2 */
|
||||
SDMA_PER_ADDR_SSI2_RX2 = SSI2_BASE_ADDR+0x0C, /* SRX1_2 */
|
||||
SDMA_PER_ADDR_SSI2_TX2 = SSI2_BASE_ADDR+0x04, /* STX1_2 */
|
||||
SDMA_PER_ADDR_SSI2_RX1 = SSI2_BASE_ADDR+0x08, /* SRX0_2 */
|
||||
SDMA_PER_ADDR_SSI2_TX1 = SSI2_BASE_ADDR+0x00, /* STX0_2 */
|
||||
/* SSI1 */
|
||||
SDMA_PER_ADDR_SSI1_RX2 = SSI1_BASE_ADDR+0x0C, /* SRX1_1 */
|
||||
SDMA_PER_ADDR_SSI1_TX2 = SSI1_BASE_ADDR+0x04, /* STX1_1 */
|
||||
SDMA_PER_ADDR_SSI1_RX1 = SSI1_BASE_ADDR+0x08, /* SRX0_1 */
|
||||
SDMA_PER_ADDR_SSI1_TX1 = SSI1_BASE_ADDR+0x00, /* STX0_1 */
|
||||
#if 0
|
||||
SDMA_PER_ADDR_NFC =
|
||||
SDMA_PER_ADDR_IPU =
|
||||
SDMA_PER_ADDR_ECT =
|
||||
#endif
|
||||
};
|
||||
|
||||
/* DMA driver defines */
|
||||
#define SDMA_SDHC_MMC_WML 16
|
||||
#define SDMA_SDHC_SD_WML 64
|
||||
#define SDMA_SSI_TXFIFO_WML 4 /* Four samples written per channel activation */
|
||||
#define SDMA_SSI_RXFIFO_WML 6 /* Six samples read per channel activation */
|
||||
#define SDMA_FIRI_WML 16
|
||||
|
||||
#define SDMA_ATA_WML 32 /* DMA watermark level in bytes */
|
||||
#define SDMA_ATA_BD_NR (512/3/4) /* Number of BDs per channel */
|
||||
|
||||
#include "sdma_struct.h"
|
||||
|
||||
void sdma_init(void);
|
||||
void sdma_read_words(unsigned long *buf, unsigned long start, int count);
|
||||
void sdma_write_words(const unsigned long *buf, unsigned long start, int count);
|
||||
void sdma_channel_set_priority(unsigned int channel, unsigned int priority);
|
||||
void sdma_channel_start(unsigned int channel);
|
||||
void sdma_channel_run(unsigned int channel);
|
||||
void sdma_channel_pause(unsigned int channel);
|
||||
void sdma_channel_stop(unsigned int channel);
|
||||
void sdma_channel_wait_nonblocking(unsigned int channel);
|
||||
bool sdma_channel_init(unsigned int channel,
|
||||
struct channel_descriptor *cd_p,
|
||||
struct buffer_descriptor *base_bd_p);
|
||||
void sdma_channel_close(unsigned int channel);
|
||||
|
||||
#endif /* SDMA_IMX31_H */
|
1060
firmware/target/arm/imx31/sdma_script_code.h
Normal file
1060
firmware/target/arm/imx31/sdma_script_code.h
Normal file
File diff suppressed because it is too large
Load diff
426
firmware/target/arm/imx31/sdma_struct.h
Normal file
426
firmware/target/arm/imx31/sdma_struct.h
Normal file
|
@ -0,0 +1,426 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 by Michael Sevakis
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Largely taken from sdmaStruct.h from the Linux BSP provided by Freescale.
|
||||
* Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* Other information gleaned from RE-ing the BSP and SDMA code */
|
||||
|
||||
#ifndef SDMA_STRUCT_H
|
||||
#define SDMA_STRUCT_H
|
||||
|
||||
/**
|
||||
* Number of channels
|
||||
*/
|
||||
#define CH_NUM 32
|
||||
|
||||
/**
|
||||
* Ownership
|
||||
*/
|
||||
#define CH_OWNSHP_EVT (1 << 0)
|
||||
#define CH_OWNSHP_MCU (1 << 1)
|
||||
#if 0
|
||||
#define CH_OWNSHP_DSP (1 << 2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Channel contexts management
|
||||
*/
|
||||
|
||||
/* Contexts for each channel begin here within SDMA core */
|
||||
#define CHANNEL_CONTEXT_BASE_ADDR 0x800
|
||||
/* Compute SDMA address where context for a channel is stored */
|
||||
#define CHANNEL_CONTEXT_ADDR(channel) \
|
||||
(CHANNEL_CONTEXT_BASE_ADDR+sizeof(struct context_data)/4*(channel))
|
||||
|
||||
/**
|
||||
* Error bit set in the CCB status field by the SDMA,
|
||||
* in setbd routine, in case of a transfer error
|
||||
*/
|
||||
#define DATA_ERROR (1 << 28) /* BD_RROR set on last buffer descriptor */
|
||||
#define DATA_FAULT (1 << 29) /* A source or destination fault occured */
|
||||
|
||||
/**
|
||||
* Buffer descriptor status values.
|
||||
*/
|
||||
#define BD_DONE 0x01 /* Set by host, cleared when SDMA has finished with
|
||||
this BD */
|
||||
#define BD_WRAP 0x02 /* If set in last descriptor, allows circular buffer
|
||||
* structure. curr_bd_ptr will be reset to base_bd_ptr
|
||||
*/
|
||||
#define BD_CONT 0x04 /* If set, more descriptors follow (multi-buffer) */
|
||||
#define BD_INTR 0x08 /* Interrupt when transfer complete */
|
||||
#define BD_RROR 0x10 /* Error during BD processing (set by SDMA) */
|
||||
#define BD_LAST 0x20 /* Set by SDMA ap_2_bp and bp_2_ap scripts.
|
||||
TODO: determine function */
|
||||
#define BD_EXTD 0x80 /* Use extended buffer address (indicates BD is 12
|
||||
bytes instead of 8) */
|
||||
|
||||
/**
|
||||
* Buffer descriptor channel 0 commands.
|
||||
*/
|
||||
#define C0_SETCTX 0x07 /* Write context for a channel (ch# = BD command [7:3]) */
|
||||
#define C0_GETCTX 0x03 /* Read context for a channel (ch# = BD command [7:3]) */
|
||||
#define C0_SETDM 0x01 /* Write 32-bit words to SDMA memory */
|
||||
#define C0_GETDM 0x02 /* Read 32-bit words from SDMA memory */
|
||||
#define C0_SETPM 0x04 /* Write 16-bit halfwords to SDMA memory */
|
||||
#define C0_GETPM 0x08 /* Read 16-bit halfwords from SDMA memory */
|
||||
|
||||
/* Treated the same as those above */
|
||||
#define C0_ADDR 0x01
|
||||
#define C0_LOAD 0x02
|
||||
#define C0_DUMP 0x03
|
||||
|
||||
/**
|
||||
* Transfer sizes, encoded in the BD command field (when not a C0_ command).
|
||||
*/
|
||||
#define TRANSFER_32BIT 0x00
|
||||
#define TRANSFER_8BIT 0x01
|
||||
#define TRANSFER_16BIT 0x02
|
||||
#define TRANSFER_24BIT 0x03
|
||||
|
||||
/**
|
||||
* Change endianness indicator in the BD command field
|
||||
*/
|
||||
#define CHANGE_ENDIANNESS 0x80
|
||||
|
||||
/**
|
||||
* Size in bytes of struct buffer_descriptor
|
||||
*/
|
||||
#define SDMA_BD_SIZE 8
|
||||
#define SDMA_EXTENDED_BD_SIZE 12
|
||||
#define BD_NUMBER 4
|
||||
|
||||
/**
|
||||
* Channel interrupt policy
|
||||
*/
|
||||
#define DEFAULT_POLL 0
|
||||
#define CALLBACK_ISR 1
|
||||
/**
|
||||
* Channel status
|
||||
*/
|
||||
#define UNINITIALIZED 0
|
||||
#define INITIALIZED 1
|
||||
|
||||
/**
|
||||
* IoCtl particular values
|
||||
*/
|
||||
#define SET_BIT_ALL 0xFFFFFFFF
|
||||
#define BD_NUM_OFFSET 16
|
||||
#define BD_NUM_MASK 0xFFFF0000
|
||||
|
||||
/**
|
||||
* Maximum values for IoCtl calls, used in high or middle level calls
|
||||
*/
|
||||
#define MAX_BD_NUM 256
|
||||
#define MAX_BD_SIZE 65536
|
||||
#define MAX_BLOCKING 2
|
||||
#define MAX_SYNCH 2
|
||||
#define MAX_OWNERSHIP 8
|
||||
#define MAX_CH_PRIORITY 8
|
||||
#define MAX_TRUST 2
|
||||
#define MAX_WML 256
|
||||
|
||||
|
||||
/**
|
||||
* Default values for channel descriptor - nobody owns the channel
|
||||
*/
|
||||
#define CD_DEFAULT_OWNERSHIP 7
|
||||
|
||||
#if 0 /* IPC not used */
|
||||
/**
|
||||
* Data Node descriptor status values.
|
||||
*/
|
||||
#define DND_END_OF_FRAME 0x80
|
||||
#define DND_END_OF_XFER 0x40
|
||||
#define DND_DONE 0x20
|
||||
#define DND_UNUSED 0x01
|
||||
|
||||
/**
|
||||
* IPCV2 descriptor status values.
|
||||
*/
|
||||
#define BD_IPCV2_END_OF_FRAME 0x40
|
||||
|
||||
#define IPCV2_MAX_NODES 50
|
||||
|
||||
/**
|
||||
* User Type Section
|
||||
*/
|
||||
|
||||
/**
|
||||
* Command/Mode/Count of buffer descriptors
|
||||
*/
|
||||
struct mode_count_ipcv2
|
||||
{
|
||||
unsigned long count : 16; /* size of the buffer pointed by this BD */
|
||||
unsigned long reserved : 8; /* reserved */
|
||||
unsigned long status : 8; /* L, E, D bits stored here */
|
||||
};
|
||||
|
||||
/**
|
||||
* Data Node descriptor - IPCv2
|
||||
* (differentiated between evolutions of SDMA)
|
||||
*/
|
||||
struct data_node_descriptor
|
||||
{
|
||||
struct mode_count_ipcv2 mode; /* command, status and count */
|
||||
void* buffer_addr; /* address of the buffer described */
|
||||
};
|
||||
|
||||
struct mode_count_ipcv1_v2
|
||||
{
|
||||
unsigned long count : 16; /* size of the buffer pointed by this BD */
|
||||
unsigned long status : 8; /* E,R,I,C,W,D status bits stored here */
|
||||
unsigned long reserved : 7;
|
||||
unsigned long endianness : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer descriptor
|
||||
* (differentiated between evolutions of SDMA)
|
||||
*/
|
||||
struct buffer_descriptor_ipcv1_v2
|
||||
{
|
||||
struct mode_count_ipcv1_v2 mode; /* command, status and count */
|
||||
void *buffer_addr; /* address of the buffer described */
|
||||
void *ext_buffer_addr; /* extended buffer address */
|
||||
};
|
||||
#endif /* No IPC */
|
||||
|
||||
/**
|
||||
* Mode/Count of data node descriptors - IPCv2
|
||||
*/
|
||||
struct mode_count
|
||||
{
|
||||
unsigned long count : 16; /* size of the buffer pointed by this BD */
|
||||
unsigned long status : 8; /* E,R,I,C,W,D status bits stored here:
|
||||
* SDMA r/w */
|
||||
unsigned long command : 8; /* channel 0 command or transfer size */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Buffer descriptor - describes each buffer in a DMA transfer.
|
||||
* (differentiated between evolutions of SDMA)
|
||||
*/
|
||||
/* (mode.status & BD_EXTD) == 0 (8 bytes) */
|
||||
struct buffer_descriptor
|
||||
{
|
||||
volatile struct mode_count mode; /* command, status and count: SDMA r/w */
|
||||
void *buf_addr; /* address of the buffer described: SDMA r */
|
||||
};
|
||||
|
||||
/* (mode.status & BD_EXTD) != 0 (12 bytes) */
|
||||
struct buffer_descriptor_extd
|
||||
{
|
||||
struct buffer_descriptor bd;
|
||||
void *buf_addr_ext; /* extended buffer address described (r6): SDMA r */
|
||||
};
|
||||
|
||||
#if 0 /* A different one is defined for Rockbox use - this has too much.
|
||||
* See below. */
|
||||
struct channel_control_block;
|
||||
struct channel_descriptor;
|
||||
/**
|
||||
* Channel Descriptor
|
||||
*/
|
||||
struct channel_descriptor
|
||||
{
|
||||
unsigned char channel_number; /* stores the channel number */
|
||||
unsigned char buffer_desc_count; /* number of BD's allocated
|
||||
for this channel */
|
||||
unsigned short buffer_per_desc_size; /* size (in bytes) of buffer
|
||||
descriptors' data buffers */
|
||||
unsigned long blocking : 3; /* polling/ callback method
|
||||
selection */
|
||||
unsigned long callback_synch : 1; /* (iapi) blocking / non blocking
|
||||
feature selection */
|
||||
unsigned long ownership : 3; /* ownership of the channel
|
||||
(host+dedicated+event) */
|
||||
unsigned long priority : 3; /* reflects the SDMA channel
|
||||
priority register */
|
||||
unsigned long trust : 1; /* trusted buffers or kernel
|
||||
allocated */
|
||||
unsigned long use_data_size : 1; /* (iapi) indicates if the dataSize
|
||||
field is meaningfull */
|
||||
unsigned long data_size : 2; /* (iapi->BD) data transfer
|
||||
size - 8,16,24 or 32 bits*/
|
||||
unsigned long force_close : 1; /* If TRUE, close channel even
|
||||
with BD owned by SDMA*/
|
||||
unsigned long script_id : 7; /* number of the script */
|
||||
unsigned long watermark_level : 10; /* (greg) Watermark level for the
|
||||
peripheral access */
|
||||
unsigned long event_mask1; /* (greg) First Event mask */
|
||||
unsigned long event_mask2; /* (greg) Second Event mask */
|
||||
unsigned long shp_addr; /* (greg) Address of the peripheral
|
||||
or its fifo when needed */
|
||||
void (* callback)(struct channel_descriptor *); /* pointer to the
|
||||
callback function (or NULL) */
|
||||
struct channel_control_block *ccb_ptr; /* pointer to the channel control
|
||||
block associated to this
|
||||
channel */
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Only what we need, members sorted by size, no code-bloating bitfields */
|
||||
struct channel_descriptor
|
||||
{
|
||||
unsigned int bd_count; /* number of BD's allocated
|
||||
for this channel */
|
||||
struct channel_control_block *ccb_ptr; /* pointer to the channel control
|
||||
block associated to this
|
||||
channel */
|
||||
void (* callback)(void); /* pointer to the
|
||||
callback function (or NULL) */
|
||||
unsigned long shp_addr; /* (greg) Address of the peripheral
|
||||
or its fifo when needed */
|
||||
unsigned short wml; /* (greg) Watermark level for the
|
||||
peripheral access */
|
||||
unsigned char per_type; /* Peripheral type */
|
||||
unsigned char tran_type; /* Transfer type */
|
||||
unsigned char event_id1; /* DMA request ID */
|
||||
unsigned char event_id2; /* DMA request ID 2 */
|
||||
unsigned char is_setup; /* Channel setup has been done */
|
||||
};
|
||||
|
||||
/**
|
||||
* Channel Status
|
||||
*/
|
||||
struct channel_status
|
||||
{
|
||||
unsigned long unused : 28;
|
||||
unsigned long error : 1; /* Last BD triggered an error:
|
||||
SDMA r/w */
|
||||
unsigned long opened_init : 1; /* Channel is initialized:
|
||||
SDMA r/w */
|
||||
unsigned long state_direction : 1; /* SDMA is reading/writing (as seen
|
||||
from channel owner core) */
|
||||
unsigned long execute : 1; /* Channel is being processed
|
||||
(started) or not */
|
||||
};
|
||||
|
||||
/**
|
||||
* Channel control Block
|
||||
* SDMA ROM code expects these are 16-bytes each in an array
|
||||
* (MC0PTR + 16*CCR)
|
||||
*/
|
||||
struct channel_control_block
|
||||
{
|
||||
/* current buffer descriptor processed: SDMA r/w */
|
||||
struct buffer_descriptor * volatile curr_bd_ptr;
|
||||
/* first element of buffer descriptor array: SDMA r */
|
||||
struct buffer_descriptor *base_bd_ptr;
|
||||
/* pointer to the channel descriptor: SDMA ignored */
|
||||
struct channel_descriptor *channel_desc;
|
||||
/* open/close ; started/stopped ; read/write: SDMA r/w */
|
||||
volatile struct channel_status status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Channel context structure.
|
||||
*/
|
||||
|
||||
/* Channel state bits on SDMA core side */
|
||||
struct state_registers
|
||||
{
|
||||
/* Offset 0 */
|
||||
unsigned long pc : 14; /* program counter */
|
||||
unsigned long unused0 : 1;
|
||||
unsigned long t : 1; /* test bit: status of arithmetic & test
|
||||
instruction */
|
||||
unsigned long rpc : 14; /* return program counter */
|
||||
unsigned long unused1 : 1;
|
||||
unsigned long sf : 1; /* source fault while loading data */
|
||||
/* Offset 1 */
|
||||
unsigned long spc : 14; /* loop start program counter */
|
||||
unsigned long unused2 : 1;
|
||||
unsigned long df : 1; /* destination falut while storing data */
|
||||
unsigned long epc : 14; /* loop end program counter */
|
||||
unsigned long lm : 2; /* loop mode */
|
||||
};
|
||||
|
||||
/* Context data saved for every channel on the SDMA core. This is 32 words
|
||||
* long which is specified in the SDMA initialization on the AP side. The
|
||||
* SDMA scripts utilize the scratch space. */
|
||||
struct context_data
|
||||
{
|
||||
struct state_registers channel_state; /* channel state bits */
|
||||
union
|
||||
{
|
||||
unsigned long r[8]; /* general registers (r0-r7) */
|
||||
struct /* script usage of said when
|
||||
setting contexts */
|
||||
{
|
||||
unsigned long event_mask2; /* 08h */
|
||||
unsigned long event_mask1; /* 0Ch */
|
||||
unsigned long r2; /* 10h */
|
||||
unsigned long r3; /* 14h */
|
||||
unsigned long r4; /* 18h */
|
||||
unsigned long r5; /* 1Ch */
|
||||
unsigned long shp_addr; /* 20h */
|
||||
unsigned long wml; /* 24h */
|
||||
};
|
||||
};
|
||||
unsigned long mda; /* burst dma destination address register */
|
||||
unsigned long msa; /* burst dma source address register */
|
||||
unsigned long ms; /* burst dma status register */
|
||||
unsigned long md; /* burst dma data register */
|
||||
unsigned long pda; /* peripheral dma destination address register */
|
||||
unsigned long psa; /* peripheral dma source address register */
|
||||
unsigned long ps; /* peripheral dma status register */
|
||||
unsigned long pd; /* peripheral dma data register */
|
||||
unsigned long ca; /* CRC polynomial register */
|
||||
unsigned long cs; /* CRC accumulator register */
|
||||
unsigned long dda; /* dedicated core destination address register */
|
||||
unsigned long dsa; /* dedicated core source address register */
|
||||
unsigned long ds; /* dedicated core status register */
|
||||
unsigned long dd; /* dedicated core data register */
|
||||
unsigned long scratch[8]; /* channel context scratch RAM */
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure holds the necessary data for the assignment in the
|
||||
* dynamic channel-script association
|
||||
*/
|
||||
struct script_data
|
||||
{
|
||||
unsigned long load_address; /* start address of the script */
|
||||
unsigned long wml; /* parameters for the channel descriptor */
|
||||
unsigned long shp_addr; /* shared peripheral base address */
|
||||
unsigned long event_mask1; /* first event mask */
|
||||
unsigned long event_mask2; /* second event mask */
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure holds the the useful bits of the CONFIG register
|
||||
*/
|
||||
struct configs_data
|
||||
{
|
||||
unsigned long dspdma : 1; /* indicates if the DSPDMA is used */
|
||||
unsigned long rtdobs : 1; /* indicates if Real-Time Debug pins are
|
||||
enabled */
|
||||
unsigned long acr : 1; /* indicates if AHB freq /core freq = 2 or 1 */
|
||||
unsigned long csm : 2; /* indicates which context switch mode is
|
||||
selected */
|
||||
};
|
||||
|
||||
#endif /* SDMA_STRUCT_H */
|
Loading…
Reference in a new issue