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/SOURCES | 23 + firmware/drivers/audio/aic3x.c | 247 ++++++ firmware/export/aic3x.h | 77 ++ firmware/export/audiohw.h | 2 + firmware/export/config.h | 6 + firmware/export/config/sansaconnect.h | 201 +++++ firmware/export/dm320.h | 51 ++ firmware/sound.c | 2 +- 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 + 33 files changed, 3567 insertions(+), 13 deletions(-) create mode 100644 firmware/drivers/audio/aic3x.c create mode 100644 firmware/export/aic3x.h create mode 100644 firmware/export/config/sansaconnect.h 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') diff --git a/firmware/SOURCES b/firmware/SOURCES index 6a84b5fc11..b918a19418 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -355,6 +355,8 @@ drivers/audio/uda1341.c drivers/audio/cs42l55.c #elif defined (HAVE_RK27XX_CODEC) drivers/audio/rk27xx_codec.c +#elif defined(HAVE_AIC3X) +drivers/audio/aic3x.c #elif defined (HAVE_DUMMY_CODEC) drivers/audio/dummy_codec.c #endif /* defined(HAVE_*) */ @@ -1064,6 +1066,9 @@ target/arm/bits-armv4.S target/arm/tms320dm320/debug-dm320.c target/arm/tms320dm320/dsp-dm320.c target/arm/tms320dm320/i2c-dm320.c +#ifdef HAVE_SOFTWARE_I2C +drivers/generic_i2c.c +#endif target/arm/tms320dm320/kernel-dm320.c target/arm/tms320dm320/spi-dm320.c target/arm/tms320dm320/system-dm320.c @@ -1112,6 +1117,24 @@ target/arm/tms320dm320/creative-zvm/usb-creativezvm.c #endif /* SIMULATOR */ #endif /* CREATIVE_ZVx */ +#ifdef SANSA_CONNECT +#ifndef SIMULATOR +target/arm/mmu-arm.S +target/arm/lcd-as-memframe.S +target/arm/tms320dm320/sdmmc-dm320.c +target/arm/tms320dm320/sansa-connect/crt0-board.S +target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c +target/arm/tms320dm320/sansa-connect/adc-sansaconnect.c +target/arm/tms320dm320/sansa-connect/power-sansaconnect.c +target/arm/tms320dm320/sansa-connect/powermgmt-sansaconnect.c +target/arm/tms320dm320/sansa-connect/usb-sansaconnect.c +target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c +target/arm/tms320dm320/sansa-connect/backlight-sansaconnect.c +target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c +target/arm/tms320dm320/dma-dm320.c +#endif /* SIMULATOR */ +#endif /* SANSA_CONNECT */ + #ifdef MROBE_100 #ifndef SIMULATOR #ifndef BOOTLOADER diff --git a/firmware/drivers/audio/aic3x.c b/firmware/drivers/audio/aic3x.c new file mode 100644 index 0000000000..3284326565 --- /dev/null +++ b/firmware/drivers/audio/aic3x.c @@ -0,0 +1,247 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "logf.h" +#include "system.h" +#include "string.h" +#include "audio.h" + +#ifdef SANSA_CONNECT +#include "avr-sansaconnect.h" +#endif + +#if CONFIG_I2C == I2C_DM320 +#include "i2c-dm320.h" +#endif +#include "audiohw.h" + +/* (7-bit) address is 0x18, the LSB is read/write flag */ +#define AIC3X_ADDR (0x18 << 1) + +static char volume_left = 0, volume_right = 0; + +const struct sound_settings_info audiohw_settings[] = { + [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN/10, VOLUME_MAX/10, -25}, + /* HAVE_SW_TONE_CONTROLS */ + [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, + [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, + [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, +}; + +/* convert tenth of dB volume to master volume register value */ +int tenthdb2master(int db) +{ + /* 0 to -63.0dB in 1dB steps, aic3x can goto -63.5 in 0.5dB steps */ + if (db < VOLUME_MIN) + { + return 0x7E; + } + else if (db >= VOLUME_MAX) + { + return 0x00; + } + else + { + return (-((db)/5)); /* VOLUME_MIN is negative */ + } +} + +static void aic3x_write_reg(unsigned reg, unsigned value) +{ + unsigned char data[2]; + + data[0] = reg; + data[1] = value; + +#if CONFIG_I2C == I2C_DM320 + if (i2c_write(AIC3X_ADDR, data, 2) != 0) +#else + #warning Implement aic3x_write_reg() +#endif + { + logf("AIC3X error reg=0x%x", reg); + return; + } +} + +static void aic3x_apply_volume(void) +{ + unsigned char data[3]; + +#if 0 /* handle page switching onve we use first page at all */ + aic3x_write_reg(0, 0); /* switch to page 0 */ +#endif + + data[0] = AIC3X_LEFT_VOL; + data[1] = volume_left; + data[2] = volume_right; + + /* use autoincrement write */ +#if CONFIG_I2C == I2C_DM320 + if (i2c_write(AIC3X_ADDR, data, 3) != 0) +#else + #warning Implement aic3x_apply_volume() +#endif + { + logf("AIC3X error in apply volume"); + return; + } +} + + +static void audiohw_mute(bool mute) +{ + if (mute) + { + volume_left |= 0x80; + volume_right |= 0x80; + } + else + { + volume_left &= 0x7F; + volume_right &= 0x7F; + } + + aic3x_apply_volume(); +} + +/* public functions */ + +/** + * Init our tlv with default values + */ +void audiohw_init(void) +{ + logf("AIC3X init"); + + /* Do software reset (self-clearing) */ + aic3x_write_reg(AIC3X_SOFT_RESET, 0x80); + + /* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */ + aic3x_write_reg(AIC3X_SMPL_RATE, 0x90); + + /* Enable PLL. Set Q=16, P=1 */ + aic3x_write_reg(AIC3X_PLL_REG_A, 0x81); + /* PLL J = 53 */ + aic3x_write_reg(AIC3X_PLL_REG_B, 0xD4); + /* PLL D = 5211 */ + aic3x_write_reg(AIC3X_PLL_REG_C, 0x51); + aic3x_write_reg(AIC3X_PLL_REG_D, 0x6C); /* PLL D = 5211 */ + + /* Left DAC plays left channel, Right DAC plays right channel */ + aic3x_write_reg(AIC3X_DATAPATH, 0xA); + + /* Audio data interface */ + /* BCLK and WCLK are outputs (master mode) */ + aic3x_write_reg(AIC3X_DATA_REG_A, 0xC0); + /* right-justified mode */ + aic3x_write_reg(AIC3X_DATA_REG_B, 0x80); + /* data offset = 0 clocks */ + aic3x_write_reg(AIC3X_DATA_REG_C, 0); + + /* GPIO1 used for audio serial data bus ADC word clock */ + aic3x_write_reg(AIC3X_GPIO1_CTRL, 0x10); + + /* power left and right DAC, HPLCOM constant VCM output */ + aic3x_write_reg(AIC3X_DAC_POWER, 0xD0); + /* HPRCOM as constant VCM output. Enable short-circuit protection + (limit current) */ + aic3x_write_reg(AIC3X_HIGH_POWER, 0xC); + + /* driver power-on time 200 ms, ramp-up step time 4 ms */ + aic3x_write_reg(AIC3X_POP_REDUCT, 0x7C); + + /* DAC_L1 routed to HPLOUT, volume analog gain 0xC (-6.0dB) */ + aic3x_write_reg(AIC3X_DAC_L1_VOL, 0x8C); + /* HPLOUT output level 0dB, not muted, fully powered up */ + aic3x_write_reg(AIC3X_HPLOUT_LVL, 0xB); + + /* HPLCOM is muted */ + aic3x_write_reg(AIC3X_HPLCOM_LVL, 0x7); + + /* DAC_R1 routed to HPROUT, volume analog gain 0xC (-6.0 dB) */ + aic3x_write_reg(AIC3X_DAC_R1_VOL, 0x8C); + /* HPROUT output level 0dB, not muted, fully powered up */ + aic3x_write_reg(AIC3X_HPROUT_LVL, 0xB); + + /* DAC_L1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */ + aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0x92); + /* DAC_R1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */ + aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0x92); + + /* MONO_LOP output level 6dB, not muted, fully powered up */ + aic3x_write_reg(AIC3X_MONO_LOP_M_LVL, 0x6b); + + /* DAC_L1 routed to LEFT_LOP/M */ + aic3x_write_reg(AIC3X_DAC_L1_LEFT_LOP_M_VOL, 0x80); + /* LEFT_LOP/M output level 0dB, not muted */ + aic3x_write_reg(AIC3X_LEFT_LOP_M_LVL, 0xB); + + /* DAC_R1 routed to RIGHT_LOP/M */ + aic3x_write_reg(AIC3X_DAC_R1_RIGHT_LOP_M_VOL, 0x80); + /* RIGHT_LOP/M output level 0dB, not muted */ + aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL, 0xB); +} + +void audiohw_postinit(void) +{ + audiohw_mute(false); + + /* Power up Left, Right DAC/LOP, HPLOUT and HPROUT */ + aic3x_write_reg(AIC3X_MOD_POWER, 0xFE); +} + +void audiohw_set_frequency(int fsel) +{ + (void)fsel; + /* TODO */ +} + +void audiohw_set_headphone_vol(int vol_l, int vol_r) +{ + if ((volume_left & 0x7F) == (vol_l & 0x7F) && + (volume_right & 0x7F) == (vol_r & 0x7F)) + { + /* Volume already set to this value */ + return; + } + + volume_left &= 0x80; /* preserve mute bit */ + volume_left |= (vol_l & 0x7F); /* set gain */ + + volume_right &= 0x80; /* preserve mute bit */ + volume_right |= (vol_r & 0x7F); /* set gain */ + + aic3x_apply_volume(); +} + +/* Nice shutdown of AIC3X codec */ +void audiohw_close(void) +{ + audiohw_mute(true); +#ifdef SANSA_CONNECT + avr_hid_reset_codec(); +#endif +} + + diff --git a/firmware/export/aic3x.h b/firmware/export/aic3x.h new file mode 100644 index 0000000000..17e5ea019a --- /dev/null +++ b/firmware/export/aic3x.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * __________ __ ___. + * 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 _AIC3X_H_ +#define _AIC3X_H_ + +#define VOLUME_MIN -630 +#define VOLUME_MAX 0 + +extern int tenthdb2master(int db); + +/*** definitions ***/ +extern void audiohw_set_headphone_vol(int vol_l, int vol_r); + +/* Page 0 registers */ +#define AIC3X_PAGE_SELECT 0 +#define AIC3X_SOFT_RESET 1 +#define AIC3X_SMPL_RATE 2 +#define AIC3X_PLL_REG_A 3 +#define AIC3X_PLL_REG_B 4 +#define AIC3X_PLL_REG_C 5 +#define AIC3X_PLL_REG_D 6 +#define AIC3X_DATAPATH 7 +#define AIC3X_DATA_REG_A 8 +#define AIC3X_DATA_REG_B 9 +#define AIC3X_DATA_REG_C 10 + +#define AIC3X_DAC_POWER 37 +#define AIC3X_HIGH_POWER 38 + +#define AIC3X_POP_REDUCT 42 +#define AIC3X_LEFT_VOL 43 +#define AIC3X_RIGHT_VOL 44 + +#define AIC3X_DAC_L1_VOL 47 +#define AIC3X_HPLOUT_LVL 51 + +#define AIC3X_HPLCOM_LVL 58 + +#define AIC3X_DAC_R1_VOL 64 +#define AIC3X_HPROUT_LVL 65 + +#define AIC3X_DAC_L1_MONO_LOP_M_VOL 75 + +#define AIC3X_DAC_R1_MONO_LOP_M_VOL 76 + +#define AIC3X_MONO_LOP_M_LVL 79 + +#define AIC3X_DAC_L1_LEFT_LOP_M_VOL 82 + +#define AIC3X_LEFT_LOP_M_LVL 86 + +#define AIC3X_DAC_R1_RIGHT_LOP_M_VOL 92 +#define AIC3X_RIGHT_LOP_M_LVL 93 +#define AIC3X_MOD_POWER 94 + +#define AIC3X_GPIO1_CTRL 98 + +#endif /*_AIC3X_H_*/ diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index 6bf4d71810..102d107d8a 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -70,6 +70,8 @@ #include "ak4537.h" #elif defined(HAVE_RK27XX_CODEC) #include "rk27xx_codec.h" +#elif defined(HAVE_AIC3X) +#include "aic3x.h" #elif defined(HAVE_CS42L55) #include "cs42l55.h" #elif defined(HAVE_IMX233_CODEC) diff --git a/firmware/export/config.h b/firmware/export/config.h index 55a194817d..2e7b4dc4d6 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -142,6 +142,7 @@ #define RK27XX_GENERIC_PAD 49 #define HM60X_PAD 50 #define HM801_PAD 51 +#define SANSA_CONNECT_PAD 52 /* CONFIG_REMOTE_KEYPAD */ #define H100_REMOTE 1 @@ -229,6 +230,7 @@ #define LCD_SPFD5420A 42 /* rk27xx */ #define LCD_CLIPZIP 43 /* as used by the Sandisk Sansa Clip Zip */ #define LCD_HX8340B 44 /* as used by the HiFiMAN HM-601/HM-602/HM-801 */ +#define LCD_CONNECT 45 /* as used by the Sandisk Sansa Connect */ /* LCD_PIXELFORMAT */ #define HORIZONTAL_PACKING 1 @@ -302,6 +304,7 @@ Lyre prototype 1 */ #define RTC_D2 18 /* Either PCF50606 or PCF50635 */ #define RTC_S35380A 19 #define RTC_IMX233 20 +#define RTC_STM41T62 21 /* ST M41T62 */ /* USB On-the-go */ #define USBOTG_M66591 6591 /* M:Robe 500 */ @@ -314,6 +317,7 @@ Lyre prototype 1 */ #define USBOTG_AS3525v2 3535 /* AMS AS3525v2 FIXME : same as S3C6400X */ #define USBOTG_S3C6400X 6400 /* Samsung S3C6400X, also used in the S5L8701/S5L8702/S5L8720 */ #define USBOTG_RK27XX 2700 /* Rockchip rk27xx */ +#define USBOTG_TNETV105 105 /* TI TNETV105 */ /* Multiple cores */ #define CPU 0 @@ -466,6 +470,8 @@ Lyre prototype 1 */ #include "config/hifimanhm60x.h" #elif defined(HM801) #include "config/hifimanhm801.h" +#elif defined(SANSA_CONNECT) +#include "config/sansaconnect.h" #elif defined(SDLAPP) #include "config/sdlapp.h" #elif defined(ANDROID) diff --git a/firmware/export/config/sansaconnect.h b/firmware/export/config/sansaconnect.h new file mode 100644 index 0000000000..714534d6ad --- /dev/null +++ b/firmware/export/config/sansaconnect.h @@ -0,0 +1,201 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * 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. + * + ****************************************************************************/ + +/* + * This config file is for the Sansa Connect + */ +#define TARGET_TREE /* this target is using the target tree system */ + +/* This is the absolute address on the bus set by OF bootloader */ +#define CONFIG_SDRAM_START 0x01000000 + +#define SANSA_CONNECT 1 +#define MODEL_NAME "Sandisk Sansa Connect" + +/* For Rolo and boot loader */ +#define MODEL_NUMBER 81 + +/* define this if you have a flash memory storage */ +#define HAVE_FLASH_STORAGE + +/* define this if you use an SD controller */ +#define CONFIG_STORAGE STORAGE_SD + +#define HAVE_MULTIDRIVE +#define NUM_DRIVES 2 +#define HAVE_HOTSWAP +#define HAVE_HOTSWAP_STORAGE_AS_MAIN + +/* define this if you have a bitmap LCD display */ +#define HAVE_LCD_BITMAP + +/* define this if you have a colour LCD */ +#define HAVE_LCD_COLOR + +/* define this if you want album art for this target */ +#define HAVE_ALBUMART + +/* define this to enable bitmap scaling */ +#define HAVE_BMP_SCALING + +/* define this to enable JPEG decoding */ +#define HAVE_JPEG + +/* define this if you have access to the quickscreen */ +#define HAVE_QUICKSCREEN + +/* define this if you have access to the pitchscreen */ +#define HAVE_PITCHSCREEN + +/* define this if you would like tagcache to build on this target */ +#define HAVE_TAGCACHE + +/* define this if the target has volume keys which can be used in the lists */ +#define HAVE_VOLUME_IN_LIST + +/* define this if you want viewport clipping enabled for safe LCD functions */ +#define HAVE_VIEWPORT_CLIP + +/* LCD dimensions */ +#define CONFIG_LCD LCD_CONNECT + +#define LCD_WIDTH 240 +#define LCD_HEIGHT 320 + +#define LCD_DEPTH 16 /* 65k colours */ +#define LCD_PIXELFORMAT RGB565 /* rgb565 */ + +#define HAVE_LCD_ENABLE +#ifndef BOOTLOADER +#define HAVE_LCD_SLEEP +#endif + +#define LCD_SLEEP_TIMEOUT (2*HZ) + +#define MAX_ICON_HEIGHT 35 +#define MAX_ICON_WIDTH 35 + + +#define CONFIG_KEYPAD SANSA_CONNECT_PAD + +/* Define this to have CPU bootsted while scrolling in the UI */ +#define HAVE_GUI_BOOST + +/* define this if the target has volume keys which can be used in the lists */ +#define HAVE_VOLUME_IN_LIST + +#define HAVE_MORSE_INPUT + +/* Define this if you do software codec */ +#define CONFIG_CODEC SWCODEC + +//#define HAVE_HARDWARE_BEEP + +/* There is no hardware tone control */ +#define HAVE_SW_TONE_CONTROLS + +#define HAVE_AIC3X + +//#define HW_SAMPR_CAPS SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11 | SAMPR_CAP_8 + +/* define this if you have a real-time clock */ +//#define CONFIG_RTC RTC_STM41T62 + +/* define this if the unit uses a scrollwheel for navigation */ +#define HAVE_SCROLLWHEEL + +/* Define this for LCD backlight available */ +#define HAVE_BACKLIGHT + +#define HAVE_BACKLIGHT_BRIGHTNESS + +#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING + +/* Main LCD backlight brightness range and defaults */ +#define MIN_BRIGHTNESS_SETTING 1 +#define MAX_BRIGHTNESS_SETTING 20 +#define DEFAULT_BRIGHTNESS_SETTING 16 /* OF default brightness (80%) */ +#define DEFAULT_DIMNESS_SETTING 6 /* OF default inactive (30%) */ + +/* Define this if you have a software controlled poweroff */ +#define HAVE_SW_POWEROFF + +/* The number of bytes reserved for loadable codecs */ +#define CODEC_SIZE 0x100000 + +/* The number of bytes reserved for loadable plugins */ +#define PLUGIN_BUFFER_SIZE 0x200000 + +#define BATTERY_CAPACITY_DEFAULT 800 /* default battery capacity */ +#define BATTERY_CAPACITY_MIN 700 /* min. capacity selectable */ +#define BATTERY_CAPACITY_MAX 1000 /* max. capacity selectable */ +#define BATTERY_CAPACITY_INC 100 /* capacity increment */ +#define BATTERY_TYPES_COUNT 1 /* only one type */ + +/* define current usage levels */ +#if 0 +/* TODO */ +#define CURRENT_NORMAL 85 +#define CURRENT_BACKLIGHT 200 +#endif + +/* Hardware controlled charging with monitoring */ +//#define CONFIG_CHARGING CHARGING_MONITOR + +#define CONFIG_CPU DM320 + +#define CONFIG_I2C I2C_DM320 +#define HAVE_SOFTWARE_I2C + +/* define this if the hardware can be powered off while charging */ +#define HAVE_POWEROFF_WHILE_CHARGING + +/* The size of the flash ROM */ +#define FLASH_SIZE 0x400000 + +/* Define this to the CPU frequency */ +#define CPU_FREQ 150000000 + +/* Define this if you have ATA power-off control */ +#define HAVE_ATA_POWER_OFF + +/* Offset ( in the firmware file's header ) to the file CRC */ +#define FIRMWARE_OFFSET_FILE_CRC 0 + +/* Offset ( in the firmware file's header ) to the real data */ +#define FIRMWARE_OFFSET_FILE_DATA 8 + +#if 0 +#define HAVE_USBSTACK +#define USB_VENDOR_ID 0x0781 +#define USB_PRODUCT_ID 0x7480 +#endif + +#define INCLUDE_TIMEOUT_API + +/* Define this if you have adjustable CPU frequency */ +#define HAVE_ADJUSTABLE_CPU_FREQ + +#define BOOTFILE_EXT "sansa" +#define BOOTFILE "rockbox." BOOTFILE_EXT +#define BOOTDIR "/.rockbox" + +/* Define this if a programmable hotkey is mapped */ +#define HAVE_HOTKEY diff --git a/firmware/export/dm320.h b/firmware/export/dm320.h index a629586be8..def8508b0b 100644 --- a/firmware/export/dm320.h +++ b/firmware/export/dm320.h @@ -870,6 +870,8 @@ extern unsigned long _ttbstart; #define CLK_MOD2_TMR0 (1 << 1) #define CLK_MOD2_WDT (1 << 0) +#define CLK_SEL0_UART0 (1 << 5) + #define CLK_SEL1_OSD (1 << 12) #define CLK_SEL1_CCD (1 << 8) #define CLK_SEL1_VENCPLL (1 << 4) @@ -884,6 +886,55 @@ extern unsigned long _ttbstart; #define CLK_BYP_DSP (1 << 4) #define CLK_BYP_ARM (1 << 0) +#define CLK_INV_MMC (1 << 0) +#define CLK_INV_VENC (1 << 4) +#define CLK_INV_CCD (1 << 8) +#define CLK_INV_SIF0 (1 << 12) +#define CLK_INV_SIF1 (1 << 13) + +#define MMC_CTRL_DATRST (1 << 0) +#define MMC_CTRL_CMDRST (1 << 1) +#define MMC_CTRL_WIDTH (1 << 2) +#define MMC_CTRL_DMASZEN (1 << 4) +#define MMC_CTRL_TEST2 (1 << 8) +#define MMC_CTRL_PERMDR (1 << 9) +#define MMC_CTRL_PERMDX (1 << 10) + +#define MMC_CMD_CMD_MASK (0x3F) +#define MMC_CMD_PPLEN (1 << 7) +#define MMC_CMD_BSYEXP (1 << 8) +#define MMC_CMD_RSPFMT_SHIFT 9 +#define MMC_CMD_RSPFMT_MASK (3 << MMC_CMD_RSPFMT_SHIFT) +#define MMC_CMD_WRITE (1 << 11) +#define MMC_CMD_STREAM (1 << 12) +#define MMC_CMD_DATA (1 << 13) +#define MMC_CMD_INITCLK (1 << 14) +#define MMC_CMD_DCLR (1 << 15) + +#define MMC_ST0_DATDNE (1 << 0) +#define MMC_ST0_BSYDNE (1 << 1) +#define MMC_ST0_RSPDNE (1 << 2) +#define MMC_ST0_DATA_TIMEOUT (1 << 3) +#define MMC_ST0_CMD_TIMEOUT (1 << 4) +#define MMC_ST0_WR_CRCERR (1 << 5) +#define MMC_ST0_RD_CRCERR (1 << 6) +#define MMC_ST0_RESP_CRCERR (1 << 7) +#define MMC_ST0_DMADNE (1 << 8) +#define MMC_ST0_DXRDY (1 << 9) +#define MMC_ST0_DRRDY (1 << 10) +#define MMC_ST0_DAT3_EDGE (1 << 11) + +#define MMC_ST1_BUSY (1 << 0) +#define MMC_ST1_CLKSTP (1 << 1) +#define MMC_ST1_DXEMPTY (1 << 2) +#define MMC_ST1_DXFULL (1 << 3) +#define MMC_ST1_DAT3ST (1 << 4) + +#define MMC_DMAMODE_RD_WORDSWAP (1 << 10) +#define MMC_DMAMODE_WR_WORDSWAP (1 << 11) +#define MMC_DMAMODE_WRITE (1 << 12) +#define MMC_DMAMODE_ENABLE (1 << 13) +#define MMC_DMAMODE_TIMEOUTIRQ_EN (1 << 14) /* * IO_EINTx bits */ diff --git a/firmware/sound.c b/firmware/sound.c index ec577d6a10..c97ccc243f 100644 --- a/firmware/sound.c +++ b/firmware/sound.c @@ -250,7 +250,7 @@ static void set_prescaled_volume(void) audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0)); #endif -#elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985) || defined(HAVE_IMX233_CODEC) +#elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985) || defined(HAVE_IMX233_CODEC) || defined(HAVE_AIC3X) audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r)); #elif defined(HAVE_JZ4740_CODEC) || defined(HAVE_SDL_AUDIO) || defined(ANDROID) audiohw_set_volume(current_volume); 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