diff --git a/firmware/export/as3525.h b/firmware/export/as3525.h index 31bbeed..18d251c 100644 --- a/firmware/export/as3525.h +++ b/firmware/export/as3525.h @@ -497,4 +497,15 @@ interface */ /* PCM addresses for obtaining buffers will be what DMA is using (physical) */ #define HAVE_PCM_DMA_ADDRESS +/* I2SIN registers */ + +#define I2SIN_CONTROL (*(volatile unsigned char*)(I2SIN_BASE+0x00)) +#define I2SIN_MASK (*(volatile unsigned char*)(I2SIN_BASE+0x04)) +#define I2SIN_RAW_STATUS (*(volatile unsigned char*)(I2SIN_BASE+0x08)) +#define I2SIN_STATUS (*(volatile unsigned char*)(I2SIN_BASE+0x0C)) +#define I2SIN_CLEAR (*(volatile unsigned char*)(I2SIN_BASE+0x10)) +#define I2SIN_DATA (volatile unsigned long*)(I2SIN_BASE+0x14) +#define I2SIN_SPDIF_STATUS (*(volatile unsigned long*)(I2SIN_BASE+0x18)) + + #endif /*__AS3525_H__*/ diff --git a/firmware/export/config-c200v2.h b/firmware/export/config-c200v2.h index ae2cd04..d3076a7 100644 --- a/firmware/export/config-c200v2.h +++ b/firmware/export/config-c200v2.h @@ -9,8 +9,6 @@ #define FIRMWARE_OFFSET_FILE_DATA 8 #define FIRMWARE_OFFSET_FILE_CRC 0 -#if 0 - #define HW_SAMPR_CAPS (SAMPR_CAP_44) /* define this if you have recording possibility */ @@ -20,8 +18,6 @@ #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ #define REC_SAMPR_DEFAULT SAMPR_22 -#endif - /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) diff --git a/firmware/export/config-clip.h b/firmware/export/config-clip.h index 37b1a31..c2b106b 100644 --- a/firmware/export/config-clip.h +++ b/firmware/export/config-clip.h @@ -9,8 +9,6 @@ #define FIRMWARE_OFFSET_FILE_DATA 8 #define FIRMWARE_OFFSET_FILE_CRC 0 -#if 0 /* disabled since there is no driver (yet) */ - #define HW_SAMPR_CAPS (SAMPR_CAP_44) /* define this if you have recording possibility */ @@ -20,8 +18,6 @@ #define REC_FREQ_DEFAULT REC_FREQ_22 /* Default is not 44.1kHz */ #define REC_SAMPR_DEFAULT SAMPR_22 -#endif - /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) diff --git a/firmware/export/config-fuze.h b/firmware/export/config-fuze.h index c8fae9a..a850687 100644 --- a/firmware/export/config-fuze.h +++ b/firmware/export/config-fuze.h @@ -9,7 +9,6 @@ #define HW_SAMPR_CAPS (SAMPR_CAP_44) -#if 0 /* define this if you have recording possibility */ #define HAVE_RECORDING @@ -24,7 +23,6 @@ /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ -#endif #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) /* define this if you have a bitmap LCD display */ diff --git a/firmware/target/arm/as3525/ata_sd_as3525.c b/firmware/target/arm/as3525/ata_sd_as3525.c index 0556cc0..f85dc50 100644 --- a/firmware/target/arm/as3525/ata_sd_as3525.c +++ b/firmware/target/arm/as3525/ata_sd_as3525.c @@ -121,6 +121,8 @@ static bool sd_enabled = false; static struct wakeup transfer_completion_signal; static volatile bool retry; +#define MAX_TRIES 10 +static int tries = 0; static inline void mci_delay(void) { int i = 0xffff; while(i--) ; } @@ -157,7 +159,10 @@ void INT_NAND(void) const int status = MCI_STATUS(INTERNAL_AS3525); if(status & MCI_ERROR) + { retry = true; + tries++; + } wakeup_signal(&transfer_completion_signal); MCI_CLEAR(INTERNAL_AS3525) = status; @@ -169,7 +174,10 @@ void INT_MCI0(void) const int status = MCI_STATUS(SD_SLOT_AS3525); if(status & MCI_ERROR) + { retry = true; + tries++; + } wakeup_signal(&transfer_completion_signal); MCI_CLEAR(SD_SLOT_AS3525) = status; @@ -574,6 +582,7 @@ static int sd_select_bank(signed char bank) unsigned char card_data[512]; int ret; + tries = 0; do { /* The ISR will set this to true if an error occurred */ retry = false; @@ -619,6 +628,9 @@ static int sd_select_bank(signed char bank) mci_delay(); + if(retry && tries >= MAX_TRIES) + return -69; + ret = sd_wait_for_state(INTERNAL_AS3525, SD_TRAN); if (ret < 0) return ret - 4; @@ -636,6 +648,7 @@ static unsigned char *uncached_buffer = UNCACHED_ADDR(&aligned_buffer[0]); static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf, const bool write) { + mci_delay(); #ifndef HAVE_MULTIVOLUME const int drive = 0; #endif @@ -668,6 +681,7 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, dma_retain(); + tries = 0; while(count) { /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH @@ -745,6 +759,12 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK); if(!retry) { + if(tries >= MAX_TRIES) + { + ret = -666; // FIXME : mci status + goto sd_transfer_error; + } + if(!write) memcpy(buf, uncached_buffer, transfer * SECTOR_SIZE); buf += transfer * SECTOR_SIZE; diff --git a/firmware/target/arm/as3525/audio-as3525.c b/firmware/target/arm/as3525/audio-as3525.c index 410fdfa..1d125b6 100644 --- a/firmware/target/arm/as3525/audio-as3525.c +++ b/firmware/target/arm/as3525/audio-as3525.c @@ -39,8 +39,8 @@ void audio_set_output_source(int source) void audio_input_mux(int source, unsigned flags) { static int last_source = AUDIO_SRC_PLAYBACK; - - (void)flags; + static bool last_recording = false; + bool recording = flags & SRCF_RECORDING; switch (source) { @@ -51,15 +51,37 @@ void audio_input_mux(int source, unsigned flags) if (source != last_source) { audiohw_set_monitor(false); + audiohw_disable_recording(); + } + break; + + case AUDIO_SRC_MIC: /* recording only */ + audio_channels = 1; + if (source != last_source) + { + audiohw_set_monitor(false); + audiohw_enable_recording(true); /* source mic */ } break; case AUDIO_SRC_FMRADIO: /* recording and playback */ audio_channels = 2; + if (source == last_source) break; - audiohw_set_monitor(true); + last_recording = recording; + + if (recording) + { + audiohw_set_monitor(false); + audiohw_enable_recording(false); + } + else + { + audiohw_disable_recording(); + audiohw_set_monitor(true); /* line 2 analog audio path */ + } break; } /* end switch */ diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index 4f9e185..be9a420 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c @@ -109,7 +109,7 @@ void pcm_play_dma_stop(void) dma_disable_channel(1); dma_size = 0; - dma_release(); + //dma_release(); CGU_PERI &= ~CGU_I2SOUT_APB_CLOCK_ENABLE; CGU_AUDIO &= ~(1<<11); @@ -151,7 +151,7 @@ void pcm_dma_apply_settings(void) panicf("unsupported frequency %ld", frequency); CGU_AUDIO &= ~(((511 ^ divider) << 2) /* I2SOUT */ - /*| ((511 ^ divider) << 14) */ /* I2SIN */ + | ((511 ^ divider) << 14) /* I2SIN */ ); } @@ -180,43 +180,134 @@ void * pcm_dma_addr(void *addr) ** Recording DMA transfer **/ #ifdef HAVE_RECORDING + +static int rec_locked = 0; +static unsigned char *dma_rec_start_addr; +static size_t dma_rec_size; /* in 4*32 bits */ +static void dma_rec_callback(void); + +#define show_fn() lcd_puts(0,13,__func__);lcd_update(); + void pcm_rec_lock(void) { + if(++rec_locked == 1) + VIC_INT_EN_CLEAR = INTERRUPT_DMAC; } void pcm_rec_unlock(void) { + if(--rec_locked == 0) + VIC_INT_ENABLE |= INTERRUPT_DMAC; } void pcm_record_more(void *start, size_t size) { - (void)start; - (void)size; + show_fn(); + dma_rec_start_addr = start; + dma_rec_size = size; } void pcm_rec_dma_stop(void) { + show_fn(); + dma_disable_channel(1); + dma_rec_size = 0; + + dma_release(); + + CGU_PERI &= ~CGU_I2SIN_APB_CLOCK_ENABLE; + CGU_AUDIO &= ~(1<<23); +} + +static void start_recording(void) +{ + size_t size = dma_rec_size; + void* addr = dma_rec_start_addr; + + if(size > MAX_TRANSFER) + size = MAX_TRANSFER; + +{ + static int x = 0; + char buf[50]; + snprintf(buf, sizeof(buf), "%d : %d %x", ++x, size, addr); + lcd_puts(0, 12, buf); + lcd_update(); +} + + dma_rec_size -= size; + dma_rec_start_addr += size; + + //dump_dcache_range((void*)dma_rec_start_addr, size); + //we might want to use a buffer aligned on cache line size (32 bytes) + dma_enable_channel(1, (void*)I2SIN_DATA, addr, DMA_PERI_I2SIN, + DMAC_FLOWCTRL_DMAC_PERI_TO_MEM, false, true, size >> 2, DMA_S1, + dma_rec_callback); } void pcm_rec_dma_start(void *addr, size_t size) { - (void)addr; - (void)size; + show_fn(); + dma_rec_start_addr = addr; + dma_rec_size = size; + + if((unsigned int)addr & 3) + panicf("unaligned pointer!"); + + CGU_PERI |= CGU_I2SIN_APB_CLOCK_ENABLE; + CGU_AUDIO |= (1<<23); + + dma_retain(); + + start_recording(); +} + +static void dma_rec_callback(void) +{ + register pcm_more_callback_type2 more_ready = pcm_callback_more_ready; + + if(dma_rec_size || (more_ready && more_ready(0) >= 0)) + { + start_recording(); + return; + } + + pcm_rec_dma_stop(); + pcm_rec_dma_stopped_callback(); } void pcm_rec_dma_close(void) { + pcm_rec_dma_stop(); } void pcm_rec_dma_init(void) { + show_fn(); + /* clock source PLLA, minimal frequency */ + CGU_AUDIO |= (511<<14) | (1<<12); + + audiohw_preinit(); } const void * pcm_rec_dma_get_peak_buffer(int *count) { - (void)count; + const void *peak_buffer; + show_fn(); + + pcm_rec_lock(); + *count = dma_rec_size >> 2; + peak_buffer = (const void*)dma_rec_start_addr; + pcm_rec_unlock(); + + char buf[50]; + snprintf(buf, sizeof(buf), "0x%x %d", peak_buffer, dma_rec_size >> 2); + lcd_puts(0, 14, buf); + lcd_update(); + + return peak_buffer; } #endif /* HAVE_RECORDING */