From 38436038a9e50e8314967672fb5e7b9a5009a4be Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Thu, 26 Feb 2009 21:15:40 +0000 Subject: [PATCH] Ingenic Jz4740: * Add initial RoLo support * Don't enable IRAM in plugins for now * Initial try at getting PCM working (doesn't crash anymore at least) * Replace hard-coded constant with #define in usb-jz4740 git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20115 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/plugin.lds | 4 +- firmware/export/audiohw.h | 2 + firmware/export/config-ondavx747.h | 9 ++- firmware/export/config.h | 2 +- firmware/export/cpu.h | 3 + firmware/export/jz4740-codec.h | 31 ++++++++ firmware/rolo.c | 10 ++- firmware/target/mips/ingenic_jz47xx/app.lds | 7 +- .../target/mips/ingenic_jz47xx/codec-jz4740.c | 28 ++++---- .../target/mips/ingenic_jz47xx/pcm-jz4740.c | 71 ++++++++++++++++--- .../mips/ingenic_jz47xx/system-jz4740.c | 2 +- .../target/mips/ingenic_jz47xx/usb-jz4740.c | 4 +- 12 files changed, 137 insertions(+), 36 deletions(-) create mode 100644 firmware/export/jz4740-codec.h diff --git a/apps/plugins/plugin.lds b/apps/plugins/plugin.lds index 8840805702..ccf60100bf 100644 --- a/apps/plugins/plugin.lds +++ b/apps/plugins/plugin.lds @@ -106,8 +106,8 @@ OUTPUT_FORMAT(elf32-littlemips) #elif CONFIG_CPU == JZ4732 #define DRAMORIG 0x80004000 + STUBOFFSET -#define IRAMORIG 0x80000000 -#define IRAMSIZE 0x4000 +//#define IRAMORIG 0x80000000 +//#define IRAMSIZE 0x4000 #else #define DRAMORIG 0x09000000 + STUBOFFSET #endif diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index b173feb77f..423b520dc5 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -57,6 +57,8 @@ #include "mas35xx.h" #elif defined(HAVE_TSC2100) #include "tsc2100.h" +#elif defined(HAVE_JZ4740_CODEC) +#include "jz4740-codec.h" #endif /* convert caps into defines */ diff --git a/firmware/export/config-ondavx747.h b/firmware/export/config-ondavx747.h index a5e22aaf26..70036e1d50 100644 --- a/firmware/export/config-ondavx747.h +++ b/firmware/export/config-ondavx747.h @@ -108,8 +108,13 @@ /* The number of bytes reserved for loadable plugins */ #define PLUGIN_BUFFER_SIZE 0x100000 -/* Define this if you have the */ -//#define HAVE_INGENIC_CODEC +/* Define this if you have the Jz4740 internal codec */ +#define HAVE_JZ4740_CODEC + +/* define the bitmask of hardware sample rates */ +#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) #define CONFIG_I2C I2C_JZ47XX diff --git a/firmware/export/config.h b/firmware/export/config.h index 2c299491f9..da35f79b33 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -593,7 +593,7 @@ #endif /* Determine if accesses should be strictly long aligned. */ -#if (CONFIG_CPU == SH7034) || defined(CPU_ARM) +#if (CONFIG_CPU == SH7034) || defined(CPU_ARM) || defined(CPU_MIPS) #define ROCKBOX_STRICT_ALIGN 1 #endif diff --git a/firmware/export/cpu.h b/firmware/export/cpu.h index 75ac252ed7..ea56d7e6a0 100644 --- a/firmware/export/cpu.h +++ b/firmware/export/cpu.h @@ -65,3 +65,6 @@ #if CONFIG_CPU == AS3525 #include "as3525.h" #endif +#if CONFIG_CPU == JZ4732 +#include "jz4740.h" +#endif diff --git a/firmware/export/jz4740-codec.h b/firmware/export/jz4740-codec.h new file mode 100644 index 0000000000..5aab348635 --- /dev/null +++ b/firmware/export/jz4740-codec.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 by Maurus Cuelenaere + * + * 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 __JZ4740_CODEC_H_ +#define __JZ4740_CODEC_H_ + +/* TODO */ +#define VOLUME_MIN -1 +#define VOLUME_MAX 1 + +int tenthdb2master(int db); +void audiohw_set_headphone_vol(int vol_l, int vol_r); + +#endif /* __JZ4740_CODEC_H_ */ diff --git a/firmware/rolo.c b/firmware/rolo.c index 014f00e2c7..510720ed1a 100644 --- a/firmware/rolo.c +++ b/firmware/rolo.c @@ -180,6 +180,12 @@ void rolo_restart(const unsigned char* source, unsigned char* dest, "mov pc, %0 \n" : : "r"(dest) ); +#elif defined(CPU_MIPS) + cpucache_invalidate(); + asm volatile( + "jr %0 \n" + : : "r"(dest) + ); #endif } #endif @@ -197,7 +203,7 @@ int rolo_load(const char* filename) { int fd; long length; -#if defined(CPU_COLDFIRE) || defined(CPU_ARM) +#if defined(CPU_COLDFIRE) || defined(CPU_ARM) || defined(CPU_MIPS) #if !defined(MI4_FORMAT) int i; #endif @@ -231,7 +237,7 @@ int rolo_load(const char* filename) #if defined(CPU_COLDFIRE) || defined(CPU_PP) || (CONFIG_CPU==DM320) \ || defined(CPU_TCC780X) || (CONFIG_CPU==IMX31L) || (CONFIG_CPU == S3C2440) \ - || (CONFIG_CPU==AS3525) + || (CONFIG_CPU==AS3525) || (CONFIG_CPU==JZ4732) /* Read and save checksum */ lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); if (read(fd, &file_checksum, 4) != 4) { diff --git a/firmware/target/mips/ingenic_jz47xx/app.lds b/firmware/target/mips/ingenic_jz47xx/app.lds index dd539b0d41..37999c1050 100644 --- a/firmware/target/mips/ingenic_jz47xx/app.lds +++ b/firmware/target/mips/ingenic_jz47xx/app.lds @@ -12,10 +12,7 @@ STARTUP(target/mips/ingenic_jz47xx/crt0.o) #define STUBOFFSET 0 #endif -#define PLUGINSIZE PLUGIN_BUFFER_SIZE -#define CODECSIZE CODEC_SIZE - -#define DRAMSIZE ((MEMORYSIZE * 0x100000) - STUBOFFSET - PLUGINSIZE - CODECSIZE) +#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGIN_BUFFER_SIZE - STUBOFFSET - CODEC_SIZE #define DRAMORIG 0x80004000 #define IRAMORIG 0x80000000 @@ -25,7 +22,7 @@ STARTUP(target/mips/ingenic_jz47xx/crt0.o) #define ENDAUDIOADDR (DRAMORIG + DRAMSIZE) /* Where the codec buffer ends, and the plugin buffer starts */ -#define ENDADDR (ENDAUDIOADDR + CODECSIZE) +#define ENDADDR (ENDAUDIOADDR + CODEC_SIZE) MEMORY { diff --git a/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c b/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c index c76c63dd78..0b187be1cc 100644 --- a/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/codec-jz4740.c @@ -77,7 +77,7 @@ static void i2s_codec_init(void) i2s_codec_reset(); //REG_ICDC_CDCCR2 = (ICDC_CDCCR2_AINVOL(ICDC_CDCCR2_AINVOL_DB(0)) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_48) - REG_ICDC_CDCCR2 = ( ICDC_CDCCR2_AINVOL(23) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_48) + REG_ICDC_CDCCR2 = ( ICDC_CDCCR2_AINVOL(23) | ICDC_CDCCR2_SMPR(ICDC_CDCCR2_SMPR_44) | ICDC_CDCCR2_HPVOL(ICDC_CDCCR2_HPVOL_6)); REG_ICDC_CDCCR1 &= ~(ICDC_CDCCR1_SUSPD | ICDC_CDCCR1_RST); @@ -98,7 +98,7 @@ static void i2s_codec_init(void) REG_ICDC_CDCCR2 |= 3; - HP_on_off_flag = 0; /* HP is off */ + HP_on_off_flag = 1; /* HP is on */ } static void i2s_codec_set_mic(unsigned short v) /* 0 <= v <= 100 */ @@ -208,37 +208,36 @@ static void i2s_codec_set_samplerate(unsigned short rate) switch (rate) { case 8000: - speed = 0; + speed = 0 << 8; break; case 11025: - speed = 1; + speed = 1 << 8; break; case 12000: - speed = 2; + speed = 2 << 8; break; case 16000: - speed = 3; + speed = 3 << 8; break; case 22050: - speed = 4; + speed = 4 << 8; break; case 24000: - speed = 5; + speed = 5 << 8; break; case 32000: - speed = 6; + speed = 6 << 8; break; case 44100: - speed = 7; + speed = 7 << 8; break; case 48000: - speed = 8; + speed = 8 << 8; break; default: break; } REG_ICDC_CDCCR2 |= 0x00000f00; - speed = speed << 8; speed |= 0xfffff0ff; REG_ICDC_CDCCR2 &= speed; @@ -327,3 +326,8 @@ void audiohw_init(void) { i2s_codec_init(); } + +void audiohw_set_frequency(int freq) +{ + i2s_codec_set_samplerate(freq); +} diff --git a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c index b649311d13..c06c22e9c4 100644 --- a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c @@ -32,13 +32,17 @@ ** Playback DMA transfer **/ +static bool playback_started = false; +static void* playback_address; void pcm_postinit(void) { audiohw_postinit(); - /* playback sample:16 bits, burst:16 bytes */ - __i2s_set_transmit_trigger(4); + /* playback sample: 16 bits burst: 16 bytes */ + __i2s_set_iss_sample_size(16); __i2s_set_oss_sample_size(16); + __i2s_set_transmit_trigger(16 - 4); + __i2s_set_receive_trigger(4); } void pcm_play_dma_init(void) @@ -54,15 +58,24 @@ void pcm_play_dma_init(void) void pcm_dma_apply_settings(void) { /* TODO */ + audiohw_set_frequency(pcm_fsel); } static void play_start_pcm(void) { + /* Prefill FIFO */ + REG_AIC_DR = 0; + REG_AIC_DR = 0; + REG_AIC_DR = 0; + REG_AIC_DR = 0; + __i2s_enable_transmit_dma(); __i2s_enable_replay(); REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) |= DMAC_DCMD_TIE; + + playback_started = true; } static void play_stop_pcm(void) @@ -73,22 +86,52 @@ static void play_stop_pcm(void) __i2s_disable_transmit_dma(); __i2s_disable_replay(); + + playback_started = false; } void pcm_play_dma_start(const void *addr, size_t size) { dma_enable(); - + + __dcache_writeback_all(); REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = DMAC_DCCSR_NDES; REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)addr); REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)AIC_DR); REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) = size; REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT; - REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI| DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DWDH_32); + REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DWDH_16); + playback_address = (void*)addr; play_start_pcm(); } + +static void play_dma_callback(void) +{ + unsigned char *start; + size_t size = 0; + + pcm_callback_for_more(&start, &size); + if(size != 0) + { + __dcache_writeback_all(); + REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) = DMAC_DCCSR_NDES; + REG_DMAC_DSAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)start); + REG_DMAC_DTAR(DMA_AIC_TX_CHANNEL) = PHYSADDR((unsigned long)AIC_DR); + REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) = size; + REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT; + REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DWDH_16); + REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; + REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) |= DMAC_DCMD_TIE; + return; + } + + /* Error, callback missing or no more DMA to do */ + pcm_play_dma_stop(); + pcm_play_dma_stopped_callback(); +} + void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void) { if (REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) & DMAC_DCCSR_AR) @@ -101,21 +144,31 @@ void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void) { REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~(DMAC_DCCSR_TT | DMAC_DCCSR_HLT); REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) &= ~DMAC_DCCSR_EN; - __aic_disable_transmit_dma(); + play_dma_callback(); } } size_t pcm_get_bytes_waiting(void) { - return REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL); + if(playback_started) + return REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) & ~3; + else + return 0; } const void * pcm_play_dma_get_peak_buffer(int *count) { /* TODO */ - //*count = REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL)>>2; - *count = 0; - return NULL; + if(playback_started) + { + *count = REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL); + return (void*)(playback_address + ((REG_DMAC_DTCR(DMA_AIC_TX_CHANNEL) + 2) & ~3)); + } + else + { + *count = 0; + return NULL; + } } void pcm_play_dma_stop(void) diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c index f78f3592e5..291716a309 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c @@ -281,7 +281,7 @@ void dma_enable(void) REG_DMAC_DCCSR(4) = 0; REG_DMAC_DCCSR(5) = 0; - REG_DMAC_DMACR = (DMAC_DMACR_PR_012345 | DMAC_DMACR_DMAE); + REG_DMAC_DMACR = (DMAC_DMACR_PR_RR | DMAC_DMACR_DMAE); } } diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c index 2dd73c01a4..14656eed5f 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c @@ -730,7 +730,7 @@ int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) { //dma_cache_wback_inv((unsigned long)ptr, length); __dcache_writeback_all(); - REG_USB_REG_ADDR1 = (unsigned long)ptr & 0x7fffffff; + REG_USB_REG_ADDR1 = PHYSADDR((unsigned long)ptr); REG_USB_REG_COUNT1 = length; REG_USB_REG_CNTL1 = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | USB_CNTL_DIR_IN | USB_CNTL_ENA | @@ -780,7 +780,7 @@ int usb_drv_recv(int endpoint, void* ptr, int length) { //dma_cache_wback_inv((unsigned long)ptr, length); __dcache_writeback_all(); - REG_USB_REG_ADDR2 = (unsigned long)ptr & 0x7fffffff; + REG_USB_REG_ADDR2 = PHYSADDR((unsigned long)ptr); REG_USB_REG_COUNT2 = length; REG_USB_REG_CNTL2 = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | USB_CNTL_ENA | USB_CNTL_EP(endpoint) |