summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2018-06-29 16:09:28 -0400
committerSolomon Peachy <pizza@shaftnet.org>2019-01-02 08:10:01 -0500
commitd4942cc74c82c465ea395637c77ed06565b8b497 (patch)
tree8c1fa737c93f8a2ade5a1566857dc4dc8f578bd6 /firmware
parentaf9459a7992596e932c6d8cc0a6366ff0f0b0fca (diff)
downloadrockbox-d4942cc74c82c465ea395637c77ed06565b8b497.tar.gz
rockbox-d4942cc74c82c465ea395637c77ed06565b8b497.tar.bz2
rockbox-d4942cc74c82c465ea395637c77ed06565b8b497.zip
Add Xuelin iHIFI 770/770C/800 support
Taken from the xvortex fork (Roman Stolyarov) Ported, rebased, and cleaned up by myself. Change-Id: I7b2bca2d29502f2e4544e42f3d122786dd4b7978
Diffstat (limited to 'firmware')
-rw-r--r--firmware/SOURCES25
-rw-r--r--firmware/drivers/audio/es9018.c134
-rw-r--r--firmware/drivers/audio/wm8740.c106
-rw-r--r--firmware/export/audiohw.h6
-rw-r--r--firmware/export/config.h17
-rw-r--r--firmware/export/config/ihifi770.h197
-rw-r--r--firmware/export/config/ihifi770c.h197
-rw-r--r--firmware/export/config/ihifi800.h198
-rw-r--r--firmware/export/config/rk27generic.h2
-rw-r--r--firmware/export/es9018.h39
-rw-r--r--firmware/export/rk27xx.h5
-rw-r--r--firmware/export/wm8740.h83
-rw-r--r--firmware/target/arm/rk27xx/backlight-rk27xx.c7
-rw-r--r--firmware/target/arm/rk27xx/debug-rk27xx.c2
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/audio-ihifi770.c88
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/audio-ihifi800.c67
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/button-ihifi.c99
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/button-target.h50
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c285
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c248
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c228
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/lcd-target.h26
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/power-ihifi.c53
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770.c64
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770c.c64
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi800.c64
-rw-r--r--firmware/target/arm/rk27xx/sd-rk27xx.c18
-rw-r--r--firmware/target/arm/rk27xx/usb-drv-rk27xx.c787
-rw-r--r--firmware/target/arm/rk27xx/usb-rk27xx.c14
-rw-r--r--firmware/target/hosted/sdl/sim-ui-defines.h22
30 files changed, 2687 insertions, 508 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 33d59fa429..16ae4cc350 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -442,6 +442,8 @@ drivers/audio/audiohw-swcodec.c
#if (CONFIG_PLATFORM & PLATFORM_NATIVE) && !defined(BOOTLOADER)
#if defined(HAVE_UDA1380)
drivers/audio/uda1380.c
+#elif defined(HAVE_WM8740)
+drivers/audio/wm8740.c
#elif defined(HAVE_WM8751) \
|| defined(HAVE_WM8750)
drivers/audio/wm8751.c
@@ -481,6 +483,8 @@ drivers/audio/df1704.c
drivers/audio/pcm1792.c
#elif defined (HAVE_CS4398)
drivers/audio/cs4398.c
+#elif defined (HAVE_ES9018)
+drivers/audio/es9018.c
#endif /* defined(HAVE_*) */
#else /* PLATFORM_HOSTED */
#if defined(SAMSUNG_YPR0) && defined(HAVE_AS3514)
@@ -791,6 +795,12 @@ target/arm/s3c2440/lcd-s3c2440.c
target/arm/rk27xx/ma/lcd-ma.c
#elif CONFIG_LCD == LCD_IHIFI
target/arm/rk27xx/ihifi/lcd-ihifi.c
+#elif CONFIG_LCD == LCD_IHIFI770
+target/arm/rk27xx/ihifi2/lcd-ihifi770.c
+#elif CONFIG_LCD == LCD_IHIFI770C
+target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
+#elif CONFIG_LCD == LCD_IHIFI800
+target/arm/rk27xx/ihifi2/lcd-ihifi800.c
#endif
/* USB Stack */
@@ -1904,6 +1914,21 @@ target/arm/rk27xx/ihifi/powermgmt-ihifi960.c
#endif
#endif
+#if defined(IHIFI770) || defined(IHIFI770C) || defined(IHIFI800)
+target/arm/rk27xx/ihifi2/button-ihifi.c
+target/arm/rk27xx/ihifi2/power-ihifi.c
+#if defined(IHIFI770)
+target/arm/rk27xx/ihifi2/powermgmt-ihifi770.c
+target/arm/rk27xx/ihifi2/audio-ihifi770.c
+#elif defined(IHIFI770C)
+target/arm/rk27xx/ihifi2/powermgmt-ihifi770c.c
+target/arm/rk27xx/ihifi2/audio-ihifi770.c
+#elif defined(IHIFI800)
+target/arm/rk27xx/ihifi2/powermgmt-ihifi800.c
+target/arm/rk27xx/ihifi2/audio-ihifi800.c
+#endif
+#endif
+
#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
target/hosted/kernel-unix.c
target/hosted/filesystem-unix.c
diff --git a/firmware/drivers/audio/es9018.c b/firmware/drivers/audio/es9018.c
new file mode 100644
index 0000000000..89e8c1d46f
--- /dev/null
+++ b/firmware/drivers/audio/es9018.c
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "system.h"
+#include "es9018.h"
+#include "config.h"
+#include "audio.h"
+#include "audiohw.h"
+
+/* NOTE: The register names are not known, as the register numbering
+ listed in the ES9018 datasheet does not match what is described below.. */
+
+static uint8_t reg0 = 0x00; /* System settings. Default value of register 0 */
+static uint8_t reg1 = 0x80; /* Input settings. Manual input, I2S, 32-bit (?) */
+static uint8_t reg4 = 0x00; /* Automute time. Default = disabled */
+static uint8_t reg5 = 0x68; /* Automute level. Default is some level */
+static uint8_t reg6 = 0x4A; /* Deemphasis. Default = disabled */
+static uint8_t reg7 = 0x83; /* General settings. Default sharp fir, pcm iir and muted */
+static uint8_t reg8 = 0x10; /* GPIO configuration */
+static uint8_t reg10 = 0x05; /* Master Mode Control. Default value: master mode off */
+static uint8_t reg11 = 0x02; /* Channel Mapping. Default stereo is Ch1=left, Ch2=right */
+static uint8_t reg12 = 0x50; /* DPLL Settings. Default = 005 for I2S, OFF for DSD */
+static uint8_t reg13 = 0x40; /* THD Compensation */
+static uint8_t reg14 = 0x8A; /* Soft Start Settings */
+static uint8_t reg21 = 0x00; /* Oversampling filter. Default: oversampling ON */
+
+#define bitSet(value, bit) ((value) |= (1UL << (bit)))
+#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
+
+static int vol_tenthdb2hw(const int tdb)
+{
+ if (tdb < ES9018_VOLUME_MIN) {
+ return 0xff;
+ } else if (tdb > ES9018_VOLUME_MAX) {
+ return 0x00;
+ } else {
+ return (-tdb/5);
+ }
+}
+
+void audiohw_set_volume(int vol_l, int vol_r)
+{
+ es9018_write_reg(15, vol_tenthdb2hw(vol_l));
+ es9018_write_reg(16, vol_tenthdb2hw(vol_r));
+}
+
+void audiohw_mute(void)
+{
+ bitSet(reg7, 0); /* Mute Channel 1 */
+ bitSet(reg7, 1); /* Mute Channel 2 */
+ es9018_write_reg(0x07, reg7);
+}
+
+void audiohw_unmute(void)
+{
+ bitClear(reg7, 0); /* Unmute Channel 1 */
+ bitClear(reg7, 1); /* Unmute Channel 2 */
+ es9018_write_reg(0x07, reg7);
+}
+
+void audiohw_init(void)
+{
+ es9018_write_reg(0x00, reg0);
+ es9018_write_reg(0x01, reg1);
+ es9018_write_reg(0x04, reg4);
+ es9018_write_reg(0x05, reg5);
+ es9018_write_reg(0x06, reg6);
+ es9018_write_reg(0x07, reg7);
+ es9018_write_reg(0x08, reg8);
+ es9018_write_reg(0x0A, reg10);
+ es9018_write_reg(0x0B, reg11);
+ es9018_write_reg(0x0C, reg12);
+ es9018_write_reg(0x0D, reg13);
+ es9018_write_reg(0x0E, reg14);
+ es9018_write_reg(0x15, reg21);
+}
+
+void audiohw_preinit(void)
+{
+}
+
+void audiohw_set_frequency(int fsel)
+{
+ (void)fsel;
+}
+
+void audiohw_set_filter_roll_off(int value)
+{
+ /* 0 = Sharp (Default)
+ 1 = Slow
+ 2 = Short
+ 3 = Bypass */
+ switch(value)
+ {
+ case 0:
+ bitClear(reg7, 5);
+ bitClear(reg7, 6);
+ bitClear(reg21, 0);
+ break;
+ case 1:
+ bitSet(reg7, 5);
+ bitClear(reg7, 6);
+ bitClear(reg21, 0);
+ break;
+ case 2:
+ bitClear(reg7, 5);
+ bitSet(reg7, 6);
+ bitClear(reg21, 0);
+ break;
+ case 3:
+ bitSet(reg21, 0);
+ break;
+ }
+ es9018_write_reg(0x07, reg7);
+ es9018_write_reg(0x15, reg21);
+}
diff --git a/firmware/drivers/audio/wm8740.c b/firmware/drivers/audio/wm8740.c
new file mode 100644
index 0000000000..d88f53bd75
--- /dev/null
+++ b/firmware/drivers/audio/wm8740.c
@@ -0,0 +1,106 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "system.h"
+#include "wm8740.h"
+#include "config.h"
+#include "audio.h"
+#include "audiohw.h"
+
+static void wm8740_write_reg(const int reg, const unsigned int value)
+{
+ int i;
+
+ for (i = (1<<15); i; i >>= 1) {
+ udelay(1);
+ wm8740_set_mc(0);
+ if ((reg|value) & i) {
+ wm8740_set_md(1);
+ } else {
+ wm8740_set_md(0);
+ }
+ udelay(1);
+ wm8740_set_mc(1);
+ }
+ udelay(1);
+ wm8740_set_ml(0);
+ udelay(1);
+ wm8740_set_mc(0);
+ udelay(1);
+ wm8740_set_ml(1);
+ udelay(1);
+}
+
+static int vol_tenthdb2hw(const int tdb)
+{
+ if (tdb < WM8740_VOLUME_MIN) {
+ return 0x00;
+ } else if (tdb > WM8740_VOLUME_MAX) {
+ return 0xff;
+ } else {
+ return ((tdb / 5 + 0xff) & 0xff);
+ }
+}
+
+void audiohw_set_volume(int vol_l, int vol_r)
+{
+ wm8740_write_reg(WM8740_REG0, vol_tenthdb2hw(vol_l));
+ wm8740_write_reg(WM8740_REG1, vol_tenthdb2hw(vol_r) | WM8740_LDR);
+}
+
+void audiohw_mute(void)
+{
+ wm8740_write_reg(WM8740_REG2, WM8740_MUT);
+}
+
+void audiohw_unmute(void)
+{
+ wm8740_write_reg(WM8740_REG2, 0x00);
+}
+
+void audiohw_init(void)
+{
+ wm8740_write_reg(WM8740_REG0, 0x00);
+ wm8740_write_reg(WM8740_REG1, 0x00);
+ wm8740_write_reg(WM8740_REG2, WM8740_MUT);
+ wm8740_write_reg(WM8740_REG3, WM8740_I2S);
+ wm8740_write_reg(WM8740_REG4, 0x00);
+}
+
+void audiohw_preinit(void)
+{
+}
+
+void audiohw_set_frequency(int fsel)
+{
+ (void)fsel;
+}
+
+void audiohw_set_filter_roll_off(int value)
+{
+ /* 0 = fast (sharp);
+ 1 = slow */
+ if (value == 0) {
+ wm8740_write_reg(WM8740_REG3, WM8740_I2S);
+ } else {
+ wm8740_write_reg(WM8740_REG3, WM8740_I2S | WM8740_SR0);
+ }
+}
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h
index 09001c8045..458fba3412 100644
--- a/firmware/export/audiohw.h
+++ b/firmware/export/audiohw.h
@@ -165,6 +165,8 @@ struct sound_settings_info
#include "uda1380.h"
#elif defined(HAVE_UDA1341)
#include "uda1341.h"
+#elif defined(HAVE_WM8740)
+#include "wm8740.h"
#elif defined(HAVE_WM8750) || defined(HAVE_WM8751)
#include "wm8751.h"
#elif defined(HAVE_WM8978)
@@ -211,6 +213,8 @@ struct sound_settings_info
#include "nwzlinux_codec.h"
#elif defined(HAVE_CS4398)
#include "cs4398.h"
+#elif defined(HAVE_ES9018)
+#include "es9018.h"
#elif (CONFIG_PLATFORM & (PLATFORM_ANDROID | PLATFORM_MAEMO\
| PLATFORM_PANDORA | PLATFORM_SDL))
#include "hosted_codec.h"
@@ -571,7 +575,7 @@ void audiohw_set_depth_3d(int val);
#ifdef AUDIOHW_HAVE_FILTER_ROLL_OFF
/**
* Set DAC's oversampling filter roll-off.
- * @param val 0 - sharp roll-off, 1 - slow roll-off.
+ * @param val 0 - sharp roll-off, 1 - slow roll-off, 2 - short roll-off, 3 - bypass.
* NOTE: AUDIOHW_CAPS need to contain
* FILTER_ROLL_OFF_CAP
*/
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 8b177963d3..2db12bea4a 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -169,6 +169,8 @@
#define SONY_NWZA860_PAD 64 /* The NWZ-A860 is too different (touchscreen) */
#define AGPTEK_ROCKER_PAD 65
#define XDUOO_X3_PAD 66
+#define IHIFI_770_PAD 67
+#define IHIFI_800_PAD 68
/* CONFIG_REMOTE_KEYPAD */
#define H100_REMOTE 1
@@ -284,6 +286,9 @@
#define LCD_NWZ_LINUX 63 /* as used in the Linux-based NWZ series */
#define LCD_INGENIC_LINUX 64
#define LCD_XDUOOX3 65 /* as used by the xDuoo X3 */
+#define LCD_IHIFI770 66 /* as used by IHIFI 770 */
+#define LCD_IHIFI770C 67 /* as used by IHIFI 770C */
+#define LCD_IHIFI800 68 /* as used by IHIFI 800 */
/* LCD_PIXELFORMAT */
#define HORIZONTAL_PACKING 1
@@ -581,6 +586,12 @@ Lyre prototype 1 */
#include "config/samsungypz5.h"
#elif defined(IHIFI760)
#include "config/ihifi760.h"
+#elif defined(IHIFI770)
+#include "config/ihifi770.h"
+#elif defined(IHIFI770C)
+#include "config/ihifi770c.h"
+#elif defined(IHIFI800)
+#include "config/ihifi800.h"
#elif defined(IHIFI960)
#include "config/ihifi960.h"
#elif defined(CREATIVE_ZENXFISTYLE)
@@ -974,7 +985,6 @@ Lyre prototype 1 */
#define USB_STATUS_BY_EVENT
#define USB_DETECT_BY_REQUEST
#elif CONFIG_USBOTG == USBOTG_RK27XX
-#define USB_STATUS_BY_EVENT
#define USB_DETECT_BY_REQUEST
#endif /* CONFIG_USB == */
#endif /* HAVE_USBSTACK */
@@ -1193,7 +1203,7 @@ Lyre prototype 1 */
#endif /* HAVE_USB_CHARGING_ENABLE && HAVE_USBSTACK */
#ifndef SIMULATOR
-#if defined(HAVE_USBSTACK) || (CONFIG_STORAGE & STORAGE_NAND)
+#if defined(HAVE_USBSTACK) || (CONFIG_STORAGE & STORAGE_NAND) || (CONFIG_STORAGE & STORAGE_RAMDISK)
#define STORAGE_GET_INFO
#endif
#endif
@@ -1211,7 +1221,8 @@ Lyre prototype 1 */
(CONFIG_USBOTG == USBOTG_JZ4760) || \
(CONFIG_USBOTG == USBOTG_M66591) || \
(CONFIG_USBOTG == USBOTG_DESIGNWARE) || \
- (CONFIG_USBOTG == USBOTG_AS3525)
+ (CONFIG_USBOTG == USBOTG_AS3525) || \
+ (CONFIG_USBOTG == USBOTG_RK27XX)
#define USB_HAS_BULK
#define USB_HAS_INTERRUPT
#elif defined(CPU_TCC780X) || defined(CPU_TCC77X)
diff --git a/firmware/export/config/ihifi770.h b/firmware/export/config/ihifi770.h
new file mode 100644
index 0000000000..af7acff206
--- /dev/null
+++ b/firmware/export/config/ihifi770.h
@@ -0,0 +1,197 @@
+/*
+ * This config file is for IHIFI 770
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 108
+
+#define MODEL_NAME "IHIFI 770"
+
+/* Define bitmask of input sources - recordable bitmask can be defined
+ explicitly if different */
+/* #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FM) */
+
+/* define the bitmask of hardware sample rates */
+#define HW_SAMPR_CAPS (SAMPR_CAP_96 | SAMPR_CAP_48 | SAMPR_CAP_44 | \
+ SAMPR_CAP_32 | SAMPR_CAP_24 | SAMPR_CAP_22 | \
+ SAMPR_CAP_16 | SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
+
+#define HAVE_WM8740
+#define CODEC_SLAVE
+
+/* define this if you have a bitmap LCD display */
+#define HAVE_LCD_BITMAP
+
+/* define this if you can flip your LCD */
+/* #define HAVE_LCD_FLIP */
+
+/* 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 can invert the colours on your LCD */
+/* #define HAVE_LCD_INVERT */
+
+/* define this if you have access to the quickscreen */
+#define HAVE_QUICKSCREEN
+
+/* define this if you would like tagcache to build on this target */
+#define HAVE_TAGCACHE
+
+/* define this if you have a flash memory storage */
+#define HAVE_FLASH_STORAGE
+
+#define CONFIG_STORAGE (STORAGE_SD | STORAGE_NAND)
+
+#define CONFIG_NAND NAND_RK27XX
+#define HAVE_SW_TONE_CONTROLS
+
+#define HAVE_HOTSWAP
+
+#define NUM_DRIVES 1
+#define SECTOR_SIZE 512
+
+/* for small(ish) SD cards */
+#define HAVE_FAT16SUPPORT
+
+/* LCD dimensions */
+#define LCD_WIDTH 320
+#define LCD_HEIGHT 240
+/* sqrt(320^2 + 240^2) / 2.4 = 166.7 */
+#define LCD_DPI 167
+#define LCD_DEPTH 16 /* pseudo 262.144 colors */
+#define LCD_PIXELFORMAT RGB565 /* rgb565 */
+
+/* Define this if the LCD can shut down */
+/* #define HAVE_LCD_SHUTDOWN */
+
+/* Define this if your LCD can be enabled/disabled */
+#define HAVE_LCD_ENABLE
+
+/* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE
+ should be defined as well. */
+#ifndef BOOTLOADER
+/* TODO: #define HAVE_LCD_SLEEP */
+/* TODO: #define HAVE_LCD_SLEEP_SETTING */
+#endif
+
+#define CONFIG_KEYPAD IHIFI_770_PAD
+
+/* define this if the target has volume keys which can be used in the lists */
+#define HAVE_VOLUME_IN_LIST
+
+/* Define this if a programmable hotkey is mapped */
+/* #define HAVE_HOTKEY */
+
+/* Define this if you do software codec */
+#define CONFIG_CODEC SWCODEC
+
+/* define this if you have a real-time clock */
+/* #define CONFIG_RTC RTC_NANO2G */
+
+/* Define if the device can wake from an RTC alarm */
+/* #define HAVE_RTC_ALARM */
+
+/* Define the type of audio codec */
+/*#define HAVE_RK27XX_CODEC */
+
+/* #define HAVE_PCM_DMA_ADDRESS */
+
+/* Define this for LCD backlight available */
+#define HAVE_BACKLIGHT
+#define HAVE_BACKLIGHT_BRIGHTNESS
+#define MIN_BRIGHTNESS_SETTING 0
+#define MAX_BRIGHTNESS_SETTING 31
+#define DEFAULT_BRIGHTNESS_SETTING 31
+#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_HW_REG
+
+/* 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 0x80000
+
+#define BATTERY_CAPACITY_DEFAULT 1050 /* default battery capacity */
+#define BATTERY_CAPACITY_MIN 500 /* min. capacity selectable */
+#define BATTERY_CAPACITY_MAX 1050 /* max. capacity selectable */
+#define BATTERY_CAPACITY_INC 10 /* capacity increment */
+#define BATTERY_TYPES_COUNT 1 /* only one type */
+
+#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
+
+/* Hardware controlled charging with monitoring */
+#define CONFIG_CHARGING CHARGING_MONITOR
+
+/* define current usage levels */
+/* TODO: #define CURRENT_NORMAL
+ * TODO: #define CURRENT_BACKLIGHT 23
+ */
+
+/* define this if the unit can be powered or charged via USB */
+#define HAVE_USB_POWER
+
+/* Define this if your LCD can set contrast */
+/* #define HAVE_LCD_CONTRAST */
+
+/* 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
+
+#define STORAGE_NEEDS_ALIGN
+
+/* Define this if you have adjustable CPU frequency */
+#define HAVE_ADJUSTABLE_CPU_FREQ
+
+/* Virtual LED (icon) */
+#define CONFIG_LED LED_VIRTUAL
+
+/** Non-simulator section **/
+#ifndef SIMULATOR
+
+/* The exact type of CPU */
+#define CONFIG_CPU RK27XX
+
+/* Define this to the CPU frequency */
+#define CPU_FREQ 200000000
+
+/* I2C interface */
+#define CONFIG_I2C I2C_RK27XX
+
+/* define this if the hardware can be powered off while charging */
+/* #define HAVE_POWEROFF_WHILE_CHARGING */
+
+/* Type of LCD */
+#define CONFIG_LCD LCD_IHIFI770
+
+/* USB On-the-go */
+#define CONFIG_USBOTG USBOTG_RK27XX
+
+/* enable these for the experimental usb stack */
+#define HAVE_USBSTACK
+
+#define USB_VENDOR_ID 0x071b
+#define USB_PRODUCT_ID 0x3202
+#define HAVE_BOOTLOADER_USB_MODE
+
+#define RKW_FORMAT
+#define BOOTFILE_EXT "rkw"
+#define BOOTFILE "rockbox." BOOTFILE_EXT
+#define BOOTDIR "/.rockbox"
+
+/* disabled for now */
+#undef HAVE_HOTSWAP
+
+#endif /* SIMULATOR */
diff --git a/firmware/export/config/ihifi770c.h b/firmware/export/config/ihifi770c.h
new file mode 100644
index 0000000000..c4058f337b
--- /dev/null
+++ b/firmware/export/config/ihifi770c.h
@@ -0,0 +1,197 @@
+/*
+ * This config file is for IHIFI 770C
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 108
+
+#define MODEL_NAME "IHIFI 770C"
+
+/* Define bitmask of input sources - recordable bitmask can be defined
+ explicitly if different */
+/* #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FM) */
+
+/* define the bitmask of hardware sample rates */
+#define HW_SAMPR_CAPS (SAMPR_CAP_96 | SAMPR_CAP_48 | SAMPR_CAP_44 | \
+ SAMPR_CAP_32 | SAMPR_CAP_24 | SAMPR_CAP_22 | \
+ SAMPR_CAP_16 | SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
+
+#define HAVE_WM8740
+#define CODEC_SLAVE
+
+/* define this if you have a bitmap LCD display */
+#define HAVE_LCD_BITMAP
+
+/* define this if you can flip your LCD */
+/* #define HAVE_LCD_FLIP */
+
+/* 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 can invert the colours on your LCD */
+/* #define HAVE_LCD_INVERT */
+
+/* define this if you have access to the quickscreen */
+#define HAVE_QUICKSCREEN
+
+/* define this if you would like tagcache to build on this target */
+#define HAVE_TAGCACHE
+
+/* define this if you have a flash memory storage */
+#define HAVE_FLASH_STORAGE
+
+#define CONFIG_STORAGE (STORAGE_SD | STORAGE_NAND)
+
+#define CONFIG_NAND NAND_RK27XX
+#define HAVE_SW_TONE_CONTROLS
+
+#define HAVE_HOTSWAP
+
+#define NUM_DRIVES 1
+#define SECTOR_SIZE 512
+
+/* for small(ish) SD cards */
+#define HAVE_FAT16SUPPORT
+
+/* LCD dimensions */
+#define LCD_WIDTH 320
+#define LCD_HEIGHT 240
+/* sqrt(320^2 + 240^2) / 2.4 = 166.7 */
+#define LCD_DPI 167
+#define LCD_DEPTH 16 /* pseudo 262.144 colors */
+#define LCD_PIXELFORMAT RGB565 /* rgb565 */
+
+/* Define this if the LCD can shut down */
+/* #define HAVE_LCD_SHUTDOWN */
+
+/* Define this if your LCD can be enabled/disabled */
+#define HAVE_LCD_ENABLE
+
+/* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE
+ should be defined as well. */
+#ifndef BOOTLOADER
+/* TODO: #define HAVE_LCD_SLEEP */
+/* TODO: #define HAVE_LCD_SLEEP_SETTING */
+#endif
+
+#define CONFIG_KEYPAD IHIFI_770_PAD
+
+/* define this if the target has volume keys which can be used in the lists */
+#define HAVE_VOLUME_IN_LIST
+
+/* Define this if a programmable hotkey is mapped */
+/* #define HAVE_HOTKEY */
+
+/* Define this if you do software codec */
+#define CONFIG_CODEC SWCODEC
+
+/* define this if you have a real-time clock */
+/* #define CONFIG_RTC RTC_NANO2G */
+
+/* Define if the device can wake from an RTC alarm */
+/* #define HAVE_RTC_ALARM */
+
+/* Define the type of audio codec */
+/*#define HAVE_RK27XX_CODEC */
+
+/* #define HAVE_PCM_DMA_ADDRESS */
+
+/* Define this for LCD backlight available */
+#define HAVE_BACKLIGHT
+#define HAVE_BACKLIGHT_BRIGHTNESS
+#define MIN_BRIGHTNESS_SETTING 0
+#define MAX_BRIGHTNESS_SETTING 31
+#define DEFAULT_BRIGHTNESS_SETTING 31
+#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_HW_REG
+
+/* 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 0x80000
+
+#define BATTERY_CAPACITY_DEFAULT 1050 /* default battery capacity */
+#define BATTERY_CAPACITY_MIN 500 /* min. capacity selectable */
+#define BATTERY_CAPACITY_MAX 1050 /* max. capacity selectable */
+#define BATTERY_CAPACITY_INC 10 /* capacity increment */
+#define BATTERY_TYPES_COUNT 1 /* only one type */
+
+#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
+
+/* Hardware controlled charging with monitoring */
+#define CONFIG_CHARGING CHARGING_MONITOR
+
+/* define current usage levels */
+/* TODO: #define CURRENT_NORMAL
+ * TODO: #define CURRENT_BACKLIGHT 23
+ */
+
+/* define this if the unit can be powered or charged via USB */
+#define HAVE_USB_POWER
+
+/* Define this if your LCD can set contrast */
+/* #define HAVE_LCD_CONTRAST */
+
+/* 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
+
+#define STORAGE_NEEDS_ALIGN
+
+/* Define this if you have adjustable CPU frequency */
+#define HAVE_ADJUSTABLE_CPU_FREQ
+
+/* Virtual LED (icon) */
+#define CONFIG_LED LED_VIRTUAL
+
+/** Non-simulator section **/
+#ifndef SIMULATOR
+
+/* The exact type of CPU */
+#define CONFIG_CPU RK27XX
+
+/* Define this to the CPU frequency */
+#define CPU_FREQ 200000000
+
+/* I2C interface */
+#define CONFIG_I2C I2C_RK27XX
+
+/* define this if the hardware can be powered off while charging */
+/* #define HAVE_POWEROFF_WHILE_CHARGING */
+
+/* Type of LCD */
+#define CONFIG_LCD LCD_IHIFI770C
+
+/* USB On-the-go */
+#define CONFIG_USBOTG USBOTG_RK27XX
+
+/* enable these for the experimental usb stack */
+#define HAVE_USBSTACK
+
+#define USB_VENDOR_ID 0x071b
+#define USB_PRODUCT_ID 0x3202
+#define HAVE_BOOTLOADER_USB_MODE
+
+#define RKW_FORMAT
+#define BOOTFILE_EXT "rkw"
+#define BOOTFILE "rockbox." BOOTFILE_EXT
+#define BOOTDIR "/.rockbox"
+
+/* disabled for now */
+#undef HAVE_HOTSWAP
+
+#endif /* SIMULATOR */
diff --git a/firmware/export/config/ihifi800.h b/firmware/export/config/ihifi800.h
new file mode 100644
index 0000000000..eb1c2015ad
--- /dev/null
+++ b/firmware/export/config/ihifi800.h
@@ -0,0 +1,198 @@
+/*
+ * This config file is for IHIFI 800
+ */
+
+/* For Rolo and boot loader */
+#define MODEL_NUMBER 109
+
+#define MODEL_NAME "IHIFI 800"
+
+/* Define bitmask of input sources - recordable bitmask can be defined
+ explicitly if different */
+/* #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FM) */
+
+/* define the bitmask of hardware sample rates */
+#define HW_SAMPR_CAPS (SAMPR_CAP_96 | SAMPR_CAP_48 | SAMPR_CAP_44 | \
+ SAMPR_CAP_32 | SAMPR_CAP_24 | SAMPR_CAP_22 | \
+ SAMPR_CAP_16 | SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
+
+#define HAVE_ES9018
+#define CODEC_SLAVE
+
+/* define this if you have a bitmap LCD display */
+#define HAVE_LCD_BITMAP
+
+/* define this if you can flip your LCD */
+/* #define HAVE_LCD_FLIP */
+
+/* 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 can invert the colours on your LCD */
+/* #define HAVE_LCD_INVERT */
+
+/* define this if you have access to the quickscreen */
+#define HAVE_QUICKSCREEN
+
+/* define this if you would like tagcache to build on this target */
+#define HAVE_TAGCACHE
+
+/* define this if you have a flash memory storage */
+#define HAVE_FLASH_STORAGE
+
+#define CONFIG_STORAGE (STORAGE_SD | STORAGE_NAND)
+
+#define CONFIG_NAND NAND_RK27XX
+#define HAVE_SW_TONE_CONTROLS
+
+#define HAVE_HOTSWAP
+
+#define NUM_DRIVES 1
+#define SECTOR_SIZE 512
+
+/* for small(ish) SD cards */
+#define HAVE_FAT16SUPPORT
+
+/* LCD dimensions */
+#define LCD_WIDTH 240
+#define LCD_HEIGHT 320
+/* sqrt(240^2 + 320^2) / 2.4 = 166.7 */
+#define LCD_DPI 167
+#define LCD_DEPTH 16 /* pseudo 262.144 colors */
+#define LCD_PIXELFORMAT RGB565 /* rgb565 */
+
+/* Define this if the LCD can shut down */
+/* #define HAVE_LCD_SHUTDOWN */
+
+/* Define this if your LCD can be enabled/disabled */
+#define HAVE_LCD_ENABLE
+
+/* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE
+ should be defined as well. */
+#ifndef BOOTLOADER
+/* TODO: #define HAVE_LCD_SLEEP */
+/* TODO: #define HAVE_LCD_SLEEP_SETTING */
+#endif
+
+#define CONFIG_KEYPAD IHIFI_800_PAD
+
+/* define this if the target has volume keys which can be used in the lists */
+#define HAVE_VOLUME_IN_LIST
+
+/* Define this if a programmable hotkey is mapped */
+/* #define HAVE_HOTKEY */
+
+/* Define this if you do software codec */
+#define CONFIG_CODEC SWCODEC
+
+/* define this if you have a real-time clock */
+/* #define CONFIG_RTC RTC_NANO2G */
+
+/* Define if the device can wake from an RTC alarm */
+/* #define HAVE_RTC_ALARM */
+
+/* Define the type of audio codec */
+/*#define HAVE_RK27XX_CODEC */
+
+/* #define HAVE_PCM_DMA_ADDRESS */
+
+/* Define this for LCD backlight available */
+#define HAVE_BACKLIGHT
+#define HAVE_BACKLIGHT_BRIGHTNESS
+#define MIN_BRIGHTNESS_SETTING 0
+#define MAX_BRIGHTNESS_SETTING 31
+#define DEFAULT_BRIGHTNESS_SETTING 31
+#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_HW_REG
+
+/* 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 0x80000
+
+/* TODO: Figure out real values */
+#define BATTERY_CAPACITY_DEFAULT 1400 /* default battery capacity */
+#define BATTERY_CAPACITY_MIN 700 /* min. capacity selectable */
+#define BATTERY_CAPACITY_MAX 1400 /* max. capacity selectable */
+#define BATTERY_CAPACITY_INC 10 /* capacity increment */
+#define BATTERY_TYPES_COUNT 1 /* only one type */
+
+#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
+
+/* Hardware controlled charging with monitoring */
+#define CONFIG_CHARGING CHARGING_MONITOR
+
+/* define current usage levels */
+/* TODO: #define CURRENT_NORMAL
+ * TODO: #define CURRENT_BACKLIGHT 23
+ */
+
+/* define this if the unit can be powered or charged via USB */
+#define HAVE_USB_POWER
+
+/* Define this if your LCD can set contrast */
+/* #define HAVE_LCD_CONTRAST */
+
+/* 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
+
+#define STORAGE_NEEDS_ALIGN
+
+/* Define this if you have adjustable CPU frequency */
+#define HAVE_ADJUSTABLE_CPU_FREQ
+
+/* Virtual LED (icon) */
+#define CONFIG_LED LED_VIRTUAL
+
+/** Non-simulator section **/
+#ifndef SIMULATOR
+
+/* The exact type of CPU */
+#define CONFIG_CPU RK27XX
+
+/* Define this to the CPU frequency */
+#define CPU_FREQ 200000000
+
+/* I2C interface */
+#define CONFIG_I2C I2C_RK27XX
+
+/* define this if the hardware can be powered off while charging */
+/* #define HAVE_POWEROFF_WHILE_CHARGING */
+
+/* Type of LCD */
+#define CONFIG_LCD LCD_IHIFI800
+
+/* USB On-the-go */
+#define CONFIG_USBOTG USBOTG_RK27XX
+
+/* enable these for the experimental usb stack */
+#define HAVE_USBSTACK
+
+#define USB_VENDOR_ID 0x071b
+#define USB_PRODUCT_ID 0x3202
+#define HAVE_BOOTLOADER_USB_MODE
+
+#define RKW_FORMAT
+#define BOOTFILE_EXT "rkw"
+#define BOOTFILE "rockbox." BOOTFILE_EXT
+#define BOOTDIR "/.rockbox"
+
+/* disabled for now */
+#undef HAVE_HOTSWAP
+
+#endif /* SIMULATOR */
diff --git a/firmware/export/config/rk27generic.h b/firmware/export/config/rk27generic.h
index 503857bd43..69cf9f3758 100644
--- a/firmware/export/config/rk27generic.h
+++ b/firmware/export/config/rk27generic.h
@@ -63,7 +63,7 @@
/* commented for now */
/* #define HAVE_HOTSWAP */
-#define NUM_DRIVES 2
+#define NUM_DRIVES 1
#define SECTOR_SIZE 512
/* for small(ish) SD cards */
diff --git a/firmware/export/es9018.h b/firmware/export/es9018.h
new file mode 100644
index 0000000000..41ea0d0b1c
--- /dev/null
+++ b/firmware/export/es9018.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 _ES9018_H
+#define _ES9018_H
+
+#define ES9018_VOLUME_MIN -1270
+#define ES9018_VOLUME_MAX 0
+
+#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP)
+#define AUDIOHW_HAVE_SHORT_ROLL_OFF
+AUDIOHW_SETTING(VOLUME, "dB", 0, 1, ES9018_VOLUME_MIN/10, ES9018_VOLUME_MAX/10, 0)
+AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 3, 0)
+
+void es9018_write_reg(uint8_t reg, uint8_t val);
+uint8_t es9018_read_reg(uint8_t reg);
+
+void audiohw_mute(void);
+void audiohw_unmute(void);
+
+#endif
diff --git a/firmware/export/rk27xx.h b/firmware/export/rk27xx.h
index 58b3fe8166..dc6bca7cbd 100644
--- a/firmware/export/rk27xx.h
+++ b/firmware/export/rk27xx.h
@@ -8,7 +8,8 @@
#define FLASH_BANK1 0x11000000
#define USB_NUM_ENDPOINTS 16
-#define USB_DEVBSS_ATTR
+/* cache aligned */
+#define USB_DEVBSS_ATTR __attribute__((aligned(CACHEALIGN_SIZE)))
/* Timers */
#define APB0_TIMER (ARM_BUS0_BASE + 0x00000000)
@@ -811,6 +812,7 @@
#define RXVOIDINTEN (1<<5)
#define RXERRINTEN (1<<6)
#define RXACKINTEN (1<<7)
+#define RXCFINTE (1<<12)
/* bits 31:8 reserved for EP0 */
/* bits 31:14 reserved for others */
@@ -833,6 +835,7 @@
#define TXERRINTEN (1<<5)
#define TXACKINTEN (1<<6)
#define TXDMADNEN (1<<7) /* reserved for EP0 */
+#define TXCFINTE (1<<12)
/* bits 31:8 reserved */
/* TXnBUF bits */
diff --git a/firmware/export/wm8740.h b/firmware/export/wm8740.h
new file mode 100644
index 0000000000..ff27a7e41e
--- /dev/null
+++ b/firmware/export/wm8740.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 _WM8740_H
+#define _WM8740_H
+
+#define WM8740_VOLUME_MIN -1270
+#define WM8740_VOLUME_MAX 0
+
+#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP)
+AUDIOHW_SETTING(VOLUME, "dB", 0, 1, WM8740_VOLUME_MIN/10, WM8740_VOLUME_MAX/10, 0)
+AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 1, 0)
+
+#define WM8740_REG0 0x0000
+#define WM8740_REG1 0x0200
+#define WM8740_REG2 0x0400
+#define WM8740_REG3 0x0600
+#define WM8740_REG4 0x0C00
+
+/**
+ * Register #0
+ */
+#define WM8740_LDL (1<<8)
+
+/**
+ * Register #1
+ */
+#define WM8740_LDR (1<<8)
+
+/**
+ * Register #2
+ */
+#define WM8740_MUT (1<<0)
+#define WM8740_DEM (1<<1)
+#define WM8740_OPE (1<<2)
+#define WM8740_IW0 (1<<3)
+#define WM8740_IW1 (1<<4)
+
+/**
+ * Register #3
+ */
+#define WM8740_I2S (1<<0)
+#define WM8740_LRP (1<<1)
+#define WM8740_ATC (1<<2)
+#define WM8740_SR0 (1<<3)
+#define WM8740_REV (1<<4)
+#define WM8740_SF0 (1<<6)
+#define WM8740_SF1 (1<<7)
+#define WM8740_IZD (1<<8)
+
+/**
+ * Register #4
+ */
+#define WM8740_DIFF0 (1<<4)
+#define WM8740_DIFF1 (1<<5)
+#define WM8740_CDD (1<<6)
+
+void audiohw_mute(void);
+void audiohw_unmute(void);
+
+void wm8740_set_ml(const int);
+void wm8740_set_mc(const int);
+void wm8740_set_md(const int);
+
+#endif
diff --git a/firmware/target/arm/rk27xx/backlight-rk27xx.c b/firmware/target/arm/rk27xx/backlight-rk27xx.c
index 1756fcdb29..61e887af46 100644
--- a/firmware/target/arm/rk27xx/backlight-rk27xx.c
+++ b/firmware/target/arm/rk27xx/backlight-rk27xx.c
@@ -75,6 +75,13 @@ static const unsigned short lin_brightness[] = {
759, 768, 778, 788, 800, 812, 826, 841,
856, 873, 891, 910, 931, 952, 975, 1000
};
+#elif defined(IHIFI770) || defined(IHIFI770C) || defined(IHIFI800)
+static const unsigned short lin_brightness[] = {
+ 4096, 4215, 4381, 4603, 4887, 5243, 5679, 6201,
+ 6818, 7538, 8370, 9320, 10397, 11609, 12963, 14469,
+ 16133, 17963, 19968, 22156, 24534, 27110, 29893, 32890,
+ 36109, 39559, 43246, 47180, 51368, 55817, 60537, 65535
+};
#endif
bool backlight_hw_init(void)
diff --git a/firmware/target/arm/rk27xx/debug-rk27xx.c b/firmware/target/arm/rk27xx/debug-rk27xx.c
index 83bc1a5af6..ea0190049f 100644
--- a/firmware/target/arm/rk27xx/debug-rk27xx.c
+++ b/firmware/target/arm/rk27xx/debug-rk27xx.c
@@ -35,6 +35,8 @@
#elif defined(HM60X) || defined(HM801) || (CONFIG_KEYPAD == MA_PAD) || \
(CONFIG_KEYPAD == IHIFI_PAD)
#define DEBUG_CANCEL BUTTON_LEFT
+#elif (CONFIG_KEYPAD == IHIFI_770_PAD) || (CONFIG_KEYPAD == IHIFI_800_PAD)
+#define DEBUG_CANCEL BUTTON_POWER
#endif
/* Skeleton for adding target specific debug info to the debug menu
diff --git a/firmware/target/arm/rk27xx/ihifi2/audio-ihifi770.c b/firmware/target/arm/rk27xx/ihifi2/audio-ihifi770.c
new file mode 100644
index 0000000000..a21ea9cfef
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/audio-ihifi770.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "system.h"
+#include "kernel.h"
+#include "audiohw.h"
+
+void wm8740_hw_init(void)
+{
+ GPIO_PADR &= ~(1<<0); /* MD */
+ GPIO_PACON |= (1<<0);
+
+ GPIO_PADR &= ~(1<<1); /* MC */
+ GPIO_PACON |= (1<<1);
+
+ SCU_IOMUXB_CON &= ~(1<<2);
+ GPIO_PCDR |= (1<<4); /* ML */
+ GPIO_PCCON |= (1<<4);
+}
+
+void wm8740_set_md(const int val)
+{
+ if (val)
+ GPIO_PADR |= (1<<0);
+ else
+ GPIO_PADR &= ~(1<<0);
+}
+
+void wm8740_set_mc(const int val)
+{
+ if (val)
+ GPIO_PADR |= (1<<1);
+ else
+ GPIO_PADR &= ~(1<<1);
+}
+
+void wm8740_set_ml(const int val)
+{
+ if (val)
+ GPIO_PCDR |= (1<<4);
+ else
+ GPIO_PCDR &= ~(1<<4);
+}
+
+static void pop_ctrl(const int val)
+{
+ if (val)
+ GPIO_PADR |= (1<<7);
+ else
+ GPIO_PADR &= ~(1<<7);
+}
+
+void audiohw_postinit(void)
+{
+ pop_ctrl(0);
+ sleep(HZ/4);
+ wm8740_hw_init();
+ audiohw_init();
+ sleep(HZ/2);
+ pop_ctrl(1);
+ sleep(HZ/4);
+ audiohw_unmute();
+}
+
+void audiohw_close(void)
+{
+ audiohw_mute();
+ pop_ctrl(0);
+ sleep(HZ/4);
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/audio-ihifi800.c b/firmware/target/arm/rk27xx/ihifi2/audio-ihifi800.c
new file mode 100644
index 0000000000..14b126c72a
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/audio-ihifi800.c
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "system.h"
+#include "kernel.h"
+#include "audiohw.h"
+#include "i2c-rk27xx.h"
+
+#define ES9018_I2C_ADDR 0x90
+
+static unsigned char buf;
+
+void es9018_write_reg(uint8_t reg, uint8_t val)
+{
+ buf = val;
+ i2c_write(ES9018_I2C_ADDR, reg, sizeof(buf), (void*)&buf);
+}
+
+uint8_t es9018_read_reg(uint8_t reg)
+{
+ i2c_read(ES9018_I2C_ADDR, reg, sizeof(buf), (void*)&buf);
+ return buf;
+}
+
+static void pop_ctrl(const int val)
+{
+ if (val)
+ GPIO_PADR |= (1<<7);
+ else
+ GPIO_PADR &= ~(1<<7);
+}
+
+void audiohw_postinit(void)
+{
+ pop_ctrl(0);
+ sleep(HZ/4);
+ audiohw_init();
+ sleep(HZ/2);
+ pop_ctrl(1);
+ sleep(HZ/4);
+ audiohw_unmute();
+}
+
+void audiohw_close(void)
+{
+ audiohw_mute();
+ pop_ctrl(0);
+ sleep(HZ/4);
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/button-ihifi.c b/firmware/target/arm/rk27xx/ihifi2/button-ihifi.c
new file mode 100644
index 0000000000..172853a83a
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/button-ihifi.c
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "button.h"
+#include "adc.h"
+#include "backlight.h"
+
+static bool soft_hold = false;
+#ifndef BOOTLOADER
+static unsigned hold_counter = 0;
+#ifndef IHIFI800
+#define HOLDBUTTON gpio_btn
+#define HOLDCNTMAX HZ
+#else
+#define HOLDBUTTON (gpio_btn) && (adc_val > 325) && (adc_val < 480)
+#define HOLDCNTMAX (HZ/10)
+#endif
+#endif
+
+void button_init_device(void) {
+ GPIO_PCCON &= ~(1<<1); /* PWR BTN */
+ GPIO_PCCON &= ~(1<<7); /* CD */
+}
+
+bool button_hold(void)
+{
+ return soft_hold;
+}
+
+int button_read_device(void) {
+ int adc_val = adc_read(ADC_BUTTONS);
+ int gpio_btn = GPIO_PCDR & (1<<1);
+
+ int button = BUTTON_NONE;
+
+ if (gpio_btn)
+ button |= BUTTON_POWER;
+
+#ifndef BOOTLOADER
+ if (HOLDBUTTON) {
+ if (++hold_counter == HOLDCNTMAX) {
+ soft_hold = !soft_hold;
+ backlight_hold_changed(soft_hold);
+ }
+ } else {
+ hold_counter = 0;
+ }
+ if (soft_hold) {
+ return (hold_counter <= HOLDCNTMAX) ? BUTTON_NONE : button;
+ }
+#endif
+
+ if (adc_val < 792) {
+ if (adc_val < 480) {
+ if (adc_val < 170) {
+ if (adc_val < 46) {
+ button |= BUTTON_HOME; // 0-45
+ } else {
+ button |= BUTTON_PLAY; // 46-169
+ }
+ } else {
+ if (adc_val < 325) {
+ button |= BUTTON_NEXT; // 170-324
+ } else {
+ button |= BUTTON_VOL_UP;// 325-479
+ }
+ }
+ } else {
+ if (adc_val < 636) {
+ button |= BUTTON_VOL_DOWN;// 480-635
+ } else {
+ button |= BUTTON_PREV; // 636-791
+ }
+ }
+ }
+
+ return button;
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/button-target.h b/firmware/target/arm/rk27xx/ihifi2/button-target.h
new file mode 100644
index 0000000000..211e20e1d6
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/button-target.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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_
+
+#define HAS_BUTTON_HOLD
+
+/* Main unit's buttons */
+#define BUTTON_POWER 0x00000001
+#define BUTTON_HOME 0x00000002
+#define BUTTON_PREV 0x00000004
+#define BUTTON_NEXT 0x00000008
+#define BUTTON_PLAY 0x00000010
+#define BUTTON_VOL_UP 0x00000020
+#define BUTTON_VOL_DOWN 0x00000040
+
+#define BUTTON_LEFT 0
+#define BUTTON_RIGHT 0
+
+#define BUTTON_MAIN (BUTTON_POWER | BUTTON_HOME | BUTTON_PREV | BUTTON_NEXT | \
+ BUTTON_PLAY | BUTTON_VOL_UP | BUTTON_VOL_DOWN)
+
+/* Software power-off */
+#ifndef IHIFI800
+#define POWEROFF_BUTTON BUTTON_POWER
+#else
+#define POWEROFF_BUTTON BUTTON_HOME
+#endif
+
+#define POWEROFF_COUNT 30
+
+#endif /* _BUTTON_TARGET_H_ */
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c
new file mode 100644
index 0000000000..23505d9fa0
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c
@@ -0,0 +1,285 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "lcdif-rk27xx.h"
+
+static bool display_on = false;
+
+void lcd_display_init(void)
+{
+ unsigned int i, x, y;
+
+ lcd_cmd(0x11);
+
+ lcd_cmd(0x13);
+
+ mdelay(120);
+
+ lcd_cmd(0x29);
+
+ lcd_cmd(0xB0);
+ lcd_data(0x05);
+ lcd_data(0x00);
+ lcd_data(0xF0);
+ lcd_data(0x0A);
+ lcd_data(0x41);
+ lcd_data(0x02);
+ lcd_data(0x0A);
+ lcd_data(0x30);
+ lcd_data(0x31);
+ lcd_data(0x36);
+ lcd_data(0x37);
+ lcd_data(0x40);
+ lcd_data(0x02);
+ lcd_data(0x3F);
+ lcd_data(0x40);
+ lcd_data(0x02);
+ lcd_data(0x81);
+ lcd_data(0x04);
+ lcd_data(0x05);
+ lcd_data(0x64);
+
+ lcd_cmd(0xFC);
+ lcd_data(0x88);
+ lcd_data(0x00);
+ lcd_data(0x10);
+ lcd_data(0x01);
+ lcd_data(0x01);
+ lcd_data(0x10);
+ lcd_data(0x42);
+ lcd_data(0x42);
+ lcd_data(0x22);
+ lcd_data(0x11);
+ lcd_data(0x11);
+ lcd_data(0x22);
+ lcd_data(0x99);
+ lcd_data(0xAA);
+ lcd_data(0xAA);
+ lcd_data(0xAA);
+ lcd_data(0xBB);
+ lcd_data(0xBB);
+ lcd_data(0xAA);
+ lcd_data(0x33);
+ lcd_data(0x33);
+ lcd_data(0x11);
+ lcd_data(0x01);
+ lcd_data(0x01);
+ lcd_data(0x01);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0xC0);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+
+ lcd_cmd(0xFD);
+ lcd_data(0x88);
+ lcd_data(0x00);
+ lcd_data(0x10);
+ lcd_data(0x01);
+ lcd_data(0x01);
+ lcd_data(0x10);
+ lcd_data(0x42);
+ lcd_data(0x42);
+ lcd_data(0x22);
+ lcd_data(0x11);
+ lcd_data(0x11);
+ lcd_data(0x22);
+ lcd_data(0x99);
+ lcd_data(0xAA);
+ lcd_data(0xAA);
+ lcd_data(0xAA);
+ lcd_data(0xBB);
+ lcd_data(0xBB);
+ lcd_data(0xAA);
+ lcd_data(0x33);
+ lcd_data(0x33);
+ lcd_data(0x11);
+ lcd_data(0x01);
+ lcd_data(0x01);
+ lcd_data(0x01);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x03);
+
+ lcd_cmd(0xBE);
+ lcd_data(0x00);
+ lcd_data(0x15);
+ lcd_data(0x16);
+ lcd_data(0x08);
+ lcd_data(0x09);
+ lcd_data(0x15);
+ lcd_data(0x10);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+
+ lcd_cmd(0xC0);
+ lcd_data(0x0E);
+ lcd_data(0x01);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+
+ lcd_cmd(0xC1);
+ lcd_data(0x2F);
+ lcd_data(0x23);
+ lcd_data(0xB4);
+ lcd_data(0xFF);
+ lcd_data(0x24);
+ lcd_data(0x03);
+ lcd_data(0x20);
+ lcd_data(0x02);
+ lcd_data(0x02);
+ lcd_data(0x02);
+ lcd_data(0x20);
+ lcd_data(0x20);
+ lcd_data(0x00);
+
+ lcd_cmd(0xC2);
+ lcd_data(0x03);
+
+ lcd_cmd(0x26);
+ lcd_data(0x08);
+
+ lcd_cmd(0x35);
+
+ lcd_cmd(0x36);
+ lcd_data(0x04);
+
+ lcd_cmd(0x3A);
+ lcd_data(0x05);
+
+ lcd_cmd(0x2A);
+ lcd_data(0x013F);
+
+ lcd_cmd(0x2B);
+ lcd_data(0xEF);
+
+ lcd_cmd(0x2C);
+
+ lcd_cmd(0x2D);
+ for (i = 0; i < 0x20; i++) {
+ lcd_data(i << 1);
+ }
+ for (i = 0; i < 0x40; i++) {
+ lcd_data(i);
+ }
+ for (i = 0; i < 0x20; i++) {
+ lcd_data(i << 1);
+ }
+
+ lcd_cmd(0x2A);
+ lcd_data(0x00);
+
+ lcd_cmd(0x2B);
+ lcd_data(0x00);
+
+ lcd_cmd(0x11);
+
+ mdelay(120);
+
+ lcd_cmd(0x29);
+
+ lcd_cmd(0x2C);
+
+ for (x = 0; x < LCD_WIDTH; x++)
+ for(y=0; y < LCD_HEIGHT; y++)
+ lcd_data(0x00);
+
+ display_on = true;
+}
+
+void lcd_enable (bool on)
+{
+ if (on == display_on)
+ return;
+
+ lcdctrl_bypass(1);
+ LCDC_CTRL |= RGB24B;
+
+ if (on) {
+ lcd_cmd(0x11);
+ mdelay(120);
+ lcd_cmd(0x29);
+ lcd_cmd(0x2C);
+ } else {
+ lcd_cmd(0x28);
+ mdelay(120);
+ lcd_cmd(0x10);
+ }
+
+ display_on = on;
+ LCDC_CTRL &= ~RGB24B;
+}
+
+void lcd_set_gram_area(int x_start, int y_start,
+ int x_end, int y_end)
+{
+ lcdctrl_bypass(1);
+ LCDC_CTRL |= RGB24B;
+
+ lcd_cmd(0x2A);
+ lcd_data((x_start&0xff00)>>8);
+ lcd_data(x_start&0x00ff);
+ lcd_data((x_end&0xff00)>>8);
+ lcd_data(x_end&0x00ff);
+
+ lcd_cmd(0x2B);
+ lcd_data((y_start&0xff00)>>8);
+ lcd_data(y_start&0x00ff);
+ lcd_data((y_end&0xff00)>>8);
+ lcd_data(y_end&0x00ff);
+
+ lcd_cmd(0x2C);
+
+ LCDC_CTRL &= ~RGB24B;
+}
+
+bool lcd_active()
+{
+ return display_on;
+}
+
+/* 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)
+{
+ (void)src;
+ (void)src_x;
+ (void)src_y;
+ (void)stride;
+ (void)x;
+ (void)y;
+ (void)width;
+ (void)height;
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
new file mode 100644
index 0000000000..311b8057cb
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
@@ -0,0 +1,248 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "lcdif-rk27xx.h"
+
+static bool display_on = false;
+
+void lcd_display_init(void)
+{
+ unsigned int x, y;
+
+ lcd_cmd(0x13);
+
+ mdelay(120);
+
+ lcd_cmd(0x35);
+ lcd_data(0x00);
+
+ lcd_cmd(0x36);
+ lcd_data(0x48);
+
+ lcd_cmd(0xD0);
+ lcd_data(0x00);
+ lcd_data(0x05);
+
+ lcd_cmd(0xEF);
+ lcd_data(0x07);
+
+ lcd_cmd(0xF2);
+ lcd_data(0x1B);
+ lcd_data(0x16);
+ lcd_data(0x0F);
+ lcd_data(0x08);
+ lcd_data(0x08);
+ lcd_data(0x08);
+ lcd_data(0x08);
+ lcd_data(0x10);
+ lcd_data(0x00);
+ lcd_data(0x1C);
+ lcd_data(0x16);
+
+ lcd_cmd(0xF3);
+ lcd_data(0x01);
+ lcd_data(0x41);
+ lcd_data(0x15);
+ lcd_data(0x0D);
+ lcd_data(0x33);
+ lcd_data(0x63);
+ lcd_data(0x46);
+ lcd_data(0x10);
+
+ lcd_cmd(0xF4);
+ lcd_data(0x5B);
+ lcd_data(0x5B);
+ lcd_data(0x55);
+ lcd_data(0x55);
+ lcd_data(0x44);
+
+ lcd_cmd(0xF5);
+ lcd_data(0x12);
+ lcd_data(0x11);
+ lcd_data(0x06);
+ lcd_data(0xF0);
+ lcd_data(0x00);
+ lcd_data(0x1F);
+
+ lcd_cmd(0xF6);
+ lcd_data(0x80);
+ lcd_data(0x10);
+ lcd_data(0x00);
+
+ lcd_cmd(0xFD);
+ lcd_data(0x11);
+ lcd_data(0x1D);
+ lcd_data(0x00);
+
+ lcd_cmd(0xF8);
+ lcd_data(0x00);
+ lcd_data(0x15);
+ lcd_data(0x01);
+ lcd_data(0x08);
+ lcd_data(0x15);
+ lcd_data(0x22);
+ lcd_data(0x25);
+ lcd_data(0x28);
+ lcd_data(0x14);
+ lcd_data(0x13);
+ lcd_data(0x10);
+ lcd_data(0x11);
+ lcd_data(0x09);
+ lcd_data(0x24);
+ lcd_data(0x28);
+
+ lcd_cmd(0xF9);
+ lcd_data(0x00);
+ lcd_data(0x15);
+ lcd_data(0x01);
+ lcd_data(0x08);
+ lcd_data(0x15);
+ lcd_data(0x22);
+ lcd_data(0x25);
+ lcd_data(0x28);
+ lcd_data(0x14);
+ lcd_data(0x13);
+ lcd_data(0x10);
+ lcd_data(0x11);
+ lcd_data(0x09);
+ lcd_data(0x24);
+ lcd_data(0x28);
+
+ lcd_cmd(0xFC);
+ lcd_data(0x00);
+ lcd_data(0x15);
+ lcd_data(0x01);
+ lcd_data(0x08);
+ lcd_data(0x15);
+ lcd_data(0x22);
+ lcd_data(0x25);
+ lcd_data(0x28);
+ lcd_data(0x14);
+ lcd_data(0x13);
+ lcd_data(0x10);
+ lcd_data(0x11);
+ lcd_data(0x09);
+ lcd_data(0x24);
+ lcd_data(0x28);
+
+ lcd_cmd(0x36);
+ lcd_data(0x48);
+
+ lcd_cmd(0x3A);
+ lcd_data(0x55);
+
+ lcd_cmd(0x2A);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x01);
+ lcd_data(0x3F);
+
+ lcd_cmd(0x2B);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0xEF);
+
+ lcd_cmd(0x11);
+
+ mdelay(120);
+
+ lcd_cmd(0x29);
+
+ lcd_cmd(0x2C);
+
+ for (x = 0; x < LCD_WIDTH; x++)
+ for(y=0; y < LCD_HEIGHT; y++)
+ lcd_data(0x00);
+
+ display_on = true;
+}
+
+void lcd_enable (bool on)
+{
+ if (on == display_on)
+ return;
+
+ lcdctrl_bypass(1);
+ LCDC_CTRL |= RGB24B;
+
+ if (on) {
+ lcd_cmd(0x11);
+ mdelay(120);
+ lcd_cmd(0x29);
+ lcd_cmd(0x2C);
+ } else {
+ lcd_cmd(0x28);
+ mdelay(120);
+ lcd_cmd(0x10);
+ }
+
+ display_on = on;
+ LCDC_CTRL &= ~RGB24B;
+}
+
+void lcd_set_gram_area(int x_start, int y_start,
+ int x_end, int y_end)
+{
+ lcdctrl_bypass(1);
+ LCDC_CTRL |= RGB24B;
+
+ lcd_cmd(0x2A);
+ lcd_data((x_start&0xff00)>>8);
+ lcd_data(x_start&0x00ff);
+ lcd_data((x_end&0xff00)>>8);
+ lcd_data(x_end&0x00ff);
+
+ lcd_cmd(0x2B);
+ lcd_data((y_start&0xff00)>>8);
+ lcd_data(y_start&0x00ff);
+ lcd_data((y_end&0xff00)>>8);
+ lcd_data(y_end&0x00ff);
+
+ lcd_cmd(0x2C);
+
+ LCDC_CTRL &= ~RGB24B;
+}
+
+bool lcd_active()
+{
+ return display_on;
+}
+
+/* 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)
+{
+ (void)src;
+ (void)src_x;
+ (void)src_y;
+ (void)stride;
+ (void)x;
+ (void)y;
+ (void)width;
+ (void)height;
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c
new file mode 100644
index 0000000000..821b52dcb6
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c
@@ -0,0 +1,228 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "lcdif-rk27xx.h"
+
+static bool display_on = false;
+
+void lcd_display_init(void)
+{
+ unsigned int x, y;
+
+ lcd_cmd(0xEF);
+ lcd_data(0x03);
+ lcd_data(0x80);
+ lcd_data(0x02);
+
+ lcd_cmd(0xCF);
+ lcd_data(0x00);
+ lcd_data(0xC1);
+ lcd_data(0x30);
+
+ lcd_cmd(0xED);
+ lcd_data(0x67);
+ lcd_data(0x03);
+ lcd_data(0x12);
+ lcd_data(0x81);
+
+ lcd_cmd(0xE8);
+ lcd_data(0x85);
+ lcd_data(0x11);
+ lcd_data(0x79);
+
+ lcd_cmd(0xCB);
+ lcd_data(0x39);
+ lcd_data(0x2C);
+ lcd_data(0x00);
+ lcd_data(0x34);
+ lcd_data(0x06);
+
+ lcd_cmd(0xF7);
+ lcd_data(0x20);
+
+ lcd_cmd(0xEA);
+ lcd_data(0x00);
+ lcd_data(0x00);
+
+ lcd_cmd(0xC0);
+ lcd_data(0x1D);
+
+ lcd_cmd(0xC1);
+ lcd_data(0x12);
+
+ lcd_cmd(0xC5);
+ lcd_data(0x44);
+ lcd_data(0x3C);
+
+ lcd_cmd(0xC7);
+ lcd_data(0x88);
+
+ lcd_cmd(0x3A);
+ lcd_data(0x55);
+
+ lcd_cmd(0x36);
+ lcd_data(0x0C);
+
+ lcd_cmd(0xB1);
+ lcd_data(0x00);
+ lcd_data(0x17);
+
+ lcd_cmd(0xB6);
+ lcd_data(0x0A);
+ lcd_data(0xA2);
+
+ lcd_cmd(0xF2);
+ lcd_data(0x00);
+
+ lcd_cmd(0x26);
+ lcd_data(0x01);
+
+ lcd_cmd(0xE0);
+ lcd_data(0x0F);
+ lcd_data(0x22);
+ lcd_data(0x1C);
+ lcd_data(0x1B);
+ lcd_data(0x08);
+ lcd_data(0x0F);
+ lcd_data(0x48);
+ lcd_data(0xB8);
+ lcd_data(0x34);
+ lcd_data(0x05);
+ lcd_data(0x0C);
+ lcd_data(0x09);
+ lcd_data(0x0F);
+ lcd_data(0x07);
+ lcd_data(0x00);
+
+ lcd_cmd(0xE1);
+ lcd_data(0x00);
+ lcd_data(0x23);
+ lcd_data(0x24);
+ lcd_data(0x07);
+ lcd_data(0x10);
+ lcd_data(0x07);
+ lcd_data(0x38);
+ lcd_data(0x47);
+ lcd_data(0x4B);
+ lcd_data(0x0A);
+ lcd_data(0x13);
+ lcd_data(0x06);
+ lcd_data(0x30);
+ lcd_data(0x38);
+ lcd_data(0x0F);
+
+ lcd_cmd(0x2A);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0xEF);
+
+ lcd_cmd(0x2B);
+ lcd_data(0x00);
+ lcd_data(0x00);
+ lcd_data(0x01);
+ lcd_data(0x3F);
+
+ lcd_cmd(0x11);
+
+ mdelay(120);
+
+ lcd_cmd(0x29);
+
+ lcd_cmd(0x2C);
+
+ for (x = 0; x < LCD_WIDTH; x++)
+ for(y=0; y < LCD_HEIGHT; y++)
+ lcd_data(0x00);
+
+ display_on = true;
+}
+
+void lcd_enable (bool on)
+{
+ if (on == display_on)
+ return;
+
+ lcdctrl_bypass(1);
+ LCDC_CTRL |= RGB24B;
+
+ if (on) {
+ lcd_cmd(0x11);
+ mdelay(120);
+ lcd_cmd(0x29);
+ lcd_cmd(0x2C);
+ } else {
+ lcd_cmd(0x28);
+ mdelay(120);
+ lcd_cmd(0x10);
+ }
+
+ display_on = on;
+ LCDC_CTRL &= ~RGB24B;
+}
+
+void lcd_set_gram_area(int x_start, int y_start,
+ int x_end, int y_end)
+{
+ lcdctrl_bypass(1);
+ LCDC_CTRL |= RGB24B;
+
+ lcd_cmd(0x2A);
+ lcd_data((x_start&0xff00)>>8);
+ lcd_data(x_start&0x00ff);
+ lcd_data((x_end&0xff00)>>8);
+ lcd_data(x_end&0x00ff);
+
+ lcd_cmd(0x2B);
+ lcd_data((y_start&0xff00)>>8);
+ lcd_data(y_start&0x00ff);
+ lcd_data((y_end&0xff00)>>8);
+ lcd_data(y_end&0x00ff);
+
+ lcd_cmd(0x2C);
+
+ LCDC_CTRL &= ~RGB24B;
+}
+
+bool lcd_active()
+{
+ return display_on;
+}
+
+/* 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)
+{
+ (void)src;
+ (void)src_x;
+ (void)src_y;
+ (void)stride;
+ (void)x;
+ (void)y;
+ (void)width;
+ (void)height;
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-target.h b/firmware/target/arm/rk27xx/ihifi2/lcd-target.h
new file mode 100644
index 0000000000..6b2aa5d8a5
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/lcd-target.h
@@ -0,0 +1,26 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ *
+ * 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
+
+#define LCD_DATABUS_WIDTH LCDIF_16BIT
+#endif
diff --git a/firmware/target/arm/rk27xx/ihifi2/power-ihifi.c b/firmware/target/arm/rk27xx/ihifi2/power-ihifi.c
new file mode 100644
index 0000000000..cc489eacfe
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/power-ihifi.c
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 <stdbool.h>
+#include "config.h"
+#include "inttypes.h"
+#include "power.h"
+#include "panic.h"
+#include "system.h"
+#include "usb_core.h" /* for usb_charging_maxcurrent_change */
+#include "adc.h"
+
+void power_off(void)
+{
+ GPIO_PCCON &= ~(1<<0);
+ while(1);
+}
+
+void power_init(void)
+{
+ GPIO_PCDR |= (1<<0);
+ GPIO_PCCON |= (1<<0);
+
+ GPIO_PADR &= ~(1<<7); /* MUTE */
+ GPIO_PACON |= (1<<7);
+}
+
+unsigned int power_input_status(void)
+{
+ return (usb_detect() == USB_INSERTED) ? POWER_INPUT_MAIN_CHARGER : POWER_INPUT_NONE;
+}
+
+bool charging_state(void)
+{
+ return (adc_read(ADC_EXTRA) < 512);
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770.c b/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770.c
new file mode 100644
index 0000000000..b0ff4f5a7b
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770.c
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "adc-target.h"
+#include "powermgmt.h"
+
+/* Battery voltage calculation and discharge/charge curves for the iHiFi 770
+
+ Battery voltage is calculated under the assumption that the adc full-scale
+ readout represents 3.00V and that the battery ADC channel is fed with
+ exactly half of the battery voltage (through a resistive divider).
+ Charge curve have not been calibrated yet.
+*/
+
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+ /* 5% */
+ 3500,
+};
+
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+ /* 0% */
+ 3300,
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+ { 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 }
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short percent_to_volt_charge[11] =
+ { 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 };
+
+/* full-scale ADC readout (2^10) in millivolt */
+#define BATTERY_SCALE_FACTOR 6296
+
+/* Returns battery voltage from ADC [millivolts] */
+int _battery_voltage(void)
+{
+ return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770c.c b/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770c.c
new file mode 100644
index 0000000000..613553010b
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770c.c
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "adc-target.h"
+#include "powermgmt.h"
+
+/* Battery voltage calculation and discharge/charge curves for the iHiFi 770C
+
+ Battery voltage is calculated under the assumption that the adc full-scale
+ readout represents 3.00V and that the battery ADC channel is fed with
+ exactly half of the battery voltage (through a resistive divider).
+ Charge curve have not been calibrated yet.
+*/
+
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+ /* 5% */
+ 3500,
+};
+
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+ /* 0% */
+ 3300,
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+ { 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 }
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short percent_to_volt_charge[11] =
+ { 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 };
+
+/* full-scale ADC readout (2^10) in millivolt */
+#define BATTERY_SCALE_FACTOR 6296
+
+/* Returns battery voltage from ADC [millivolts] */
+int _battery_voltage(void)
+{
+ return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
+}
diff --git a/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi800.c b/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi800.c
new file mode 100644
index 0000000000..26f4e47b93
--- /dev/null
+++ b/firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi800.c
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2016 by Roman Stolyarov
+ *
+ * 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 "adc-target.h"
+#include "powermgmt.h"
+
+/* Battery voltage calculation and discharge/charge curves for the iHiFi 800
+
+ Battery voltage is calculated under the assumption that the adc full-scale
+ readout represents 3.00V and that the battery ADC channel is fed with
+ exactly half of the battery voltage (through a resistive divider).
+ Charge curve have not been calibrated yet.
+*/
+
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+ /* 5% */
+ 3628,
+};
+
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+ /* 0% */
+ 3300,
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+ { 3300, 3649, 3701, 3726, 3745, 3778, 3831, 3904, 3965, 4056, 4160 }
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short percent_to_volt_charge[11] =
+ { 3300, 3649, 3701, 3726, 3745, 3778, 3831, 3904, 3965, 4056, 4160 };
+
+/* full-scale ADC readout (2^10) in millivolt */
+#define BATTERY_SCALE_FACTOR 6296
+
+/* Returns battery voltage from ADC [millivolts] */
+int _battery_voltage(void)
+{
+ return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
+}
diff --git a/firmware/target/arm/rk27xx/sd-rk27xx.c b/firmware/target/arm/rk27xx/sd-rk27xx.c
index 2ddfd0cf0a..e5467058de 100644
--- a/firmware/target/arm/rk27xx/sd-rk27xx.c
+++ b/firmware/target/arm/rk27xx/sd-rk27xx.c
@@ -97,7 +97,7 @@ void INT_SD(void)
/* get the status */
cmd_error = SD_CMDRES;
semaphore_release(&command_completion_signal);
- }
+ }
/* data transfer status pending */
if(status & DATA_XFER_STAT)
@@ -140,13 +140,15 @@ static void mmu_buff_reset(void)
static inline bool card_detect_target(void)
{
-#if defined(RK27_GENERIC)
-/* My generic device uses PC7 pin, active low */
+#if defined(RK27_GENERIC) || defined(IHIFI770) || defined(IHIFI770C) || defined(IHIFI800)
+ /* PC7, active low */
return !(GPIO_PCDR & 0x80);
#elif defined(HM60X) || defined(HM801)
+ /* PF2, active low */
return !(GPIO_PFDR & (1<<2));
#elif defined(MA9) || defined(MA9C) || defined(MA8) || defined(MA8C)
- return (GPIO_PCDR & 0x80);
+ /* PC7, active high */
+ return (GPIO_PCDR & (1<<7));
#elif defined(IHIFI760) || defined(IHIFI960)
/* TODO: find out pin */
return true;
@@ -190,7 +192,7 @@ static bool send_cmd(const int cmd, const int arg, const int res,
#if 0
/* for some misterious reason the card does not report itself as being in TRAN
* but transfers are successful. Rockchip OF does not check the card state
- * after SELECT. I checked two different cards.
+ * after SELECT. I checked two different cards.
*/
static void print_card_status(void)
{
@@ -224,7 +226,7 @@ static int sd_wait_for_tran_state(void)
{
return 0;
}
-
+
if(TIME_AFTER(current_tick, timeout))
{
return -10 * ((response >> 9) & 0xf);
@@ -265,7 +267,7 @@ static int sd_init_card(void)
/* CMD0 Go Idle */
if(!send_cmd(SD_GO_IDLE_STATE, 0, RES_NO, NULL))
return -1;
-
+
sleep(1);
/* CMD8 Check for v2 sd card. Must be sent before using ACMD41
@@ -671,7 +673,7 @@ int sd_write_sectors(IF_MD(int drive,) unsigned long start, int count,
#endif
return ret;
-
+
#endif /* defined(BOOTLOADER) */
}
diff --git a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
index badc3ab5ed..057ecf6ebc 100644
--- a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
+++ b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
@@ -28,37 +28,16 @@
#include "kernel.h"
#include "panic.h"
-//#include "usb-s3c6400x.h"
-
#include "usb_ch9.h"
#include "usb_core.h"
#include <inttypes.h>
#include "power.h"
+#define LOGF_ENABLE
#include "logf.h"
typedef volatile uint32_t reg32;
-/* Bulk OUT: ep1, ep4, ep7, ep10, ep13 */
-#define BOUT_RXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x54+0x38*(ep_num/3)))
-#define BOUT_RXCON(ep_num) (*(reg32*)(AHB0_UDC+0x58+0x38*(ep_num/3)))
-#define BOUT_DMAOUTCTL(ep_num) (*(reg32*)(AHB0_UDC+0x5C+0x38*(ep_num/3)))
-#define BOUT_DMAOUTLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x60+0x38*(ep_num/3)))
-
-/* Bulk IN: ep2, ep5, ep8, ep11, ep4 */
-#define BIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x64+0x38*(ep_num/3)))
-#define BIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x68+0x38*(ep_num/3)))
-#define BIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x6C+0x38*(ep_num/3)))
-#define BIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x70+0x38*(ep_num/3)))
-#define BIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x74+0x38*(ep_num/3)))
-
-/* INTERRUPT IN: ep3, ep6, ep9, ep12, ep15 */
-#define IIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x78+0x38*((ep_num/3)-1)))
-#define IIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x7C+0x38*((ep_num/3)-1)))
-#define IIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x80+0x38*((ep_num/3)-1)))
-#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1)))
-#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1)))
-
#ifdef LOGF_ENABLE
#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT")
#define XFER_TYPE_STR(type) \
@@ -68,9 +47,12 @@ typedef volatile uint32_t reg32;
((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
#endif
-struct endpoint_t {
+struct endpoint_t
+{
+ const int ep_num; /* EP number */
const int type; /* EP type */
const int dir; /* DIR_IN/DIR_OUT */
+ volatile unsigned long *stat; /* RXSTAT/TXSTAT register */
bool allocated; /* flag to mark EPs taken */
volatile void *buf; /* tx/rx buffer address */
volatile int len; /* size of the transfer (bytes) */
@@ -79,110 +61,91 @@ struct endpoint_t {
struct semaphore complete; /* semaphore for blocking transfers */
};
-#define EP_INIT(_type, _dir, _alloced, _buf, _len, _cnt, _block) \
- { .type = (_type), .dir = (_dir), .allocated = (_alloced), .buf = (_buf), \
- .len = (_len), .cnt = (_cnt), .block = (_block) }
-
-static struct endpoint_t ctrlep[2] = {
- EP_INIT(USB_ENDPOINT_XFER_CONTROL, DIR_OUT, true, NULL, 0, 0, true),
- EP_INIT(USB_ENDPOINT_XFER_CONTROL, DIR_IN, true, NULL, 0, 0, true),
+/* compute RXCON address from RXSTAT, and so on */
+#define RXSTAT(endp) *((endp)->stat)
+#define RXCON(endp) *(1 + (endp)->stat)
+#define DMAOUTCTL(endp) *(2 + (endp)->stat)
+#define DMAOUTLMADDR(endp) *(3 + (endp)->stat)
+/* compute TXCON address from TXSTAT, and so on */
+#define TXSTAT(endp) *((endp)->stat)
+#define TXCON(endp) *(1 + (endp)->stat)
+#define TXBUF(endp) *(2 + (endp)->stat)
+#define DMAINCTL(endp) *(3 + (endp)->stat)
+#define DMAINLMADDR(endp) *(4 + (endp)->stat)
+
+#define ENDPOINT(num, type, dir, reg) \
+ {num, USB_ENDPOINT_XFER_##type, USB_DIR_##dir, reg, false, NULL, 0, 0, true, {{0, 0}, 0, 0}}
+
+static struct endpoint_t ctrlep[2] =
+{
+ ENDPOINT(0, CONTROL, OUT, &RX0STAT),
+ ENDPOINT(0, CONTROL, IN, &TX0STAT),
};
-static struct endpoint_t endpoints[16] = {
- EP_INIT(USB_ENDPOINT_XFER_CONTROL, 3, true, NULL, 0, 0, true ), /* stub */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT1 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN2 */
- EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN3 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT4 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN5 */
- EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN6 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT7 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN8 */
- EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN9 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT10 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN11 */
- EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN12 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT13 */
- EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN14 */
- EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN15 */
+static struct endpoint_t endpoints[16] =
+{
+ ENDPOINT(0, CONTROL, OUT, NULL), /* stub */
+ ENDPOINT(1, BULK, OUT, &RX1STAT), /* BOUT1 */
+ ENDPOINT(2, BULK, IN, &TX2STAT), /* BIN2 */
+ ENDPOINT(3, INT, IN, &TX3STAT), /* IIN3 */
+ ENDPOINT(4, BULK, OUT, &RX4STAT), /* BOUT4 */
+ ENDPOINT(5, BULK, IN, &TX5STAT), /* BIN5 */
+ ENDPOINT(6, INT, IN, &TX6STAT), /* IIN6 */
+ ENDPOINT(7, BULK, OUT, &RX7STAT), /* BOUT7 */
+ ENDPOINT(8, BULK, IN, &TX8STAT), /* BIN8 */
+ ENDPOINT(9, INT, IN, &TX9STAT), /* IIN9 */
+ ENDPOINT(10, BULK, OUT, &RX10STAT), /* BOUT10 */
+ ENDPOINT(11, BULK, IN, &TX11STAT), /* BIN11 */
+ ENDPOINT(12, INT, IN, &TX12STAT), /* IIN12 */
+ ENDPOINT(13, BULK, OUT, &RX13STAT), /* BOUT13 */
+ ENDPOINT(14, BULK, IN, &TX14STAT), /* BIN14 */
+ ENDPOINT(15, INT, IN, &TX15STAT), /* IIN15 */
};
+static volatile bool set_address = false;
+static volatile bool set_configuration = false;
+
+#undef ENDPOINT
+
static void setup_received(void)
{
static uint32_t setup_data[2];
-
+ logf("udc: setup");
+
/* copy setup data from packet */
setup_data[0] = SETUP1;
setup_data[1] = SETUP2;
- /* clear all pending control transfers
- * do we need this here?
- */
-
/* pass setup data to the upper layer */
usb_core_control_request((struct usb_ctrlrequest*)setup_data);
}
-/* service ep0 IN transaction */
-static void ctr_write(void)
+static int max_pkt_size(struct endpoint_t *endp)
{
- int xfer_size = (ctrlep[DIR_IN].cnt > 64) ? 64 : ctrlep[DIR_IN].cnt;
- unsigned int timeout = current_tick + HZ/10;
-
- while (TX0BUF & TXFULL) /* TX0FULL flag */
+ switch(endp->type)
{
- if(TIME_AFTER(current_tick, timeout))
- break;
+ case USB_ENDPOINT_XFER_CONTROL: return 64;
+ case USB_ENDPOINT_XFER_BULK: return usb_drv_port_speed() ? 512 : 64;
+ case USB_ENDPOINT_XFER_INT: return usb_drv_port_speed() ? 1024 : 64;
+ default: panicf("die"); return 0;
}
-
- TX0STAT = xfer_size; /* size of the transfer */
- TX0DMALM_IADDR = (uint32_t)ctrlep[DIR_IN].buf; /* local buffer address */
- TX0DMAINCTL = DMA_START; /* start DMA */
- TX0CON &= ~TXNAK; /* clear NAK */
-
- /* Decrement by max packet size is intentional.
- * This way if we have final packet short one we will get negative len
- * after transfer, which in turn indicates we *don't* need to send
- * zero length packet. If the final packet is max sized packet we will
- * get zero len after transfer which indicates we need to send
- * zero length packet to signal host end of the transfer.
- */
- ctrlep[DIR_IN].cnt -= 64;
- ctrlep[DIR_IN].buf += xfer_size;
-}
-
-static void ctr_read(void)
-{
- int xfer_size = RX0STAT & 0xffff;
-
- /* clear NAK bit */
- RX0CON &= ~RXNAK;
-
- ctrlep[DIR_OUT].cnt -= xfer_size;
- ctrlep[DIR_OUT].buf += xfer_size;
-
- RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf; /* buffer address */
- RX0DMACTLO = DMA_START; /* start DMA */
}
-static void blk_write(int ep)
+static void ep_write(struct endpoint_t *endp)
{
- int ep_num = EP_NUM(ep);
- int max = usb_drv_port_speed() ? 512 : 64;
- int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
+ int xfer_size = MIN(max_pkt_size(endp), endp->cnt);
unsigned int timeout = current_tick + HZ/10;
-
- while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
+
+ while(TXBUF(endp) & TXFULL) /* TXFULL flag */
{
if(TIME_AFTER(current_tick, timeout))
break;
}
-
- BIN_TXSTAT(ep_num) = xfer_size; /* size */
- BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
- BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */
- BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */
-
+
+ /* setup transfer size and DMA */
+ TXSTAT(endp) = xfer_size;
+ DMAINLMADDR(endp) = (uint32_t)endp->buf; /* local buffer address */
+ DMAINCTL(endp) = DMA_START;
/* Decrement by max packet size is intentional.
* This way if we have final packet short one we will get negative len
* after transfer, which in turn indicates we *don't* need to send
@@ -190,247 +153,141 @@ static void blk_write(int ep)
* get zero len after transfer which indicates we need to send
* zero length packet to signal host end of the transfer.
*/
- endpoints[ep_num].cnt -= max;
- endpoints[ep_num].buf += xfer_size;
+ endp->cnt -= max_pkt_size(endp);
+ endp->buf += xfer_size;
+ /* clear NAK */
+ TXCON(endp) &= ~TXNAK;
}
-static void blk_read(int ep)
+static void ep_read(struct endpoint_t *endp)
{
- int ep_num = EP_NUM(ep);
- int xfer_size = BOUT_RXSTAT(ep_num) & 0xffff;
-
- /* clear NAK bit */
- BOUT_RXCON(ep_num) &= ~RXNAK;
-
- endpoints[ep_num].cnt -= xfer_size;
- endpoints[ep_num].buf += xfer_size;
-
- BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf;
- BOUT_DMAOUTCTL(ep_num) = DMA_START;
-}
-
-static void int_write(int ep)
-{
- int ep_num = EP_NUM(ep);
- int max = usb_drv_port_speed() ? 1024 : 64;
- int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
- unsigned int timeout = current_tick + HZ/10;
-
- while (IIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
- {
- if(TIME_AFTER(current_tick, timeout))
- break;
- }
-
- IIN_TXSTAT(ep_num) = xfer_size; /* size */
- IIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
- IIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */
- IIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */
-
- /* Decrement by max packet size is intentional.
- * This way if we have final packet short one we will get negative len
- * after transfer, which in turn indicates we *don't* need to send
- * zero length packet. If the final packet is max sized packet we will
- * get zero len after transfer which indicates we need to send
- * zero length packet to signal host end of the transfer.
- */
- endpoints[ep_num].cnt -= max;
- endpoints[ep_num].buf += xfer_size;
+ /* setup DMA */
+ DMAOUTLMADDR(endp) = (uint32_t)endp->buf; /* local buffer address */
+ DMAOUTCTL(endp) = DMA_START;
+ /* clear NAK */
+ RXCON(endp) &= ~RXNAK;
}
-/* UDC ISR function */
-void INT_UDC(void)
+static void in_intr(struct endpoint_t *endp)
{
- uint32_t txstat, rxstat;
- int tmp, ep_num;
-
- /* read what caused UDC irq */
- uint32_t intsrc = INT2FLAG & 0x7fffff;
-
- if (intsrc & SETUP_INTR) /* setup interrupt */
+ uint32_t txstat = TXSTAT(endp);
+ /* check if clear feature was sent by host */
+ if(txstat & TXCFINT)
{
- setup_received();
+ logf("clear_stall: %d", endp->ep_num);
+ usb_drv_stall(endp->ep_num, false, true);
}
- else if (intsrc & IN0_INTR) /* ep0 in interrupt */
+ /* check if a transfer has finished */
+ if(txstat & TXACK)
{
- txstat = TX0STAT; /* read clears flags */
-
- /* TODO handle errors */
- if (txstat & TXACK) /* check TxACK flag */
+ logf("udc: ack(%d)", endp->ep_num);
+ /* finished ? */
+ if(endp->cnt <= 0)
{
- if (ctrlep[DIR_IN].cnt >= 0)
- {
- /* we still have data to send (or ZLP) */
- ctr_write();
- }
- else
- {
- /* final ack received */
- usb_core_transfer_complete(0, /* ep */
- USB_DIR_IN, /* dir */
- 0, /* status */
- ctrlep[DIR_IN].len); /* length */
-
- /* release semaphore for blocking transfer */
- if (ctrlep[DIR_IN].block)
- semaphore_release(&ctrlep[DIR_IN].complete);
- }
+ usb_core_transfer_complete(endp->ep_num, endp->dir, 0, endp->len);
+ /* release semaphore for blocking transfer */
+ if(endp->block)
+ semaphore_release(&endp->complete);
}
+ else /* more data to send */
+ ep_write(endp);
}
- else if (intsrc & OUT0_INTR) /* ep0 out interrupt */
- {
- rxstat = RX0STAT;
+}
- /* TODO handle errors */
- if (rxstat & RXACK) /* RxACK */
- {
- if (ctrlep[DIR_OUT].cnt > 0)
- ctr_read();
- else
- usb_core_transfer_complete(0, /* ep */
- USB_DIR_OUT, /* dir */
- 0, /* status */
- ctrlep[DIR_OUT].len); /* length */
- }
- }
- else if (intsrc & USBRST_INTR) /* usb reset */
- {
- usb_drv_init();
- }
- else if (intsrc & RESUME_INTR) /* usb resume */
- {
- TX0CON |= TXCLR; /* TxClr */
- TX0CON &= ~TXCLR;
- RX0CON |= RXCLR; /* RxClr */
- RX0CON &= ~RXCLR;
- }
- else if (intsrc & SUSP_INTR) /* usb suspend */
+static void out_intr(struct endpoint_t *endp)
+{
+ uint32_t rxstat = RXSTAT(endp);
+ logf("udc: out intr(%d)", endp->ep_num);
+ /* check if clear feature was sent by host */
+ if(rxstat & RXCFINT)
{
+ logf("clear_stall: %d", endp->ep_num);
+ usb_drv_stall(endp->ep_num, false, false);
}
- else if (intsrc & CONN_INTR) /* usb connect */
+ /* check if a transfer has finished */
+ if(rxstat & RXACK)
{
+ int xfer_size = rxstat & 0xffff;
+ endp->cnt -= xfer_size;
+ endp->buf += xfer_size;
+ logf("udc: ack(%d) -> %d/%d", endp->ep_num, xfer_size, endp->cnt);
+ /* finished ? */
+ if(endp->cnt <= 0 || xfer_size < max_pkt_size(endp))
+ usb_core_transfer_complete(endp->ep_num, endp->dir, 0, endp->len);
+ else
+ ep_read(endp);
}
- else
- {
- /* lets figure out which ep generated irq */
- tmp = intsrc >> 7;
- for (ep_num=1; ep_num < 15; ep_num++)
- {
- tmp >>= ep_num;
- if (tmp & 0x01)
- break;
- }
-
- if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20)))
- {
- /* bulk out */
- rxstat = BOUT_RXSTAT(ep_num);
-
- /* TODO handle errors */
- if (rxstat & (1<<18)) /* RxACK */
- {
- if (endpoints[ep_num].cnt > 0)
- blk_read(ep_num);
- else
- usb_core_transfer_complete(ep_num, /* ep */
- USB_DIR_OUT, /* dir */
- 0, /* status */
- endpoints[ep_num].len); /* length */
- }
- }
- else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21)))
+}
+
+static void udc_phy_reset(void)
+{
+ DEV_CTL |= SOFT_POR;
+ udelay(10000); /* min 10ms */
+ DEV_CTL &= ~SOFT_POR;
+}
+
+static void udc_soft_connect(void)
+{
+ DEV_CTL |= CSR_DONE |
+ DEV_SOFT_CN |
+ DEV_SELF_PWR;
+}
+
+static void udc_helper(void)
+{
+ uint32_t dev_info = DEV_INFO;
+
+ /* This polls for DEV_EN bit set in DEV_INFO register
+ * as well as tracks current requested configuration
+ * (DEV_INFO [11:8]). On state change it notifies usb stack
+ * about it.
+ */
+
+ /* SET ADDRESS request */
+ if(!set_address)
+ if(dev_info & 0x7f)
{
- /* bulk in */
- txstat = BIN_TXSTAT(ep_num);
-
- /* TODO handle errors */
- if (txstat & (1<<18)) /* check TxACK flag */
- {
- if (endpoints[ep_num].cnt >= 0)
- {
- /* we still have data to send (or ZLP) */
- blk_write(ep_num);
- }
- else
- {
- /* final ack received */
- usb_core_transfer_complete(ep_num, /* ep */
- USB_DIR_IN, /* dir */
- 0, /* status */
- endpoints[ep_num].len); /* length */
-
- /* release semaphore for blocking transfer */
- if (endpoints[ep_num].block)
- semaphore_release(&endpoints[ep_num].complete);
- }
- }
+ set_address = true;
+ usb_core_notify_set_address(dev_info & 0x7f);
}
- else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22)))
+
+ /* SET CONFIGURATION request */
+ if(!set_configuration)
+ if(dev_info & DEV_EN)
{
- /* int in */
- txstat = IIN_TXSTAT(ep_num);
-
- /* TODO handle errors */
- if (txstat & TXACK) /* check TxACK flag */
- {
- if (endpoints[ep_num].cnt >= 0)
- {
- /* we still have data to send (or ZLP) */
- int_write(ep_num);
- }
- else
- {
- /* final ack received */
- usb_core_transfer_complete(ep_num, /* ep */
- USB_DIR_IN, /* dir */
- 0, /* status */
- endpoints[ep_num].len); /* length */
-
- /* release semaphore for blocking transfer */
- if (endpoints[ep_num].block)
- semaphore_release(&endpoints[ep_num].complete);
- }
- }
+ set_configuration = true;
+ usb_core_notify_set_config(((dev_info >> 7) & 0xf) + 1);
}
- }
}
/* return port speed FS=0, HS=1 */
int usb_drv_port_speed(void)
{
- return ((DEV_INFO & DEV_SPEED) == 0) ? 0 : 1;
+ return (DEV_INFO & DEV_SPEED) ? 0 : 1;
}
/* Reserve endpoint */
int usb_drv_request_endpoint(int type, int dir)
{
- int ep_num, ep_dir;
- int ep_type;
-
- /* Safety */
- ep_dir = EP_DIR(dir);
- ep_type = type & USB_ENDPOINT_XFERTYPE_MASK;
+ logf("req: %s %s", XFER_DIR_STR(dir), XFER_TYPE_STR(type));
- logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type));
-
/* Find an available ep/dir pair */
- for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++)
+ for(int ep_num = 1; ep_num<USB_NUM_ENDPOINTS;ep_num++)
{
- struct endpoint_t* endpoint = &endpoints[ep_num];
-
- if (endpoint->type == ep_type &&
- endpoint->dir == ep_dir &&
- !endpoint->allocated)
- {
- /* mark endpoint as taken */
- endpoint->allocated = true;
-
- /* enable interrupt from this endpoint */
- EN_INT |= (1<<(ep_num+7));
-
- logf("add: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
- return (ep_num | (dir & USB_ENDPOINT_DIR_MASK));
- }
+ struct endpoint_t *endp = &endpoints[ep_num];
+
+ if(endp->allocated || endp->type != type || endp->dir != dir)
+ continue;
+ /* allocate endpoint and enable interrupt */
+ endp->allocated = true;
+ if(dir == USB_DIR_IN)
+ TXCON(endp) = (ep_num << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
+ else
+ RXCON(endp) = (ep_num << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
+ EN_INT |= 1 << (ep_num + 7);
+
+ logf("add: ep%d %s", ep_num, XFER_DIR_STR(dir));
+ return ep_num | dir;
}
return -1;
}
@@ -439,14 +296,12 @@ int usb_drv_request_endpoint(int type, int dir)
void usb_drv_release_endpoint(int ep)
{
int ep_num = EP_NUM(ep);
- int ep_dir = EP_DIR(ep);
- (void) ep_dir;
- logf("rel: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
+ logf("rel: ep%d", ep_num);
endpoints[ep_num].allocated = false;
-
+
/* disable interrupt from this endpoint */
- EN_INT &= ~(1<<(ep_num+7));
+ EN_INT &= ~(1 << (ep_num + 7));
}
/* Set the address (usually it's in a register).
@@ -463,39 +318,25 @@ void usb_drv_set_address(int address)
static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
{
+ logf("udc: send(%x)", endpoint);
struct endpoint_t *ep;
int ep_num = EP_NUM(endpoint);
-
+
if (ep_num == 0)
ep = &ctrlep[DIR_IN];
else
ep = &endpoints[ep_num];
+ /* for send transfers, make sure the data is committed */
+ commit_discard_dcache_range(ptr, length);
ep->buf = ptr;
ep->len = ep->cnt = length;
-
- if (block)
- ep->block = true;
- else
- ep->block = false;
-
- switch (ep->type)
- {
- case USB_ENDPOINT_XFER_CONTROL:
- ctr_write();
- break;
-
- case USB_ENDPOINT_XFER_BULK:
- blk_write(ep_num);
- break;
-
- case USB_ENDPOINT_XFER_INT:
- int_write(ep_num);
- break;
- }
-
- if (block)
- /* wait for transfer to end */
+ ep->block = block;
+
+ ep_write(ep);
+
+ /* wait for transfer to end */
+ if(block)
semaphore_wait(&ep->complete, TIMEOUT_BLOCK);
return 0;
@@ -516,28 +357,20 @@ int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
/* Setup a receive transfer. (non blocking) */
int usb_drv_recv(int endpoint, void* ptr, int length)
{
+ logf("udc: recv(%x)", endpoint);
struct endpoint_t *ep;
int ep_num = EP_NUM(endpoint);
-
- if (ep_num == 0)
- {
+
+ if(ep_num == 0)
ep = &ctrlep[DIR_OUT];
-
- ctr_read();
- }
else
- {
ep = &endpoints[ep_num];
-
- /* clear NAK bit */
- BOUT_RXCON(ep_num) &= ~RXNAK;
- BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr;
- BOUT_DMAOUTCTL(ep_num) = DMA_START;
- }
-
+
+ /* for recv, discard the cache lines related to the buffer */
+ commit_discard_dcache_range(ptr, length);
ep->buf = ptr;
ep->len = ep->cnt = length;
-
+ ep_read(ep);
return 0;
}
@@ -560,173 +393,54 @@ void usb_drv_set_test_mode(int mode)
/* Check if endpoint is in stall state */
bool usb_drv_stalled(int endpoint, bool in)
{
- int ep_num = EP_NUM(endpoint);
-
- switch (endpoints[ep_num].type)
- {
- case USB_ENDPOINT_XFER_CONTROL:
- if (in)
- return (TX0CON & TXSTALL) ? true : false;
- else
- return (RX0CON & RXSTALL) ? true : false;
-
- break;
+ struct endpoint_t *endp = &endpoints[EP_NUM(endpoint)];
- case USB_ENDPOINT_XFER_BULK:
- if (in)
- return (BIN_TXCON(ep_num) & TXSTALL) ? true : false;
- else
- return (BOUT_RXCON(ep_num) & RXSTALL) ? true : false;
-
- break;
-
- case USB_ENDPOINT_XFER_INT:
- if (in)
- return (IIN_TXCON(ep_num) & TXSTALL) ? true : false;
- else
- return false; /* we don't have such endpoint anyway */
-
- break;
- }
-
- return false;
+ if(in)
+ return !!(TXCON(endp) & TXSTALL);
+ else
+ return !!(RXCON(endp) & RXSTALL);
}
/* Stall the endpoint. Usually set a flag in the controller */
void usb_drv_stall(int endpoint, bool stall, bool in)
{
- int ep_num = EP_NUM(endpoint);
-
- switch (endpoints[ep_num].type)
+ struct endpoint_t *endp = &endpoints[EP_NUM(endpoint)];
+ if(in)
{
- case USB_ENDPOINT_XFER_CONTROL:
- if (in)
- {
- if (stall)
- TX0CON |= TXSTALL;
- else
- TX0CON &= ~TXSTALL;
- }
- else
- {
- if (stall)
- RX0CON |= RXSTALL;
- else
- RX0CON &= ~RXSTALL; /* doc says Auto clear by UDC 2.0 */
- }
- break;
-
- case USB_ENDPOINT_XFER_BULK:
- if (in)
- {
- if (stall)
- BIN_TXCON(ep_num) |= TXSTALL;
- else
- BIN_TXCON(ep_num) &= ~TXSTALL;
- }
- else
- {
- if (stall)
- BOUT_RXCON(ep_num) |= RXSTALL;
- else
- BOUT_RXCON(ep_num) &= ~RXSTALL;
- }
- break;
-
- case USB_ENDPOINT_XFER_INT:
- if (in)
- {
- if (stall)
- IIN_TXCON(ep_num) |= TXSTALL;
- else
- IIN_TXCON(ep_num) &= ~TXSTALL;
- }
- break;
+ if(stall)
+ TXCON(endp) |= TXSTALL;
+ else
+ TXCON(endp) &= ~TXSTALL;
+ }
+ else
+ {
+ if(stall)
+ RXCON(endp) |= RXSTALL;
+ else
+ RXCON(endp) &= ~RXSTALL;
}
}
/* one time init (once per connection) - basicaly enable usb core */
void usb_drv_init(void)
{
- int ep_num;
-
- /* enable USB clock */
- SCU_CLKCFG &= ~CLKCFG_UDC;
-
- /* 1. do soft disconnect */
- DEV_CTL = DEV_SELF_PWR;
-
- /* 2. do power on reset to PHY */
- DEV_CTL = DEV_SELF_PWR |
- SOFT_POR;
-
- /* 3. wait more than 10ms */
- udelay(20000);
-
- /* 4. clear SOFT_POR bit */
- DEV_CTL &= ~SOFT_POR;
-
- /* 5. configure minimal EN_INT */
- EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */
- EN_RESUME_INTR | /* Enable Resume Interrupt */
- EN_USBRST_INTR | /* Enable USB Reset Interrupt */
- EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */
- EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */
- EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */
-
- /* 6. configure INTCON */
- INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
- UDC_INTEN; /* enable EP0 interrupts */
-
- /* 7. configure EP0 control registers */
- TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
- TXNAK; /* Set as one to response NAK handshake */
-
- RX0CON = RXACKINTEN |
- RXEPEN | /* Endpoint 0 Enable. When cleared the endpoint does
- * not respond to an SETUP or OUT token
- */
-
- RXNAK; /* Set as one to response NAK handshake */
-
- /* 8. write final bits to DEV_CTL */
- DEV_CTL = CSR_DONE | /* Configure CSR done */
- DEV_PHY16BIT | /* 16-bit data path enabled. udc_clk = 30MHz */
- DEV_SOFT_CN | /* Device soft connect */
- DEV_SELF_PWR; /* Device self power */
-
/* init semaphore of ep0 */
semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0);
semaphore_init(&ctrlep[DIR_IN].complete, 1, 0);
-
- for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
- {
+
+ for(int ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
semaphore_init(&endpoints[ep_num].complete, 1, 0);
-
- if (ep_num%3 == 0) /* IIN 3, 6, 9, 12, 15 */
- {
- IIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
- }
- else if (ep_num%3 == 1) /* BOUT 1, 4, 7, 10, 13 */
- {
- BOUT_RXCON(ep_num) |= (ep_num<<8)|RXEPEN|RXNAK; /* ep_num, NAK, enable */
- }
- else if (ep_num%3 == 2) /* BIN 2, 5, 8, 11, 14 */
- {
- BIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
- }
- }
}
/* turn off usb core */
void usb_drv_exit(void)
{
DEV_CTL = DEV_SELF_PWR;
-
+
/* disable USB interrupts in interrupt controller */
INTC_IMR &= ~IRQ_ARM_UDC;
INTC_IECR &= ~IRQ_ARM_UDC;
-
+
/* we cannot disable UDC clock since this causes data abort
* when reading DEV_INFO in order to check usb connect event
*/
@@ -734,9 +448,94 @@ void usb_drv_exit(void)
int usb_detect(void)
{
- if (DEV_INFO & VBUS_STS)
+ if(DEV_INFO & VBUS_STS)
return USB_INSERTED;
else
return USB_EXTRACTED;
}
+/* UDC ISR function */
+void INT_UDC(void)
+{
+ /* read what caused UDC irq */
+ uint32_t intsrc = INT2FLAG & 0x7fffff;
+
+ if(intsrc & USBRST_INTR) /* usb reset */
+ {
+ logf("udc_int: reset, %ld", current_tick);
+
+ EN_INT = EN_SUSP_INTR | /* Enable Suspend Irq */
+ EN_RESUME_INTR | /* Enable Resume Irq */
+ EN_USBRST_INTR | /* Enable USB Reset Irq */
+ EN_OUT0_INTR | /* Enable OUT Token receive Irq EP0 */
+ EN_IN0_INTR | /* Enable IN Token transmit Irq EP0 */
+ EN_SETUP_INTR; /* Enable SETUP Packet Receive Irq */
+
+ INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
+ UDC_INTEN; /* enable EP0 irqs */
+
+ TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
+ TXNAK; /* Set as one to response NAK handshake */
+
+ RX0CON = RXACKINTEN |
+ RXEPEN | /* Endpoint 0 Enable. When cleared the
+ * endpoint does not respond to an SETUP
+ * or OUT token */
+ RXNAK; /* Set as one to response NAK handshake */
+
+ set_address = false;
+ set_configuration = false;
+ }
+ /* This needs to be processed AFTER usb reset */
+ udc_helper();
+
+ if(intsrc & SETUP_INTR) /* setup interrupt */
+ {
+ setup_received();
+ }
+ if(intsrc & IN0_INTR)
+ {
+ /* EP0 IN done */
+ in_intr(&ctrlep[DIR_IN]);
+ }
+ if(intsrc & OUT0_INTR)
+ {
+ /* EP0 OUT done */
+ out_intr(&ctrlep[DIR_OUT]);
+ }
+ if(intsrc & USBRST_INTR)
+ {
+ /* usb reset */
+ usb_drv_init();
+ }
+ if(intsrc & RESUME_INTR)
+ {
+ /* usb resume */
+ TX0CON |= TXCLR; /* TxClr */
+ TX0CON &= ~TXCLR;
+ RX0CON |= RXCLR; /* RxClr */
+ RX0CON &= ~RXCLR;
+ }
+ if(intsrc & SUSP_INTR)
+ {
+ /* usb suspend */
+ }
+ if(intsrc & CONN_INTR)
+ {
+ /* usb connect */
+ udc_phy_reset();
+ udelay(10000); /* wait at least 10ms */
+ udc_soft_connect();
+ }
+ /* other endpoints */
+ for(int ep_num = 1; ep_num < 16; ep_num++)
+ {
+ if(!(intsrc & (1 << (ep_num + 7))))
+ continue;
+ struct endpoint_t *endp = &endpoints[ep_num];
+ if(endp->dir == USB_DIR_IN)
+ in_intr(endp);
+ else
+ out_intr(endp);
+ }
+}
diff --git a/firmware/target/arm/rk27xx/usb-rk27xx.c b/firmware/target/arm/rk27xx/usb-rk27xx.c
index 20bf867c8d..09c9090a3b 100644
--- a/firmware/target/arm/rk27xx/usb-rk27xx.c
+++ b/firmware/target/arm/rk27xx/usb-rk27xx.c
@@ -32,6 +32,20 @@ int usb_status = USB_EXTRACTED;
void usb_init_device(void)
{
+ /* enable UDC interrupt */
+ INTC_IMR |= (1<<16);
+ INTC_IECR |= (1<<16);
+
+ EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */
+ EN_RESUME_INTR | /* Enable Resume Interrupt */
+ EN_USBRST_INTR | /* Enable USB Reset Interrupt */
+ EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */
+ EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */
+ EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */
+
+ /* configure INTCON */
+ INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
+ UDC_INTEN; /* enable EP0 interrupts */
}
void usb_attach(void)
diff --git a/firmware/target/hosted/sdl/sim-ui-defines.h b/firmware/target/hosted/sdl/sim-ui-defines.h
index 0303ac8ca2..99ae062595 100644
--- a/firmware/target/hosted/sdl/sim-ui-defines.h
+++ b/firmware/target/hosted/sdl/sim-ui-defines.h
@@ -527,6 +527,28 @@
#define UI_HEIGHT 457 /* height of GUI window */
#define UI_LCD_POSX 34
#define UI_LCD_POSY 73
+
+#elif defined(IHIFI770)
+#define UI_TITLE "iHiFi 770"
+#define UI_WIDTH 382 /* width of GUI window */
+#define UI_HEIGHT 690 /* height of GUI window */
+#define UI_LCD_POSX 32
+#define UI_LCD_POSY 86
+
+#elif defined(IHIFI770C)
+#define UI_TITLE "iHiFi 770C"
+#define UI_WIDTH 382 /* width of GUI window */
+#define UI_HEIGHT 690 /* height of GUI window */
+#define UI_LCD_POSX 32
+#define UI_LCD_POSY 86
+
+#elif defined(IHIFI800)
+#define UI_TITLE "iHiFi 800"
+#define UI_WIDTH 300 /* width of GUI window */
+#define UI_HEIGHT 670 /* height of GUI window */
+#define UI_LCD_POSX 26
+#define UI_LCD_POSY 40
+
#elif defined(SIMULATOR)
#error no UI defines
#endif