From e8a8a1be43afe63079ae48ce1a9eb3052df3b1a4 Mon Sep 17 00:00:00 2001 From: Tomasz Moń Date: Wed, 16 Nov 2011 14:08:01 +0000 Subject: Sandisk Sansa Connect port (FS #12363) Included are drivers for buttons, backlight, lcd, audio and storage. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31000 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/tms320dm320/app.lds | 2 +- firmware/target/arm/tms320dm320/boot.lds | 19 +- firmware/target/arm/tms320dm320/debug-dm320.c | 2 + firmware/target/arm/tms320dm320/dma-dm320.c | 78 ++ firmware/target/arm/tms320dm320/dma-target.h | 44 + firmware/target/arm/tms320dm320/i2c-dm320.c | 138 ++- firmware/target/arm/tms320dm320/kernel-dm320.c | 9 +- .../tms320dm320/sansa-connect/adc-sansaconnect.c | 35 + .../arm/tms320dm320/sansa-connect/adc-target.h | 25 + .../tms320dm320/sansa-connect/avr-sansaconnect.c | 461 ++++++++++ .../tms320dm320/sansa-connect/avr-sansaconnect.h | 38 + .../sansa-connect/backlight-sansaconnect.c | 93 ++ .../tms320dm320/sansa-connect/backlight-target.h | 33 + .../arm/tms320dm320/sansa-connect/button-target.h | 64 ++ .../arm/tms320dm320/sansa-connect/crt0-board.S | 238 ++++++ .../tms320dm320/sansa-connect/lcd-sansaconnect.c | 273 ++++++ .../arm/tms320dm320/sansa-connect/lcd-target.h | 25 + .../tms320dm320/sansa-connect/pcm-sansaconnect.c | 207 +++++ .../tms320dm320/sansa-connect/power-sansaconnect.c | 59 ++ .../sansa-connect/powermgmt-sansaconnect.c | 56 ++ .../tms320dm320/sansa-connect/usb-sansaconnect.c | 53 ++ .../arm/tms320dm320/sansa-connect/usb-target.h | 32 + firmware/target/arm/tms320dm320/sdmmc-dm320.c | 949 +++++++++++++++++++++ firmware/target/arm/tms320dm320/system-dm320.c | 33 +- firmware/target/arm/tms320dm320/system-target.h | 5 + 25 files changed, 2959 insertions(+), 12 deletions(-) create mode 100644 firmware/target/arm/tms320dm320/dma-dm320.c create mode 100644 firmware/target/arm/tms320dm320/dma-target.h create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/adc-target.h create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/button-target.h create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c create mode 100644 firmware/target/arm/tms320dm320/sansa-connect/usb-target.h create mode 100644 firmware/target/arm/tms320dm320/sdmmc-dm320.c (limited to 'firmware/target') diff --git a/firmware/target/arm/tms320dm320/app.lds b/firmware/target/arm/tms320dm320/app.lds index 1e0d1839c0..4ea22a7902 100644 --- a/firmware/target/arm/tms320dm320/app.lds +++ b/firmware/target/arm/tms320dm320/app.lds @@ -29,7 +29,7 @@ STARTUP(target/arm/tms320dm320/crt0.o) #define DRAMSIZE (MEMORYSIZE * 0x100000) -#define DRAMORIG 0x00900000 +#define DRAMORIG CONFIG_SDRAM_START #define FLASHORIG 0x00100000 #define FLASHSIZE 0x00800000 diff --git a/firmware/target/arm/tms320dm320/boot.lds b/firmware/target/arm/tms320dm320/boot.lds index 2b9f345a23..65649d7268 100644 --- a/firmware/target/arm/tms320dm320/boot.lds +++ b/firmware/target/arm/tms320dm320/boot.lds @@ -28,14 +28,27 @@ STARTUP(target/arm/tms320dm320/crt0.o) #define LCD_TTB_AREA 0x100000*((LCD_BUFFER_SIZE>>19)+1) /* Bootloader only uses/knows about the upper 32 M */ -#define DRAMORIG 0x02900000 +#define DRAMORIG CONFIG_SDRAM_START+0x02000000 #define DRAMSIZE (MEMORYSIZE * 0x80000) #define IRAMORIG 0x00000000 #define IRAMSIZE 0x4000 +#ifdef SANSA_CONNECT +/* Offset in flash from beginning, we don't want overwrite OF bootloader + due to recovery mode and more importantly - hardware block protection. + This offset makes Rockbox bootloader a replacement for OF vmlinux. + In .srr file header add any valid memory address from following + <0x1000000; 0x1300180) u (0x131EAF4; 0x1420000) u (0x1440000; 0x5000000> + ensuring that complete bootloader fits in. + Entry point in .srr file should be 0x120010. */ +#define FLASHOFFSET 0x20010 +#else +#define FLASHOFFSET 0 +#endif + #define FLASHORIG 0x00100000 -#define FLASHSIZE 0x00800000 +#define FLASHSIZE 0x00800000-FLASHOFFSET PRO_STACK_SIZE = 0x2000; IRQ_STACK_SIZE = 0x400; @@ -48,7 +61,7 @@ MEMORY { DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE - FLASH : ORIGIN = FLASHORIG, LENGTH = FLASHSIZE + FLASH : ORIGIN = FLASHORIG+FLASHOFFSET, LENGTH = FLASHSIZE } SECTIONS diff --git a/firmware/target/arm/tms320dm320/debug-dm320.c b/firmware/target/arm/tms320dm320/debug-dm320.c index de17d54843..262d843bfc 100644 --- a/firmware/target/arm/tms320dm320/debug-dm320.c +++ b/firmware/target/arm/tms320dm320/debug-dm320.c @@ -212,6 +212,7 @@ bool dbg_hw_info(void) button = button_get(false); if(button & BUTTON_POWER) done = true; +#if defined(CREATIVE_ZVx) else if(button & BUTTON_LEFT) lcd_set_direct_fb(false); else if(button & BUTTON_RIGHT) @@ -221,6 +222,7 @@ bool dbg_hw_info(void) lcd_putsf(0, line++, " LCD direct FB access? %s", (lcd_get_direct_fb() ? "yes" : "no")); line++; +#endif #endif lcd_puts(0, line++, "[Rockbox info]"); lcd_putsf(0, line++, "current tick: %08x Seconds running: %08d", diff --git a/firmware/target/arm/tms320dm320/dma-dm320.c b/firmware/target/arm/tms320dm320/dma-dm320.c new file mode 100644 index 0000000000..e60102b6fb --- /dev/null +++ b/firmware/target/arm/tms320dm320/dma-dm320.c @@ -0,0 +1,78 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "kernel.h" +#include "thread.h" +#include "system.h" +#include "dma-target.h" +#include "dm320.h" +#include + +void dma_init(void) +{ + /* TODO */ +} + +/* + Requests channel for peripheral. + Returns channel assigned for caller which must be released after + transfer complete using dma_release_channel(). +*/ +int dma_request_channel(int peripheral, int mode) +{ + /* TODO: proper checking if channel is already taken + currently only SDMMC and DSP uses DMA on this target */ + int channel = -1; + + if (peripheral == DMA_PERIPHERAL_MMCSD) + { + /* Set first DMA channel */ + IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0xFFE0) | peripheral | + (mode << 3); + channel = 1; + } + else if (peripheral == DMA_PERIPHERAL_DSP) + { + /* Set second DMA channel */ + IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0xFC1F) | + (peripheral << 5) | + (mode << 8); + channel = 2; + } + else if (peripheral == DMA_PERIPHERAL_SIF) + { + IO_SDRAM_SDDMASEL = (IO_SDRAM_SDDMASEL & 0x83FF) | + (peripheral << 10) | + (mode << 13); + channel = 3; + } + + return channel; +} + +void dma_release_channel(int channel) +{ + (void)channel; + /* TODO */ +} + + diff --git a/firmware/target/arm/tms320dm320/dma-target.h b/firmware/target/arm/tms320dm320/dma-target.h new file mode 100644 index 0000000000..37053b319b --- /dev/null +++ b/firmware/target/arm/tms320dm320/dma-target.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 DMA_TARGET_H +#define DMA_TARGET_H + +/* These defines match DMA Select bits */ +#define DMA_PERIPHERAL_MTC 0 +#define DMA_PERIPHERAL_SIF 1 +#define DMA_PERIPHERAL_MS 2 +#define DMA_PERIPHERAL_MMCSD 3 +#define DMA_PERIPHERAL_DSP 4 + +/* These defines match DMA Burst bits */ +/* 1 burst DMA - address must be 4 byte aligned */ +#define DMA_MODE_1_BURST 0 +/* 4 burst DMA - address must be 16 byte aligned */ +#define DMA_MODE_4_BURST 1 +/* 8 burst DMA - address must be 32 byte aligned */ +#define DMA_MODE_8_BURST 2 + +void dma_init(void); +int dma_request_channel(int peripheral, int mode); +void dma_release_channel(int channel); + +#endif diff --git a/firmware/target/arm/tms320dm320/i2c-dm320.c b/firmware/target/arm/tms320dm320/i2c-dm320.c index 8bcc84dd8f..990dad0721 100644 --- a/firmware/target/arm/tms320dm320/i2c-dm320.c +++ b/firmware/target/arm/tms320dm320/i2c-dm320.c @@ -7,6 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * + * Copyright (C) 2011 by Tomasz Moń * Copyright (C) 2008 by Maurus Cuelenaere * * DM320 I²C driver @@ -24,11 +25,11 @@ #include "thread.h" #include "i2c-dm320.h" -#define I2C_SCS_COND_START 0x0001 -#define I2C_SCS_COND_STOP 0x0002 -#define I2C_SCS_XMIT 0x0004 +#ifdef HAVE_SOFTWARE_I2C +#include "generic_i2c.h" +#endif -#define I2C_TX_ACK (1 << 8) +#ifndef HAVE_SOFTWARE_I2C static struct mutex i2c_mtx; @@ -42,6 +43,12 @@ static inline void i2c_end(void) mutex_unlock(&i2c_mtx); } +#define I2C_SCS_COND_START 0x0001 +#define I2C_SCS_COND_STOP 0x0002 +#define I2C_SCS_XMIT 0x0004 + +#define I2C_TX_ACK (1 << 8) + static inline bool i2c_getack(void) { return (IO_I2C_RXDATA >> 8) & 1; @@ -158,3 +165,126 @@ void i2c_init(void) IO_I2C_SCS &= ~0x8; //set clock to 100 kHz IO_INTC_EINT2 &= ~INTR_EINT2_I2C; // disable I²C interrupt } + +#else /* Software I2C implementation */ + +#ifdef SANSA_CONNECT + /* SDA - GIO35 */ + #define SDA_SET_REG IO_GIO_BITSET2 + #define SDA_CLR_REG IO_GIO_BITCLR2 + #define SOFTI2C_SDA (1 << 3) + /* SCL - GIO36 */ + #define SCL_SET_REG IO_GIO_BITSET2 + #define SCL_CLR_REG IO_GIO_BITCLR2 + #define SOFTI2C_SCL (1 << 4) +#else + #error Configure SDA and SCL lines +#endif + +static int dm320_i2c_bus; + +static void dm320_scl_dir(bool out) +{ + if (out) + { + IO_GIO_DIR2 &= ~(SOFTI2C_SCL); + } + else + { + IO_GIO_DIR2 |= SOFTI2C_SCL; + } +} + +static void dm320_sda_dir(bool out) +{ + if (out) + { + IO_GIO_DIR2 &= ~(SOFTI2C_SDA); + } + else + { + IO_GIO_DIR2 |= SOFTI2C_SDA; + } +} + +static void dm320_scl_out(bool high) +{ + if (high) + { + SCL_SET_REG = SOFTI2C_SCL; + } + else + { + SCL_CLR_REG = SOFTI2C_SCL; + } +} + +static void dm320_sda_out(bool high) +{ + if (high) + { + SDA_SET_REG = SOFTI2C_SDA; + } + else + { + SDA_CLR_REG = SOFTI2C_SDA; + } +} + +static bool dm320_scl_in(void) +{ + return (SCL_SET_REG & SOFTI2C_SCL); +} + +static bool dm320_sda_in(void) +{ + return (SDA_SET_REG & SOFTI2C_SDA); +} + +/* simple delay */ +static void dm320_i2c_delay(int delay) +{ + udelay(delay); +} + +/* interface towards the generic i2c driver */ +static const struct i2c_interface dm320_i2c_interface = { + .scl_dir = dm320_scl_dir, + .sda_dir = dm320_sda_dir, + .scl_out = dm320_scl_out, + .sda_out = dm320_sda_out, + .scl_in = dm320_scl_in, + .sda_in = dm320_sda_in, + .delay = dm320_i2c_delay, + + /* uncalibrated */ + .delay_hd_sta = 1, + .delay_hd_dat = 1, + .delay_su_dat = 1, + .delay_su_sto = 1, + .delay_su_sta = 1, + .delay_thigh = 1 +}; + +void i2c_init(void) +{ +#ifdef SANSA_CONNECT + IO_GIO_FSEL3 &= 0xFF0F; /* GIO35, GIO36 as normal GIO */ + IO_GIO_INV2 &= ~(SOFTI2C_SDA | SOFTI2C_SCL); /* not inverted */ +#endif + + /* generic_i2c takes care of setting direction */ + dm320_i2c_bus = i2c_add_node(&dm320_i2c_interface); +} + +int i2c_write(unsigned short address, const unsigned char* buf, int count) +{ + return i2c_write_data(dm320_i2c_bus, address, -1, buf, count); +} + +int i2c_read(unsigned short address, unsigned char* buf, int count) +{ + return i2c_read_data(dm320_i2c_bus, address, -1, buf, count); +} + +#endif diff --git a/firmware/target/arm/tms320dm320/kernel-dm320.c b/firmware/target/arm/tms320dm320/kernel-dm320.c index 08c50432e4..79206c3413 100644 --- a/firmware/target/arm/tms320dm320/kernel-dm320.c +++ b/firmware/target/arm/tms320dm320/kernel-dm320.c @@ -37,7 +37,7 @@ void tick_start(unsigned int interval_in_ms) /* Setup the Divisor */ IO_TIMER1_TMDIV = (TIMER_FREQ / (10*1000))*interval_in_ms - 1; - + /* Turn Timer1 to Free Run mode */ IO_TIMER1_TMMD = CONFIG_TIMER1_TMMD_FREE_RUN; @@ -45,6 +45,13 @@ void tick_start(unsigned int interval_in_ms) bitset16(&IO_INTC_EINT0, INTR_EINT0_TMR1); } +#ifdef BOOTLOADER +void tick_stop(void) +{ + bitclr16(&IO_CLK_MOD2, CLK_MOD2_TMR1); /* disable TIMER1 clock */ +} +#endif + void TIMER1(void) __attribute__ ((section(".icode"))); void TIMER1(void) { diff --git a/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c new file mode 100644 index 0000000000..b3e427b9a5 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c @@ -0,0 +1,35 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "cpu.h" +#include "adc.h" +#include "adc-target.h" +#include "kernel.h" + +void adc_init(void) +{ +} + +/* Called to get the recent ADC reading */ +inline unsigned short adc_read(int channel) +{ + return (short)channel; +} diff --git a/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h b/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h new file mode 100644 index 0000000000..49244b4c3b --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/adc-target.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 _ADC_TARGET_H_ +#define _ADC_TARGET_H_ + +#endif diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c new file mode 100644 index 0000000000..3a6a748621 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c @@ -0,0 +1,461 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id: $ +* +* Copyright (C) 2011 by Tomasz Moń +* +* 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 +#include "config.h" +#include "system.h" +#include "kernel.h" +#include "logf.h" +#include "avr-sansaconnect.h" +#include "uart-target.h" +#include "button.h" +#include "backlight.h" +#include "powermgmt.h" + +//#define BUTTON_DEBUG + +#ifdef BUTTON_DEBUG +#include "lcd-target.h" +#include "lcd.h" +#include "font.h" +#include "common.h" +#endif + +#ifdef BUTTON_DEBUG +#define dbgprintf DEBUGF +#else +#define dbgprintf(...) +#endif + +#define CMD_SYNC 0xAA +#define CMD_CLOSE 0xCC +#define CMD_LCM_POWER 0xC9 +#define LCM_POWER_OFF 0x00 +#define LCM_POWER_ON 0x01 +#define LCM_POWER_SLEEP 0x02 +#define LCM_POWER_WAKE 0x03 +#define LCM_REPOWER_ON 0x04 + +#define CMD_STATE 0xBB +#define CMD_VER 0xBC +#define CMD_WHEEL_EN 0xD0 +#define CMD_SET_INTCHRG 0xD1 +#define CMD_CODEC_RESET 0xD7 +#define CMD_FILL 0xFF + +#define CMD_SYS_CTRL 0xDA +#define SYS_CTRL_POWEROFF 0x00 + +/* protects spi avr commands from concurrent access */ +static struct mutex avr_mtx; + +/* buttons thread */ +#define BTN_INTERRUPT 1 +static int btn = 0; +static bool hold_switch; +#ifndef BOOTLOADER +static long btn_stack[DEFAULT_STACK_SIZE/sizeof(long)]; +static const char btn_thread_name[] = "buttons"; +static struct event_queue btn_queue; +#endif + +static inline unsigned short be2short(unsigned char* buf) +{ + return (unsigned short)((buf[0] << 8) | buf[1]); +} + +#define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV) + +#ifndef BOOTLOADER +static void handle_wheel(unsigned char wheel) +{ + static int key = 0; + static unsigned char velocity = 0; + static unsigned long wheel_delta = 1ul << 24; + static unsigned char wheel_prev = 0; + static long next_backlight_on = 0; + static int prev_key = -1; + static int prev_key_post = 0; + + if (TIME_AFTER(current_tick, next_backlight_on)) + { + backlight_on(); + reset_poweroff_timer(); + next_backlight_on = current_tick + HZ/4; + } + + if (wheel_prev < wheel) + { + key = BUTTON_SCROLL_FWD; + velocity = wheel - wheel_prev; + } + else if (wheel_prev > wheel) + { + key = BUTTON_SCROLL_BACK; + velocity = wheel_prev - wheel; + } + + if (prev_key != key && velocity < 2 /* filter "rewinds" */) + { + /* direction reversal */ + prev_key = key; + wheel_delta = 1ul << 24; + return; + } + + /* TODO: take velocity into account */ + if (queue_empty(&button_queue)) + { + if (prev_key_post == key) + { + key |= BUTTON_REPEAT; + } + + /* Post directly, don't update btn as avr doesn't give + interrupt on scroll stop */ + queue_post(&button_queue, key, wheel_delta); + + wheel_delta = 1ul << 24; + + prev_key_post = key; + } + else + { + /* skipped post - increment delta and limit to 7 bits */ + wheel_delta += 1ul << 24; + + if (wheel_delta > (0x7ful << 24)) + wheel_delta = 0x7ful << 24; + } + + wheel_prev = wheel; + + prev_key = key; +} +#endif + +/* buf must be 11-byte array of byte (reply from avr_hid_get_state() */ +static void parse_button_state(unsigned char *buf) +{ + unsigned short main_btns_state = be2short(&buf[4]); +#ifdef BUTTON_DEBUG + unsigned short main_btns_changed = be2short(&buf[6]); +#endif + + /* make sure other bits doesn't conflict with our "free bits" buttons */ + main_btns_state &= BUTTON_DIRECT_MASK; + + if (buf[3] & 0x01) /* is power button pressed? */ + { + main_btns_state |= BUTTON_POWER; + } + + btn = main_btns_state; + +#ifndef BOOTLOADER + /* check if stored hold_switch state changed (prevents lost changes) */ + if ((buf[3] & 0x20) /* hold change notification */ || + (hold_switch != ((buf[3] & 0x02) >> 1))) + { +#endif + hold_switch = (buf[3] & 0x02) >> 1; +#ifdef BUTTON_DEBUG + dbgprintf("HOLD changed (%d)", hold_switch); +#endif +#ifndef BOOTLOADER + backlight_hold_changed(hold_switch); + } +#endif +#ifndef BOOTLOADER + if ((hold_switch == false) && (buf[3] & 0x80)) /* scrollwheel change */ + { + handle_wheel(buf[2]); + } +#endif + +#ifdef BUTTON_DEBUG + if (buf[3] & 0x10) /* power button change */ + { + /* power button state has changed */ + main_btns_changed |= BUTTON_POWER; + } + + if (btn & BUTTON_LEFT) dbgprintf("LEFT"); + if (btn & BUTTON_UP) dbgprintf("UP"); + if (btn & BUTTON_RIGHT) dbgprintf("RIGHT"); + if (btn & BUTTON_DOWN) dbgprintf("DOWN"); + if (btn & BUTTON_SELECT) dbgprintf("SELECT"); + if (btn & BUTTON_VOL_UP) dbgprintf("VOL UP"); + if (btn & BUTTON_VOL_DOWN) dbgprintf("VOL DOWN"); + if (btn & BUTTON_NEXT) dbgprintf("NEXT"); + if (btn & BUTTON_PREV) dbgprintf("PREV"); + if (btn & BUTTON_POWER) dbgprintf("POWER"); + if (btn & BUTTON_HOLD) dbgprintf("HOLD"); + if (btn & BUTTON_SCROLL_FWD) dbgprintf("SCROLL FWD"); + if (btn & BUTTON_SCROLL_BACK) dbgprintf("SCROLL BACK"); +#endif +} + +/* HID Slave Select - GIO14 */ +#define HID_SS (1<<14) + +static inline void select_hid(bool on) +{ + if (on == true) + { + /* SS is active low */ + IO_GIO_BITCLR0 = HID_SS; + } + else + { + IO_GIO_BITSET0 = HID_SS; + } +} + +static void spi_txrx(unsigned char *buf_tx, unsigned char *buf_rx, int n) +{ + int i; + unsigned short rxdata; + + mutex_lock(&avr_mtx); + + bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF1); + IO_SERIAL1_TX_ENABLE = 0x0001; + select_hid(true); + + for (i = 0; i 200 kHz */ + IO_SERIAL1_MODE = 0x6DB; + + mutex_init(&avr_mtx); + + avr_hid_sync(); +} + + +static void avr_hid_get_state(void) +{ + static unsigned char cmd[11] = {CMD_SYNC, CMD_STATE, + CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, + CMD_CLOSE}; + + static unsigned char buf[11]; + static unsigned char cmd_empty[1] = {0xCC}; + + spi_txrx(cmd, buf, sizeof(cmd)); + + spi_txrx(cmd_empty, NULL, 1); /* request interrupt on button press */ + + parse_button_state(buf); +} + +static void avr_hid_enable_wheel(void) +{ + unsigned char wheel_en[4] = {CMD_SYNC, CMD_WHEEL_EN, 0x01, CMD_CLOSE}; + + spi_txrx(wheel_en, NULL, sizeof(wheel_en)); +} + +/* command that is sent by "hidtool -J 1" issued on every OF boot */ +void avr_hid_enable_charger(void) +{ + unsigned char charger_en[4] = {CMD_SYNC, CMD_SET_INTCHRG, 0x01, CMD_CLOSE}; + + spi_txrx(charger_en, NULL, sizeof(charger_en)); +} + +void avr_hid_lcm_sleep(void) +{ + unsigned char lcm_sleep[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_SLEEP, CMD_CLOSE}; + + spi_txrx(lcm_sleep, NULL, sizeof(lcm_sleep)); +} + + +void avr_hid_lcm_wake(void) +{ + unsigned char lcm_wake[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_WAKE, CMD_CLOSE}; + + spi_txrx(lcm_wake, NULL, sizeof(lcm_wake)); +} + +void avr_hid_lcm_power_on(void) +{ + unsigned char lcm_power_on[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_ON, CMD_CLOSE}; + + spi_txrx(lcm_power_on, NULL, sizeof(lcm_power_on)); +} + +void avr_hid_lcm_power_off(void) +{ + unsigned char lcm_power_off[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_OFF, CMD_CLOSE}; + + spi_txrx(lcm_power_off, NULL, sizeof(lcm_power_off)); +} + +void avr_hid_reset_codec(void) +{ + unsigned char codec_reset[4] = {CMD_SYNC, CMD_CODEC_RESET, CMD_CLOSE, CMD_FILL}; + + spi_txrx(codec_reset, NULL, sizeof(codec_reset)); +} + +void avr_hid_power_off(void) +{ + unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE}; + + spi_txrx(prg, NULL, sizeof(prg)); +} + +#ifndef BOOTLOADER +void btn_thread(void) +{ + struct queue_event ev; + + while (1) + { + queue_wait(&btn_queue, &ev); + + /* Ignore all messages except BTN_INTERRUPT */ + if (ev.id != BTN_INTERRUPT) + continue; + + /* Enable back button interrupt */ + IO_INTC_EINT1 |= INTR_EINT1_EXT0; + + /* Read buttons state */ + avr_hid_get_state(); + + yield(); + + if (queue_empty(&btn_queue) && ((IO_GIO_BITSET0 & 0x1) == 0)) + { + /* for some reason we have lost next interrupt */ + queue_post(&btn_queue, BTN_INTERRUPT, 0); + } + } +} + +void GIO0(void) __attribute__ ((section(".icode"))); +void GIO0(void) +{ + /* Clear interrupt */ + IO_INTC_IRQ1 = (1 << 5); + /* Disable interrupt */ + IO_INTC_EINT1 &= ~INTR_EINT1_EXT0; + + /* interrupt will be enabled back after button read */ + queue_post(&btn_queue, BTN_INTERRUPT, 0); +} +#endif + +void button_init_device(void) +{ + btn = 0; + hold_switch = false; +#ifndef BOOTLOADER + queue_init(&btn_queue, true); + create_thread(btn_thread, btn_stack, sizeof(btn_stack), 0, + btn_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU)); +#endif + IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */ + + /* Enable wheel */ + avr_hid_enable_wheel(); + /* Read button status and tell avr we want interrupt on next change */ + avr_hid_get_state(); + +#ifndef BOOTLOADER + IO_GIO_IRQPORT |= 0x01; /* Enable GIO0 external interrupt */ + IO_GIO_INV0 &= ~0x01; /* Clear INV for GIO0 (falling edge detection) */ + IO_GIO_IRQEDGE &= ~0x01; /* Set edge detection (falling) */ + + /* Enable GIO0 interrupt */ + IO_INTC_EINT1 |= INTR_EINT1_EXT0; +#endif +} + +int button_read_device(void) +{ + if(hold_switch) + return 0; + else + return btn; +} + +bool button_hold(void) +{ + return hold_switch; +} + +void lcd_enable(bool on) +{ + (void)on; +} + diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h new file mode 100644 index 0000000000..64b44675f7 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h @@ -0,0 +1,38 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id: $ +* +* Copyright (C) 2011 by Tomasz Moń +* +* 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 _AVR_SANSACONNECT_H_ +#define _AVR_SANSACONNECT_H_ + +#include "config.h" + +void avr_hid_init(void); + +void avr_hid_enable_charger(void); + +void avr_hid_lcm_sleep(void); +void avr_hid_lcm_wake(void); +void avr_hid_lcm_power_on(void); +void avr_hid_lcm_power_off(void); +void avr_hid_reset_codec(void); +void avr_hid_power_off(void); + +#endif /* _AVR_SANSACONNECT_H_ */ diff --git a/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c new file mode 100644 index 0000000000..b7989849d7 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c @@ -0,0 +1,93 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "cpu.h" +#include "system.h" +#include "backlight-target.h" +#include "backlight.h" +#include "lcd.h" +#include "power.h" +#include "spi-target.h" +#include "lcd-target.h" + +static void _backlight_write_brightness(int brightness) +{ + /* + Maps brightness int to percentage value found in OF + + OF PWM1H + 5% 14 + 10% 140 + 15% 210 + 20% 280 + ... + 95% 1330 + 100% 1400 + */ + if (brightness > 20) + brightness = 20; + else if (brightness < 0) + brightness = 0; + + IO_CLK_PWM1H = brightness*70; +} + +void _backlight_on(void) +{ + /* set GIO34 as PWM1 */ + IO_GIO_FSEL3 = (IO_GIO_FSEL3 & 0xFFF3) | (1 << 2); + +#if (CONFIG_BACKLIGHT_FADING == BACKLIGHT_NO_FADING) + _backlight_write_brightness(backlight_brightness); +#endif +} + +void _backlight_off(void) +{ + _backlight_write_brightness(0); + + bitclr16(&IO_GIO_FSEL3, 0xC); /* set GIO34 to normal GIO */ + bitclr16(&IO_GIO_INV2, (1 << 2)); /* make sure GIO34 is not inverted */ + IO_GIO_BITCLR2 = (1 << 2); /* drive GIO34 low */ +} + +/* Assumes that the backlight has been initialized */ +void _backlight_set_brightness(int brightness) +{ + _backlight_write_brightness(brightness); +} + +void __backlight_dim(bool dim_now) +{ + _backlight_set_brightness(dim_now ? + DEFAULT_BRIGHTNESS_SETTING : + DEFAULT_DIMNESS_SETTING); +} + +bool _backlight_init(void) +{ + IO_CLK_PWM1C = 0x58D; /* as found in OF */ + + _backlight_set_brightness(backlight_brightness); + return true; +} + diff --git a/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h b/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h new file mode 100644 index 0000000000..89bd837cee --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/backlight-target.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 BACKLIGHT_TARGET_H +#define BACKLIGHT_TARGET_H + +bool _backlight_init(void); +void _backlight_on(void); +void _backlight_off(void); +void _backlight_set_brightness(int brightness); + +/* true: backlight fades off - false: backlight fades on */ +void __backlight_dim(bool dim); + +#endif diff --git a/firmware/target/arm/tms320dm320/sansa-connect/button-target.h b/firmware/target/arm/tms320dm320/sansa-connect/button-target.h new file mode 100644 index 0000000000..2eb571ae68 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/button-target.h @@ -0,0 +1,64 @@ +/*************************************************************************** +* __________ __ ___. +* Open \______ \ ____ ____ | | _\_ |__ _______ ___ +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +* \/ \/ \/ \/ \/ +* $Id: $ +* +* Copyright (C) 2011 by Tomasz Moń +* +* 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 _BUTTON_TARGET_H_ +#define _BUTTON_TARGET_H_ + +#include "config.h" + +#define BUTTON_REMOTE 0 + +/* these definitions match the avr hid reply */ +#define BUTTON_LEFT (1 << 2) +#define BUTTON_UP (1 << 3) +#define BUTTON_RIGHT (1 << 4) +#define BUTTON_DOWN (1 << 5) +#define BUTTON_SELECT (1 << 6) +#define BUTTON_VOL_UP (1 << 10) +#define BUTTON_VOL_DOWN (1 << 11) +#define BUTTON_NEXT (1 << 13) +#define BUTTON_PREV (1 << 14) + +/* following definitions use "free bits" from avr hid reply */ +#define BUTTON_POWER (1 << 0) +#define BUTTON_HOLD (1 << 1) +#define BUTTON_SCROLL_FWD (1 << 7) +#define BUTTON_SCROLL_BACK (1 << 8) + + +#define BUTTON_REMOTE 0 +#define BUTTON_MAIN (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN |\ + BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN |\ + BUTTON_NEXT | BUTTON_PREV | BUTTON_POWER |\ + BUTTON_SCROLL_FWD | BUTTON_SCROLL_BACK) + +#define POWEROFF_BUTTON BUTTON_POWER +#define POWEROFF_COUNT 5 + +#define HAS_BUTTON_HOLD + +void button_init_device(void); +int button_read_device(void); +bool button_hold(void); + +int get_debug_info(int choice); + +#endif /* _BUTTON_TARGET_H_ */ diff --git a/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S b/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S new file mode 100644 index 0000000000..debd2cd2be --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/crt0-board.S @@ -0,0 +1,238 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "cpu.h" + +/* Macro for reading a register */ +.macro mrh register + ldr r1, =\register + ldrh r0, [r1] +.endm + +/* Macro for writing a register */ +.macro mwh register, value + ldr r0, =\value + ldr r1, =\register + strh r0, [r1] +.endm + +/* This version uses a mov to save on the literal pool size. Otherwise it is + * functionally equivalent. + */ +.macro mwhm register, value + mov r0, #\value + ldr r1, =\register + strh r0, [r1] +.endm + + /* + * _init_board: + * This function initializes the specific board this SoC is on. + */ +.section .init, "ax" +.code 32 +.align 0x04 +.global _init_board +.type _init_board, %function + +_init_board: + + /* Setup the EMIF interface timings */ + + /* FLASH interface: + * These are based on the OF setup + */ + /* IO_EMIF_CS0CTRL1 and + * IO_EMIF_CS0CTRL2 + */ + mwh 0x30A00, 0x889A + mwh 0x30A02, 0x1110 + + mwhm 0x30A04, 0 + mwh 0x30A06, 0x1415 + mwh 0x30A08, 0x1109 + + mwh 0x30A0A, 0x1220 + mwh 0x30A0C, 0x1104 + mwh 0x30A0E, 0x0222 + + /* IO_EMIF_CS3CTRL1 and + * IO_EMIF_CS3CTRL2 + */ + mwh 0x30A10, 0x8899 + mwh 0x30A12, 0x5110 + + /* USB interface */ + /* IO_EMIF_CS4CTRL1 and + * IO_EMIF_CS4CTRL2 + */ + mwh 0x30A14, 0x77DF + mwh 0x30A16, 0x7740 + + /* IO_EMIF_BUSCTRL */ + mwhm 0x30A18, 0 + mwhm 0x30A1A, 0 + mwhm 0x30A1C, 0 + mwhm 0x30A1E, 0 + +_clock_setup: + /* Clock initialization */ + + /* IO_CLK_BYP: Bypass the PLLs for the following changes */ + mwh 0x30894, 0x1111 + + /* + * IO_CLK_PLLA + * IO_CLK_PLLB + */ + mwhm 0x30880, 0x00A0 + mwhm 0x30882, 0x1000 + + /* IO_CLK_SEL0 */ + mwh 0x30884, 0x0066 + + /* IO_CLK_SEL1 */ + mwhm 0x30886, 0x0003 + + # IO_CLK_SEL2: ARM, AXL, SDRAM and DSP are from PLLA */ + mwh 0x30888, 0 + + /* IO_CLK_DIV0: Set the slow clock speed for the ARM/AHB */ + mwh 0x3088A, 0x0101 + + /* IO_CLK_DIV1: Accelerator, SDRAM */ + mwh 0x3088C, 0x0102 + + /* IO_CLK_DIV2: DSP, MS Clock */ + mwhm 0x3088E, 0x0200 + + # PLLA &= ~0x1000 (BIC #0x1000) + mrh 0x30880 + bic r0, r0, #0x1000 + strh r0, [r1] + + /* Wait for PLLs to lock before feeding them to the downstream devices */ +_plla_wait: + mrh 0x30880 + bic r0, r0, #0x7F + tst r0, r0 + beq _plla_wait + + /* IO_CLK_BYP: Enable PLL feeds */ + mwhm 0x30894, 0x0 + + /* IO_CLK_MOD0 */ + mwh 0x30898, 0x01A7 + + /* IO_CLK_MOD1 */ + mwhm 0x3089A, 0x18 + + /* IO_CLK_MOD2 */ + mwhm 0x3089C, 0x4A0 + + /* Setup the SDRAM range on the AHB bus */ + /* SDRAMSA */ + mov r0, #0x60000 + mov r1, #0x1000000 + str r1, [r0, #0xF00] + + /* SDRAMEA: 64MB */ + mov r1, #0x5000000 + str r1, [r0, #0xF04] + + /* SDRC_REFCTL */ + mwh 0x309A8, 0 + + ldr r0, =0x309A6 + mov r2, #0x1380 + orr r1, r2, #2 + strh r1, [r0] + orr r1, r2, #4 + strh r1, [r0] + strh r1, [r0] + strh r1, [r0] + strh r1, [r0] + strh r1, [r0] + strh r1, [r0] + strh r1, [r0] + strh r1, [r0] + orr r1, r2, #1 + strh r1, [r0] + strh r2, [r0] + strh r2, [r0] + + mwhm 0x309A8, 0x0140 + + mwhm 0x309BE, 0x4 + mwhm 0x309BC, 0x2 + ldr r0, =0x309C4 + ldr r1, [r0] + orr r1, r1, #1 + strh r1, [r0] + + ldr r0, =0x309A6 + mov r1, #0x1380 + strh r1, [r0] + bic r1, r1, #0x80 + strh r1, [r0] + orr r1, r1, #0x40 + strh r1, [r0] + + mwhm 0x309A8, 0x0140 + + /* Go through the GPIO initialization */ + /* Warning: setting some of the functions wrong will make OF unable + to boot (freeze during startup) */ + /* IO_GIO_FSEL0: Set up the GPIO pin functions 0-16 */ + mwhm 0x305A4, 0xC000 + + /* IO_GIO_FSEL1: 17-24 */ + mwh 0x305A6, 0xAAAA + + /* IO_GIO_FSEL2: 18-32 */ + mwh 0x305A8, 0xA80A + + /* IO_GIO_FSEL3: 33-40 */ + mwh 0x305AA, 0x1007 + + /* IO_GIO_DIR0 */ + mwh 0x30580, 0xFF77 + + /* IO_GIO_DIR1 */ + mwh 0x30582, 0xEFFE + + /* IO_GIO_DIR2 */ + mwh 0x30584, 0x01FD + + /* IO_GIO_INV0 */ + mwh 0x30586, 0x0000 + + /* IO_GIO_INV1 */ + mwh 0x30588, 0x0000 + + /* IO_GIO_INV2 */ + mwh 0x3058A, 0x0000 + + bx lr + +.ltorg +.size _init_board, .-_init_board + diff --git a/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c new file mode 100644 index 0000000000..fcfc82e876 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c @@ -0,0 +1,273 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 +#include "config.h" +#include "cpu.h" +#include "string.h" +#include "kernel.h" +#include "system.h" +#include "system-target.h" +#include "lcd.h" +#include "lcd-target.h" +#include "avr-sansaconnect.h" + +/* Copies a rectangle from one framebuffer to another. Can be used in + single transfer mode with width = num pixels, and height = 1 which + allows a full-width rectangle to be copied more efficiently. */ +extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src, + int width, int height); + +static bool lcd_on = true; + +bool lcd_active(void) +{ + return lcd_on; +} + +#if defined(HAVE_LCD_SLEEP) +void lcd_sleep(void) +{ + if (lcd_on) + { + lcd_on = false; + avr_hid_lcm_sleep(); + sleep(HZ/20); + + /* disable video encoder */ + bitclr16(&IO_VID_ENC_VMOD, 0x01); + + sleep(HZ/20); + + /* disable video encoder clock */ + bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC); + } +} + +void lcd_awake(void) +{ + if (!lcd_on) + { + lcd_on = true; + /* enable video encoder clock */ + bitset16(&IO_CLK_MOD1, CLK_MOD1_VENC); + + /* enable video encoder */ + bitset16(&IO_VID_ENC_VMOD, 0x01); + + avr_hid_lcm_wake(); + + send_event(LCD_EVENT_ACTIVATION, NULL); + + lcd_update(); + } +} +#endif + +void lcd_init_device(void) +{ + unsigned int addr; + + /* Disable Video Encoder clock */ + bitclr16(&IO_CLK_MOD1, CLK_MOD1_VENC); + + /* configure GIO39, GIO34 and GIO33 as outputs */ + IO_GIO_DIR2 &= ~((1 << 7) /* GIO39 */ | (1 << 2) /* GIO34 */ | + (1 << 1) /* GIO33 */); + + IO_GIO_FSEL3 = (IO_GIO_FSEL3 & ~(0x300F)) | + (0x1000) /* GIO39 - FIELD_VENC */ | + (0x3) /* GIO33 - CLKOUT1B (bootloader does this) */ | + (0x4); /* GIO34 - PWM1 (brightness control) */ + + /* OSD Clock = VENC Clock /2, + CCD clock PCLK, + VENC Clock from PLLA */ + IO_CLK_SEL1 = 0x3; + + /* Set VENC Clock Division to 11 + OF bootloader sets division to 8, vmlinux sets it to 11 */ + IO_CLK_DIV3 = (IO_CLK_DIV3 & ~(0x1F00)) | 0xB00; + + /* Enable DAC and OSD clocks */ + bitset16(&IO_CLK_MOD1, CLK_MOD1_DAC | CLK_MOD1_OSD); + + /* magic values based on OF bootloader initialization */ + IO_VID_ENC_VMOD = 0x2010; + IO_VID_ENC_VDPRO = 0x80; + IO_VID_ENC_HSPLS = 0x4; + IO_VID_ENC_HINT = 0x4B0; + IO_VID_ENC_HSTART = 0x88; + IO_VID_ENC_HVALID = 0x3C0; + IO_VID_ENC_HSDLY = 0; + IO_VID_ENC_VSPLS = 0x2; + IO_VID_ENC_VINT = 0x152; + IO_VID_ENC_VSTART = 0x6; + IO_VID_ENC_VVALID = 0x140; + IO_VID_ENC_VSDLY = 0; + IO_VID_ENC_DCLKCTL = 0x3; + IO_VID_ENC_DCLKPTN0 = 0xC; + IO_VID_ENC_VDCTL = 0x6000; + IO_VID_ENC_SYNCTL = 0x2; + IO_VID_ENC_LCDOUT = 0x101; + IO_VID_ENC_VMOD = 0x2011; + + /* Copy Rockbox frame buffer to the second framebuffer */ + lcd_update(); + + avr_hid_lcm_power_on(); + + /* set framebuffer address - OF sets RAM start address to 0x1000000 */ + addr = ((int)FRAME-CONFIG_SDRAM_START)/32; + + IO_OSD_OSDWINADH = addr >> 16; + IO_OSD_OSDWIN0ADL = addr & 0xFFFF; + + IO_OSD_BASEPX = 0x44; + IO_OSD_BASEPY = 0x6; + IO_OSD_OSDWIN0XP = 0; + IO_OSD_OSDWIN0YP = 0; + IO_OSD_OSDWIN0XL = LCD_WIDTH*2; /* OF bootloader sets 480 */ + IO_OSD_OSDWIN0YL = LCD_HEIGHT; /* OF bootloader sets 320 */ + IO_OSD_OSDWIN0OFST = 0xF; + IO_OSD_OSDWINMD0 = 0x25FB;/* OF bootloader sets 25C3, + vmlinux changes this to 0x25FB */ + IO_OSD_VIDWINMD = 0; /* disable video windows (OF sets 0x03) */ + + IO_OSD_OSDWINMD1 = 0; /* disable OSD window 1 */ + + /* Enable DAC, Video Encoder and OSD clocks */ + bitset16(&IO_CLK_MOD1, CLK_MOD1_DAC | CLK_MOD1_VENC | CLK_MOD1_OSD); + + /* Enable Video Encoder - RGB666, custom timing */ + IO_VID_ENC_VMOD = 0x2011; + avr_hid_lcm_wake(); +} + +/* Update a fraction of the display. */ +void lcd_update_rect(int x, int y, int width, int height) + __attribute__ ((section(".icode"))); +void lcd_update_rect(int x, int y, int width, int height) +{ + register fb_data *dst, *src; + + if (!lcd_on) + return; + + if ((width | height) < 0) + return; /* Nothing left to do */ + + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; /* Clip right */ + if (x < 0) + width += x, x = 0; /* Clip left */ + + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; /* Clip bottom */ + if (y < 0) + height += y, y = 0; /* Clip top */ + + dst = FRAME + LCD_WIDTH*y + x; + src = &lcd_framebuffer[y][x]; + + /* Copy part of the Rockbox framebuffer to the second framebuffer */ + if (width < LCD_WIDTH) + { + /* Not full width - do line-by-line */ + lcd_copy_buffer_rect(dst, src, width, height); + } + else + { + /* Full width - copy as one line */ + lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1); + } +} + +/* Update the display. + This must be called after all other LCD functions that change the display. */ +void lcd_update(void) __attribute__ ((section(".icode"))); +void lcd_update(void) +{ + if (!lcd_on) + return; + + lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); +} + +void lcd_set_contrast(int val) { + (void) val; + // TODO: +} + +void lcd_set_invert_display(bool yesno) { + (void) yesno; + // TODO: +} + +void lcd_set_flip(bool yesno) { + (void) yesno; + // TODO: +} + +/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ +extern void lcd_write_yuv420_lines(fb_data *dst, + unsigned char chroma_buf[LCD_HEIGHT/2*3], + unsigned char const * const src[3], + int width, int stride); + +/* Performance function to blit a YUV bitmap directly to the LCD */ +void lcd_blit_yuv(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + /* Caches for chroma data so it only need be recalculated every other + line */ + unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 480 bytes */ + unsigned char const * yuv_src[3]; + off_t z; + + if (!lcd_on) + return; + + /* Sorry, but width and height must be >= 2 or else */ + width &= ~1; + height >>= 1; + + fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; + + z = stride*src_y; + yuv_src[0] = src[0] + z + src_x; + yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); + yuv_src[2] = src[2] + (yuv_src[1] - src[1]); + + do + { + lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, + stride); + + yuv_src[0] += stride << 1; /* Skip down two luma lines */ + yuv_src[1] += stride >> 1; /* Skip down one chroma line */ + yuv_src[2] += stride >> 1; + dst -= 2; + } + while (--height > 0); +} + diff --git a/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h b/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h new file mode 100644 index 0000000000..0c1ad0d5f5 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/lcd-target.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 _LCD_TARGET_H_ +#define _LCD_TARGET_H_ + +#endif diff --git a/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c new file mode 100644 index 0000000000..3f04838388 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c @@ -0,0 +1,207 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 +#include "system.h" +#include "kernel.h" +#include "logf.h" +#include "audio.h" +#include "sound.h" +#include "file.h" +#include "dsp-target.h" +#include "dsp/ipc.h" +#include "mmu-arm.h" +#include "pcm-internal.h" +#include "dma-target.h" + +/* This is global to save some latency when pcm_play_dma_get_peak_buffer is + * called. + */ +static void *start; +static int dma_channel; + +void pcm_play_dma_postinit(void) +{ + audiohw_postinit(); +} + +/* Return the current location in the SDRAM to SARAM transfer along with the + * number of bytes read in the current buffer (count). There is latency with + * this method equivalent to ~ the size of the SARAM buffer since there is + * another buffer between your ears and this calculation, but this works for + * key clicks and an approximate peak meter. + */ +const void * pcm_play_dma_get_peak_buffer(int *count) +{ + int cnt = DSP_(_sdem_level); + + unsigned long addr = (unsigned long) start + cnt; + + *count = (cnt & 0xFFFFF) >> 1; + return (void *)((addr + 2) & ~3); +} + +void pcm_play_dma_init(void) +{ + /* GIO16 is DSP/AIC3X CLK */ + IO_GIO_FSEL0 &= 0x3FFF; + IO_CLK_OSEL = (IO_CLK_OSEL & 0xFFF0) | 4; /* PLLIN clock */ + IO_CLK_O0DIV = 7; + IO_GIO_DIR1 &= ~(1 << 0); /* GIO16 - output */ + IO_GIO_FSEL0 |= 0xC000; /* GIO16 - CLKOUT0 */ + + audiohw_init(); + audiohw_set_frequency(HW_FREQ_DEFAULT); + + IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF; + bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF); + + /* Set this as a FIQ */ + bitset16(&IO_INTC_FISEL0, INTR_EINT0_IMGBUF); + + /* Enable the HPIB clock */ + bitset16(&IO_CLK_MOD0, (CLK_MOD0_HPIB | CLK_MOD0_DSP)); + + /* Enable IMGBUF clock */ + bitset16(&IO_CLK_MOD1, CLK_MOD1_IMGBUF); + + dma_channel = dma_request_channel(DMA_PERIPHERAL_DSP, + DMA_MODE_1_BURST); + + IO_DSPC_HPIB_CONTROL = 1 << 10 | 1 << 9 | 1 << 8 | 1 << 7 | 1 << 3 | 1 << 0; + + dsp_reset(); + dsp_load(dsp_image); + + DSP_(_dma0_stopped)=1; + dsp_wake(); +} + +void pcm_dma_apply_settings(void) +{ + audiohw_set_frequency(pcm_fsel); +} + +/* Note that size is actually limited to the size of a short right now due to + * the implementation on the DSP side (and the way that we access it) + */ +void pcm_play_dma_start(const void *addr, size_t size) +{ + unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START; + /* Initialize codec. */ + DSP_(_sdem_addrl) = sdem_addr & 0xffff; + DSP_(_sdem_addrh) = sdem_addr >> 16; + DSP_(_sdem_dsp_size) = size; + DSP_(_dma0_stopped)=0; + + dsp_wake(); +} + +void pcm_play_dma_stop(void) +{ + DSP_(_dma0_stopped)=1; + dsp_wake(); +} + +void pcm_play_lock(void) +{ + +} + +void pcm_play_unlock(void) +{ + +} + +void pcm_play_dma_pause(bool pause) +{ + if (pause) + { + DSP_(_dma0_stopped)=2; + dsp_wake(); + } + else + { + DSP_(_dma0_stopped)=0; + dsp_wake(); + } +} + +size_t pcm_get_bytes_waiting(void) +{ + return DSP_(_sdem_dsp_size)-DSP_(_sdem_level); +} + +/* Only used when debugging */ +static char buffer[80]; + +void DSPHINT(void) __attribute__ ((section(".icode"))); +void DSPHINT(void) +{ + unsigned int i; + size_t size; + + IO_INTC_FIQ0 = INTR_IRQ0_IMGBUF; + + switch (dsp_message.msg) + { + case MSG_DEBUGF: + /* DSP stores one character per word. */ + for (i = 0; i < sizeof(buffer); i++) + { + buffer[i] = dsp_message.payload.debugf.buffer[i]; + } + + DEBUGF("DSP: %s", buffer); + break; + + case MSG_REFILL: + /* Buffer empty. Try to get more. */ + pcm_play_get_more_callback(&start, &size); + + if (size != 0) + { + unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START; + /* Flush any pending cache writes */ + clean_dcache_range(start, size); + + /* set the new DMA values */ + DSP_(_sdem_addrl) = sdem_addr & 0xffff; + DSP_(_sdem_addrh) = sdem_addr >> 16; + DSP_(_sdem_dsp_size) = size; + + DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", + (unsigned long)start, (unsigned long)sdem_addr); + + pcm_play_dma_started_callback(); + } + + break; + default: + DEBUGF("DSP: unknown msg 0x%04x", dsp_message.msg); + break; + } + + /* Re-Activate the channel */ + dsp_wake(); + + DEBUGF("DSP: %s", buffer); +} + diff --git a/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c new file mode 100644 index 0000000000..52ea9be1d9 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c @@ -0,0 +1,59 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "cpu.h" +#include +#include "kernel.h" +#include "system.h" +#include "power.h" +#include "backlight.h" +#include "backlight-target.h" +#include "avr-sansaconnect.h" + +void power_init(void) +{ +} + +void power_off(void) +{ + avr_hid_reset_codec(); + avr_hid_power_off(); +} + +#if CONFIG_CHARGING +unsigned int power_input_status(void) +{ + return POWER_INPUT_NONE; +} + +/* Returns true if the unit is charging the batteries. */ +bool charging_state(void) +{ + return false; +} +#endif + +void ide_power_enable(bool on) +{ + (void)on; +} + diff --git a/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c new file mode 100644 index 0000000000..bd90c51072 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c @@ -0,0 +1,56 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "adc.h" +#include "powermgmt.h" +#include "kernel.h" + +/* THIS CONTAINS CURRENTLY DUMMY CODE! */ + +static const unsigned short current_voltage = 3910; +const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = +{ + 0 +}; + +const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = +{ + 0 +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ +const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = +{ + { 100, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, 1320 }, +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ +const unsigned short percent_to_volt_charge[11] = +{ + 100, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, 1320, +}; + +/* Returns battery voltage from ADC [millivolts] */ +unsigned int battery_adc_voltage(void) +{ + return current_voltage; +} diff --git a/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c new file mode 100644 index 0000000000..ab42beb2b4 --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "kernel.h" +#include "usb.h" +#ifdef HAVE_USBSTACK +#include "usb_drv.h" +#include "usb_core.h" +#endif + +bool usb_drv_connected(void) +{ + return false; +} + +int usb_detect(void) +{ + return USB_EXTRACTED; +} + +void usb_init_device(void) +{ + return; +} + +void usb_enable(bool on) +{ + (void)on; +} + +void usb_attach(void) +{ +} diff --git a/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h b/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h new file mode 100644 index 0000000000..6142b09f0b --- /dev/null +++ b/firmware/target/arm/tms320dm320/sansa-connect/usb-target.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 USB_TARGET_H +#define USB_TARGET_H + +#include "dm320.h" + +#include +int usb_detect(void); +void usb_init_device(void); +bool usb_drv_connected(void); + +#endif diff --git a/firmware/target/arm/tms320dm320/sdmmc-dm320.c b/firmware/target/arm/tms320dm320/sdmmc-dm320.c new file mode 100644 index 0000000000..307b90ec3b --- /dev/null +++ b/firmware/target/arm/tms320dm320/sdmmc-dm320.c @@ -0,0 +1,949 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2011 by Tomasz Moń + * + * 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 "sd.h" +#include "system.h" +#include +#include "gcc_extensions.h" +#include "thread.h" +#include "panic.h" +#include "kernel.h" +#include "dma-target.h" + +//#define SD_DEBUG + +#ifdef SD_DEBUG +#include "lcd-target.h" +#include "lcd.h" +#include "font.h" +#ifdef BOOTLOADER +#include "common.h" +#else +#include "debug.h" +#endif +#endif +#include "sdmmc.h" +#include "disk.h" +#include "fat.h" +#include "system-target.h" + +/* The configuration method is not very flexible. */ +#define CARD_NUM_SLOT 1 +#define NUM_CARDS 2 + +#define EC_OK 0 +#define EC_FAILED 1 +#define EC_NOCARD 2 +#define EC_WAIT_STATE_FAILED 3 +#define EC_POWER_UP 4 +#define EC_FIFO_WR_EMPTY 5 +#define EC_FIFO_WR_DONE 6 +#define EC_TRAN_READ_ENTRY 7 +#define EC_TRAN_READ_EXIT 8 +#define EC_TRAN_WRITE_ENTRY 9 +#define EC_TRAN_WRITE_EXIT 10 +#define EC_COMMAND 11 +#define EC_WRITE_PROTECT 12 +#define EC_DATA_TIMEOUT 13 +#define EC_RESP_TIMEOUT 14 +#define EC_CRC_ERROR 15 +#define NUM_EC 16 + +#define MIN_YIELD_PERIOD 1000 +#define UNALIGNED_NUM_SECTORS 10 +#define MAX_TRANSFER_ERRORS 10 + +#define SECTOR_SIZE 512 +#define BLOCKS_PER_BANK 0x7A7800 + +/* command flags for send_cmd */ +#define SDHC_RESP_FMT_NONE 0x0000 +#define SDHC_RESP_FMT_1 0x0200 +#define SDHC_RESP_FMT_2 0x0400 +#define SDHC_RESP_FMT_3 0x0600 + +#define INITIAL_CLK 312500 /* Initial clock */ +#define SD_CLK 24000000 /* Clock for SD cards */ +#define MMC_CLK 15000000 /* Clock for MMC cards */ + +#ifdef SD_DEBUG +#ifdef BOOTLOADER +#define dbgprintf printf +#else +#define dbgprintf DEBUGF +#endif +#else +#define dbgprintf(...) +#endif + +struct sd_card_status +{ + int retry; + int retry_max; +}; + +/** static, private data **/ + +/* for compatibility */ +static long last_disk_activity = -1; + +static bool initialized = false; +static unsigned int sd_thread_id = 0; + +static bool sd_enabled = false; +static long next_yield = 0; + +static tCardInfo card_info [NUM_CARDS]; +static tCardInfo *currcard; + +static struct sd_card_status sd_status[NUM_CARDS] = +{ +#if NUM_CARDS > 1 + {0, 10}, +#endif + {0, 10} +}; + +/* Shoot for around 75% usage */ +static long sd_stack [(DEFAULT_STACK_SIZE*2 + 0x1c0)/sizeof(long)]; +static const char sd_thread_name[] = "sd"; +static struct mutex sd_mtx SHAREDBSS_ATTR; +static struct event_queue sd_queue; +static volatile unsigned int transfer_error[NUM_DRIVES]; +/* align on cache line size */ +static unsigned char aligned_buffer[UNALIGNED_NUM_SECTORS * SD_BLOCK_SIZE] + __attribute__((aligned(32))); + +static void sd_card_mux(int card_no) +{ +#ifdef HAVE_MULTIDRIVE +#ifdef SANSA_CONNECT + /* GIO6 - select Card; GIO5 - select iNAND (both active low) */ + if (card_no == CARD_NUM_SLOT) + { + IO_GIO_BITSET0 = (1 << 5); /* deselect iNAND (GIO5) */ + IO_GIO_BITCLR0 = (1 << 6); /* select card (GIO6) */ + } + else + { + IO_GIO_BITSET0 = (1 << 6); /* deselect card (GIO6) */ + IO_GIO_BITCLR0 = (1 << 5); /* select iNAND (GIO5) */ + } +#else /* Different players */ + (void)card_no; +#endif +#else /* No multidrive */ + (void)card_no; +#endif +} + + +void sd_enable(bool on) +{ + if (sd_enabled == on) + return; /* nothing to do */ + + if (on) + { + sd_enabled = true; + } + else + { + sd_enabled = false; + } +} + +/* sets clock rate just like OF does */ +static void sd_set_clock_rate(unsigned long rate) +{ + unsigned char rate_val = 0; + + if (rate == INITIAL_CLK) + { + rate_val = 0x3B; + } + else if (rate > INITIAL_CLK) + { + rate_val = 0; + } + else + { + rate_val = 0xFF; + } + + IO_MMC_MEM_CLK_CONTROL = (IO_MMC_MEM_CLK_CONTROL & 0xFF00) | rate_val; +} + +static int sd_poll_status(int st_reg_num, volatile unsigned int flag) +{ + unsigned int status; + unsigned int status1; + bool done; + + do + { + long time = current_tick; + + if (TIME_AFTER(time, next_yield)) + { + long ty = current_tick; + yield(); + next_yield = ty + MIN_YIELD_PERIOD; + } + + status = IO_MMC_STATUS0; + status1 = IO_MMC_STATUS1; + + if (status & MMC_ST0_CMD_TIMEOUT) + { + dbgprintf("CMD timeout"); + return -EC_RESP_TIMEOUT; + } + if (status & MMC_ST0_DATA_TIMEOUT) + { + dbgprintf("DATA timeout"); + return -EC_DATA_TIMEOUT; + } + + if (status & + (MMC_ST0_WR_CRCERR | MMC_ST0_RD_CRCERR | MMC_ST0_RESP_CRCERR)) + { + dbgprintf("CRC error"); + return -EC_CRC_ERROR; + } + + if (st_reg_num == 0) + { + done = status & flag; + } + else + { + done = status1 & flag; + } + } while (!done); + + return EC_OK; +} + +static int dma_wait_for_completion(void) +{ + unsigned short dma_status; + + do + { + long time = current_tick; + + if (TIME_AFTER(time, next_yield)) + { + long ty = current_tick; + yield(); + next_yield = ty + MIN_YIELD_PERIOD; + } + + dma_status = IO_MMC_SD_DMA_STATUS1; + if (dma_status & (1 << 13)) + { + return -EC_DATA_TIMEOUT; + } + } while (dma_status & (1 << 12)); + + return EC_OK; +} + +static int sd_command(int cmd, unsigned long arg, + int cmdat, unsigned long *response) +{ + int ret; + + /* Clear response registers */ + IO_MMC_RESPONSE0 = 0; + IO_MMC_RESPONSE1 = 0; + IO_MMC_RESPONSE2 = 0; + IO_MMC_RESPONSE3 = 0; + IO_MMC_RESPONSE4 = 0; + IO_MMC_RESPONSE5 = 0; + IO_MMC_RESPONSE6 = 0; + IO_MMC_RESPONSE7 = 0; + IO_MMC_COMMAND_INDEX = 0; + IO_MMC_SPI_DATA = 0; + + IO_MMC_ARG_LOW = (unsigned int)((arg & 0xFFFF)); + IO_MMC_ARG_HI = (unsigned int)((arg & 0xFFFF0000) >> 16); + + /* SD is always in push-pull mode */ + cmdat |= MMC_CMD_PPLEN; + + cmdat |= (cmd & MMC_CMD_CMD_MASK); + + if (cmdat & MMC_CMD_DATA) + cmdat |= MMC_CMD_DCLR; + + IO_MMC_COMMAND = cmdat; + + if (cmdat & MMC_CMD_DATA) + { + /* Command requires data - do not wait for RSPDNE */ + ret = EC_OK; + } + else + { + ret = sd_poll_status(0, MMC_ST0_RSPDNE); + } + + if (ret != EC_OK) + { + dbgprintf("Command failed (ret %d)", ret); + return ret; + } + + if (response == NULL) + { + /* discard response */ + } + else if ((cmdat & SDHC_RESP_FMT_1) || (cmdat & SDHC_RESP_FMT_3)) + { + response[0] = (IO_MMC_RESPONSE7 << 16) | IO_MMC_RESPONSE6; + } + else if (cmdat & SDHC_RESP_FMT_2) + { + response[0] = (IO_MMC_RESPONSE7 << 16) | IO_MMC_RESPONSE6; + response[1] = (IO_MMC_RESPONSE5 << 16) | IO_MMC_RESPONSE4; + response[2] = (IO_MMC_RESPONSE3 << 16) | IO_MMC_RESPONSE2; + response[3] = (IO_MMC_RESPONSE1 << 16) | IO_MMC_RESPONSE0; + } + + return 0; +} + +static int sd_init_card(const int card_no) +{ + bool sdhc = false; + unsigned long response[4]; + int ret; + int i; + + memset(currcard, 0, sizeof(*currcard)); + sd_card_mux(card_no); + + /* Set data bus width to 1 bit */ + bitclr16(&IO_MMC_CONTROL, MMC_CTRL_WIDTH); + sd_set_clock_rate(INITIAL_CLK); + + ret = sd_command(SD_GO_IDLE_STATE, 0, MMC_CMD_INITCLK, NULL); + + if (ret < 0) + return -1; + + ret = sd_command(SD_SEND_IF_COND, 0x1AA, + SDHC_RESP_FMT_3, response); + if ((response[0] & 0xFFF) == 0x1AA) + { + sdhc = true; + dbgprintf("found sdhc card"); + } + + while ((currcard->ocr & (1 << 31)) == 0) /* until card is powered up */ + { + ret = sd_command(SD_APP_CMD, currcard->rca, + SDHC_RESP_FMT_1, NULL); + if (ret < 0) + { + dbgprintf("SD_APP_CMD failed"); + return -1; + } + + ret = sd_command(SD_APP_OP_COND, + (1 << 20) /* 3.2-3.3V */ | + (1 << 21) /* 3.3-3.4V */ | + (sdhc ? (1 << 30) : 0), + SDHC_RESP_FMT_3, &currcard->ocr); + + if (ret < 0) + { + dbgprintf("SD_APP_OP_COND failed"); + return -1; + } + } + + dbgprintf("Card powered up"); + + ret = sd_command(SD_ALL_SEND_CID, 0, + SDHC_RESP_FMT_2, response); + if (ret < 0) + { + dbgprintf("SD_ALL_SEND_CID failed"); + return -1; + } + + for (i = 0; i<4; i++) + { + currcard->cid[i] = response[i]; + } + + ret = sd_command(SD_SEND_RELATIVE_ADDR, 0, + SDHC_RESP_FMT_1, &currcard->rca); + if (ret < 0) + { + dbgprintf("SD_SEND_RELATIVE_ADDR failed"); + return -1; + } + + ret = sd_command(SD_SEND_CSD, currcard->rca, + SDHC_RESP_FMT_2, response); + if (ret < 0) + { + dbgprintf("SD_SEND_CSD failed"); + return -1; + } + + for (i = 0; i<4; i++) + { + currcard->csd[i] = response[i]; + } + + sd_parse_csd(currcard); + + sd_set_clock_rate(currcard->speed); + + ret = sd_command(SD_SELECT_CARD, currcard->rca, + SDHC_RESP_FMT_1, NULL); + if (ret < 0) + { + dbgprintf("SD_SELECT_CARD failed"); + return -1; + } + + ret = sd_command(SD_APP_CMD, currcard->rca, + SDHC_RESP_FMT_1, NULL); + if (ret < 0) + { + dbgprintf("SD_APP_CMD failed"); + return -1; + } + + ret = sd_command(SD_SET_BUS_WIDTH, currcard->rca | 2, + SDHC_RESP_FMT_1, NULL); /* 4 bit */ + if (ret < 0) + { + dbgprintf("SD_SET_BUS_WIDTH failed"); + return -1; + } + + /* Set data bus width to 4 bits */ + bitset16(&IO_MMC_CONTROL, MMC_CTRL_WIDTH); + + ret = sd_command(SD_SET_BLOCKLEN, currcard->blocksize, + SDHC_RESP_FMT_1, NULL); + if (ret < 0) + { + dbgprintf("SD_SET_BLOCKLEN failed"); + return -1; + } + + IO_MMC_BLOCK_LENGTH = currcard->blocksize; + + dbgprintf("Card initialized"); + currcard->initialized = 1; + + return EC_OK; +} + +/* lock must already by aquired */ +static void sd_select_device(int card_no) +{ + currcard = &card_info[card_no]; + + if (card_no == 0) + { + /* Main card always gets a chance */ + sd_status[0].retry = 0; + } + + if (currcard->initialized > 0) + { + /* This card is already initialized - switch to it */ + sd_card_mux(card_no); + return; + } + + if (currcard->initialized == 0) + { + /* Card needs (re)init */ + sd_init_card(card_no); + } +} + +static inline bool card_detect_target(void) +{ +#ifdef SANSA_CONNECT + bool removed; + + removed = IO_GIO_BITSET0 & (1 << 14); + + return !removed; +#else + return false; +#endif +} + + +#ifdef HAVE_HOTSWAP + +static int sd1_oneshot_callback(struct timeout *tmo) +{ + (void)tmo; + + /* This is called only if the state was stable for 300ms - check state + * and post appropriate event. */ + if (card_detect_target()) + { + queue_broadcast(SYS_HOTSWAP_INSERTED, 0); + } + else + queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); + return 0; +} + +#ifdef SANSA_CONNECT +void GIO14(void) __attribute__ ((section(".icode"))); +void GIO14(void) +{ + static struct timeout sd1_oneshot; + + /* clear interrupt */ + IO_INTC_IRQ2 = (1<<3); + + timeout_register(&sd1_oneshot, sd1_oneshot_callback, (3*HZ/10), 0); +} +#endif + +bool sd_removable(IF_MD_NONVOID(int card_no)) +{ +#ifndef HAVE_MULTIDRIVE + const int card_no = 0; +#endif + + return (card_no == CARD_NUM_SLOT); +} + +bool sd_present(IF_MD_NONVOID(int card_no)) +{ +#ifndef HAVE_MULTIDRIVE + const int card_no = 0; +#endif + + return (card_no == CARD_NUM_SLOT) ? card_detect_target() : +#ifdef SANSA_CONNECT + true; /* iNAND is always present */ +#else + false; +#endif +} + +#else /* no hotswap */ + +bool sd_removable(IF_MD_NONVOID(int card_no)) +{ +#ifdef HAVE_MULTIDRIVE + (void)card_no; +#endif + + /* not applicable */ + return false; +} + +#endif /* HAVE_HOTSWAP */ + +static void sd_thread(void) NORETURN_ATTR; +static void sd_thread(void) +{ + struct queue_event ev; + + /* TODO */ + while (1) + { + queue_wait_w_tmo(&sd_queue, &ev, HZ); + switch ( ev.id ) + { +#ifdef HAVE_HOTSWAP + case SYS_HOTSWAP_INSERTED: + case SYS_HOTSWAP_EXTRACTED: + { + int success = 1; + fat_lock(); /* lock-out FAT activity first - + prevent deadlocking via disk_mount that + would cause a reverse-order attempt with + another thread */ + mutex_lock(&sd_mtx); /* lock-out card activity - direct calls + into driver that bypass the fat cache */ + + /* We now have exclusive control of fat cache and ata */ + + disk_unmount(0); /* release "by force", ensure file + descriptors aren't leaked and any busy + ones are invalid if mounting */ + + /* Force card init for new card, re-init for re-inserted one or + * clear if the last attempt to init failed with an error. */ + card_info[0].initialized = 0; + + if (ev.id == SYS_HOTSWAP_INSERTED) + { + /* FIXME: once sd_enabled is implement properly, + * reinitializing the controllers might be needed */ + sd_enable(true); + if (success < 0) /* initialisation failed */ + panicf("SD init failed : %d", success); + success = disk_mount(0); /* 0 if fail */ + } + + /* notify the system about the changed filesystems + */ + if (success) + queue_broadcast(SYS_FS_CHANGED, 0); + + /* Access is now safe */ + mutex_unlock(&sd_mtx); + fat_unlock(); + sd_enable(false); + } + break; +#endif + } + } +} + +static int sd_wait_for_state(unsigned int state) +{ + unsigned long response = 0; + unsigned int timeout = HZ; /* ticks */ + long t = current_tick; + + while (1) + { + long tick; + int ret = sd_command(SD_SEND_STATUS, currcard->rca, + SDHC_RESP_FMT_1, &response); + if (ret < 0) + return ret; + + if ((SD_R1_CURRENT_STATE(response) == state)) + { + return EC_OK; + } + + if(TIME_AFTER(current_tick, t + timeout)) + return -2; + + if (TIME_AFTER((tick = current_tick), next_yield)) + { + yield(); + timeout += current_tick - tick; + next_yield = tick + MIN_YIELD_PERIOD; + } + } +} + +static int sd_transfer_sectors(int card_no, unsigned long start, + int count, void *buffer, bool write) +{ + int ret; + unsigned long start_addr; + int dma_channel = -1; + bool use_direct_dma; + int count_per_dma; + unsigned long rel_addr; + + dbgprintf("transfer %d %d %d", card_no, start, count); + mutex_lock(&sd_mtx); + sd_enable(true); + +sd_transfer_retry: + if (card_no == CARD_NUM_SLOT && !card_detect_target()) + { + /* no external sd-card inserted */ + ret = -EC_NOCARD; + goto sd_transfer_error; + } + + sd_select_device(card_no); + + if (currcard->initialized < 0) + { + ret = currcard->initialized; + goto sd_transfer_error; + } + + last_disk_activity = current_tick; + + ret = sd_wait_for_state(SD_TRAN); + if (ret < EC_OK) + { + goto sd_transfer_error; + } + + IO_MMC_BLOCK_LENGTH = currcard->blocksize; + + start_addr = start; + + do + { + count_per_dma = count; + + if (((unsigned long)buffer) & 0x1F) + { + /* MMC/SD interface requires 32-byte alignment of buffer */ + use_direct_dma = false; + if (count > UNALIGNED_NUM_SECTORS) + { + count_per_dma = UNALIGNED_NUM_SECTORS; + } + } + else + { + use_direct_dma = true; + } + + if (write == true) + { + if (use_direct_dma == false) + { + memcpy(aligned_buffer, buffer, count_per_dma*SD_BLOCK_SIZE); + } + commit_dcache_range(use_direct_dma ? buffer : aligned_buffer, + count_per_dma*SD_BLOCK_SIZE); + } + + IO_MMC_NR_BLOCKS = count_per_dma; + + /* Set start_addr to the correct unit (blocks or bytes) */ + if (!(card_info[card_no].ocr & SD_OCR_CARD_CAPACITY_STATUS)) + start_addr *= SD_BLOCK_SIZE; /* not SDHC */ + + ret = sd_command(write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK, + start_addr, MMC_CMD_DCLR | MMC_CMD_DATA | + SDHC_RESP_FMT_1 | (write ? MMC_CMD_WRITE : 0), + NULL); + + if (ret < 0) + goto sd_transfer_error; + + /* other burst modes are not supported for this peripheral */ + dma_channel = dma_request_channel(DMA_PERIPHERAL_MMCSD, + DMA_MODE_8_BURST); + + if (use_direct_dma == true) + { + rel_addr = ((unsigned long)buffer)-CONFIG_SDRAM_START; + } + else + { + rel_addr = ((unsigned long)aligned_buffer)-CONFIG_SDRAM_START; + } + + IO_MMC_SD_DMA_ADDR_LOW = rel_addr & 0xFFFF; + IO_MMC_SD_DMA_ADDR_HI = (rel_addr & 0xFFFF0000) >> 16; + + IO_MMC_SD_DMA_MODE |= MMC_DMAMODE_ENABLE; + if (write == true) + { + IO_MMC_SD_DMA_MODE |= MMC_DMAMODE_WRITE; + } + + IO_MMC_SD_DMA_TRIGGER = 1; + + dbgprintf("SD DMA transfer in progress"); + + ret = dma_wait_for_completion(); + dma_release_channel(dma_channel); + + dbgprintf("SD DMA transfer complete"); + + if (ret != EC_OK) + { + goto sd_transfer_error; + } + + count -= count_per_dma; + + if (write == false) + { + discard_dcache_range(use_direct_dma ? buffer : aligned_buffer, + count_per_dma*SD_BLOCK_SIZE); + + if (use_direct_dma == false) + { + memcpy(buffer, aligned_buffer, count_per_dma*SD_BLOCK_SIZE); + } + } + + buffer += count_per_dma*SD_BLOCK_SIZE; + start_addr += count_per_dma; + + last_disk_activity = current_tick; + + ret = sd_command(SD_STOP_TRANSMISSION, 0, SDHC_RESP_FMT_1, NULL); + if (ret < 0) + { + goto sd_transfer_error; + } + + ret = sd_wait_for_state(SD_TRAN); + if (ret < 0) + { + goto sd_transfer_error; + } + } while (count > 0); + + while (1) + { + sd_enable(false); + mutex_unlock(&sd_mtx); + + return ret; + +sd_transfer_error: + if (sd_status[card_no].retry < sd_status[card_no].retry_max + && ret != -EC_NOCARD) + { + sd_status[card_no].retry++; + currcard->initialized = 0; + goto sd_transfer_retry; + } + } +} + +int sd_read_sectors(IF_MD2(int card_no,) unsigned long start, int incount, + void* inbuf) +{ +#ifndef HAVE_MULTIDRIVE + const int card_no = 0; +#endif + return sd_transfer_sectors(card_no, start, incount, inbuf, false); +} + +int sd_write_sectors(IF_MD2(int card_no,) unsigned long start, int count, + const void* outbuf) +{ +#ifndef BOOTLOADER +#ifndef HAVE_MULTIDRIVE + const int card_no = 0; +#endif + return sd_transfer_sectors(card_no, start, count, (void*)outbuf, true); +#else /* we don't need write support in bootloader */ +#ifdef HAVE_MULTIDRIVE + (void)card_no; +#endif + (void)start; + (void)count; + (void)outbuf; + return 0; +#endif +} + +int sd_init(void) +{ + int ret = EC_OK; + +#ifndef BOOTLOADER + sd_enabled = true; + sd_enable(false); +#endif + mutex_init(&sd_mtx); + + mutex_lock(&sd_mtx); + initialized = true; + + /* based on linux/drivers/mmc/dm320mmc.c + Copyright (C) 2006 ZSI, All Rights Reserved. + Written by: Ben Bostwick */ + + bitclr16(&IO_CLK_MOD2, CLK_MOD2_MMC); + bitset16(&IO_CLK_INV, CLK_INV_MMC); + + /* mmc module clock: 75 Mhz (AHB) / 2 = ~37.5 Mhz */ + /* OF uses 1, but for some reason it freezes on us */ + IO_CLK_DIV3 = (IO_CLK_DIV3 & 0xFF00) | 0x02; + + bitset16(&IO_CLK_MOD2, CLK_MOD2_MMC); + + /* set mmc module into reset */ + bitset16(&IO_MMC_CONTROL, (MMC_CTRL_DATRST | MMC_CTRL_CMDRST)); + + /* set resp timeout to max */ + IO_MMC_RESPONSE_TIMEOUT |= 0x1FFF; + IO_MMC_READ_TIMEOUT = 0xFFFF; + + /* all done, take mmc module out of reset */ + bitclr16(&IO_MMC_CONTROL, (MMC_CTRL_DATRST | MMC_CTRL_CMDRST)); + +#ifdef SANSA_CONNECT + /* GIO37 - Power Card; GIO38 - Power iNAND (both active low) */ + IO_GIO_DIR2 &= ~((1 << 5) /* GIO37 */ | (1 << 6) /* GIO38 */); + IO_GIO_INV2 &= ~((1 << 5) /* GIO37 */ | (1 << 6) /* GIO38 */); + IO_GIO_BITCLR2 = (1 << 5) | (1 << 6); + + /* GIO6 - select Card; GIO5 - select iNAND (both active low) */ + IO_GIO_DIR0 &= ~((1 << 6) /* GIO6 */ | (1 << 5) /* GIO5 */); + IO_GIO_INV0 &= ~((1 << 6) /* GIO6 */ | (1 << 5) /* GIO5 */); + IO_GIO_BITSET0 = (1 << 6) | (1 << 5); + +#ifdef HAVE_HOTSWAP + /* GIO14 is card detect */ + IO_GIO_DIR0 |= (1 << 14); /* Set GIO14 as input */ + IO_GIO_INV0 &= ~(1 << 14); /* GIO14 not inverted */ + IO_GIO_IRQPORT |= (1 << 14); /* Enable GIO14 external interrupt */ + IO_GIO_IRQEDGE |= (1 << 14); /* Any edge detection */ + + /* Enable GIO14 interrupt */ + IO_INTC_EINT2 |= INTR_EINT2_EXT14; +#endif +#endif + + sd_select_device(1); + + /* Enable Memory Card CLK */ + bitset16(&IO_MMC_MEM_CLK_CONTROL, (1 << 8)); + + queue_init(&sd_queue, true); + sd_thread_id = create_thread(sd_thread, sd_stack, sizeof(sd_stack), + 0, sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU)); + + mutex_unlock(&sd_mtx); + + return ret; +} + +long sd_last_disk_activity(void) +{ + return last_disk_activity; +} + +tCardInfo *card_get_info_target(int card_no) +{ + return &card_info[card_no]; +} + +void sd_sleepnow(void) +{ +} + diff --git a/firmware/target/arm/tms320dm320/system-dm320.c b/firmware/target/arm/tms320dm320/system-dm320.c index f2a4aacb68..528d442ce5 100644 --- a/firmware/target/arm/tms320dm320/system-dm320.c +++ b/firmware/target/arm/tms320dm320/system-dm320.c @@ -26,11 +26,16 @@ #include "uart-target.h" #include "system-arm.h" #include "spi.h" +#include "i2c.h" #ifdef CREATIVE_ZVx #include "dma-target.h" -#else +#endif +#ifdef MROBE_500 #include "usb-mr500.h" #endif +#ifdef SANSA_CONNECT +#include "avr-sansaconnect.h" +#endif static unsigned short clock_arm_slow = 0xFFFF; static unsigned short clock_arm_fast = 0xFFFF; @@ -182,7 +187,12 @@ void system_exception_wait(void) IO_INTC_EINT0 = 0; IO_INTC_EINT1 = 0; IO_INTC_EINT2 = 0; +#ifdef MROBE_500 while ((IO_GIO_BITSET0&0x01) != 0); /* Wait for power button */ +#endif +#ifdef SANSA_CONNECT + while (1); /* Holding power button for a while makes avr system reset */ +#endif } void system_init(void) @@ -311,7 +321,7 @@ void system_init(void) clock_arm_slow = (0 << 8) | 3; clock_arm_fast = (1 << 8) | 1; } - + /* M48XI disabled, USB buffer powerdown */ IO_CLK_LPCTL1 = 0x11; /* I2C wodn't work with this disabled */ @@ -337,14 +347,22 @@ void system_init(void) uart_init(); spi_init(); +#ifdef MROBE_500 /* Initialization is done so shut the front LED off so that the battery * can charge. */ IO_GIO_BITCLR2 = 0x0001; - +#endif + #ifdef CREATIVE_ZVx dma_init(); #endif + +#ifdef SANSA_CONNECT + i2c_init(); + avr_hid_init(); + avr_hid_enable_charger(); +#endif } int system_memory_guard(int newmode) @@ -388,4 +406,13 @@ void udelay(int usec) { } } +#ifdef BOOTLOADER +void system_prepare_fw_start(void) +{ + tick_stop(); + IO_INTC_EINT0 = 0; + IO_INTC_EINT1 = 0; + IO_INTC_EINT2 = 0; +} +#endif diff --git a/firmware/target/arm/tms320dm320/system-target.h b/firmware/target/arm/tms320dm320/system-target.h index 22cf5546b2..59ae61f8df 100644 --- a/firmware/target/arm/tms320dm320/system-target.h +++ b/firmware/target/arm/tms320dm320/system-target.h @@ -41,4 +41,9 @@ void udelay(int usec); true; }) /* handled here */ #endif +#ifdef BOOTLOADER +void tick_stop(void); +void system_prepare_fw_start(void); +#endif + #endif /* SYSTEM_TARGET_H */ -- cgit v1.2.3