New port: FiiO M3K on bare metal
Change-Id: I7517e7d5459e129dcfc9465c6fbd708619888fbe
This commit is contained in:
parent
83fcbedc65
commit
3ec66893e3
143 changed files with 16585 additions and 24 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -118,6 +118,7 @@ __pycache__
|
|||
/tools/mknkboot
|
||||
/tools/mktccboot
|
||||
/tools/mkzenboot
|
||||
/tools/mkspl-x1000
|
||||
/tools/iaudio_bl_flash.c
|
||||
/tools/iaudio_bl_flash.h
|
||||
/tools/.vagrant
|
||||
|
|
|
@ -302,6 +302,8 @@ keymaps/keymap-xduoox3ii.c
|
|||
keymaps/keymap-xduoox20.c
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
|
||||
keymaps/keymap-fiiom3klinux.c
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
keymaps/keymap-fiiom3k.c
|
||||
#elif CONFIG_KEYPAD == EROSQ_PAD
|
||||
keymaps/keymap-erosq.c
|
||||
#endif
|
||||
|
|
|
@ -126,6 +126,10 @@
|
|||
#include "bootdata.h"
|
||||
#endif
|
||||
|
||||
#ifdef FIIO_M3K
|
||||
#include "installer.h"
|
||||
#endif
|
||||
|
||||
static const char* threads_getname(int selected_item, void *data,
|
||||
char *buffer, size_t buffer_len)
|
||||
{
|
||||
|
@ -2491,6 +2495,52 @@ static bool dbg_boot_data(void)
|
|||
}
|
||||
#endif /* defined(HAVE_BOOTDATA) && !defined(SIMULATOR) */
|
||||
|
||||
#ifdef FIIO_M3K
|
||||
/* Note: this is temporary and should NOT be merged, ensure it is removed */
|
||||
static int fiio_debug_menu_action_callback(int action, struct gui_synclist *lists)
|
||||
{
|
||||
if(action == ACTION_REDRAW) {
|
||||
simplelist_set_line_count(0);
|
||||
simplelist_addline("Back to menu");
|
||||
simplelist_addline("Install bootloader");
|
||||
simplelist_addline("Dump bootloader");
|
||||
action = ACTION_REDRAW;
|
||||
}
|
||||
|
||||
if(action == ACTION_STD_OK) {
|
||||
int sel = gui_synclist_get_sel_pos(lists);
|
||||
int rc = 0;
|
||||
switch(sel) {
|
||||
case 1:
|
||||
rc = install_bootloader("/boot.install");
|
||||
break;
|
||||
case 2:
|
||||
rc = dump_bootloader("/boot.dump");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(sel == 1 || sel == 2) {
|
||||
const char* msg = installer_strerror(rc);
|
||||
splashf(3*HZ, "(%d) %s", rc, msg);
|
||||
}
|
||||
|
||||
action = ACTION_STD_CANCEL;
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
static bool dbg_fiio_menu(void)
|
||||
{
|
||||
struct simplelist_info info;
|
||||
simplelist_info_init(&info, "FiiO debug menu", 3, NULL);
|
||||
info.action_callback = fiio_debug_menu_action_callback;
|
||||
return simplelist_show_list(&info);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****** The menu *********/
|
||||
static const struct {
|
||||
unsigned char *desc; /* string or ID */
|
||||
|
@ -2598,6 +2648,9 @@ static const struct {
|
|||
#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)
|
||||
{"Boot data", dbg_boot_data },
|
||||
#endif
|
||||
#ifdef FIIO_M3K
|
||||
{"FiiO debug menu", dbg_fiio_menu},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int menu_action_callback(int btn, struct gui_synclist *lists)
|
||||
|
|
|
@ -182,10 +182,15 @@ depth_3d
|
|||
#endif
|
||||
|
||||
/* This should be AUDIOHW_HAVE_FILTER_ROLL_OFF but that is only defined later */
|
||||
#if defined(DX50) || defined(HAVE_DF1704_CODEC) || defined(HAVE_PCM1792_CODEC) || defined(HAVE_CS4398) || defined(HAVE_WM8740) || defined(HAVE_ES9018) || defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC)
|
||||
#if defined(DX50) || defined(HAVE_DF1704_CODEC) || defined(HAVE_PCM1792_CODEC) || defined(HAVE_CS4398) || defined(HAVE_WM8740) || defined(HAVE_ES9018) || defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_AK4376)
|
||||
filter_roll_off
|
||||
#endif
|
||||
|
||||
/* This should be AUDIOHW_HAVE_POWER_MODE but that is not defined yet */
|
||||
#if defined(HAVE_AK4376)
|
||||
dac_power_mode
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ES9018)
|
||||
es9018
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "screen_access.h"
|
||||
#include "settings.h"
|
||||
|
||||
#if defined (HAVE_SCROLLWHEEL)
|
||||
#if defined (HAVE_SCROLLWHEEL) && !defined(FIIO_M3K)
|
||||
/* Define this if your target makes sense to have
|
||||
smaller values at the top of the list increasing down the list */
|
||||
#define ASCENDING_INT_SETTINGS
|
||||
|
|
219
apps/keymaps/keymap-fiiom3k.c
Normal file
219
apps/keymaps/keymap-fiiom3k.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Button Code Definitions for FiiO M3K target */
|
||||
|
||||
#include "config.h"
|
||||
#include "action.h"
|
||||
#include "button.h"
|
||||
#include "settings.h"
|
||||
|
||||
/* {Action Code, Button code, Prereq button code } */
|
||||
|
||||
static const struct button_mapping button_context_standard[] = {
|
||||
{ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_PREV, BUTTON_SCROLL_BACK, BUTTON_NONE},
|
||||
{ACTION_STD_PREVREPEAT, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_NEXT, BUTTON_SCROLL_FWD, BUTTON_NONE},
|
||||
{ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_OK, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
|
||||
{ACTION_STD_CANCEL, BUTTON_BACK|BUTTON_REL, BUTTON_BACK},
|
||||
{ACTION_STD_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
|
||||
{ACTION_STD_CONTEXT, BUTTON_MENU|BUTTON_REL, BUTTON_MENU},
|
||||
{ACTION_STD_MENU, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK},
|
||||
{ACTION_STD_QUICKSCREEN, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
|
||||
{ACTION_STD_KEYLOCK, BUTTON_POWER|BUTTON_REL, BUTTON_POWER},
|
||||
{ACTION_STD_HOTKEY, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_standard */
|
||||
|
||||
static const struct button_mapping button_context_wps[] = {
|
||||
{ACTION_WPS_PLAY, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY},
|
||||
{ACTION_WPS_PLAY, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
|
||||
{ACTION_WPS_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER},
|
||||
{ACTION_WPS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_WPS_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_SKIPNEXT, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT},
|
||||
{ACTION_WPS_SKIPPREV, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT},
|
||||
{ACTION_WPS_SEEKFWD, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_STOPSEEK, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT|BUTTON_REPEAT},
|
||||
{ACTION_WPS_SEEKBACK, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_WPS_STOPSEEK, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT|BUTTON_REPEAT},
|
||||
{ACTION_WPS_BROWSE, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK},
|
||||
{ACTION_WPS_MENU, BUTTON_BACK|BUTTON_REL, BUTTON_BACK},
|
||||
{ACTION_WPS_CONTEXT, BUTTON_MENU|BUTTON_REL, BUTTON_MENU},
|
||||
{ACTION_WPS_QUICKSCREEN, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
|
||||
{ACTION_STD_KEYLOCK, BUTTON_POWER|BUTTON_REL, BUTTON_POWER},
|
||||
{ACTION_WPS_HOTKEY, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
|
||||
{ACTION_WPS_VIEW_PLAYLIST, BUTTON_SCROLL_FWD, BUTTON_NONE},
|
||||
{ACTION_WPS_VIEW_PLAYLIST, BUTTON_SCROLL_BACK, BUTTON_NONE},
|
||||
{ACTION_WPS_ABSETA_PREVDIR, BUTTON_UP|BUTTON_REPEAT, BUTTON_UP},
|
||||
{ACTION_WPS_ABSETB_NEXTDIR, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_DOWN},
|
||||
{ACTION_WPS_ABRESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_wps */
|
||||
|
||||
static const struct button_mapping button_context_tree[] = {
|
||||
{ACTION_TREE_STOP, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
|
||||
{ACTION_TREE_WPS, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST)
|
||||
}; /* button_context_tree */
|
||||
|
||||
static const struct button_mapping button_context_list[] = {
|
||||
{ACTION_LISTTREE_PGUP, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_LISTTREE_PGUP, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_LISTTREE_PGDOWN, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_LISTTREE_PGDOWN, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
}; /* button_context_list */
|
||||
|
||||
static const struct button_mapping button_context_settings[] = {
|
||||
{ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INC, BUTTON_SCROLL_BACK, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCREPEAT, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DEC, BUTTON_SCROLL_FWD, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECREPEAT, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_RESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
|
||||
{ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
}; /* button_context_settings */
|
||||
|
||||
static const struct button_mapping button_context_settings_eq[] = {
|
||||
{ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
}; /* button_context_settings_eq */
|
||||
|
||||
static const struct button_mapping button_context_quickscreen[] = {
|
||||
{ACTION_QS_TOP, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_QS_DOWN, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_QS_LEFT, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_QS_RIGHT, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_QS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_QS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_quickscreen */
|
||||
|
||||
static const struct button_mapping button_context_pitchscreen[] = {
|
||||
{ACTION_PS_INC_SMALL, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_PS_INC_SMALL, BUTTON_SCROLL_BACK, BUTTON_NONE},
|
||||
{ACTION_PS_INC_BIG, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_PS_DEC_SMALL, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_PS_DEC_SMALL, BUTTON_SCROLL_FWD, BUTTON_NONE},
|
||||
{ACTION_PS_DEC_BIG, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_PS_NUDGE_LEFT, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_PS_NUDGE_LEFTOFF, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE},
|
||||
{ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE},
|
||||
{ACTION_PS_TOGGLE_MODE, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
|
||||
{ACTION_PS_RESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
|
||||
{ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE},
|
||||
{ACTION_PS_FASTER, BUTTON_BACK, BUTTON_NONE},
|
||||
{ACTION_PS_SLOWER, BUTTON_MENU, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_pitchscreen */
|
||||
|
||||
static const struct button_mapping button_context_yesnoscreen[] = {
|
||||
{ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE},
|
||||
{ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE},
|
||||
{ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_yesnoscreen */
|
||||
|
||||
static const struct button_mapping button_context_keyboard[] = {
|
||||
{ACTION_KBD_UP, BUTTON_UP, BUTTON_NONE},
|
||||
{ACTION_KBD_DOWN, BUTTON_DOWN, BUTTON_NONE},
|
||||
{ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE},
|
||||
{ACTION_KBD_RIGHT, BUTTON_RIGHT, BUTTON_NONE},
|
||||
{ACTION_KBD_UP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_SELECT, BUTTON_SELECT, BUTTON_NONE},
|
||||
{ACTION_KBD_BACKSPACE, BUTTON_BACK, BUTTON_NONE},
|
||||
{ACTION_KBD_BACKSPACE, BUTTON_BACK|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_DONE, BUTTON_PLAY, BUTTON_NONE},
|
||||
{ACTION_KBD_ABORT, BUTTON_POWER, BUTTON_NONE},
|
||||
{ACTION_KBD_PAGE_FLIP, BUTTON_MENU, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_LEFT, BUTTON_VOL_DOWN, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_LEFT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_RIGHT, BUTTON_VOL_UP, BUTTON_NONE},
|
||||
{ACTION_KBD_CURSOR_RIGHT, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
|
||||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_keyboard */
|
||||
|
||||
const struct button_mapping* get_context_mapping(int context)
|
||||
{
|
||||
switch (context)
|
||||
{
|
||||
default:
|
||||
case CONTEXT_STD:
|
||||
return button_context_standard;
|
||||
case CONTEXT_WPS:
|
||||
return button_context_wps;
|
||||
case CONTEXT_TREE:
|
||||
case CONTEXT_MAINMENU:
|
||||
case CONTEXT_BOOKMARKSCREEN:
|
||||
return button_context_tree;
|
||||
case CONTEXT_LIST:
|
||||
return button_context_list;
|
||||
case CONTEXT_SETTINGS:
|
||||
case CONTEXT_SETTINGS_TIME:
|
||||
case CONTEXT_SETTINGS_RECTRIGGER:
|
||||
return button_context_settings;
|
||||
case CONTEXT_SETTINGS_EQ:
|
||||
case CONTEXT_SETTINGS_COLOURCHOOSER:
|
||||
return button_context_settings_eq;
|
||||
case CONTEXT_QUICKSCREEN:
|
||||
return button_context_quickscreen;
|
||||
case CONTEXT_PITCHSCREEN:
|
||||
return button_context_pitchscreen;
|
||||
case CONTEXT_YESNOSCREEN:
|
||||
return button_context_yesnoscreen;
|
||||
case CONTEXT_KEYBOARD:
|
||||
return button_context_keyboard;
|
||||
}
|
||||
}
|
|
@ -9611,15 +9611,15 @@
|
|||
user: core
|
||||
<source>
|
||||
*: none
|
||||
gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
|
||||
gigabeatfx,sansafuzeplus,fiiom3k: "Touchpad Sensitivity"
|
||||
</source>
|
||||
<dest>
|
||||
*: none
|
||||
gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
|
||||
gigabeatfx,sansafuzeplus,fiiom3k: "Touchpad Sensitivity"
|
||||
</dest>
|
||||
<voice>
|
||||
*: none
|
||||
gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
|
||||
gigabeatfx,sansafuzeplus,fiiom3k: "Touchpad Sensitivity"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
|
|
|
@ -9702,15 +9702,15 @@
|
|||
user: core
|
||||
<source>
|
||||
*: none
|
||||
gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
|
||||
gigabeatfx,sansafuzeplus,fiiom3k: "Touchpad Sensitivity"
|
||||
</source>
|
||||
<dest>
|
||||
*: none
|
||||
gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
|
||||
gigabeatfx,sansafuzeplus,fiiom3k: "Touchpad Sensitivity"
|
||||
</dest>
|
||||
<voice>
|
||||
*: none
|
||||
gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
|
||||
gigabeatfx,sansafuzeplus,fiiom3k: "Touchpad Sensitivity"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
|
|
|
@ -242,6 +242,12 @@
|
|||
#define BATTERY_OFF_TXT "Power"
|
||||
#define BATTERY_ON_TXT "Menu - start"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define BATTERY_ON BUTTON_PLAY
|
||||
#define BATTERY_OFF BUTTON_POWER
|
||||
#define BATTERY_ON_TXT "Play"
|
||||
#define BATTERY_OFF_TXT "Power"
|
||||
|
||||
#else
|
||||
#error "No keymap defined!"
|
||||
#endif
|
||||
|
|
|
@ -607,6 +607,22 @@ enum {
|
|||
#define BJACK_RIGHT BUTTON_SCROLL_FWD
|
||||
#define BJACK_LEFT BUTTON_SCROLL_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define BJACK_SELECT_NAME "SELECT"
|
||||
#define BJACK_STAY_NAME "PLAY"
|
||||
#define BJACK_QUIT_NAME "POWER"
|
||||
#define BJACK_DOUBLE_NAME "MENU"
|
||||
#define BJACK_SELECT BUTTON_SELECT
|
||||
#define BJACK_QUIT BUTTON_POWER
|
||||
#define BJACK_MAX BUTTON_VOL_UP
|
||||
#define BJACK_MIN BUTTON_VOL_DOWN
|
||||
#define BJACK_STAY BUTTON_PLAY
|
||||
#define BJACK_DOUBLEDOWN BUTTON_MENU
|
||||
#define BJACK_UP BUTTON_UP
|
||||
#define BJACK_DOWN BUTTON_DOWN
|
||||
#define BJACK_RIGHT BUTTON_RIGHT
|
||||
#define BJACK_LEFT BUTTON_LEFT
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -342,6 +342,14 @@ CONFIG_KEYPAD == SANSA_CONNECT_PAD
|
|||
#define UP BUTTON_PREV
|
||||
#define DOWN BUTTON_NEXT
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define QUIT BUTTON_POWER
|
||||
#define LEFT BUTTON_LEFT
|
||||
#define RIGHT BUTTON_RIGHT
|
||||
#define SELECT BUTTON_PLAY
|
||||
#define UP BUTTON_UP
|
||||
#define DOWN BUTTON_DOWN
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -536,6 +536,16 @@ F3: equal to "="
|
|||
#define CALCULATOR_CALC BUTTON_MENU
|
||||
#define CALCULATOR_CLEAR BUTTON_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define CALCULATOR_LEFT BUTTON_LEFT
|
||||
#define CALCULATOR_RIGHT BUTTON_RIGHT
|
||||
#define CALCULATOR_UP BUTTON_UP
|
||||
#define CALCULATOR_DOWN BUTTON_DOWN
|
||||
#define CALCULATOR_QUIT BUTTON_POWER
|
||||
#define CALCULATOR_INPUT BUTTON_PLAY
|
||||
#define CALCULATOR_CALC BUTTON_MENU
|
||||
#define CALCULATOR_CLEAR BUTTON_BACK
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -421,6 +421,16 @@
|
|||
#define CALENDAR_NEXT_MONTH BUTTON_VOL_UP
|
||||
#define CALENDAR_PREV_MONTH BUTTON_VOL_DOWN
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define CALENDAR_QUIT BUTTON_POWER
|
||||
#define CALENDAR_SELECT BUTTON_SELECT
|
||||
#define CALENDAR_NEXT_WEEK BUTTON_DOWN
|
||||
#define CALENDAR_PREV_WEEK BUTTON_UP
|
||||
#define CALENDAR_NEXT_DAY BUTTON_LEFT
|
||||
#define CALENDAR_PREV_DAY BUTTON_RIGHT
|
||||
#define CALENDAR_NEXT_MONTH BUTTON_VOL_UP
|
||||
#define CALENDAR_PREV_MONTH BUTTON_VOL_DOWN
|
||||
|
||||
#else
|
||||
#error "No keypad setting."
|
||||
#endif
|
||||
|
|
|
@ -581,6 +581,20 @@
|
|||
#define CB_SCROLL_LEFT (BUTTON_SCROLL_BACK|BUTTON_REPEAT)
|
||||
#define CB_SCROLL_RIGHT (BUTTON_SCROLL_FWD|BUTTON_REPEAT)
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define CB_SELECT BUTTON_SELECT
|
||||
#define CB_UP BUTTON_UP
|
||||
#define CB_DOWN BUTTON_DOWN
|
||||
#define CB_LEFT BUTTON_LEFT
|
||||
#define CB_RIGHT BUTTON_RIGHT
|
||||
#define CB_PLAY BUTTON_PLAY
|
||||
#define CB_MENU BUTTON_MENU
|
||||
#define CB_LEVEL BUTTON_BACK
|
||||
#define CB_SCROLL_UP (BUTTON_UP|BUTTON_REPEAT)
|
||||
#define CB_SCROLL_DOWN (BUTTON_DOWN|BUTTON_REPEAT)
|
||||
#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT)
|
||||
#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT)
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -406,6 +406,16 @@
|
|||
#define CHC_SETTINGS_OK BUTTON_PLAY
|
||||
#define CHC_SETTINGS_CANCEL BUTTON_POWER
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define CHC_QUIT BUTTON_POWER
|
||||
#define CHC_STARTSTOP BUTTON_PLAY
|
||||
#define CHC_RESET BUTTON_BACK
|
||||
#define CHC_MENU BUTTON_MENU
|
||||
#define CHC_SETTINGS_INC BUTTON_UP
|
||||
#define CHC_SETTINGS_DEC BUTTON_DOWN
|
||||
#define CHC_SETTINGS_OK BUTTON_SELECT
|
||||
#define CHC_SETTINGS_CANCEL BUTTON_POWER
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -1283,6 +1283,14 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define CHIP8_KEY6 BUTTON_BACK
|
||||
#define CHIP8_KEY8 BUTTON_PREV
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define CHIP8_OFF BUTTON_POWER
|
||||
#define CHIP8_KEY2 BUTTON_MENU
|
||||
#define CHIP8_KEY4 BUTTON_LEFT
|
||||
#define CHIP8_KEY5 BUTTON_SELECT
|
||||
#define CHIP8_KEY6 BUTTON_RIGHT
|
||||
#define CHIP8_KEY8 BUTTON_BACK
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -203,6 +203,11 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define ACTION BUTTON_PLAY
|
||||
#define ACTIONTEXT "PLAY"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define QUIT BUTTON_POWER
|
||||
#define ACTION BUTTON_PLAY
|
||||
#define ACTIONTEXT "PLAY"
|
||||
|
||||
#elif !defined(HAVE_TOUCHSCREEN)
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -316,6 +316,14 @@
|
|||
#define CLIX_BUTTON_RIGHT BUTTON_SCROLL_FWD
|
||||
#define CLIX_BUTTON_CLICK BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define CLIX_BUTTON_QUIT BUTTON_POWER
|
||||
#define CLIX_BUTTON_UP BUTTON_UP
|
||||
#define CLIX_BUTTON_DOWN BUTTON_DOWN
|
||||
#define CLIX_BUTTON_LEFT BUTTON_LEFT
|
||||
#define CLIX_BUTTON_RIGHT BUTTON_RIGHT
|
||||
#define CLIX_BUTTON_CLICK BUTTON_SELECT
|
||||
|
||||
#else
|
||||
#error "no keymap"
|
||||
#endif
|
||||
|
|
|
@ -410,6 +410,16 @@
|
|||
#define CUBE_PAUSE BUTTON_BACK
|
||||
#define CUBE_HIGHSPEED BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define CUBE_QUIT BUTTON_POWER
|
||||
#define CUBE_NEXT BUTTON_RIGHT
|
||||
#define CUBE_PREV BUTTON_LEFT
|
||||
#define CUBE_INC BUTTON_SCROLL_FWD
|
||||
#define CUBE_DEC BUTTON_SCROLL_BACK
|
||||
#define CUBE_MODE BUTTON_MENU
|
||||
#define CUBE_PAUSE BUTTON_PLAY
|
||||
#define CUBE_HIGHSPEED BUTTON_BACK
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -612,6 +612,18 @@ void I_ShutdownGraphics(void)
|
|||
#define DOOMBUTTON_WEAPON BUTTON_VOL_UP
|
||||
#define DOOMBUTTON_MAP BUTTON_VOL_DOWN
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define DOOMBUTTON_UP BUTTON_UP
|
||||
#define DOOMBUTTON_DOWN BUTTON_DOWN
|
||||
#define DOOMBUTTON_LEFT BUTTON_LEFT
|
||||
#define DOOMBUTTON_RIGHT BUTTON_RIGHT
|
||||
#define DOOMBUTTON_SHOOT BUTTON_SELECT
|
||||
#define DOOMBUTTON_OPEN BUTTON_PLAY
|
||||
#define DOOMBUTTON_ESC BUTTON_POWER
|
||||
#define DOOMBUTTON_ENTER BUTTON_SELECT
|
||||
#define DOOMBUTTON_WEAPON BUTTON_VOL_UP
|
||||
#define DOOMBUTTON_MAP BUTTON_VOL_DOWN
|
||||
|
||||
#else
|
||||
#error Keymap not defined!
|
||||
#endif
|
||||
|
|
|
@ -484,6 +484,18 @@
|
|||
#define FLIPIT_STEP_BY_STEP BUTTON_VOL_UP
|
||||
#define FLIPIT_TOGGLE BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
|
||||
#define FLIPIT_LEFT BUTTON_LEFT
|
||||
#define FLIPIT_RIGHT BUTTON_RIGHT
|
||||
#define FLIPIT_UP BUTTON_UP
|
||||
#define FLIPIT_DOWN BUTTON_DOWN
|
||||
#define FLIPIT_QUIT BUTTON_POWER
|
||||
#define FLIPIT_SHUFFLE BUTTON_PLAY
|
||||
#define FLIPIT_SOLVE BUTTON_VOL_DOWN
|
||||
#define FLIPIT_STEP_BY_STEP BUTTON_VOL_UP
|
||||
#define FLIPIT_TOGGLE BUTTON_SELECT
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -506,6 +506,18 @@
|
|||
#define FRACTAL_PRECISION_DEC BUTTON_BACK
|
||||
#define FRACTAL_RESET BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define FRACTAL_QUIT BUTTON_POWER
|
||||
#define FRACTAL_UP BUTTON_UP
|
||||
#define FRACTAL_DOWN BUTTON_DOWN
|
||||
#define FRACTAL_LEFT BUTTON_LEFT
|
||||
#define FRACTAL_RIGHT BUTTON_RIGHT
|
||||
#define FRACTAL_ZOOM_IN BUTTON_VOL_UP
|
||||
#define FRACTAL_ZOOM_OUT BUTTON_VOL_DOWN
|
||||
#define FRACTAL_PRECISION_INC BUTTON_MENU
|
||||
#define FRACTAL_PRECISION_DEC BUTTON_BACK
|
||||
#define FRACTAL_RESET BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -492,6 +492,18 @@
|
|||
#define GBN_BUTTON_CONTEXT BUTTON_MENU | BUTTON_REPEAT
|
||||
#define GBN_BUTTON_NEXT_VAR BUTTON_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define GBN_BUTTON_UP BUTTON_UP
|
||||
#define GBN_BUTTON_DOWN BUTTON_DOWN
|
||||
#define GBN_BUTTON_LEFT BUTTON_LEFT
|
||||
#define GBN_BUTTON_RIGHT BUTTON_RIGHT
|
||||
#define GBN_BUTTON_RETREAT BUTTON_VOL_DOWN
|
||||
#define GBN_BUTTON_ADVANCE BUTTON_VOL_UP
|
||||
#define GBN_BUTTON_MENU BUTTON_MENU
|
||||
#define GBN_BUTTON_PLAY BUTTON_PLAY
|
||||
#define GBN_BUTTON_CONTEXT (BUTTON_SELECT|BUTTON_REPEAT)
|
||||
#define GBN_BUTTON_NEXT_VAR BUTTON_BACK
|
||||
|
||||
#else
|
||||
#error Unsupported keypad
|
||||
#endif
|
||||
|
|
|
@ -536,6 +536,20 @@
|
|||
#define IMGVIEW_MENU BUTTON_MENU
|
||||
#define IMGVIEW_SLIDE_SHOW BUTTON_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define IMGVIEW_ZOOM_IN BUTTON_VOL_UP
|
||||
#define IMGVIEW_ZOOM_OUT BUTTON_VOL_DOWN
|
||||
#define IMGVIEW_UP BUTTON_UP
|
||||
#define IMGVIEW_DOWN BUTTON_DOWN
|
||||
#define IMGVIEW_LEFT BUTTON_LEFT
|
||||
#define IMGVIEW_RIGHT BUTTON_RIGHT
|
||||
#define IMGVIEW_NEXT BUTTON_BACK
|
||||
#define IMGVIEW_NEXT_REPEAT (BUTTON_BACK|BUTTON_REPEAT)
|
||||
#define IMGVIEW_PREVIOUS BUTTON_MENU
|
||||
#define IMGVIEW_PREVIOUS_REPEAT (BUTTON_MENU|BUTTON_REPEAT)
|
||||
#define IMGVIEW_MENU BUTTON_POWER
|
||||
#define IMGVIEW_SLIDE_SHOW BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -296,6 +296,13 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define RIGHT BUTTON_SCROLL_FWD
|
||||
#define FIRE BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
|
||||
#define QUIT BUTTON_POWER
|
||||
#define LEFT BUTTON_LEFT
|
||||
#define RIGHT BUTTON_RIGHT
|
||||
#define FIRE BUTTON_SELECT
|
||||
|
||||
#else
|
||||
#error INVADROX: Unsupported keypad
|
||||
#endif
|
||||
|
|
|
@ -387,6 +387,15 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define HK_SELECT "PLAY"
|
||||
#define HK_CANCEL "BACK"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define JEWELS_UP BUTTON_UP
|
||||
#define JEWELS_DOWN BUTTON_DOWN
|
||||
#define JEWELS_LEFT BUTTON_LEFT
|
||||
#define JEWELS_RIGHT BUTTON_RIGHT
|
||||
#define JEWELS_SELECT BUTTON_SELECT
|
||||
#define JEWELS_CANCEL BUTTON_BACK
|
||||
#define HK_SELECT "SELECT"
|
||||
#define HK_CANCEL "BACK"
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
|
|
|
@ -247,6 +247,14 @@
|
|||
#define BTN_FIRE BUTTON_PLAY
|
||||
#define BTN_PAUSE BUTTON_POWER
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define BTN_UP BUTTON_UP
|
||||
#define BTN_DOWN BUTTON_DOWN
|
||||
#define BTN_LEFT BUTTON_LEFT
|
||||
#define BTN_RIGHT BUTTON_RIGHT
|
||||
#define BTN_FIRE BUTTON_SELECT
|
||||
#define BTN_PAUSE BUTTON_POWER
|
||||
|
||||
#else
|
||||
#error Unsupported keypad
|
||||
#endif
|
||||
|
|
|
@ -269,6 +269,15 @@ const struct button_mapping pla_main_ctx[] =
|
|||
{ PLA_DOWN_REPEAT, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ PLA_LEFT_REPEAT, BUTTON_HOME|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ PLA_RIGHT_REPEAT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
|
||||
#elif (CONFIG_KEYPAD == FIIO_M3K_PAD)
|
||||
{ PLA_UP, BUTTON_UP, BUTTON_NONE },
|
||||
{ PLA_DOWN, BUTTON_DOWN, BUTTON_NONE },
|
||||
{ PLA_LEFT, BUTTON_LEFT, BUTTON_NONE },
|
||||
{ PLA_RIGHT, BUTTON_RIGHT, BUTTON_NONE },
|
||||
{ PLA_UP_REPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ PLA_DOWN_REPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ PLA_LEFT_REPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ PLA_RIGHT_REPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
|
||||
#else
|
||||
# ifndef HAVE_TOUCHSCREEN
|
||||
# error pluginlib_actions: No directions defined
|
||||
|
@ -506,6 +515,12 @@ const struct button_mapping pla_main_ctx[] =
|
|||
{PLA_SELECT, BUTTON_PLAY, BUTTON_NONE},
|
||||
{PLA_SELECT_REL, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY},
|
||||
{PLA_SELECT_REPEAT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE},
|
||||
#elif (CONFIG_KEYPAD == FIIO_M3K_PAD)
|
||||
{PLA_CANCEL, BUTTON_BACK, BUTTON_NONE},
|
||||
{PLA_EXIT, BUTTON_POWER, BUTTON_NONE},
|
||||
{PLA_SELECT, BUTTON_SELECT, BUTTON_NONE},
|
||||
{PLA_SELECT_REL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
|
||||
{PLA_SELECT_REPEAT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE},
|
||||
#else
|
||||
# ifndef HAVE_TOUCHSCREEN
|
||||
# error pluginlib_actions: No actions defined
|
||||
|
|
|
@ -325,6 +325,14 @@
|
|||
#define MIDI_VOL_DOWN BUTTON_VOL_DOWN
|
||||
#define MIDI_PLAYPAUSE BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define MIDI_QUIT BUTTON_POWER
|
||||
#define MIDI_FFWD BUTTON_LEFT
|
||||
#define MIDI_REWIND BUTTON_RIGHT
|
||||
#define MIDI_VOL_UP BUTTON_VOL_UP
|
||||
#define MIDI_VOL_DOWN BUTTON_VOL_DOWN
|
||||
#define MIDI_PLAYPAUSE BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -432,6 +432,17 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
# define MINESWP_DISCOVER (BUTTON_PLAY | BUTTON_REPEAT)
|
||||
# define MINESWP_INFO BUTTON_VOL_UP
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
# define MINESWP_LEFT BUTTON_LEFT
|
||||
# define MINESWP_RIGHT BUTTON_RIGHT
|
||||
# define MINESWP_UP BUTTON_UP
|
||||
# define MINESWP_DOWN BUTTON_DOWN
|
||||
# define MINESWP_QUIT BUTTON_POWER
|
||||
# define MINESWP_TOGGLE_PRE BUTTON_SELECT
|
||||
# define MINESWP_TOGGLE (BUTTON_SELECT|BUTTON_REL)
|
||||
# define MINESWP_DISCOVER (BUTTON_SELECT|BUTTON_REPEAT)
|
||||
# define MINESWP_INFO BUTTON_MENU
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -2580,6 +2580,12 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define MP3ENC_DONE BUTTON_POWER
|
||||
#define MP3ENC_SELECT BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define MP3ENC_PREV BUTTON_LEFT
|
||||
#define MP3ENC_NEXT BUTTON_RIGHT
|
||||
#define MP3ENC_DONE BUTTON_POWER
|
||||
#define MP3ENC_SELECT BUTTON_SELECT
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -354,6 +354,14 @@ struct mpeg_settings settings;
|
|||
#define MPEG_START_TIME_DOWN BUTTON_NEXT
|
||||
#define MPEG_START_TIME_EXIT BUTTON_POWER
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define MPEG_START_TIME_SELECT BUTTON_SELECT
|
||||
#define MPEG_START_TIME_LEFT BUTTON_LEFT
|
||||
#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
|
||||
#define MPEG_START_TIME_UP BUTTON_UP
|
||||
#define MPEG_START_TIME_DOWN BUTTON_DOWN
|
||||
#define MPEG_START_TIME_EXIT BUTTON_POWER
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -486,6 +486,15 @@ CONFIG_KEYPAD == SANSA_M200_PAD
|
|||
#define MPEG_RW BUTTON_PREV
|
||||
#define MPEG_FF BUTTON_NEXT
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define MPEG_MENU BUTTON_MENU
|
||||
#define MPEG_STOP BUTTON_POWER
|
||||
#define MPEG_PAUSE BUTTON_PLAY
|
||||
#define MPEG_VOLDOWN BUTTON_VOL_DOWN
|
||||
#define MPEG_VOLUP BUTTON_VOL_UP
|
||||
#define MPEG_RW BUTTON_LEFT
|
||||
#define MPEG_FF BUTTON_RIGHT
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -537,6 +537,17 @@
|
|||
#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
|
||||
#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define OSCILLOSCOPE_QUIT BUTTON_POWER
|
||||
#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
|
||||
#define OSCILLOSCOPE_ADVMODE BUTTON_PLAY
|
||||
#define OSCILLOSCOPE_ORIENTATION BUTTON_BACK
|
||||
#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
|
||||
#define OSCILLOSCOPE_SPEED_UP BUTTON_SCROLL_BACK
|
||||
#define OSCILLOSCOPE_SPEED_DOWN BUTTON_SCROLL_FWD
|
||||
#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
|
||||
#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -401,6 +401,15 @@
|
|||
#define PACMAN_1UP BUTTON_VOL_UP
|
||||
#define PACMAN_COIN BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define PACMAN_UP BUTTON_UP
|
||||
#define PACMAN_DOWN BUTTON_DOWN
|
||||
#define PACMAN_LEFT BUTTON_LEFT
|
||||
#define PACMAN_RIGHT BUTTON_RIGHT
|
||||
#define PACMAN_MENU BUTTON_MENU
|
||||
#define PACMAN_1UP BUTTON_VOL_UP
|
||||
#define PACMAN_COIN BUTTON_PLAY
|
||||
|
||||
#else
|
||||
|
||||
#error Keymap not defined!
|
||||
|
|
|
@ -711,6 +711,23 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define LVL_UP_TEXT "VOL+"
|
||||
#define LVL_DOWN_TEXT "VOL-"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define PEGBOX_SELECT BUTTON_SELECT
|
||||
#define PEGBOX_QUIT BUTTON_POWER
|
||||
#define PEGBOX_RESTART BUTTON_BACK
|
||||
#define PEGBOX_LVL_UP BUTTON_VOL_UP
|
||||
#define PEGBOX_LVL_DOWN BUTTON_VOL_DOWN
|
||||
#define PEGBOX_UP BUTTON_UP
|
||||
#define PEGBOX_DOWN BUTTON_DOWN
|
||||
#define PEGBOX_RIGHT BUTTON_RIGHT
|
||||
#define PEGBOX_LEFT BUTTON_LEFT
|
||||
|
||||
#define SELECT_TEXT "SELECT"
|
||||
#define QUIT_TEXT "POWER"
|
||||
#define RESTART_TEXT "BACK"
|
||||
#define LVL_UP_TEXT "VOL+"
|
||||
#define LVL_DOWN_TEXT "VOL-"
|
||||
|
||||
#else
|
||||
#error "Unsupported keymap!"
|
||||
#endif
|
||||
|
|
|
@ -76,6 +76,10 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#elif CONFIG_CPU==IMX233
|
||||
#include "cpu.h"
|
||||
#define DRAMSIZE (DRAM_SIZE - PLUGIN_BUFFER_SIZE - CODEC_SIZE - FRAME_SIZE - TTB_SIZE)
|
||||
#elif CONFIG_CPU==X1000
|
||||
#include "config.h"
|
||||
#undef STUBOFFSET
|
||||
#define STUBOFFSET 0x4000
|
||||
#endif
|
||||
|
||||
/* default to full RAM (minus codecs&plugins) unless specified otherwise */
|
||||
|
@ -174,6 +178,11 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#define IRAMSIZE 0
|
||||
/* The bit of IRAM that is available is used in the core */
|
||||
|
||||
#elif CONFIG_CPU == X1000
|
||||
#define DRAMORIG (0x80000000 + STUBOFFSET)
|
||||
#define IRAM DRAM
|
||||
#define IRAMSIZE 0
|
||||
|
||||
#elif CONFIG_CPU == RK27XX
|
||||
#define DRAMORIG 0x60000000
|
||||
#define IRAM DRAM
|
||||
|
|
|
@ -325,6 +325,13 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define PONG_RIGHT_UP BUTTON_PREV
|
||||
#define PONG_RIGHT_DOWN BUTTON_NEXT
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define PONG_QUIT BUTTON_POWER
|
||||
#define PONG_PAUSE BUTTON_PLAY
|
||||
#define PONG_LEFT_UP BUTTON_MENU
|
||||
#define PONG_LEFT_DOWN BUTTON_LEFT
|
||||
#define PONG_RIGHT_UP BUTTON_BACK
|
||||
#define PONG_RIGHT_DOWN BUTTON_RIGHT
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
|
|
|
@ -361,6 +361,15 @@
|
|||
#define REVERSI_BUTTON_MAKE_MOVE BUTTON_PLAY
|
||||
#define REVERSI_BUTTON_MENU BUTTON_MENU
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define REVERSI_BUTTON_QUIT BUTTON_POWER
|
||||
#define REVERSI_BUTTON_UP BUTTON_UP
|
||||
#define REVERSI_BUTTON_DOWN BUTTON_DOWN
|
||||
#define REVERSI_BUTTON_LEFT BUTTON_LEFT
|
||||
#define REVERSI_BUTTON_RIGHT BUTTON_RIGHT
|
||||
#define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT
|
||||
#define REVERSI_BUTTON_MENU BUTTON_MENU
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -477,6 +477,16 @@
|
|||
#define ROCKBLOX_DROP BUTTON_PLAY
|
||||
#define ROCKBLOX_RESTART BUTTON_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define ROCKBLOX_OFF BUTTON_POWER
|
||||
#define ROCKBLOX_ROTATE_CCW BUTTON_UP
|
||||
#define ROCKBLOX_ROTATE_CW BUTTON_DOWN
|
||||
#define ROCKBLOX_DOWN BUTTON_SELECT
|
||||
#define ROCKBLOX_LEFT BUTTON_LEFT
|
||||
#define ROCKBLOX_RIGHT BUTTON_RIGHT
|
||||
#define ROCKBLOX_DROP BUTTON_PLAY
|
||||
#define ROCKBLOX_RESTART BUTTON_BACK
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -467,6 +467,17 @@ static void setoptions (void)
|
|||
options.SELECT = BUTTON_VOL_UP;
|
||||
options.MENU = BUTTON_POWER;
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
options.UP = BUTTON_UP;
|
||||
options.DOWN = BUTTON_DOWN;
|
||||
options.LEFT = BUTTON_LEFT;
|
||||
options.RIGHT = BUTTON_RIGHT;
|
||||
options.A = BUTTON_MENU;
|
||||
options.B = BUTTON_BACK;
|
||||
options.START = BUTTON_VOL_DOWN;
|
||||
options.SELECT = BUTTON_VOL_UP;
|
||||
options.MENU = BUTTON_POWER;
|
||||
|
||||
#else
|
||||
#error No Keymap Defined!
|
||||
#endif
|
||||
|
|
|
@ -393,6 +393,17 @@
|
|||
#define ROCKPAINT_LEFT BUTTON_HOME
|
||||
#define ROCKPAINT_RIGHT BUTTON_VOL_DOWN
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define ROCKPAINT_QUIT BUTTON_POWER
|
||||
#define ROCKPAINT_DRAW BUTTON_SELECT
|
||||
#define ROCKPAINT_MENU BUTTON_MENU
|
||||
#define ROCKPAINT_TOOLBAR BUTTON_VOL_UP
|
||||
#define ROCKPAINT_TOOLBAR2 BUTTON_VOL_DOWN
|
||||
#define ROCKPAINT_UP BUTTON_UP
|
||||
#define ROCKPAINT_DOWN BUTTON_DOWN
|
||||
#define ROCKPAINT_LEFT BUTTON_LEFT
|
||||
#define ROCKPAINT_RIGHT BUTTON_RIGHT
|
||||
|
||||
#else
|
||||
#error "Please define keys for this keypad"
|
||||
#endif
|
||||
|
|
|
@ -348,6 +348,14 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define PUZZLE_SHUFFLE BUTTON_BACK
|
||||
#define PUZZLE_PICTURE BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define PUZZLE_QUIT BUTTON_POWER
|
||||
#define PUZZLE_LEFT BUTTON_LEFT
|
||||
#define PUZZLE_RIGHT BUTTON_RIGHT
|
||||
#define PUZZLE_UP BUTTON_UP
|
||||
#define PUZZLE_DOWN BUTTON_DOWN
|
||||
#define PUZZLE_SHUFFLE BUTTON_BACK
|
||||
#define PUZZLE_PICTURE BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
|
|
|
@ -305,6 +305,14 @@ dir is the current direction of the snake - 0=up, 1=right, 2=down, 3=left;
|
|||
#define SNAKE_DOWN BUTTON_NEXT
|
||||
#define SNAKE_PLAYPAUSE BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define SNAKE_QUIT BUTTON_POWER
|
||||
#define SNAKE_LEFT BUTTON_LEFT
|
||||
#define SNAKE_RIGHT BUTTON_RIGHT
|
||||
#define SNAKE_UP BUTTON_UP
|
||||
#define SNAKE_DOWN BUTTON_DOWN
|
||||
#define SNAKE_PLAYPAUSE BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -437,6 +437,15 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define SNAKE2_PLAYPAUSE BUTTON_PLAY
|
||||
#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define SNAKE2_LEFT BUTTON_LEFT
|
||||
#define SNAKE2_RIGHT BUTTON_RIGHT
|
||||
#define SNAKE2_UP BUTTON_UP
|
||||
#define SNAKE2_DOWN BUTTON_DOWN
|
||||
#define SNAKE2_QUIT BUTTON_POWER
|
||||
#define SNAKE2_PLAYPAUSE BUTTON_PLAY
|
||||
#define SNAKE2_PLAYPAUSE_TEXT "PLAY"
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -695,6 +695,21 @@
|
|||
#define BUTTON_SAVE BUTTON_PLAY
|
||||
#define BUTTON_SAVE_NAME "PLAY"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define SOKOBAN_LEFT BUTTON_LEFT
|
||||
#define SOKOBAN_RIGHT BUTTON_RIGHT
|
||||
#define SOKOBAN_UP BUTTON_UP
|
||||
#define SOKOBAN_DOWN BUTTON_DOWN
|
||||
#define SOKOBAN_MENU BUTTON_MENU
|
||||
#define SOKOBAN_UNDO BUTTON_VOL_DOWN
|
||||
#define SOKOBAN_REDO BUTTON_VOL_UP
|
||||
#define SOKOBAN_LEVEL_DOWN (BUTTON_PLAY|BUTTON_VOL_DOWN)
|
||||
#define SOKOBAN_LEVEL_UP (BUTTON_PLAY|BUTTON_VOL_UP)
|
||||
#define SOKOBAN_LEVEL_REPEAT (BUTTON_PLAY|BUTTON_POWER)
|
||||
#define SOKOBAN_PAUSE BUTTON_SELECT
|
||||
#define BUTTON_SAVE BUTTON_BACK
|
||||
#define BUTTON_SAVE_NAME "BACK"
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -722,6 +722,25 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
# define HK_CUR2STACK "DBL PLAY"
|
||||
# define HK_REM2STACK "NEXT"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
# define SOL_QUIT BUTTON_POWER
|
||||
# define SOL_UP BUTTON_UP
|
||||
# define SOL_DOWN BUTTON_DOWN
|
||||
# define SOL_LEFT BUTTON_LEFT
|
||||
# define SOL_RIGHT BUTTON_RIGHT
|
||||
# define SOL_MOVE_PRE BUTTON_SELECT
|
||||
# define SOL_MOVE (BUTTON_SELECT|BUTTON_REL)
|
||||
# define SOL_DRAW BUTTON_PLAY
|
||||
# define SOL_REM2CUR BUTTON_VOL_DOWN
|
||||
# define SOL_CUR2STACK_PRE BUTTON_SELECT
|
||||
# define SOL_CUR2STACK (BUTTON_SELECT|BUTTON_REPEAT)
|
||||
# define SOL_REM2STACK BUTTON_VOL_UP
|
||||
# define HK_MOVE "SELECT"
|
||||
# define HK_DRAW "PLAY"
|
||||
# define HK_REM2CUR "VOL-"
|
||||
# define HK_CUR2STACK "HOLD SELECT"
|
||||
# define HK_REM2STACK "VOL+"
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -363,6 +363,15 @@
|
|||
#define AST_RIGHT BUTTON_SCROLL_FWD
|
||||
#define AST_FIRE BUTTON_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define AST_PAUSE BUTTON_MENU
|
||||
#define AST_QUIT BUTTON_POWER
|
||||
#define AST_THRUST BUTTON_SELECT
|
||||
#define AST_HYPERSPACE BUTTON_BACK
|
||||
#define AST_LEFT BUTTON_LEFT
|
||||
#define AST_RIGHT BUTTON_RIGHT
|
||||
#define AST_FIRE BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -652,6 +652,22 @@
|
|||
#define STAR_LEVEL_DOWN_NAME "VOL DN"
|
||||
#define STAR_LEVEL_REPEAT_NAME "BACK"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define STAR_QUIT BUTTON_POWER
|
||||
#define STAR_LEFT BUTTON_LEFT
|
||||
#define STAR_RIGHT BUTTON_RIGHT
|
||||
#define STAR_UP BUTTON_UP
|
||||
#define STAR_DOWN BUTTON_DOWN
|
||||
#define STAR_TOGGLE_CONTROL BUTTON_PLAY
|
||||
#define STAR_LEVEL_UP BUTTON_VOL_UP
|
||||
#define STAR_LEVEL_DOWN BUTTON_VOL_DOWN
|
||||
#define STAR_LEVEL_REPEAT BUTTON_BACK
|
||||
#define STAR_TOGGLE_CONTROL_NAME "PLAY"
|
||||
#define STAR_QUIT_NAME "POWER"
|
||||
#define STAR_LEVEL_UP_NAME "VOL+"
|
||||
#define STAR_LEVEL_DOWN_NAME "VOL-"
|
||||
#define STAR_LEVEL_REPEAT_NAME "BACK"
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -309,6 +309,14 @@
|
|||
#define STOPWATCH_SCROLL_UP BUTTON_SCROLL_FWD
|
||||
#define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define STOPWATCH_QUIT BUTTON_POWER
|
||||
#define STOPWATCH_START_STOP BUTTON_PLAY
|
||||
#define STOPWATCH_RESET_TIMER BUTTON_BACK
|
||||
#define STOPWATCH_LAP_TIMER BUTTON_SELECT
|
||||
#define STOPWATCH_SCROLL_UP BUTTON_SCROLL_BACK
|
||||
#define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_FWD
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -459,6 +459,17 @@
|
|||
#define SUDOKU_BUTTON_MENU (BUTTON_MENU | BUTTON_REL)
|
||||
#define SUDOKU_BUTTON_POSSIBLE BUTTON_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define SUDOKU_BUTTON_QUIT BUTTON_POWER
|
||||
#define SUDOKU_BUTTON_UP BUTTON_UP
|
||||
#define SUDOKU_BUTTON_DOWN BUTTON_DOWN
|
||||
#define SUDOKU_BUTTON_LEFT BUTTON_LEFT
|
||||
#define SUDOKU_BUTTON_RIGHT BUTTON_RIGHT
|
||||
#define SUDOKU_BUTTON_TOGGLEBACK BUTTON_VOL_DOWN
|
||||
#define SUDOKU_BUTTON_TOGGLE BUTTON_VOL_UP
|
||||
#define SUDOKU_BUTTON_MENU BUTTON_MENU
|
||||
#define SUDOKU_BUTTON_POSSIBLE BUTTON_BACK
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -583,6 +583,18 @@
|
|||
#define TV_LINE_DOWN (BUTTON_POWER | BUTTON_VOL_DOWN)
|
||||
#define TV_BOOKMARK (BUTTON_POWER | BUTTON_PLAY)
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define TV_QUIT BUTTON_POWER
|
||||
#define TV_SCROLL_UP BUTTON_VOL_UP
|
||||
#define TV_SCROLL_DOWN BUTTON_VOL_DOWN
|
||||
#define TV_SCREEN_LEFT BUTTON_LEFT
|
||||
#define TV_SCREEN_RIGHT BUTTON_RIGHT
|
||||
#define TV_MENU BUTTON_MENU
|
||||
#define TV_AUTOSCROLL BUTTON_SELECT
|
||||
#define TV_LINE_UP BUTTON_SCROLL_BACK
|
||||
#define TV_LINE_DOWN BUTTON_SCROLL_FWD
|
||||
#define TV_BOOKMARK BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -441,6 +441,17 @@
|
|||
#define LABEL_MENU "MENU"
|
||||
#define LABEL_VOLUME "VOL UP/DN"
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define VUMETER_QUIT BUTTON_POWER
|
||||
#define VUMETER_HELP BUTTON_BACK
|
||||
#define VUMETER_MENU BUTTON_MENU
|
||||
#define VUMETER_UP BUTTON_VOL_UP
|
||||
#define VUMETER_DOWN BUTTON_VOL_DOWN
|
||||
#define LABEL_HELP "BACK"
|
||||
#define LABEL_QUIT "POWER"
|
||||
#define LABEL_MENU "MENU"
|
||||
#define LABEL_VOLUME "VOL+/VOL-"
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -398,6 +398,15 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define BTN_QUIT BUTTON_POWER
|
||||
#define BTN_STOPRESET BUTTON_BACK
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define BTN_DIR_UP BUTTON_UP
|
||||
#define BTN_DIR_DOWN BUTTON_DOWN
|
||||
#define BTN_DIR_LEFT BUTTON_LEFT
|
||||
#define BTN_DIR_RIGHT BUTTON_RIGHT
|
||||
#define BTN_STARTPAUSE BUTTON_PLAY
|
||||
#define BTN_QUIT BUTTON_POWER
|
||||
#define BTN_STOPRESET BUTTON_BACK
|
||||
|
||||
#else
|
||||
#error No keymap defined!
|
||||
#endif
|
||||
|
|
|
@ -351,6 +351,15 @@ CONFIG_KEYPAD == MROBE500_PAD
|
|||
#define DOWN BUTTON_NEXT
|
||||
#define PAUSE BUTTON_PLAY
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
|
||||
#define QUIT BUTTON_POWER
|
||||
#define LEFT BUTTON_LEFT
|
||||
#define RIGHT BUTTON_RIGHT
|
||||
#define UP BUTTON_UP
|
||||
#define DOWN BUTTON_DOWN
|
||||
#define PAUSE BUTTON_PLAY
|
||||
|
||||
#else
|
||||
#error "No keymap defined!"
|
||||
#endif
|
||||
|
|
|
@ -298,6 +298,14 @@
|
|||
#define ZX_UP BUTTON_PREV
|
||||
#define ZX_DOWN BUTTON_NEXT
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
#define ZX_SELECT BUTTON_SELECT
|
||||
#define ZX_MENU BUTTON_MENU
|
||||
#define ZX_LEFT BUTTON_LEFT
|
||||
#define ZX_RIGHT BUTTON_RIGHT
|
||||
#define ZX_UP BUTTON_UP
|
||||
#define ZX_DOWN BUTTON_DOWN
|
||||
|
||||
#else
|
||||
#error Keymap not defined!
|
||||
|
||||
|
|
|
@ -293,6 +293,15 @@
|
|||
#define KBD_UP BUTTON_PREV
|
||||
#define KBD_DOWN BUTTON_NEXT
|
||||
|
||||
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
|
||||
|
||||
#define KBD_SELECT BUTTON_SELECT
|
||||
#define KBD_ABORT BUTTON_BACK
|
||||
#define KBD_LEFT BUTTON_LEFT
|
||||
#define KBD_RIGHT BUTTON_RIGHT
|
||||
#define KBD_UP BUTTON_UP
|
||||
#define KBD_DOWN BUTTON_DOWN
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
|
|
|
@ -89,4 +89,11 @@ show_logo.c
|
|||
#elif defined(SANSA_CONNECT)
|
||||
sansaconnect.c
|
||||
show_logo.c
|
||||
#elif defined(FIIO_M3K)
|
||||
#ifdef BOOTLOADER_SPL
|
||||
x1000-spl.c
|
||||
fiiom3k-spl.c
|
||||
#else
|
||||
fiiom3k.c
|
||||
#endif
|
||||
#endif
|
||||
|
|
204
bootloader/fiiom3k-spl.c
Normal file
204
bootloader/fiiom3k-spl.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "nand-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "mmu-mips.h"
|
||||
#include <string.h>
|
||||
|
||||
/* "fiio" in little endian */
|
||||
#define BOOTMAGIC 0x6f696966
|
||||
|
||||
/* Argument structure needed by Linux */
|
||||
struct linux_kargs {
|
||||
void* arg0;
|
||||
void* arg1;
|
||||
};
|
||||
|
||||
#define LINUX_KARGSADDR 0x80004000
|
||||
|
||||
static const char recovery_cmdline[] = "mem=xxM@0x0\
|
||||
no_console_suspend\
|
||||
console=ttyS2,115200n8\
|
||||
lpj=5009408\
|
||||
ip=off";
|
||||
|
||||
static const char normal_cmdline[] = "mem=64M@0x0\
|
||||
no_console_suspend\
|
||||
console=ttyS2,115200n8\
|
||||
lpj=5009408\
|
||||
ip=off\
|
||||
init=/linuxrc\
|
||||
ubi.mtd=3\
|
||||
root=ubi0:rootfs\
|
||||
ubi.mtd=4\
|
||||
rootfstype=ubifs\
|
||||
rw\
|
||||
loglevel=8";
|
||||
|
||||
#define BOOTOPTION_ROCKBOX 0
|
||||
#define BOOTOPTION_FIIOLINUX 1
|
||||
#define BOOTOPTION_RECOVERY 2
|
||||
#define NUM_BOOTOPTIONS 3
|
||||
|
||||
static const struct bootoption {
|
||||
uint32_t nand_addr;
|
||||
uint32_t nand_size;
|
||||
unsigned long load_addr;
|
||||
unsigned long exec_addr;
|
||||
const char* cmdline;
|
||||
} boot_options[NUM_BOOTOPTIONS] = {
|
||||
{
|
||||
/* Rockbox: the first unused NAND page is 26 KiB in, and the
|
||||
* remainder of the block is unused, giving us 102 KiB to use.
|
||||
*/
|
||||
.nand_addr = 0x6800,
|
||||
.nand_size = 0x19800,
|
||||
.load_addr = 0x80003ff8, /* first 8 bytes are bootloader ID */
|
||||
.exec_addr = 0x80004000,
|
||||
.cmdline = NULL,
|
||||
},
|
||||
{
|
||||
/* Original firmware */
|
||||
.nand_addr = 0x20000,
|
||||
.nand_size = 0x400000,
|
||||
.load_addr = 0x80efffc0,
|
||||
.exec_addr = 0x80f00000,
|
||||
.cmdline = normal_cmdline,
|
||||
},
|
||||
{
|
||||
/* Recovery image */
|
||||
.nand_addr = 0x420000,
|
||||
.nand_size = 0x500000,
|
||||
.load_addr = 0x80efffc0,
|
||||
.exec_addr = 0x80f00000,
|
||||
.cmdline = recovery_cmdline,
|
||||
},
|
||||
};
|
||||
|
||||
/* Simple diagnostic if something goes wrong -- a little nicer than wondering
|
||||
* what's going on when the machine hangs
|
||||
*/
|
||||
void die(void)
|
||||
{
|
||||
const int pin = (1 << 24);
|
||||
|
||||
/* Turn on button light */
|
||||
jz_clr(GPIO_INT(GPIO_C), pin);
|
||||
jz_set(GPIO_MSK(GPIO_C), pin);
|
||||
jz_clr(GPIO_PAT1(GPIO_C), pin);
|
||||
jz_set(GPIO_PAT0(GPIO_C), pin);
|
||||
|
||||
while(1) {
|
||||
/* Turn it off */
|
||||
mdelay(100);
|
||||
jz_set(GPIO_PAT0(GPIO_C), pin);
|
||||
|
||||
/* Turn it on */
|
||||
mdelay(100);
|
||||
jz_clr(GPIO_PAT0(GPIO_C), pin);
|
||||
}
|
||||
}
|
||||
|
||||
/* Boot select button state must remain stable for this duration
|
||||
* before the choice will be accepted. Currently 100ms.
|
||||
*/
|
||||
#define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000))
|
||||
|
||||
int get_boot_option(void)
|
||||
{
|
||||
const uint32_t pinmask = (1 << 17) | (1 << 19);
|
||||
|
||||
uint32_t pin = 1, lastpin = 0;
|
||||
uint32_t deadline = 0;
|
||||
|
||||
/* Configure the button GPIOs as inputs */
|
||||
gpio_config(GPIO_A, pinmask, GPIO_INPUT);
|
||||
|
||||
/* Poll the pins for a short duration to detect a keypress */
|
||||
do {
|
||||
lastpin = pin;
|
||||
pin = ~REG_GPIO_PIN(GPIO_A) & pinmask;
|
||||
if(pin != lastpin) {
|
||||
/* This will always be set on the first iteration */
|
||||
deadline = __ost_read32() + BTN_STABLE_TIME;
|
||||
}
|
||||
} while(__ost_read32() < deadline);
|
||||
|
||||
/* Play button boots original firmware */
|
||||
if(pin == (1 << 17))
|
||||
return BOOTOPTION_FIIOLINUX;
|
||||
|
||||
/* Volume up boots recovery */
|
||||
if(pin == (1 << 19))
|
||||
return BOOTOPTION_RECOVERY;
|
||||
|
||||
/* Default is to boot Rockbox */
|
||||
return BOOTOPTION_ROCKBOX;
|
||||
}
|
||||
|
||||
void spl_main(void)
|
||||
{
|
||||
/* Get user boot option */
|
||||
int booti = get_boot_option();
|
||||
const struct bootoption* opt = &boot_options[booti];
|
||||
|
||||
/* Load selected firmware from flash */
|
||||
if(nand_open())
|
||||
die();
|
||||
if(nand_read_bytes(opt->nand_addr, opt->nand_size, (void*)opt->load_addr))
|
||||
die();
|
||||
|
||||
if(booti == BOOTOPTION_ROCKBOX) {
|
||||
/* If bootloader is not installed, return back to boot ROM.
|
||||
* Also read in the first eraseblock of NAND flash so it can be
|
||||
* dumped back over USB.
|
||||
*/
|
||||
if(*(unsigned*)(opt->load_addr + 4) != BOOTMAGIC) {
|
||||
nand_read_bytes(0, 128 * 1024, (void*)0x80000000);
|
||||
commit_discard_idcache();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Linux boot not implemented yet
|
||||
*
|
||||
* - Have to initialize UART2, as it's used for the serial console
|
||||
* - Must initialize APLL and change clocks over
|
||||
* - There are some other clocks which need to be initialized
|
||||
* - We should turn off OST since the OF SPL does not turn it on
|
||||
*/
|
||||
die();
|
||||
}
|
||||
|
||||
if(boot_options[booti].cmdline) {
|
||||
/* Handle Linux command line arguments */
|
||||
struct linux_kargs* kargs = (struct linux_kargs*)LINUX_KARGSADDR;
|
||||
kargs->arg0 = 0;
|
||||
kargs->arg1 = (void*)boot_options[booti].cmdline;
|
||||
}
|
||||
|
||||
/* Flush caches and jump to address */
|
||||
void* execaddr = (void*)opt->exec_addr;
|
||||
commit_discard_idcache();
|
||||
__asm__ __volatile__ ("jr %0" :: "r"(execaddr));
|
||||
__builtin_unreachable();
|
||||
}
|
96
bootloader/fiiom3k.c
Normal file
96
bootloader/fiiom3k.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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/kernel-internal.h"
|
||||
#include "i2c.h"
|
||||
#include "power.h"
|
||||
#include "lcd.h"
|
||||
#include "backlight.h"
|
||||
#include "button.h"
|
||||
#include "storage.h"
|
||||
#include "file_internal.h"
|
||||
#include "disk.h"
|
||||
#include "rb-loader.h"
|
||||
#include "loader_strerror.h"
|
||||
|
||||
/* Load address where the binary needs to be placed */
|
||||
extern unsigned char loadaddress[];
|
||||
|
||||
/* Fixed buffer to contain the loaded binary in memory */
|
||||
extern unsigned char loadbuffer[];
|
||||
extern unsigned char loadbufferend[];
|
||||
#define MAX_LOAD_SIZE (loadbufferend - loadbuffer)
|
||||
|
||||
void exec(void* dst, const void* src, int bytes)
|
||||
__attribute__((noreturn, section(".icode")));
|
||||
|
||||
void exec(void* dst, const void* src, int bytes)
|
||||
{
|
||||
memcpy(dst, src, bytes);
|
||||
commit_discard_idcache();
|
||||
__asm__ __volatile__ ("jr %0" :: "r"(dst));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static void error(const char* msg)
|
||||
{
|
||||
/* Initialization of the LCD/buttons only if needed */
|
||||
lcd_init();
|
||||
backlight_init();
|
||||
button_init();
|
||||
|
||||
lcd_clear_display();
|
||||
lcd_puts(0, 0, msg);
|
||||
lcd_puts(0, 2, "Press POWER to power off");
|
||||
lcd_update();
|
||||
|
||||
while(button_get(true) != BUTTON_POWER);
|
||||
power_off();
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
system_init();
|
||||
kernel_init();
|
||||
i2c_init();
|
||||
power_init();
|
||||
enable_irq();
|
||||
|
||||
if(storage_init() < 0)
|
||||
error("Storage initialization failed");
|
||||
|
||||
filesystem_init();
|
||||
|
||||
if(!storage_present(0))
|
||||
error("No SD card present");
|
||||
|
||||
if(disk_mount_all() <= 0)
|
||||
error("Unable to mount filesystem");
|
||||
|
||||
int loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE);
|
||||
if(loadsize <= 0)
|
||||
error(loader_strerror(loadsize));
|
||||
|
||||
disable_irq();
|
||||
|
||||
exec(loadaddress, loadbuffer, loadsize);
|
||||
}
|
230
bootloader/x1000-spl.c
Normal file
230
bootloader/x1000-spl.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "clk-x1000.h"
|
||||
#include "x1000/cpm.h"
|
||||
#include "x1000/ost.h"
|
||||
#include "x1000/ddrc.h"
|
||||
#include "x1000/ddrc_apb.h"
|
||||
#include "x1000/ddrphy.h"
|
||||
|
||||
#ifdef FIIO_M3K
|
||||
# define DDR_USE_AUTOSR 1
|
||||
# define DDR_NEED_BYPASS 1
|
||||
# define DDR_MEMORYSIZE 64
|
||||
#else
|
||||
# error "Please add DDR definitions for new target!"
|
||||
#endif
|
||||
|
||||
#define hang() do { } while(1)
|
||||
|
||||
/* Target-specific routine to load & execute the Rockbox bootloader */
|
||||
extern void spl_main(void);
|
||||
|
||||
/* Note: This is based purely on disassembly of the SPL from the FiiO M3K.
|
||||
* The code there is somewhat generic and corresponds roughly to Ingenic's
|
||||
* U-Boot code, but isn't entirely the same.
|
||||
*
|
||||
* I converted all the runtime conditionals to compile-time ones in order to
|
||||
* save code space, since they should be constant for any given target.
|
||||
*
|
||||
* I haven't bothered to decode all the register fields. Some of the values
|
||||
* written are going to bits documented as "Reserved" by Ingenic, but their
|
||||
* documentation doesn't seem completely reliable, so either these are bits
|
||||
* which _do_ have a purpose, or they're only defined on other Ingenic CPUs.
|
||||
*
|
||||
* The DDR PHY registers appear to be from Synopsys "PHY Utility Block Lite".
|
||||
* These aren't documented by Ingenic, but the addresses and names can be found
|
||||
* in their U-Boot code.
|
||||
*/
|
||||
static void ddr_init(void)
|
||||
{
|
||||
REG_CPM_DRCG = 0x73;
|
||||
mdelay(3);
|
||||
REG_CPM_DRCG = 0x71;
|
||||
mdelay(3);
|
||||
REG_DDRC_APB_PHYRST_CFG = 0x1a00001;
|
||||
mdelay(3);
|
||||
REG_DDRC_APB_PHYRST_CFG = 0;
|
||||
mdelay(3);
|
||||
REG_DDRC_CTRL = 0xf00000;
|
||||
mdelay(3);
|
||||
REG_DDRC_CTRL = 0;
|
||||
mdelay(3);
|
||||
|
||||
REG_DDRC_CFG = 0xa468a6c;
|
||||
REG_DDRC_CTRL = 2;
|
||||
REG_DDRPHY_DTAR = 0x150000;
|
||||
REG_DDRPHY_DCR = 0;
|
||||
REG_DDRPHY_MR0 = 0x42;
|
||||
REG_DDRPHY_MR2 = 0x98;
|
||||
REG_DDRPHY_PTR0 = 0x21000a;
|
||||
REG_DDRPHY_PTR1 = 0xa09c40;
|
||||
REG_DDRPHY_PTR2 = 0x280014;
|
||||
REG_DDRPHY_DTPR0 = 0x1a69444a;
|
||||
REG_DDRPHY_DTPR1 = 0x180090;
|
||||
REG_DDRPHY_DTPR2 = 0x1ff99428;
|
||||
REG_DDRPHY_DXGCR(0) = 0x90881;
|
||||
REG_DDRPHY_DXGCR(1) = 0x90881;
|
||||
REG_DDRPHY_DXGCR(2) = 0x90e80;
|
||||
REG_DDRPHY_DXGCR(3) = 0x90e80;
|
||||
REG_DDRPHY_PGCR = 0x1042e03;
|
||||
REG_DDRPHY_ACIOCR = 0x30c00813;
|
||||
REG_DDRPHY_DXCCR = 0x4912;
|
||||
|
||||
int i = 10000;
|
||||
while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f)
|
||||
i -= 1;
|
||||
if(i == 0)
|
||||
hang();
|
||||
|
||||
#if DDR_NEED_BYPASS
|
||||
REG_DDRPHY_ACDLLCR = 0x80000000;
|
||||
REG_DDRPHY_DSGCR &= ~0x10;
|
||||
REG_DDRPHY_DLLGCR |= 0x800000;
|
||||
REG_DDRPHY_PIR = 0x20020041;
|
||||
#else
|
||||
REG_DDRPHY_PIR = 0x41;
|
||||
#endif
|
||||
|
||||
while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f)
|
||||
i -= 1;
|
||||
if(i == 0)
|
||||
hang();
|
||||
|
||||
REG_DDRC_APB_PHYRST_CFG = 0x400000;
|
||||
mdelay(3);
|
||||
REG_DDRC_APB_PHYRST_CFG = 0;
|
||||
mdelay(3);
|
||||
|
||||
REG_DDRC_CFG = 0xa468aec;
|
||||
REG_DDRC_CTRL = 2;
|
||||
#if DDR_NEED_BYPASS
|
||||
REG_DDRPHY_PIR = 0x20020081;
|
||||
#else
|
||||
REG_DDRPHY_PIR = 0x85;
|
||||
#endif
|
||||
|
||||
i = 500000;
|
||||
while(REG_DDRPHY_PGSR != 0x1f) {
|
||||
if(REG_DDRPHY_PGSR & 0x70)
|
||||
break;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
if(i == 0)
|
||||
hang();
|
||||
|
||||
if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0)
|
||||
hang();
|
||||
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 10;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CFG = 0xa468a6c;
|
||||
REG_DDRC_TIMING1 = 0x2050501;
|
||||
REG_DDRC_TIMING2 = 0x4090404;
|
||||
REG_DDRC_TIMING3 = 0x2704030d;
|
||||
REG_DDRC_TIMING4 = 0xb7a0251;
|
||||
REG_DDRC_TIMING5 = 0xff090200;
|
||||
REG_DDRC_TIMING6 = 0xa0a0202;
|
||||
#if DDR_MEMORYSIZE == 64
|
||||
REG_DDRC_MMAP0 = 0x20fc;
|
||||
REG_DDRC_MMAP1 = 0x2400;
|
||||
#elif DDR_MEMORYSIZE == 32
|
||||
REG_DDRC_MMAP0 = 0x20fe;
|
||||
REG_DDRC_MMAP1 = 0x2200;
|
||||
#else
|
||||
# error "Unsupported DDR_MEMORYSIZE"
|
||||
#endif
|
||||
REG_DDRC_CTRL = 10;
|
||||
REG_DDRC_REFCNT = 0x2f0003;
|
||||
REG_DDRC_CTRL = 0xc91e;
|
||||
|
||||
#if DDR_MEMORYSIZE == 64
|
||||
REG_DDRC_REMAP1 = 0x03020c0b;
|
||||
REG_DDRC_REMAP2 = 0x07060504;
|
||||
REG_DDRC_REMAP3 = 0x000a0908;
|
||||
REG_DDRC_REMAP4 = 0x0f0e0d01;
|
||||
REG_DDRC_REMAP5 = 0x13121110;
|
||||
#elif DDR_MEMORYSIZE == 32
|
||||
REG_DDRC_REMAP1 = 0x03020b0a;
|
||||
REG_DDRC_REMAP2 = 0x07060504;
|
||||
REG_DDRC_REMAP3 = 0x01000908;
|
||||
REG_DDRC_REMAP4 = 0x0f0e0d0c;
|
||||
REG_DDRC_REMAP5 = 0x13121110;
|
||||
#else
|
||||
# error "Unsupported DDR_MEMORYSIZE"
|
||||
#endif
|
||||
|
||||
REG_DDRC_STATUS &= ~0x40;
|
||||
|
||||
#if DDR_USE_AUTOSR
|
||||
#if DDR_NEED_BYPASS
|
||||
jz_writef(CPM_DDRCDR, GATE_EN(1));
|
||||
REG_DDRC_APB_CLKSTP_CFG = 0x9000000f;
|
||||
#else
|
||||
REG_DDRC_DLP = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
REG_DDRC_AUTOSR_EN = DDR_USE_AUTOSR;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
/* from original firmware SPL */
|
||||
REG_CPM_PSWC0ST = 0x00;
|
||||
REG_CPM_PSWC1ST = 0x10;
|
||||
REG_CPM_PSWC2ST = 0x18;
|
||||
REG_CPM_PSWC3ST = 0x08;
|
||||
|
||||
/* enable MPLL */
|
||||
#if X1000_EXCLK_FREQ == 24000000
|
||||
/* 24 * (24+1) = 600 MHz */
|
||||
jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(24), PLLOD(0));
|
||||
#elif X1000_EXCLK_FREQ == 26000000
|
||||
/* 26 * (22+1) = 598 MHz */
|
||||
jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(22), PLLOD(0));
|
||||
#else
|
||||
# error "unknown EXCLK frequency"
|
||||
#endif
|
||||
while(jz_readf(CPM_MPCR, ON) == 0);
|
||||
|
||||
/* set DDR clock to MPLL/3 = 200 MHz */
|
||||
jz_writef(CPM_CLKGR, DDR(0));
|
||||
clk_set_ddr(X1000_CLK_MPLL, 3);
|
||||
|
||||
/* start OST so we can use mdelay/udelay */
|
||||
jz_writef(CPM_CLKGR, OST(0));
|
||||
jz_writef(OST_CTRL, PRESCALE2_V(BY_4));
|
||||
jz_writef(OST_CLEAR, OST2(1));
|
||||
jz_write(OST_2CNTH, 0);
|
||||
jz_write(OST_2CNTL, 0);
|
||||
jz_setf(OST_ENABLE, OST2);
|
||||
|
||||
/* init DDR memory */
|
||||
ddr_init();
|
||||
|
||||
/* jump to the target's main routine */
|
||||
spl_main();
|
||||
}
|
|
@ -398,6 +398,8 @@ drivers/rtc/rtc_tcc77x.c
|
|||
drivers/rtc/rtc_jz4740.c
|
||||
#elif (CONFIG_RTC == RTC_JZ4760)
|
||||
drivers/rtc/rtc_jz4760.c
|
||||
#elif (CONFIG_RTC == RTC_X1000)
|
||||
drivers/rtc/rtc_x1000.c
|
||||
#elif (CONFIG_RTC == RTC_S35390A)
|
||||
drivers/rtc/rtc_s35390a.c
|
||||
#elif (CONFIG_RTC == RTC_S35380A)
|
||||
|
@ -488,6 +490,8 @@ drivers/audio/as3514.c
|
|||
drivers/audio/tlv320.c
|
||||
#elif defined(HAVE_AK4537)
|
||||
drivers/audio/ak4537.c
|
||||
#elif defined(HAVE_AK4376)
|
||||
drivers/audio/ak4376.c
|
||||
#elif defined(HAVE_UDA1341)
|
||||
drivers/audio/uda1341.c
|
||||
#elif defined(HAVE_CS42L55)
|
||||
|
@ -1721,6 +1725,30 @@ target/mips/ingenic_jz47xx/pcm-jz4760.c
|
|||
drivers/nand_id.c
|
||||
#endif /* CONFIG_CPU == JZ4760B */
|
||||
|
||||
#if CONFIG_CPU == X1000
|
||||
target/mips/ingenic_x1000/crt0.S
|
||||
target/mips/ingenic_x1000/aic-x1000.c
|
||||
target/mips/ingenic_x1000/clk-x1000.c
|
||||
target/mips/ingenic_x1000/debug-x1000.c
|
||||
target/mips/ingenic_x1000/dma-x1000.c
|
||||
target/mips/ingenic_x1000/gpio-x1000.c
|
||||
target/mips/ingenic_x1000/i2c-x1000.c
|
||||
target/mips/ingenic_x1000/kernel-x1000.c
|
||||
target/mips/ingenic_x1000/lcd-x1000.c
|
||||
target/mips/ingenic_x1000/nand-x1000.c
|
||||
target/mips/ingenic_x1000/pcm-x1000.c
|
||||
target/mips/ingenic_x1000/pwm-x1000.c
|
||||
target/mips/ingenic_x1000/sfc-x1000.c
|
||||
target/mips/ingenic_x1000/system-x1000.c
|
||||
target/mips/ingenic_x1000/timer-x1000.c
|
||||
#if (CONFIG_STORAGE & (STORAGE_SD|STORAGE_MMC|STORAGE_ATA))
|
||||
target/mips/ingenic_x1000/msc-x1000.c
|
||||
#endif
|
||||
#if (CONFIG_STORAGE & STORAGE_SD)
|
||||
target/mips/ingenic_x1000/sd-x1000.c
|
||||
#endif
|
||||
#endif /* CONFIG_CPU == X1000 */
|
||||
|
||||
#if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777)
|
||||
target/mips/ingenic_jz47xx/onda_vx747/backlight-onda_vx7X7.c
|
||||
target/mips/ingenic_jz47xx/onda_vx747/lcd-onda_vx747.c
|
||||
|
@ -1744,6 +1772,16 @@ target/mips/ingenic_jz47xx/xduoo_x3/power-xduoo_x3.c
|
|||
target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c
|
||||
#endif /* XDUOO_X3 */
|
||||
|
||||
#if defined(FIIO_M3K)
|
||||
target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c
|
||||
target/mips/ingenic_x1000/fiiom3k/backlight-fiiom3k.c
|
||||
target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
|
||||
target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
|
||||
target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
|
||||
target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c
|
||||
target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
|
||||
#endif /* FIIO_M3K */
|
||||
|
||||
#if defined(LYRE_PROTO1)
|
||||
target/arm/at91sam/lyre_proto1/adc-lyre_proto1.c
|
||||
target/arm/at91sam/lyre_proto1/backlight-lyre_proto1.c
|
||||
|
@ -1969,6 +2007,10 @@ drivers/touchpad.c
|
|||
drivers/i2c-async.c
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AXP173
|
||||
drivers/axp173.c
|
||||
#endif
|
||||
|
||||
/* firmware/kernel section */
|
||||
#ifdef HAVE_CORELOCK_OBJECT
|
||||
kernel/corelock.c
|
||||
|
|
274
firmware/drivers/audio/ak4376.c
Normal file
274
firmware/drivers/audio/ak4376.c
Normal file
|
@ -0,0 +1,274 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "audiohw.h"
|
||||
#include "sound.h"
|
||||
#include "panic.h"
|
||||
#include "pcm_sampr.h"
|
||||
#include "pcm_sw_volume.h"
|
||||
#include "system.h"
|
||||
#include "i2c-async.h"
|
||||
|
||||
#ifndef HAVE_SW_VOLUME_CONTROL
|
||||
# error "AK4376 requires HAVE_SW_VOLUME_CONTROL!"
|
||||
#endif
|
||||
|
||||
/* NOTE: At present, only the FiiO M3K uses this driver so the handling of
|
||||
* the clock / audio interface is limited to I2S slave, 16-bit samples, with
|
||||
* DAC master clock provided directly on the MCLK input pin, fitting the
|
||||
* clock setup of the M3K.
|
||||
*
|
||||
* Feel free to expand upon this if another target ever needs this driver.
|
||||
*/
|
||||
|
||||
/* Converts HW_FREQ_XX constants to register values */
|
||||
static const int ak4376_fsel_to_hw[] = {
|
||||
HW_HAVE_192_(AK4376_FS_192,)
|
||||
HW_HAVE_176_(AK4376_FS_176,)
|
||||
HW_HAVE_96_(AK4376_FS_96,)
|
||||
HW_HAVE_88_(AK4376_FS_88,)
|
||||
HW_HAVE_64_(AK4376_FS_64,)
|
||||
HW_HAVE_48_(AK4376_FS_48,)
|
||||
HW_HAVE_44_(AK4376_FS_44,)
|
||||
HW_HAVE_32_(AK4376_FS_32,)
|
||||
HW_HAVE_24_(AK4376_FS_24,)
|
||||
HW_HAVE_22_(AK4376_FS_22,)
|
||||
HW_HAVE_16_(AK4376_FS_16,)
|
||||
HW_HAVE_12_(AK4376_FS_12,)
|
||||
HW_HAVE_11_(AK4376_FS_11,)
|
||||
HW_HAVE_8_(AK4376_FS_8,)
|
||||
};
|
||||
|
||||
static struct ak4376 {
|
||||
int fsel;
|
||||
int low_mode;
|
||||
int regs[AK4376_NUM_REGS];
|
||||
} ak4376;
|
||||
|
||||
void ak4376_init(void)
|
||||
{
|
||||
/* Initialize DAC state */
|
||||
ak4376.fsel = HW_FREQ_48;
|
||||
ak4376.low_mode = 0;
|
||||
for(int i = 0; i < AK4376_NUM_REGS; ++i)
|
||||
ak4376.regs[i] = -1;
|
||||
|
||||
/* Initial reset after power-on */
|
||||
ak4376_set_pdn_pin(0);
|
||||
mdelay(1);
|
||||
ak4376_set_pdn_pin(1);
|
||||
mdelay(1);
|
||||
|
||||
static const int init_config[] = {
|
||||
/* Ensure HPRHZ, HPLHZ are 0 */
|
||||
AK4376_REG_OUTPUT_MODE, 0x00,
|
||||
/* Mute all volume controls */
|
||||
AK4376_REG_MIXER, 0x00,
|
||||
AK4376_REG_LCH_VOLUME, 0x80,
|
||||
AK4376_REG_RCH_VOLUME, 0x00,
|
||||
AK4376_REG_AMP_VOLUME, 0x00,
|
||||
/* Clock source = MCLK, divider = 1 */
|
||||
AK4376_REG_DAC_CLK_SRC, 0x00,
|
||||
AK4376_REG_DAC_CLK_DIV, 0x00,
|
||||
/* I2S slave mode, 16-bit samples */
|
||||
AK4376_REG_AUDIO_IF_FMT, 0x03,
|
||||
/* Recommended by datasheet */
|
||||
AK4376_REG_ADJUST1, 0x20,
|
||||
AK4376_REG_ADJUST2, 0x05,
|
||||
/* Power controls */
|
||||
AK4376_REG_PWR2, 0x33,
|
||||
AK4376_REG_PWR3, 0x01,
|
||||
AK4376_REG_PWR4, 0x03,
|
||||
};
|
||||
|
||||
/* Write initial configuration prior to power-up */
|
||||
for(size_t i = 0; i < ARRAYLEN(init_config); i += 2)
|
||||
ak4376_write(init_config[i], init_config[i+1]);
|
||||
|
||||
/* Initial frequency setting, also handles DAC/amp power-up */
|
||||
audiohw_set_frequency(HW_FREQ_48);
|
||||
}
|
||||
|
||||
void ak4376_close(void)
|
||||
{
|
||||
/* Shut off power */
|
||||
ak4376_write(AK4376_REG_PWR3, 0x00);
|
||||
ak4376_write(AK4376_REG_PWR4, 0x00);
|
||||
ak4376_write(AK4376_REG_PWR2, 0x00);
|
||||
|
||||
/* PDN pin low */
|
||||
ak4376_set_pdn_pin(0);
|
||||
}
|
||||
|
||||
void ak4376_write(int reg, int value)
|
||||
{
|
||||
/* Ensure value is sensible and differs from the last set value */
|
||||
if((value & 0xff) == value && ak4376.regs[reg] != value) {
|
||||
int r = i2c_reg_write1(AK4376_BUS, AK4376_ADDR, reg, value);
|
||||
if(r == I2C_STATUS_OK)
|
||||
ak4376.regs[reg] = value;
|
||||
else
|
||||
ak4376.regs[reg] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int ak4376_read(int reg)
|
||||
{
|
||||
/* Only read from I2C if we don't already know the value */
|
||||
if(ak4376.regs[reg] < 0)
|
||||
ak4376.regs[reg] = i2c_reg_read1(AK4376_BUS, AK4376_ADDR, reg);
|
||||
|
||||
return ak4376.regs[reg];
|
||||
}
|
||||
|
||||
static int round_step_up(int x, int step)
|
||||
{
|
||||
int rem = x % step;
|
||||
if(rem > 0)
|
||||
rem -= step;
|
||||
return x - rem;
|
||||
}
|
||||
|
||||
static void calc_volumes(int vol, int* mix, int* dig, int* sw)
|
||||
{
|
||||
/* Mixer can divide by 2, which gives an extra -6 dB adjustment */
|
||||
if(vol < AK4376_DIG_VOLUME_MIN) {
|
||||
*mix |= AK4376_MIX_HALF;
|
||||
vol += 60;
|
||||
}
|
||||
|
||||
*dig = round_step_up(vol, AK4376_DIG_VOLUME_STEP);
|
||||
*dig = MIN(*dig, AK4376_DIG_VOLUME_MAX);
|
||||
*dig = MAX(*dig, AK4376_DIG_VOLUME_MIN);
|
||||
vol -= *dig;
|
||||
|
||||
/* Seems that this is the allowable range for software volume */
|
||||
*sw = MIN(vol, 60);
|
||||
*sw = MAX(*sw, -730);
|
||||
vol -= *sw;
|
||||
}
|
||||
|
||||
static int dig_vol_to_hw(int vol)
|
||||
{
|
||||
if(vol < AK4376_DIG_VOLUME_MIN) return 0;
|
||||
if(vol > AK4376_DIG_VOLUME_MAX) return 31;
|
||||
return (vol - AK4376_DIG_VOLUME_MIN) / AK4376_DIG_VOLUME_STEP + 1;
|
||||
}
|
||||
|
||||
static int amp_vol_to_hw(int vol)
|
||||
{
|
||||
if(vol < AK4376_AMP_VOLUME_MIN) return 0;
|
||||
if(vol > AK4376_AMP_VOLUME_MAX) return 14;
|
||||
return (vol - AK4376_AMP_VOLUME_MIN) / AK4376_AMP_VOLUME_STEP + 1;
|
||||
}
|
||||
|
||||
void audiohw_set_volume(int vol_l, int vol_r)
|
||||
{
|
||||
int amp;
|
||||
int mix_l = AK4376_MIX_LCH, dig_l, sw_l;
|
||||
int mix_r = AK4376_MIX_RCH, dig_r, sw_r;
|
||||
|
||||
if(vol_l <= AK4376_MIN_VOLUME && vol_r <= AK4376_MIN_VOLUME) {
|
||||
/* Special case for full mute */
|
||||
amp = AK4376_AMP_VOLUME_MUTE;
|
||||
dig_l = dig_r = AK4376_DIG_VOLUME_MUTE;
|
||||
sw_l = sw_r = PCM_MUTE_LEVEL;
|
||||
} else {
|
||||
/* Amp is a mono control -- calculate based on the loudest channel.
|
||||
* The quieter channel then gets reduced more by digital controls. */
|
||||
amp = round_step_up(MAX(vol_l, vol_r), AK4376_AMP_VOLUME_STEP);
|
||||
amp = MIN(amp, AK4376_AMP_VOLUME_MAX);
|
||||
amp = MAX(amp, AK4376_AMP_VOLUME_MIN);
|
||||
|
||||
/* Other controls are stereo */
|
||||
calc_volumes(vol_l - amp, &mix_l, &dig_l, &sw_l);
|
||||
calc_volumes(vol_r - amp, &mix_r, &dig_r, &sw_r);
|
||||
}
|
||||
|
||||
ak4376_write(AK4376_REG_MIXER, (mix_l & 0xf) | ((mix_r & 0xf) << 4));
|
||||
ak4376_write(AK4376_REG_LCH_VOLUME, dig_vol_to_hw(dig_l) | (1 << 7));
|
||||
ak4376_write(AK4376_REG_RCH_VOLUME, dig_vol_to_hw(dig_r));
|
||||
ak4376_write(AK4376_REG_AMP_VOLUME, amp_vol_to_hw(amp));
|
||||
pcm_set_master_volume(sw_l, sw_r);
|
||||
}
|
||||
|
||||
void audiohw_set_filter_roll_off(int val)
|
||||
{
|
||||
int reg = ak4376_read(AK4376_REG_FILTER);
|
||||
reg &= ~0xc0;
|
||||
reg |= (val & 3) << 6;
|
||||
ak4376_write(AK4376_REG_FILTER, reg);
|
||||
}
|
||||
|
||||
void audiohw_set_frequency(int fsel)
|
||||
{
|
||||
/* Determine master clock multiplier */
|
||||
int mult = ak4376_set_mclk_freq(fsel, false);
|
||||
|
||||
/* Calculate clock mode for frequency. Multipliers of 32/64 are only
|
||||
* for rates >= 256 KHz which are not supported by Rockbox, so they
|
||||
* are commented out -- but they're in the correct place. */
|
||||
int clock_mode = ak4376_fsel_to_hw[fsel];
|
||||
switch(mult) {
|
||||
/* case 32: */
|
||||
case 256:
|
||||
break;
|
||||
/* case 64: */
|
||||
case 512:
|
||||
clock_mode |= 0x20;
|
||||
break;
|
||||
case 1024:
|
||||
clock_mode |= 0x40;
|
||||
break;
|
||||
case 128:
|
||||
clock_mode |= 0x60;
|
||||
break;
|
||||
default:
|
||||
panicf("ak4376: bad master clock multiple %d", mult);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle the DSMLP bit in the MODE_CTRL register */
|
||||
int mode_ctrl = 0x00;
|
||||
if(ak4376.low_mode || hw_freq_sampr[fsel] <= SAMPR_12)
|
||||
mode_ctrl |= 0x40;
|
||||
|
||||
/* Program the new settings */
|
||||
ak4376_write(AK4376_REG_CLOCK_MODE, clock_mode);
|
||||
ak4376_write(AK4376_REG_MODE_CTRL, mode_ctrl);
|
||||
ak4376_write(AK4376_REG_PWR3, ak4376.low_mode ? 0x11 : 0x01);
|
||||
|
||||
/* Enable the master clock */
|
||||
ak4376_set_mclk_freq(fsel, true);
|
||||
|
||||
/* Remember the frequency */
|
||||
ak4376.fsel = fsel;
|
||||
}
|
||||
|
||||
void audiohw_set_power_mode(int mode)
|
||||
{
|
||||
/* This is handled via audiohw_set_frequency() since changing LPMODE
|
||||
* bit requires power-down/power-up & changing other bits as well */
|
||||
if(ak4376.low_mode != mode) {
|
||||
ak4376.low_mode = mode;
|
||||
audiohw_set_frequency(ak4376.fsel);
|
||||
}
|
||||
}
|
419
firmware/drivers/axp173.c
Normal file
419
firmware/drivers/axp173.c
Normal file
|
@ -0,0 +1,419 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "axp173.h"
|
||||
#include "power.h"
|
||||
#include "i2c-async.h"
|
||||
|
||||
/* Headers for the debug menu */
|
||||
#ifndef BOOTLOADER
|
||||
# include "action.h"
|
||||
# include "list.h"
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
static const struct axp173_adc_info {
|
||||
uint8_t reg;
|
||||
uint8_t en_reg;
|
||||
uint8_t en_bit;
|
||||
} axp173_adc_info[NUM_ADC_CHANNELS] = {
|
||||
{0x56, 0x82, 5}, /* ACIN_VOLTAGE */
|
||||
{0x58, 0x82, 4}, /* ACIN_CURRENT */
|
||||
{0x5a, 0x82, 3}, /* VBUS_VOLTAGE */
|
||||
{0x5c, 0x82, 2}, /* VBUS_CURRENT */
|
||||
{0x5e, 0x83, 7}, /* INTERNAL_TEMP */
|
||||
{0x62, 0x82, 1}, /* TS_INPUT */
|
||||
{0x78, 0x82, 7}, /* BATTERY_VOLTAGE */
|
||||
{0x7a, 0x82, 6}, /* CHARGE_CURRENT */
|
||||
{0x7c, 0x82, 6}, /* DISCHARGE_CURRENT */
|
||||
{0x7e, 0x82, 1}, /* APS_VOLTAGE */
|
||||
{0x70, 0xff, 0}, /* BATTERY_POWER */
|
||||
};
|
||||
|
||||
static struct axp173 {
|
||||
int adc_enable;
|
||||
} axp173;
|
||||
|
||||
static void axp173_init_enabled_adcs(void)
|
||||
{
|
||||
axp173.adc_enable = 0;
|
||||
|
||||
/* Read enabled ADCs from the hardware */
|
||||
uint8_t regs[2];
|
||||
int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, 0x82, 2, ®s[0]);
|
||||
if(rc != I2C_STATUS_OK)
|
||||
return;
|
||||
|
||||
/* Parse registers to set ADC enable bits */
|
||||
const struct axp173_adc_info* info = axp173_adc_info;
|
||||
for(int i = 0; i < NUM_ADC_CHANNELS; ++i) {
|
||||
if(info[i].en_reg == 0xff)
|
||||
continue;
|
||||
|
||||
if(regs[info[i].en_reg - 0x82] & info[i].en_bit)
|
||||
axp173.adc_enable |= 1 << i;
|
||||
}
|
||||
|
||||
/* Handle battery power ADC */
|
||||
if((axp173.adc_enable & (1 << ADC_BATTERY_VOLTAGE)) &&
|
||||
(axp173.adc_enable & (1 << ADC_DISCHARGE_CURRENT))) {
|
||||
axp173.adc_enable |= (1 << ADC_BATTERY_POWER);
|
||||
}
|
||||
}
|
||||
|
||||
void axp173_init(void)
|
||||
{
|
||||
axp173_init_enabled_adcs();
|
||||
|
||||
/* We need discharge current ADC to reliably poll for a full battery */
|
||||
int bits = axp173.adc_enable;
|
||||
bits |= (1 << ADC_DISCHARGE_CURRENT);
|
||||
axp173_adc_set_enabled(bits);
|
||||
}
|
||||
|
||||
/* TODO: this can STILL indicate some false positives! */
|
||||
int axp173_battery_status(void)
|
||||
{
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x00);
|
||||
if(r >= 0) {
|
||||
/* Charging bit indicates we're currently charging */
|
||||
if((r & 0x04) != 0)
|
||||
return AXP173_BATT_CHARGING;
|
||||
|
||||
/* Not plugged in means we're discharging */
|
||||
if((r & 0xf0) == 0)
|
||||
return AXP173_BATT_DISCHARGING;
|
||||
} else {
|
||||
/* Report discharging if we can't find out power status */
|
||||
return AXP173_BATT_DISCHARGING;
|
||||
}
|
||||
|
||||
/* If the battery is full and not in use, the charging bit will be 0,
|
||||
* there will be an external power source, AND the discharge current
|
||||
* will be zero. Seems to rule out all false positives. */
|
||||
int d = axp173_adc_read_raw(ADC_DISCHARGE_CURRENT);
|
||||
if(d == 0)
|
||||
return AXP173_BATT_FULL;
|
||||
|
||||
return AXP173_BATT_DISCHARGING;
|
||||
}
|
||||
|
||||
int axp173_input_status(void)
|
||||
{
|
||||
#ifdef HAVE_BATTERY_SWITCH
|
||||
int input_status = 0;
|
||||
#else
|
||||
int input_status = AXP173_INPUT_BATTERY;
|
||||
#endif
|
||||
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x00);
|
||||
if(r < 0)
|
||||
return input_status;
|
||||
|
||||
/* Check for AC input */
|
||||
if(r & 0x80)
|
||||
input_status |= AXP173_INPUT_AC;
|
||||
|
||||
/* Only report USB if ACIN and VBUS are not shorted */
|
||||
if((r & 0x20) != 0 && (r & 0x02) == 0)
|
||||
input_status |= AXP173_INPUT_USB;
|
||||
|
||||
#ifdef HAVE_BATTERY_SWITCH
|
||||
/* Check for battery presence if target defines it as removable */
|
||||
r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x01);
|
||||
if(r >= 0 && (r & 0x20) != 0)
|
||||
input_status |= AXP173_INPUT_BATTERY;
|
||||
#endif
|
||||
|
||||
return input_status;
|
||||
}
|
||||
|
||||
int axp173_adc_read(int adc)
|
||||
{
|
||||
int value = axp173_adc_read_raw(adc);
|
||||
if(value == INT_MIN)
|
||||
return INT_MIN;
|
||||
|
||||
return axp173_adc_conv_raw(adc, value);
|
||||
}
|
||||
|
||||
int axp173_adc_read_raw(int adc)
|
||||
{
|
||||
/* Don't give a reading if the ADC is not enabled */
|
||||
if((axp173.adc_enable & (1 << adc)) == 0)
|
||||
return INT_MIN;
|
||||
|
||||
/* Read the ADC */
|
||||
uint8_t buf[3];
|
||||
int count = (adc == ADC_BATTERY_POWER) ? 3 : 2;
|
||||
uint8_t reg = axp173_adc_info[adc].reg;
|
||||
int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, reg, count, &buf[0]);
|
||||
if(rc != I2C_STATUS_OK)
|
||||
return INT_MIN;
|
||||
|
||||
/* Parse the value */
|
||||
if(adc == ADC_BATTERY_POWER)
|
||||
return (buf[0] << 16) | (buf[1] << 8) | buf[2];
|
||||
else if(adc == ADC_CHARGE_CURRENT || adc == ADC_DISCHARGE_CURRENT)
|
||||
return (buf[0] << 5) | (buf[1] & 0x1f);
|
||||
else
|
||||
return (buf[0] << 4) | (buf[1] & 0xf);
|
||||
}
|
||||
|
||||
int axp173_adc_conv_raw(int adc, int value)
|
||||
{
|
||||
switch(adc) {
|
||||
case ADC_ACIN_VOLTAGE:
|
||||
case ADC_VBUS_VOLTAGE:
|
||||
/* 0 mV ... 6.9615 mV, step 1.7 mV */
|
||||
return value * 17 / 10;
|
||||
case ADC_ACIN_CURRENT:
|
||||
/* 0 mA ... 2.5594 A, step 0.625 mA */
|
||||
return value * 5 / 8;
|
||||
case ADC_VBUS_CURRENT:
|
||||
/* 0 mA ... 1.5356 A, step 0.375 mA */
|
||||
return value * 3 / 8;
|
||||
case ADC_INTERNAL_TEMP:
|
||||
/* -144.7 C ... 264.8 C, step 0.1 C */
|
||||
return value - 1447;
|
||||
case ADC_TS_INPUT:
|
||||
/* 0 mV ... 3.276 V, step 0.8 mV */
|
||||
return value * 4 / 5;
|
||||
case ADC_BATTERY_VOLTAGE:
|
||||
/* 0 mV ... 4.5045 V, step 1.1 mV */
|
||||
return value * 11 / 10;
|
||||
case ADC_CHARGE_CURRENT:
|
||||
case ADC_DISCHARGE_CURRENT:
|
||||
/* 0 mA to 4.095 A, step 0.5 mA */
|
||||
return value / 2;
|
||||
case ADC_APS_VOLTAGE:
|
||||
/* 0 mV to 5.733 V, step 1.4 mV */
|
||||
return value * 7 / 5;
|
||||
case ADC_BATTERY_POWER:
|
||||
/* 0 uW to 23.6404 W, step 0.55 uW */
|
||||
return value * 11 / 20;
|
||||
default:
|
||||
/* Shouldn't happen */
|
||||
return INT_MIN;
|
||||
}
|
||||
}
|
||||
|
||||
int axp173_adc_get_enabled(void)
|
||||
{
|
||||
return axp173.adc_enable;
|
||||
}
|
||||
|
||||
void axp173_adc_set_enabled(int adc_bits)
|
||||
{
|
||||
/* Ignore no-op */
|
||||
if(adc_bits == axp173.adc_enable)
|
||||
return;
|
||||
|
||||
/* Compute the new register values */
|
||||
const struct axp173_adc_info* info = axp173_adc_info;
|
||||
uint8_t regs[2] = {0, 0};
|
||||
for(int i = 0; i < NUM_ADC_CHANNELS; ++i) {
|
||||
if(info[i].en_reg == 0xff)
|
||||
continue;
|
||||
|
||||
if(adc_bits & (1 << i))
|
||||
regs[info[i].en_reg - 0x82] |= 1 << info[i].en_bit;
|
||||
}
|
||||
|
||||
/* These ADCs share an enable bit */
|
||||
if(adc_bits & ((1 << ADC_CHARGE_CURRENT)|(1 << ADC_DISCHARGE_CURRENT))) {
|
||||
adc_bits |= (1 << ADC_CHARGE_CURRENT);
|
||||
adc_bits |= (1 << ADC_DISCHARGE_CURRENT);
|
||||
}
|
||||
|
||||
/* Enable required bits for battery power ADC */
|
||||
if(adc_bits & (1 << ADC_BATTERY_POWER)) {
|
||||
regs[0] |= 1 << info[ADC_DISCHARGE_CURRENT].en_bit;
|
||||
regs[0] |= 1 << info[ADC_BATTERY_VOLTAGE].en_bit;
|
||||
}
|
||||
|
||||
/* Update the configuration */
|
||||
i2c_reg_write(AXP173_BUS, AXP173_ADDR, 0x82, 2, ®s[0]);
|
||||
axp173.adc_enable = adc_bits;
|
||||
}
|
||||
|
||||
int axp173_adc_get_rate(void)
|
||||
{
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x84);
|
||||
if(r < 0)
|
||||
return AXP173_ADC_RATE_100HZ; /* an arbitrary value */
|
||||
|
||||
return (r >> 6) & 3;
|
||||
}
|
||||
|
||||
void axp173_adc_set_rate(int rate)
|
||||
{
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x84,
|
||||
0xc0, (rate & 3) << 6, NULL);
|
||||
}
|
||||
|
||||
static uint32_t axp173_cc_parse(const uint8_t* buf)
|
||||
{
|
||||
return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
}
|
||||
|
||||
void axp173_cc_read(uint32_t* charge, uint32_t* discharge)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, 0xb0, 8, &buf[0]);
|
||||
if(rc != I2C_STATUS_OK) {
|
||||
if(charge)
|
||||
*charge = 0;
|
||||
if(discharge)
|
||||
*discharge = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(charge)
|
||||
*charge = axp173_cc_parse(&buf[0]);
|
||||
if(discharge)
|
||||
*discharge = axp173_cc_parse(&buf[4]);
|
||||
}
|
||||
|
||||
void axp173_cc_clear(void)
|
||||
{
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0xb8, 5, 1, NULL);
|
||||
}
|
||||
|
||||
void axp173_cc_enable(bool en)
|
||||
{
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0xb8, 7, en ? 1 : 0, NULL);
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
#define AXP173_DEBUG_BATTERY_STATUS 0
|
||||
#define AXP173_DEBUG_INPUT_STATUS 1
|
||||
#define AXP173_DEBUG_ADC_RATE 2
|
||||
#define AXP173_DEBUG_FIRST_ADC 3
|
||||
#define AXP173_DEBUG_ENTRIES (AXP173_DEBUG_FIRST_ADC + NUM_ADC_CHANNELS)
|
||||
|
||||
static int axp173_debug_menu_cb(int action, struct gui_synclist* lists)
|
||||
{
|
||||
(void)lists;
|
||||
|
||||
if(action == ACTION_NONE)
|
||||
action = ACTION_REDRAW;
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
static const char* axp173_debug_menu_get_name(int item, void* data,
|
||||
char* buf, size_t buflen)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
static const char* const adc_names[] = {
|
||||
"V_acin", "I_acin", "V_vbus", "I_vbus", "T_int",
|
||||
"V_ts", "V_batt", "I_chrg", "I_dchg", "V_aps", "P_batt"
|
||||
};
|
||||
|
||||
static const char* const adc_units[] = {
|
||||
"mV", "mA", "mV", "mA", "C", "mV", "mV", "mA", "mA", "mV", "uW",
|
||||
};
|
||||
|
||||
int adc = item - AXP173_DEBUG_FIRST_ADC;
|
||||
if(item >= AXP173_DEBUG_FIRST_ADC && adc < NUM_ADC_CHANNELS) {
|
||||
int raw_value = axp173_adc_read_raw(adc);
|
||||
if(raw_value == INT_MIN) {
|
||||
snprintf(buf, buflen, "%s: [Disabled]", adc_names[adc]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int value = axp173_adc_conv_raw(adc, raw_value);
|
||||
if(adc == ADC_INTERNAL_TEMP) {
|
||||
snprintf(buf, buflen, "%s: %d.%d %s", adc_names[adc],
|
||||
value/10, value%10, adc_units[adc]);
|
||||
} else {
|
||||
snprintf(buf, buflen, "%s: %d %s", adc_names[adc],
|
||||
value, adc_units[adc]);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
switch(item) {
|
||||
case AXP173_DEBUG_BATTERY_STATUS: {
|
||||
switch(axp173_battery_status()) {
|
||||
case AXP173_BATT_FULL:
|
||||
return "Battery: Full";
|
||||
case AXP173_BATT_CHARGING:
|
||||
return "Battery: Charging";
|
||||
case AXP173_BATT_DISCHARGING:
|
||||
return "Battery: Discharging";
|
||||
default:
|
||||
return "Battery: Unknown";
|
||||
}
|
||||
} break;
|
||||
|
||||
case AXP173_DEBUG_INPUT_STATUS: {
|
||||
int s = axp173_input_status();
|
||||
const char* ac = (s & AXP173_INPUT_AC) ? " AC" : "";
|
||||
const char* usb = (s & AXP173_INPUT_USB) ? " USB" : "";
|
||||
const char* batt = (s & AXP173_INPUT_BATTERY) ? " Battery" : "";
|
||||
snprintf(buf, buflen, "Inputs:%s%s%s", ac, usb, batt);
|
||||
return buf;
|
||||
} break;
|
||||
|
||||
case AXP173_DEBUG_ADC_RATE: {
|
||||
int rate = 25 << axp173_adc_get_rate();
|
||||
snprintf(buf, buflen, "ADC sample rate: %d Hz", rate);
|
||||
return buf;
|
||||
} break;
|
||||
|
||||
default:
|
||||
return "---";
|
||||
}
|
||||
}
|
||||
|
||||
bool axp173_debug_menu(void)
|
||||
{
|
||||
struct simplelist_info info;
|
||||
simplelist_info_init(&info, "AXP173 debug", AXP173_DEBUG_ENTRIES, NULL);
|
||||
info.action_callback = axp173_debug_menu_cb;
|
||||
info.get_name = axp173_debug_menu_get_name;
|
||||
return simplelist_show_list(&info);
|
||||
}
|
||||
#endif /* !BOOTLOADER */
|
||||
|
||||
/* This is basically the only valid implementation, so define it here */
|
||||
unsigned int power_input_status(void)
|
||||
{
|
||||
unsigned int state = 0;
|
||||
int input_status = axp173_input_status();
|
||||
|
||||
if(input_status & AXP173_INPUT_AC)
|
||||
state |= POWER_INPUT_MAIN_CHARGER;
|
||||
|
||||
if(input_status & AXP173_INPUT_USB)
|
||||
state |= POWER_INPUT_USB_CHARGER;
|
||||
|
||||
#ifdef HAVE_BATTERY_SWITCH
|
||||
if(input_status & AXP173_INPUT_BATTERY)
|
||||
state |= POWER_INPUT_BATTERY;
|
||||
#endif
|
||||
|
||||
return state;
|
||||
}
|
104
firmware/drivers/rtc/rtc_x1000.c
Normal file
104
firmware/drivers/rtc/rtc_x1000.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* Based mainly on rtc_jz4760.c,
|
||||
* 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 "rtc.h"
|
||||
#include "x1000/rtc.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* 4 byte magic number 'RTCV' */
|
||||
#define RTCV 0x52544356
|
||||
|
||||
/* expected RTC clock frequency */
|
||||
#define NC1HZ_EXPECTED (32768 - 1)
|
||||
|
||||
static void rtc_write_reg(uint32_t addr, uint32_t value)
|
||||
{
|
||||
while(jz_readf(RTC_CR, WRDY) == 0);
|
||||
REG_RTC_WENR = 0xa55a;
|
||||
while(jz_readf(RTC_WENR, WEN) == 0);
|
||||
while(jz_readf(RTC_CR, WRDY) == 0);
|
||||
(*(volatile uint32_t*)addr) = value;
|
||||
while(jz_readf(RTC_CR, WRDY) == 0);
|
||||
}
|
||||
|
||||
void rtc_init(void)
|
||||
{
|
||||
/* Check if we totally lost power and need to reset the RTC */
|
||||
if(REG_RTC_HSPR != RTCV || jz_readf(RTC_GR, NC1HZ) != NC1HZ_EXPECTED) {
|
||||
rtc_write_reg(JA_RTC_GR, NC1HZ_EXPECTED);
|
||||
rtc_write_reg(JA_RTC_HWFCR, 3200);
|
||||
rtc_write_reg(JA_RTC_HRCR, 2048);
|
||||
rtc_write_reg(JA_RTC_SR, 1546300800); /* 01/01/2019 */
|
||||
rtc_write_reg(JA_RTC_CR, 1);
|
||||
rtc_write_reg(JA_RTC_HSPR, RTCV);
|
||||
}
|
||||
|
||||
rtc_write_reg(JA_RTC_HWRSR, 0);
|
||||
}
|
||||
|
||||
int rtc_read_datetime(struct tm* tm)
|
||||
{
|
||||
time_t time = REG_RTC_SR;
|
||||
gmtime_r(&time, tm);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rtc_write_datetime(const struct tm* tm)
|
||||
{
|
||||
time_t time = mktime((struct tm*)tm);
|
||||
rtc_write_reg(JA_RTC_SR, time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_RTC_ALARM
|
||||
/* TODO: implement the RTC alarm */
|
||||
|
||||
void rtc_set_alarm(int h, int m)
|
||||
{
|
||||
(void)h;
|
||||
(void)m;
|
||||
}
|
||||
|
||||
void rtc_get_alarm(int* h, int* m)
|
||||
{
|
||||
(void)h;
|
||||
(void)m;
|
||||
}
|
||||
|
||||
void rtc_enable_alarm(bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
}
|
||||
|
||||
bool rtc_check_alarm_started(bool release_alarm)
|
||||
{
|
||||
(void)release_alarm;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rtc_check_alarm_flag(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
152
firmware/export/ak4376.h
Normal file
152
firmware/export/ak4376.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __AK4376_H__
|
||||
#define __AK4376_H__
|
||||
|
||||
#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP)
|
||||
#define AUDIOHW_HAVE_SHORT2_ROLL_OFF
|
||||
|
||||
#define AK4376_MIN_VOLUME (-890)
|
||||
#define AK4376_MAX_VOLUME 150
|
||||
|
||||
AUDIOHW_SETTING(VOLUME, "dB", 1, 5, AK4376_MIN_VOLUME, AK4376_MAX_VOLUME, -200)
|
||||
AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 3, 0)
|
||||
AUDIOHW_SETTING(POWER_MODE, "", 0, 1, 0, 1, 0)
|
||||
|
||||
/* Register addresses */
|
||||
#define AK4376_REG_PWR1 0x00
|
||||
#define AK4376_REG_PWR2 0x01
|
||||
#define AK4376_REG_PWR3 0x02
|
||||
#define AK4376_REG_PWR4 0x03
|
||||
#define AK4376_REG_OUTPUT_MODE 0x04
|
||||
#define AK4376_REG_CLOCK_MODE 0x05
|
||||
#define AK4376_REG_FILTER 0x06
|
||||
#define AK4376_REG_MIXER 0x07
|
||||
#define AK4376_REG_LCH_VOLUME 0x0b
|
||||
#define AK4376_REG_RCH_VOLUME 0x0c
|
||||
#define AK4376_REG_AMP_VOLUME 0x0d
|
||||
#define AK4376_REG_PLL_CLK_SRC 0x0e
|
||||
#define AK4376_REG_PLL_REF_DIV1 0x0f
|
||||
#define AK4376_REG_PLL_REF_DIV2 0x10
|
||||
#define AK4376_REG_PLL_FB_DIV1 0x11
|
||||
#define AK4376_REG_PLL_FB_DIV2 0x12
|
||||
#define AK4376_REG_DAC_CLK_SRC 0x13
|
||||
#define AK4376_REG_DAC_CLK_DIV 0x14
|
||||
#define AK4376_REG_AUDIO_IF_FMT 0x15
|
||||
#define AK4376_REG_CHIP_ID 0x21
|
||||
#define AK4376_REG_MODE_CTRL 0x24
|
||||
#define AK4376_REG_ADJUST1 0x26
|
||||
#define AK4376_REG_ADJUST2 0x2a
|
||||
#define AK4376_NUM_REGS 0x2b
|
||||
|
||||
/* Mixer controls, simply OR them together.
|
||||
* LCH = add LCH signal to output
|
||||
* RCH = add RCH signal to output
|
||||
* HALF = multiply output by 1/2
|
||||
* INVERT = invert the output after everything else
|
||||
*/
|
||||
#define AK4376_MIX_MUTE 0
|
||||
#define AK4376_MIX_LCH 1
|
||||
#define AK4376_MIX_RCH 2
|
||||
#define AK4376_MIX_HALF 4
|
||||
#define AK4376_MIX_INVERT 8
|
||||
|
||||
/* Min/max digital volumes in units of dB/10 */
|
||||
#define AK4376_DIG_VOLUME_MIN (-120)
|
||||
#define AK4376_DIG_VOLUME_MAX 30
|
||||
#define AK4376_DIG_VOLUME_STEP 5
|
||||
#define AK4376_DIG_VOLUME_MUTE (AK4376_DIG_VOLUME_MIN - 1)
|
||||
|
||||
/* Min/max headphone amp volumes in units of dB/10 */
|
||||
#define AK4376_AMP_VOLUME_MIN (-200)
|
||||
#define AK4376_AMP_VOLUME_MAX 60
|
||||
#define AK4376_AMP_VOLUME_STEP 20
|
||||
#define AK4376_AMP_VOLUME_MUTE (AK4376_AMP_VOLUME_MIN - 1)
|
||||
|
||||
/* Digital filters */
|
||||
#define AK4376_FILTER_SHARP 0
|
||||
#define AK4376_FILTER_SLOW 1
|
||||
#define AK4376_FILTER_SHORT_SHARP 2
|
||||
#define AK4376_FILTER_SHORT_SLOW 3
|
||||
|
||||
/* Frequency selection */
|
||||
#define AK4376_FS_8 0
|
||||
#define AK4376_FS_11 1
|
||||
#define AK4376_FS_12 2
|
||||
#define AK4376_FS_16 4
|
||||
#define AK4376_FS_22 5
|
||||
#define AK4376_FS_24 6
|
||||
#define AK4376_FS_32 8
|
||||
#define AK4376_FS_44 9
|
||||
#define AK4376_FS_48 10
|
||||
#define AK4376_FS_64 12
|
||||
#define AK4376_FS_88 13
|
||||
#define AK4376_FS_96 14
|
||||
#define AK4376_FS_176 17
|
||||
#define AK4376_FS_192 18
|
||||
|
||||
/* Functions to power on / off the DAC which should be called from
|
||||
* the target's audiohw_init() / audiohw_close() implementation.
|
||||
*/
|
||||
extern void ak4376_init(void);
|
||||
extern void ak4376_close(void);
|
||||
|
||||
/* Register read/write. Cached to avoid redundant reads/writes. */
|
||||
extern void ak4376_write(int reg, int value);
|
||||
extern int ak4376_read(int reg);
|
||||
|
||||
/* Target-specific function to set the PDN pin level. */
|
||||
extern void ak4376_set_pdn_pin(int level);
|
||||
|
||||
/* Target-specific function to control the external master clock frequency.
|
||||
* This is called by the ak4376's audiohw implementation when switching to
|
||||
* or from a frequency that is configured to use this clock source.
|
||||
*
|
||||
* - hw_freq is the new sample rate -- one of the HW_FREQ_XX constants.
|
||||
* - enabled is true if clock should be output, false if not.
|
||||
*
|
||||
* The return value is the master clock rate as a multiple of the sampling
|
||||
* frequency. The allowed multiples depend on the sampling frequency, shown
|
||||
* in the table below.
|
||||
*
|
||||
* +-----------+------------------------+
|
||||
* | frequency | master clock rate |
|
||||
* +-----------+------------------------+
|
||||
* | 8 - 24 | 256fs / 512fs / 1024fs |
|
||||
* | 32 - 48 | 256fs / 512fs |
|
||||
* | 64 - 96 | 256fs |
|
||||
* | 128 - 192 | 128fs |
|
||||
* +-----------+------------------------+
|
||||
*
|
||||
* For example, at 48 KHz you could return either 256 or 512 depending on
|
||||
* the rate you decided to actually use.
|
||||
*
|
||||
* You need to return a valid master multiplier for supported frequencies
|
||||
* even when enabled = false, since the driver needs to know the multiplier
|
||||
* _before_ enabling the clock.
|
||||
*
|
||||
* For unsupported frequencies you don't need to return a valid master
|
||||
* multiplier, because the DAC doesn't need the return value in such cases.
|
||||
*/
|
||||
extern int ak4376_set_mclk_freq(int hw_freq, bool enabled);
|
||||
|
||||
#endif /* __AK4376_H__ */
|
|
@ -194,6 +194,8 @@ struct sound_settings_info
|
|||
#include "jz4740-codec.h"
|
||||
#elif defined(HAVE_AK4537)
|
||||
#include "ak4537.h"
|
||||
#elif defined(HAVE_AK4376)
|
||||
#include "ak4376.h"
|
||||
#elif defined(HAVE_RK27XX_CODEC)
|
||||
#include "rk27xx_codec.h"
|
||||
#elif defined(HAVE_AIC3X)
|
||||
|
|
94
firmware/export/axp173.h
Normal file
94
firmware/export/axp173.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __AXP173_H__
|
||||
#define __AXP173_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define ADC_ACIN_VOLTAGE 0
|
||||
#define ADC_ACIN_CURRENT 1
|
||||
#define ADC_VBUS_VOLTAGE 2
|
||||
#define ADC_VBUS_CURRENT 3
|
||||
#define ADC_INTERNAL_TEMP 4
|
||||
#define ADC_TS_INPUT 5
|
||||
#define ADC_BATTERY_VOLTAGE 6
|
||||
#define ADC_CHARGE_CURRENT 7
|
||||
#define ADC_DISCHARGE_CURRENT 8
|
||||
#define ADC_APS_VOLTAGE 9
|
||||
#define ADC_BATTERY_POWER 10
|
||||
#define NUM_ADC_CHANNELS 11
|
||||
|
||||
/* ADC sampling rates */
|
||||
#define AXP173_ADC_RATE_25HZ 0
|
||||
#define AXP173_ADC_RATE_50HZ 1
|
||||
#define AXP173_ADC_RATE_100HZ 2
|
||||
#define AXP173_ADC_RATE_200HZ 3
|
||||
|
||||
/* Return values of axp173_battery_status() */
|
||||
#define AXP173_BATT_DISCHARGING 0
|
||||
#define AXP173_BATT_CHARGING 1
|
||||
#define AXP173_BATT_FULL 2
|
||||
|
||||
/* Bits returned by axp173_input_status() */
|
||||
#define AXP173_INPUT_AC (1 << 0)
|
||||
#define AXP173_INPUT_USB (1 << 1)
|
||||
#define AXP173_INPUT_BATTERY (1 << 2)
|
||||
#define AXP173_INPUT_EXTERNAL (AXP173_INPUT_AC|AXP173_INPUT_USB)
|
||||
|
||||
/* Must be called from power_init() to initialize the driver state */
|
||||
extern void axp173_init(void);
|
||||
|
||||
/* Basic battery and power supply status */
|
||||
extern int axp173_battery_status(void);
|
||||
extern int axp173_input_status(void);
|
||||
|
||||
/* ADC access -- ADCs which are not enabled will return INT_MIN if read.
|
||||
* The output of axp173_adc_read() is normalized to appropriate units:
|
||||
*
|
||||
* - for voltages, the scale is millivolts
|
||||
* - for currents, the scale is milliamps
|
||||
* - for temperatures, the scale is tenths of a degree Celsius
|
||||
* - for power, the scale is microwatts
|
||||
*
|
||||
* See the comment in axp173_adc_conv_raw() for raw value precision/scale.
|
||||
*/
|
||||
extern int axp173_adc_read(int adc);
|
||||
extern int axp173_adc_read_raw(int adc);
|
||||
extern int axp173_adc_conv_raw(int adc, int value);
|
||||
extern int axp173_adc_get_enabled(void);
|
||||
extern void axp173_adc_set_enabled(int adc_bits);
|
||||
extern int axp173_adc_get_rate(void);
|
||||
extern void axp173_adc_set_rate(int rate);
|
||||
|
||||
/* - axp173_cc_read() reads the coulomb counters
|
||||
* - axp173_cc_clear() resets both counters to zero
|
||||
* - axp173_cc_enable() will stop/start the counters running
|
||||
*/
|
||||
extern void axp173_cc_read(uint32_t* charge, uint32_t* discharge);
|
||||
extern void axp173_cc_clear(void);
|
||||
extern void axp173_cc_enable(bool en);
|
||||
|
||||
/* Debug menu */
|
||||
extern bool axp173_debug_menu(void);
|
||||
|
||||
#endif /* __AXP173_H__ */
|
|
@ -82,6 +82,7 @@
|
|||
#define AS3525v2 35252
|
||||
#define IMX233 233
|
||||
#define RK27XX 2700
|
||||
#define X1000 1000
|
||||
|
||||
/* platforms
|
||||
* bit fields to allow PLATFORM_HOSTED to be OR'ed e.g. with a
|
||||
|
@ -165,6 +166,7 @@
|
|||
#define XDUOO_X20_PAD 70
|
||||
#define FIIO_M3K_LINUX_PAD 71
|
||||
#define EROSQ_PAD 72
|
||||
#define FIIO_M3K_PAD 73
|
||||
|
||||
/* CONFIG_REMOTE_KEYPAD */
|
||||
#define H100_REMOTE 1
|
||||
|
@ -281,6 +283,7 @@
|
|||
#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 */
|
||||
#define LCD_FIIOM3K 69 /* as used by the FiiO M3K */
|
||||
|
||||
/* LCD_PIXELFORMAT */
|
||||
#define HORIZONTAL_PACKING 1
|
||||
|
@ -320,6 +323,7 @@ Lyre prototype 1 */
|
|||
#define I2C_S5L8702 16 /* Same as S5L8700, but with two channels */
|
||||
#define I2C_IMX233 17
|
||||
#define I2C_RK27XX 18
|
||||
#define I2C_X1000 19
|
||||
|
||||
/* CONFIG_LED */
|
||||
#define LED_REAL 1 /* SW controlled LED (Archos recorders, player) */
|
||||
|
@ -356,6 +360,7 @@ Lyre prototype 1 */
|
|||
#define RTC_IMX233 20
|
||||
#define RTC_STM41T62 21 /* ST M41T62 */
|
||||
#define RTC_JZ4760 22 /* Ingenic Jz4760 */
|
||||
#define RTC_X1000 23 /* Ingenic X1000 */
|
||||
|
||||
/* USB On-the-go */
|
||||
#define USBOTG_M66591 6591 /* M:Robe 500 */
|
||||
|
@ -605,6 +610,8 @@ Lyre prototype 1 */
|
|||
#include "config/xduoox20.h"
|
||||
#elif defined(FIIO_M3K_LINUX)
|
||||
#include "config/fiiom3klinux.h"
|
||||
#elif defined(FIIO_M3K)
|
||||
#include "config/fiiom3k.h"
|
||||
#elif defined(EROS_Q)
|
||||
#include "config/aigoerosq.h"
|
||||
#else
|
||||
|
|
116
firmware/export/config/fiiom3k.h
Normal file
116
firmware/export/config/fiiom3k.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* RoLo-related defines */
|
||||
#define MODEL_NAME "FiiO M3K"
|
||||
#define MODEL_NUMBER 114
|
||||
#define BOOTFILE_EXT "m3k"
|
||||
#define BOOTFILE "rockbox." BOOTFILE_EXT
|
||||
#define BOOTDIR "/.rockbox"
|
||||
#define FIRMWARE_OFFSET_FILE_CRC 0
|
||||
#define FIRMWARE_OFFSET_FILE_DATA 8
|
||||
|
||||
/* CPU defines */
|
||||
#define CONFIG_CPU X1000
|
||||
#define X1000_EXCLK_FREQ 24000000
|
||||
#define TIMER_FREQ X1000_EXCLK_FREQ
|
||||
#define CPU_FREQ 1008000000
|
||||
#define CPUFREQ_MAX CPU_FREQ
|
||||
/* TODO: figure out if this does in fact affect power consumption. */
|
||||
#define CPUFREQ_DEFAULT (CPUFREQ_MAX/4)
|
||||
#define CPUFREQ_NORMAL (CPUFREQ_MAX/4)
|
||||
#define HAVE_ADJUSTABLE_CPU_FREQ
|
||||
#define HAVE_GUI_BOOST
|
||||
|
||||
/* Kernel defines */
|
||||
#define INCLUDE_TIMEOUT_API
|
||||
#define HAVE_SEMAPHORE_OBJECTS
|
||||
|
||||
/* Drivers */
|
||||
#define HAVE_I2C_ASYNC
|
||||
|
||||
/* Buffer for plugins and codecs. */
|
||||
#define PLUGIN_BUFFER_SIZE 0x200000 /* 2 MiB */
|
||||
#define CODEC_SIZE 0x100000 /* 1 MiB */
|
||||
|
||||
/* LCD defines */
|
||||
#define CONFIG_LCD LCD_FIIOM3K
|
||||
#define LCD_WIDTH 240
|
||||
#define LCD_HEIGHT 320
|
||||
#define LCD_DEPTH 16
|
||||
#define LCD_PIXELFORMAT RGB565
|
||||
#define LCD_DPI 200
|
||||
#define HAVE_LCD_COLOR
|
||||
#define HAVE_LCD_BITMAP
|
||||
#define HAVE_LCD_ENABLE
|
||||
#define LCD_X1000_FASTSLEEP
|
||||
|
||||
/* Backlight defines */
|
||||
#define HAVE_BACKLIGHT
|
||||
#define HAVE_BACKLIGHT_BRIGHTNESS
|
||||
#define HAVE_BUTTON_LIGHT
|
||||
#define HAVE_BUTTONLIGHT_BRIGHTNESS
|
||||
#define MIN_BRIGHTNESS_SETTING 1
|
||||
#define MAX_BRIGHTNESS_SETTING 100
|
||||
#define BRIGHTNESS_STEP 5
|
||||
#define DEFAULT_BRIGHTNESS_SETTING 70
|
||||
#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING
|
||||
|
||||
/* Codec / audio hardware defines */
|
||||
#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192
|
||||
#define HAVE_AK4376
|
||||
#define HAVE_SW_TONE_CONTROLS
|
||||
#define HAVE_SW_VOLUME_CONTROL
|
||||
|
||||
/* TODO: Need to implement recording */
|
||||
|
||||
/* Button defines */
|
||||
#define CONFIG_KEYPAD FIIO_M3K_PAD
|
||||
#define HAVE_HEADPHONE_DETECTION
|
||||
#define HAVE_TOUCHPAD
|
||||
#define HAVE_TOUCHPAD_SENSITIVITY_SETTING
|
||||
#define MIN_TOUCHPAD_SENSITIVITY_SETTING (-25)
|
||||
#define MAX_TOUCHPAD_SENSITIVITY_SETTING (25)
|
||||
#define DEFAULT_TOUCHPAD_SENSITIVITY_SETTING (0)
|
||||
#define HAVE_SCROLLWHEEL
|
||||
/* #define HAVE_WHEEL_ACCELERATION */
|
||||
/* #define WHEEL_ACCELERATION */
|
||||
/* #define WHEEL_ACCEL_START */
|
||||
|
||||
/* Storage defines */
|
||||
#define CONFIG_STORAGE STORAGE_SD
|
||||
#define HAVE_HOTSWAP
|
||||
#define HAVE_HOTSWAP_STORAGE_AS_MAIN
|
||||
#define HAVE_MULTIDRIVE
|
||||
#define NUM_DRIVES 1
|
||||
#define STORAGE_WANTS_ALIGN
|
||||
#define STORAGE_NEEDS_BOUNCE_BUFFER
|
||||
|
||||
/* RTC settings */
|
||||
#define CONFIG_RTC RTC_X1000
|
||||
/* TODO: implement HAVE_RTC_ALARM */
|
||||
|
||||
/* Power management */
|
||||
#define HAVE_AXP173
|
||||
#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE
|
||||
#define CONFIG_CHARGING CHARGING_MONITOR
|
||||
#define HAVE_SW_POWEROFF
|
||||
#define HAVE_POWEROFF_WHILE_CHARGING
|
||||
|
||||
/* Only one battery type */
|
||||
#define BATTERY_CAPACITY_DEFAULT 1100
|
||||
#define BATTERY_CAPACITY_MIN 1100
|
||||
#define BATTERY_CAPACITY_MAX 1100
|
||||
#define BATTERY_CAPACITY_INC 0
|
||||
#define BATTERY_TYPES_COUNT 1
|
||||
|
||||
/* USB is still TODO. */
|
||||
#define USB_NONE
|
||||
|
||||
/* Rockbox capabilities */
|
||||
#define HAVE_FAT16SUPPORT
|
||||
#define HAVE_ALBUMART
|
||||
#define HAVE_BMP_SCALING
|
||||
#define HAVE_JPEG
|
||||
#define HAVE_TAGCACHE
|
||||
#define HAVE_VOLUME_IN_LIST
|
||||
#define HAVE_QUICKSCREEN
|
||||
#define HAVE_HOTKEY
|
||||
#define AB_REPEAT_ENABLE
|
31
firmware/export/installer.h
Normal file
31
firmware/export/installer.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 _INSTALLER_H_
|
||||
#define _INSTALLER_H_
|
||||
|
||||
/* Provisional interface for installing/dumping a bootloader */
|
||||
|
||||
extern int install_bootloader(const char* path);
|
||||
extern int dump_bootloader(const char* path);
|
||||
extern const char* installer_strerror(int rc);
|
||||
|
||||
#endif /* _INSTALLER_H_ */
|
|
@ -131,7 +131,8 @@ static int battery_type = 0;
|
|||
/* Power history: power_history[0] is the newest sample */
|
||||
unsigned short power_history[POWER_HISTORY_LEN] = {0};
|
||||
|
||||
#if (CONFIG_CPU == JZ4732) || (CONFIG_CPU == JZ4760B) || (CONFIG_PLATFORM & PLATFORM_HOSTED)
|
||||
#if (CONFIG_CPU == JZ4732) || (CONFIG_CPU == JZ4760B) || \
|
||||
(CONFIG_CPU == X1000) || (CONFIG_PLATFORM & PLATFORM_HOSTED)
|
||||
static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK];
|
||||
#else
|
||||
static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
|
||||
|
|
119
firmware/target/mips/ingenic_x1000/aic-x1000.c
Normal file
119
firmware/target/mips/ingenic_x1000/aic-x1000.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "aic-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "x1000/aic.h"
|
||||
#include "x1000/cpm.h"
|
||||
|
||||
/* Given a rational number m/n < 1, find its representation as a continued
|
||||
* fraction [0; a1, a2, a3, ..., a_k]. At most "cnt" terms are calculated
|
||||
* and written out to "buf". Returns the number of terms written; the result
|
||||
* is complete if this value is less than "cnt", and may be incomplete if it
|
||||
* is equal to "cnt". (Note the leading zero term is not written to "buf".)
|
||||
*/
|
||||
static unsigned cf_derive(unsigned m, unsigned n, unsigned* buf, unsigned cnt)
|
||||
{
|
||||
unsigned wrote = 0;
|
||||
unsigned a = m / n;
|
||||
while(cnt--) {
|
||||
unsigned tmp = n;
|
||||
n = m - n * a;
|
||||
if(n == 0)
|
||||
break;
|
||||
|
||||
m = tmp;
|
||||
a = m / n;
|
||||
*buf++ = a;
|
||||
wrote++;
|
||||
}
|
||||
|
||||
return wrote;
|
||||
}
|
||||
|
||||
/* Given a finite continued fraction [0; buf[0], buf[1], ..., buf[count-1]],
|
||||
* calculate the rational number m/n which it represents. Returns m and n.
|
||||
* If count is zero, then m and n are undefined.
|
||||
*/
|
||||
static void cf_expand(const unsigned* buf, unsigned count,
|
||||
unsigned* m, unsigned* n)
|
||||
{
|
||||
if(count == 0)
|
||||
return;
|
||||
|
||||
unsigned i = count - 1;
|
||||
unsigned mx = 1, nx = buf[i];
|
||||
while(i--) {
|
||||
unsigned tmp = nx;
|
||||
nx = mx + buf[i] * nx;
|
||||
mx = tmp;
|
||||
}
|
||||
|
||||
*m = mx;
|
||||
*n = nx;
|
||||
}
|
||||
|
||||
int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult)
|
||||
{
|
||||
/* get the input clock rate */
|
||||
uint32_t src_freq = clk_get(clksrc);
|
||||
|
||||
/* reject invalid parameters */
|
||||
if(mult % 64 != 0)
|
||||
return -1;
|
||||
|
||||
if(clksrc == X1000_EXCLK_FREQ) {
|
||||
if(mult != 0)
|
||||
return -1;
|
||||
|
||||
jz_writef(AIC_I2SCR, STPBK(1));
|
||||
jz_writef(CPM_I2SCDR, CS(0), CE(0));
|
||||
REG_AIC_I2SDIV = X1000_EXCLK_FREQ / 64 / fs;
|
||||
} else {
|
||||
if(mult == 0)
|
||||
return -1;
|
||||
if(fs*mult > src_freq)
|
||||
return -1;
|
||||
|
||||
/* calculate best rational approximation that fits our constraints */
|
||||
unsigned m = 0, n = 0;
|
||||
unsigned buf[16];
|
||||
unsigned cnt = cf_derive(fs*mult, src_freq, &buf[0], 16);
|
||||
do {
|
||||
cf_expand(&buf[0], cnt, &m, &n);
|
||||
cnt -= 1;
|
||||
} while(cnt > 0 && (m > 512 || n > 8192) && (n >= 2*m));
|
||||
|
||||
/* wrong values */
|
||||
if(cnt == 0 || n == 0 || m == 0)
|
||||
return -1;
|
||||
|
||||
jz_writef(AIC_I2SCR, STPBK(1));
|
||||
jz_writef(CPM_I2SCDR, PCS(clksrc == X1000_CLK_MPLL ? 1 : 0),
|
||||
CS(1), CE(1), DIV_M(m), DIV_N(n));
|
||||
jz_write(CPM_I2SCDR1, REG_CPM_I2SCDR1);
|
||||
REG_AIC_I2SDIV = (mult / 64) - 1;
|
||||
}
|
||||
|
||||
jz_writef(AIC_I2SCR, STPBK(0));
|
||||
return 0;
|
||||
}
|
46
firmware/target/mips/ingenic_x1000/aic-x1000.h
Normal file
46
firmware/target/mips/ingenic_x1000/aic-x1000.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __AIC_X1000_H__
|
||||
#define __AIC_X1000_H__
|
||||
|
||||
#include "clk-x1000.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Set frequency of I2S master clock supplied by AIC. Has no use if an
|
||||
* external DAC is supplying the master clock. Must be called with the
|
||||
* bit clock disabled.
|
||||
*
|
||||
* - clksrc can be one of EXCLK, SCLK_A, MPLL.
|
||||
* - This function does not modify PLL settings. It's the caller's job
|
||||
* to ensure the PLL is configured and runing.
|
||||
* - fs is the audio sampling frequency (8 KHz - 192 KHz)
|
||||
* - mult is multiplied by fs to get the master clock rate.
|
||||
* - mult must be a multiple of 64 due to AIC bit clock requirements.
|
||||
* - Note: EXCLK bypasses the decimal divider so it is not very flexible.
|
||||
* If using EXCLK you must set mult=0. If EXCLK is not a multiple of
|
||||
* the bit clock (= 64*fs), then the clock rate will be inaccurate.
|
||||
*
|
||||
* Returns zero on success and nonzero if the frequency is not achievable.
|
||||
*/
|
||||
extern int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult);
|
||||
|
||||
#endif /* __AIC_X1000_H__ */
|
119
firmware/target/mips/ingenic_x1000/app.lds
Normal file
119
firmware/target/mips/ingenic_x1000/app.lds
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include "config.h"
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlemips")
|
||||
OUTPUT_ARCH(MIPS)
|
||||
ENTRY(_start)
|
||||
STARTUP(target/mips/ingenic_x1000/crt0.o)
|
||||
|
||||
/* Stub area is used for loading new firmware via RoLo */
|
||||
#define STUBSIZE 0x4000
|
||||
#define SDRAM_ORIG 0x80000000
|
||||
|
||||
/* IRAM contains stub, DRAM contains main app */
|
||||
#define IRAMORIG SDRAM_ORIG
|
||||
#define IRAMSIZE STUBSIZE
|
||||
#define DRAMORIG (SDRAM_ORIG + STUBSIZE)
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000 - STUBSIZE)
|
||||
|
||||
/* End of the audio buffer, where the codec buffer starts */
|
||||
#define ENDAUDIOADDR (DRAMORIG + DRAMSIZE - PLUGIN_BUFFER_SIZE - CODEC_SIZE)
|
||||
|
||||
/* Where the codec buffer ends, and the plugin buffer starts */
|
||||
#define ENDCODECADDR (ENDAUDIOADDR + CODEC_SIZE)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
|
||||
DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
loadaddress = .;
|
||||
_loadaddress = .;
|
||||
*(.init.text);
|
||||
*(.text*);
|
||||
} > DRAM
|
||||
|
||||
. = ALIGN(4);
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata*);
|
||||
} > DRAM
|
||||
|
||||
. = ALIGN(4);
|
||||
.data :
|
||||
{
|
||||
*(.data*);
|
||||
*(.sdata*);
|
||||
} > DRAM
|
||||
|
||||
.iram IRAMORIG: AT (_bssbegin)
|
||||
{
|
||||
_iramstart = .;
|
||||
. = 0x000; /* TLB refill */
|
||||
KEEP(*(.vectors.1));
|
||||
. = 0x100; /* Cache error */
|
||||
KEEP(*(.vectors.2));
|
||||
. = 0x180; /* General exception */
|
||||
KEEP(*(.vectors.3));
|
||||
. = 0x200; /* Interrupt */
|
||||
KEEP(*(.vectors.4));
|
||||
KEEP(*(.vectors));
|
||||
|
||||
*(.icode);
|
||||
*(.irodata);
|
||||
*(.idata);
|
||||
_iramend = .;
|
||||
} > IRAM
|
||||
_iramcopy = LOADADDR(.iram);
|
||||
|
||||
. = ALIGN(4);
|
||||
.stack (NOLOAD) :
|
||||
{
|
||||
*(.stack);
|
||||
stackbegin = .;
|
||||
. += 0x1E00;
|
||||
stackend = .;
|
||||
_irqstackbegin = .;
|
||||
. += 0x300;
|
||||
_irqstackend = .;
|
||||
} > IRAM
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_bssbegin = .;
|
||||
*(.sbss*);
|
||||
*(.bss*);
|
||||
*(COMMON);
|
||||
*(.scommon*);
|
||||
_bssend = .;
|
||||
_end = .;
|
||||
} > DRAM
|
||||
|
||||
#ifdef BOOTLOADER
|
||||
. = ALIGN(4);
|
||||
loadbuffer = .;
|
||||
. += 0x100000 * 4; /* Allow 4 MiB for the rockbox binary */
|
||||
loadbufferend = .;
|
||||
#else
|
||||
|
||||
.audiobuf :
|
||||
{
|
||||
. = ALIGN(4); /* XXX might need more alignment here */
|
||||
audiobuffer = .;
|
||||
} > DRAM
|
||||
|
||||
audiobufend = ENDAUDIOADDR;
|
||||
codecbuf = ENDAUDIOADDR;
|
||||
pluginbuf = ENDCODECADDR;
|
||||
#endif
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.eh_frame);
|
||||
*(.rel.dyn);
|
||||
}
|
||||
}
|
5
firmware/target/mips/ingenic_x1000/boot.lds
Normal file
5
firmware/target/mips/ingenic_x1000/boot.lds
Normal file
|
@ -0,0 +1,5 @@
|
|||
#ifdef BOOTLOADER_SPL
|
||||
# include "spl.lds"
|
||||
#else
|
||||
# include "app.lds"
|
||||
#endif
|
258
firmware/target/mips/ingenic_x1000/clk-x1000.c
Normal file
258
firmware/target/mips/ingenic_x1000/clk-x1000.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "clk-x1000.h"
|
||||
#include "x1000/cpm.h"
|
||||
#include "x1000/msc.h"
|
||||
#include "x1000/aic.h"
|
||||
|
||||
static uint32_t pll_get(uint32_t pllreg, uint32_t onbit)
|
||||
{
|
||||
if((pllreg & (1 << onbit)) == 0)
|
||||
return 0;
|
||||
|
||||
/* Both PLL registers share the same layout of N/M/OD bits.
|
||||
* The max multiplier is 128 and max EXCLK is 26 MHz, so the
|
||||
* multiplication should fit within 32 bits without overflow.
|
||||
*/
|
||||
uint32_t rate = X1000_EXCLK_FREQ;
|
||||
rate *= jz_vreadf(pllreg, CPM_APCR, PLLM) + 1;
|
||||
rate /= jz_vreadf(pllreg, CPM_APCR, PLLN) + 1;
|
||||
rate >>= jz_vreadf(pllreg, CPM_APCR, PLLOD);
|
||||
return rate;
|
||||
}
|
||||
|
||||
static uint32_t sclk_a_get(void)
|
||||
{
|
||||
switch(jz_readf(CPM_CCR, SEL_SRC)) {
|
||||
case 1: return X1000_EXCLK_FREQ;
|
||||
case 2: return clk_get(X1000_CLK_APLL);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ccr_get(uint32_t selbit, uint32_t divbit)
|
||||
{
|
||||
uint32_t reg = REG_CPM_CCR;
|
||||
uint32_t sel = (reg >> selbit) & 0x3;
|
||||
uint32_t div = (reg >> divbit) & 0xf;
|
||||
|
||||
switch(sel) {
|
||||
case 1: return clk_get(X1000_CLK_SCLK_A) / (div + 1);
|
||||
case 2: return clk_get(X1000_CLK_MPLL) / (div + 1);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ddr_get(void)
|
||||
{
|
||||
uint32_t reg = REG_CPM_DDRCDR;
|
||||
uint32_t div = jz_vreadf(reg, CPM_DDRCDR, CLKDIV);
|
||||
|
||||
switch(jz_vreadf(reg, CPM_DDRCDR, CLKSRC)) {
|
||||
case 1: return clk_get(X1000_CLK_SCLK_A) / (div + 1);
|
||||
case 2: return clk_get(X1000_CLK_MPLL) / (div + 1);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t lcd_get(void)
|
||||
{
|
||||
if(jz_readf(CPM_CLKGR, LCD))
|
||||
return 0;
|
||||
|
||||
uint32_t reg = REG_CPM_LPCDR;
|
||||
uint32_t rate;
|
||||
switch(jz_vreadf(reg, CPM_LPCDR, CLKSRC)) {
|
||||
case 0: rate = clk_get(X1000_CLK_SCLK_A); break;
|
||||
case 1: rate = clk_get(X1000_CLK_MPLL); break;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
rate /= jz_vreadf(reg, CPM_LPCDR, CLKDIV) + 1;
|
||||
return rate;
|
||||
}
|
||||
|
||||
static uint32_t msc_get(int msc)
|
||||
{
|
||||
if((msc == 0 && jz_readf(CPM_CLKGR, MSC0)) ||
|
||||
(msc == 1 && jz_readf(CPM_CLKGR, MSC1)))
|
||||
return 0;
|
||||
|
||||
uint32_t reg = REG_CPM_MSC0CDR;
|
||||
uint32_t rate;
|
||||
switch(jz_vreadf(reg, CPM_MSC0CDR, CLKSRC)) {
|
||||
case 0: rate = clk_get(X1000_CLK_SCLK_A); break;
|
||||
case 1: rate = clk_get(X1000_CLK_MPLL); break;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
uint32_t div;
|
||||
if(msc == 0)
|
||||
div = jz_readf(CPM_MSC0CDR, CLKDIV);
|
||||
else
|
||||
div = jz_readf(CPM_MSC1CDR, CLKDIV);
|
||||
|
||||
rate /= 2 * (div + 1);
|
||||
rate >>= REG_MSC_CLKRT(msc);
|
||||
return rate;
|
||||
}
|
||||
|
||||
static uint32_t i2s_mclk_get(void)
|
||||
{
|
||||
if(jz_readf(CPM_CLKGR, AIC))
|
||||
return 0;
|
||||
|
||||
uint32_t reg = REG_CPM_I2SCDR;
|
||||
unsigned long long rate;
|
||||
if(jz_vreadf(reg, CPM_I2SCDR, CS) == 0)
|
||||
rate = X1000_EXCLK_FREQ;
|
||||
else {
|
||||
if(jz_vreadf(reg, CPM_I2SCDR, PCS) == 0)
|
||||
rate = clk_get(X1000_CLK_SCLK_A);
|
||||
else
|
||||
rate = clk_get(X1000_CLK_MPLL);
|
||||
|
||||
rate *= jz_vreadf(reg, CPM_I2SCDR, DIV_M);
|
||||
rate /= jz_vreadf(reg, CPM_I2SCDR, DIV_N);
|
||||
}
|
||||
|
||||
/* Clamp invalid setting to 32 bits */
|
||||
if(rate > 0xffffffffull)
|
||||
rate = 0xffffffff;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static uint32_t i2s_bclk_get(void)
|
||||
{
|
||||
return i2s_mclk_get() / (REG_AIC_I2SDIV + 1);
|
||||
}
|
||||
|
||||
static uint32_t sfc_get(void)
|
||||
{
|
||||
if(jz_readf(CPM_CLKGR, SFC))
|
||||
return 0;
|
||||
|
||||
uint32_t reg = REG_CPM_SSICDR;
|
||||
uint32_t rate;
|
||||
if(jz_vreadf(reg, CPM_SSICDR, SFC_CS) == 0)
|
||||
rate = clk_get(X1000_CLK_SCLK_A);
|
||||
else
|
||||
rate = clk_get(X1000_CLK_MPLL);
|
||||
|
||||
rate /= jz_vreadf(reg, CPM_SSICDR, CLKDIV) + 1;
|
||||
return rate;
|
||||
}
|
||||
|
||||
uint32_t clk_get(x1000_clk_t clk)
|
||||
{
|
||||
switch(clk) {
|
||||
case X1000_CLK_EXCLK: return X1000_EXCLK_FREQ;
|
||||
case X1000_CLK_APLL: return pll_get(REG_CPM_APCR, BP_CPM_APCR_ON);
|
||||
case X1000_CLK_MPLL: return pll_get(REG_CPM_MPCR, BP_CPM_MPCR_ON);
|
||||
case X1000_CLK_SCLK_A: return sclk_a_get();
|
||||
case X1000_CLK_CPU: return ccr_get(BP_CPM_CCR_SEL_CPLL, BP_CPM_CCR_CDIV);
|
||||
case X1000_CLK_L2CACHE: return ccr_get(BP_CPM_CCR_SEL_CPLL, BP_CPM_CCR_L2DIV);
|
||||
case X1000_CLK_AHB0: return ccr_get(BP_CPM_CCR_SEL_H0PLL, BP_CPM_CCR_H0DIV);
|
||||
case X1000_CLK_AHB2: return ccr_get(BP_CPM_CCR_SEL_H2PLL, BP_CPM_CCR_H2DIV);
|
||||
case X1000_CLK_PCLK: return ccr_get(BP_CPM_CCR_SEL_H2PLL, BP_CPM_CCR_PDIV);
|
||||
case X1000_CLK_DDR: return ddr_get();
|
||||
case X1000_CLK_LCD: return lcd_get();
|
||||
case X1000_CLK_MSC0: return msc_get(0);
|
||||
case X1000_CLK_MSC1: return msc_get(1);
|
||||
case X1000_CLK_I2S_MCLK: return i2s_mclk_get();
|
||||
case X1000_CLK_I2S_BCLK: return i2s_bclk_get();
|
||||
case X1000_CLK_SFC: return sfc_get();
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char* clk_get_name(x1000_clk_t clk)
|
||||
{
|
||||
switch(clk) {
|
||||
#define CASE(x) case X1000_CLK_##x: return #x
|
||||
CASE(EXCLK);
|
||||
CASE(APLL);
|
||||
CASE(MPLL);
|
||||
CASE(SCLK_A);
|
||||
CASE(CPU);
|
||||
CASE(L2CACHE);
|
||||
CASE(AHB0);
|
||||
CASE(AHB2);
|
||||
CASE(PCLK);
|
||||
CASE(DDR);
|
||||
CASE(LCD);
|
||||
CASE(MSC0);
|
||||
CASE(MSC1);
|
||||
CASE(I2S_MCLK);
|
||||
CASE(I2S_BCLK);
|
||||
CASE(SFC);
|
||||
#undef CASE
|
||||
default:
|
||||
return "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
#define CCR_MUX_BITS jz_orm(CPM_CCR, SEL_SRC, SEL_CPLL, SEL_H0PLL, SEL_H2PLL)
|
||||
#define CSR_MUX_BITS jz_orm(CPM_CSR, SRC_MUX, CPU_MUX, AHB0_MUX, AHB2_MUX)
|
||||
#define CSR_DIV_BITS jz_orm(CPM_CSR, H2DIV_BUSY, H0DIV_BUSY, CDIV_BUSY)
|
||||
|
||||
void clk_set_ccr_mux(uint32_t muxbits)
|
||||
{
|
||||
/* Set new mux configuration */
|
||||
uint32_t reg = REG_CPM_CCR;
|
||||
reg &= ~CCR_MUX_BITS;
|
||||
reg |= muxbits & CCR_MUX_BITS;
|
||||
REG_CPM_CCR = reg;
|
||||
|
||||
/* Wait for mux change to complete */
|
||||
while((REG_CPM_CSR & CSR_MUX_BITS) != CSR_MUX_BITS);
|
||||
}
|
||||
|
||||
void clk_set_ccr_div(int cpu, int l2, int ahb0, int ahb2, int pclk)
|
||||
{
|
||||
/* Set new divider configuration */
|
||||
jz_writef(CPM_CCR, CDIV(cpu - 1), L2DIV(l2 - 1),
|
||||
H0DIV(ahb0 - 1), H2DIV(ahb2 - 1), PDIV(pclk - 1),
|
||||
CE_CPU(1), CE_AHB0(1), CE_AHB2(1));
|
||||
|
||||
/* Wait until divider change completes */
|
||||
while(REG_CPM_CSR & CSR_DIV_BITS);
|
||||
|
||||
/* Disable CE bits after change */
|
||||
jz_writef(CPM_CCR, CE_CPU(0), CE_AHB0(0), CE_AHB2(0));
|
||||
}
|
||||
|
||||
void clk_set_ddr(x1000_clk_t src, uint32_t div)
|
||||
{
|
||||
/* Write new configuration */
|
||||
jz_writef(CPM_DDRCDR, CE(1), CLKDIV(div - 1),
|
||||
CLKSRC(src == X1000_CLK_MPLL ? 2 : 1));
|
||||
|
||||
/* Wait until mux and divider change are complete */
|
||||
while(jz_readf(CPM_CSR, DDR_MUX) == 0);
|
||||
while(jz_readf(CPM_DDRCDR, BUSY));
|
||||
|
||||
/* Disable CE bit after change */
|
||||
jz_writef(CPM_DDRCDR, CE(0));
|
||||
}
|
82
firmware/target/mips/ingenic_x1000/clk-x1000.h
Normal file
82
firmware/target/mips/ingenic_x1000/clk-x1000.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __CLK_X1000_H__
|
||||
#define __CLK_X1000_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "x1000/cpm.h"
|
||||
|
||||
/* Used as arguments to clk_set_ccr_mux() */
|
||||
#define CLKMUX_SCLK_A(x) jz_orf(CPM_CCR, SEL_SRC_V(x))
|
||||
#define CLKMUX_CPU(x) jz_orf(CPM_CCR, SEL_CPLL_V(x))
|
||||
#define CLKMUX_AHB0(x) jz_orf(CPM_CCR, SEL_H0PLL_V(x))
|
||||
#define CLKMUX_AHB2(x) jz_orf(CPM_CCR, SEL_H2PLL_V(x))
|
||||
|
||||
typedef enum x1000_clk_t {
|
||||
X1000_CLK_EXCLK,
|
||||
X1000_CLK_APLL,
|
||||
X1000_CLK_MPLL,
|
||||
X1000_CLK_SCLK_A,
|
||||
X1000_CLK_CPU,
|
||||
X1000_CLK_L2CACHE,
|
||||
X1000_CLK_AHB0,
|
||||
X1000_CLK_AHB2,
|
||||
X1000_CLK_PCLK,
|
||||
X1000_CLK_DDR,
|
||||
X1000_CLK_LCD,
|
||||
X1000_CLK_MSC0,
|
||||
X1000_CLK_MSC1,
|
||||
X1000_CLK_I2S_MCLK,
|
||||
X1000_CLK_I2S_BCLK,
|
||||
X1000_CLK_SFC,
|
||||
X1000_CLK_COUNT,
|
||||
} x1000_clk_t;
|
||||
|
||||
/* Calculate the current frequency of a clock */
|
||||
extern uint32_t clk_get(x1000_clk_t clk);
|
||||
|
||||
/* Get the name of a clock for debug purposes */
|
||||
extern const char* clk_get_name(x1000_clk_t clk);
|
||||
|
||||
/* Sets system clock multiplexers */
|
||||
extern void clk_set_ccr_mux(uint32_t muxbits);
|
||||
|
||||
/* Sets system clock dividers */
|
||||
extern void clk_set_ccr_div(int cpu, int l2, int ahb0, int ahb2, int pclk);
|
||||
|
||||
/* Sets DDR clock source and divider */
|
||||
extern void clk_set_ddr(x1000_clk_t src, uint32_t div);
|
||||
|
||||
/* Returns the smallest n such that infreq/n <= outfreq */
|
||||
inline uint32_t clk_calc_div(uint32_t infreq, uint32_t outfreq)
|
||||
{
|
||||
return (infreq + (outfreq - 1)) / outfreq;
|
||||
}
|
||||
|
||||
/* Returns the smallest n such that (infreq >> n) <= outfreq */
|
||||
inline uint32_t clk_calc_shift(uint32_t infreq, uint32_t outfreq)
|
||||
{
|
||||
uint32_t div = clk_calc_div(infreq, outfreq);
|
||||
return __builtin_clz(div) ^ 31;
|
||||
}
|
||||
|
||||
#endif /* __CLK_X1000_H__ */
|
265
firmware/target/mips/ingenic_x1000/crt0.S
Normal file
265
firmware/target/mips/ingenic_x1000/crt0.S
Normal file
|
@ -0,0 +1,265 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "mips.h"
|
||||
|
||||
.text
|
||||
.extern main
|
||||
.global _start
|
||||
|
||||
.set push
|
||||
.set mips32
|
||||
.set noreorder
|
||||
.set noat
|
||||
|
||||
.section .init.text
|
||||
|
||||
_start:
|
||||
/* Clear data watchpoint */
|
||||
mtc0 zero, C0_WATCHLO
|
||||
mtc0 zero, C0_WATCHHI
|
||||
|
||||
/* Set BEV, ERL, mask interrupts */
|
||||
li v0, 0x40fc04
|
||||
mtc0 v0, C0_Status
|
||||
|
||||
/* Set Cause_IV to 1 (use special interrupt vector) */
|
||||
li v0, M_CauseIV
|
||||
mtc0 v0, C0_Cause
|
||||
|
||||
/* Set CPU_MODE and BUS_MODE to 1 in CPM_OPCR (Ingenic does this) */
|
||||
lui v0, 0xb000
|
||||
lw v1, 0x24(v0)
|
||||
ori v1, v1, 0x22
|
||||
sw v1, 0x24(v0)
|
||||
|
||||
/* Enable kseg0 cacheability */
|
||||
li v0, 3
|
||||
mtc0 v0, C0_Config
|
||||
nop
|
||||
|
||||
/* According to ingenic: "enable idx-store-data cache insn" */
|
||||
li v0, 0x20000000
|
||||
mtc0 v0, C0_ErrCtl
|
||||
|
||||
/* Cache init */
|
||||
li v0, 0x80000000
|
||||
ori v1, v0, 0x4000
|
||||
mtc0 zero, C0_TAGLO
|
||||
mtc0 zero, C0_TAGHI
|
||||
_cache_loop:
|
||||
cache ICIndexStTag, 0(v0)
|
||||
cache DCIndexStTag, 0(v0)
|
||||
addiu v0, v0, 32
|
||||
bne v0, v1, _cache_loop
|
||||
nop
|
||||
|
||||
/* Invalidate BTB */
|
||||
mfc0 v0, C0_Config, 7
|
||||
nop
|
||||
ori v0, v0, 2
|
||||
mtc0 v0, C0_Config, 7
|
||||
nop
|
||||
|
||||
#ifndef BOOTLOADER_SPL
|
||||
/* Copy IRAM from BSS to low memory. */
|
||||
la t0, _iramcopy
|
||||
la t1, _iramstart
|
||||
la t2, _iramend
|
||||
_iram_loop:
|
||||
lw t3, 0(t0)
|
||||
addiu t1, 4
|
||||
addiu t0, 4
|
||||
bne t1, t2, _iram_loop
|
||||
sw t3, -4(t1)
|
||||
#endif
|
||||
|
||||
/* Clear the BSS segment (needed to zero-initialize C static values) */
|
||||
la t0, _bssbegin
|
||||
la t1, _bssend
|
||||
beq t0, t1, _bss_done
|
||||
_bss_loop:
|
||||
addiu t0, 4
|
||||
bne t0, t1, _bss_loop
|
||||
sw zero, -4(t0)
|
||||
_bss_done:
|
||||
|
||||
#ifndef BOOTLOADER_SPL
|
||||
/* Set stack pointer and clear the stack */
|
||||
la sp, stackend
|
||||
la t0, stackbegin
|
||||
li t1, 0xDEADBEEF
|
||||
_stack_loop:
|
||||
addiu t0, 4
|
||||
bne t0, sp, _stack_loop
|
||||
sw t1, -4(t0)
|
||||
|
||||
/* Clear the IRQ stack */
|
||||
la k0, _irqstackend
|
||||
la t0, _irqstackbegin
|
||||
_irqstack_loop:
|
||||
addiu t0, 4
|
||||
bne t0, k0, _irqstack_loop
|
||||
sw t1, -4(t0)
|
||||
#endif
|
||||
|
||||
/* Jump to C code */
|
||||
j main
|
||||
nop
|
||||
|
||||
#ifndef BOOTLOADER_SPL
|
||||
/* Exception entry points */
|
||||
.section .vectors.1, "ax", %progbits
|
||||
j tlb_refill_handler
|
||||
nop
|
||||
|
||||
.section .vectors.2, "ax", %progbits
|
||||
j real_exception_handler
|
||||
nop
|
||||
|
||||
.section .vectors.3, "ax", %progbits
|
||||
j real_exception_handler
|
||||
nop
|
||||
|
||||
.section .vectors.4, "ax", %progbits
|
||||
j real_exception_handler
|
||||
nop
|
||||
|
||||
.section .vectors, "ax", %progbits
|
||||
real_exception_handler:
|
||||
move k0, sp
|
||||
la sp, _irqstackend
|
||||
addiu sp, -0x84
|
||||
sw k0, 0x80(sp)
|
||||
sw ra, 0x00(sp)
|
||||
sw fp, 0x04(sp)
|
||||
sw gp, 0x08(sp)
|
||||
sw t9, 0x0c(sp)
|
||||
sw t8, 0x10(sp)
|
||||
sw s7, 0x14(sp)
|
||||
sw s6, 0x18(sp)
|
||||
sw s5, 0x1c(sp)
|
||||
sw s4, 0x20(sp)
|
||||
sw s3, 0x24(sp)
|
||||
sw s2, 0x28(sp)
|
||||
sw s1, 0x2c(sp)
|
||||
sw s0, 0x30(sp)
|
||||
sw t7, 0x34(sp)
|
||||
sw t6, 0x38(sp)
|
||||
sw t5, 0x3c(sp)
|
||||
sw t4, 0x40(sp)
|
||||
sw t3, 0x44(sp)
|
||||
sw t2, 0x48(sp)
|
||||
sw t1, 0x4c(sp)
|
||||
sw t0, 0x50(sp)
|
||||
sw a3, 0x54(sp)
|
||||
sw a2, 0x58(sp)
|
||||
sw a1, 0x5c(sp)
|
||||
sw a0, 0x60(sp)
|
||||
sw v1, 0x64(sp)
|
||||
sw v0, 0x68(sp)
|
||||
sw $1, 0x6c(sp)
|
||||
mflo k0
|
||||
nop
|
||||
sw k0, 0x70(sp)
|
||||
mfhi k0
|
||||
nop
|
||||
sw k0, 0x74(sp)
|
||||
mfc0 k0, C0_STATUS
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
sw k0, 0x78(sp)
|
||||
mfc0 k0, C0_EPC
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
sw k0, 0x7c(sp)
|
||||
|
||||
li k1, M_CauseExcCode
|
||||
mfc0 a0, C0_CAUSE
|
||||
and k0, a0, k1
|
||||
bnez k0, _exception
|
||||
nop
|
||||
jal intr_handler
|
||||
nop
|
||||
j _exception_return
|
||||
|
||||
_exception:
|
||||
mfc0 a1, C0_EPC
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jal exception_handler
|
||||
move a2, sp
|
||||
|
||||
_exception_return:
|
||||
lw ra, 0x00(sp)
|
||||
lw fp, 0x04(sp)
|
||||
lw gp, 0x08(sp)
|
||||
lw t9, 0x0c(sp)
|
||||
lw t8, 0x10(sp)
|
||||
lw s7, 0x14(sp)
|
||||
lw s6, 0x18(sp)
|
||||
lw s5, 0x1c(sp)
|
||||
lw s4, 0x20(sp)
|
||||
lw s3, 0x24(sp)
|
||||
lw s2, 0x28(sp)
|
||||
lw s1, 0x2c(sp)
|
||||
lw s0, 0x30(sp)
|
||||
lw t7, 0x34(sp)
|
||||
lw t6, 0x38(sp)
|
||||
lw t5, 0x3c(sp)
|
||||
lw t4, 0x40(sp)
|
||||
lw t3, 0x44(sp)
|
||||
lw t2, 0x48(sp)
|
||||
lw t1, 0x4c(sp)
|
||||
lw t0, 0x50(sp)
|
||||
lw a3, 0x54(sp)
|
||||
lw a2, 0x58(sp)
|
||||
lw a1, 0x5c(sp)
|
||||
lw a0, 0x60(sp)
|
||||
lw v1, 0x64(sp)
|
||||
lw v0, 0x68(sp)
|
||||
lw $1, 0x6c(sp)
|
||||
lw k0, 0x70(sp)
|
||||
mtlo k0
|
||||
nop
|
||||
lw k0, 0x74(sp)
|
||||
mthi k0
|
||||
nop
|
||||
lw k0, 0x78(sp)
|
||||
mtc0 k0, C0_STATUS
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
lw k0, 0x7c(sp)
|
||||
mtc0 k0, C0_EPC
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
lw sp, 0x80(sp)
|
||||
eret
|
||||
nop
|
||||
#endif
|
||||
|
||||
.set pop
|
215
firmware/target/mips/ingenic_x1000/debug-x1000.c
Normal file
215
firmware/target/mips/ingenic_x1000/debug-x1000.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 BOOTLOADER
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "button.h"
|
||||
#include "lcd.h"
|
||||
#include "font.h"
|
||||
#include "action.h"
|
||||
#include "list.h"
|
||||
|
||||
#include "clk-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
|
||||
static bool dbg_clocks(void)
|
||||
{
|
||||
do {
|
||||
lcd_clear_display();
|
||||
int line = 0;
|
||||
for(int i = 0; i < X1000_CLK_COUNT; ++i) {
|
||||
uint32_t hz = clk_get(i);
|
||||
uint32_t khz = hz / 1000;
|
||||
uint32_t mhz = khz / 1000;
|
||||
lcd_putsf(2, line++, "%8s %4u,%03u,%03u Hz", clk_get_name(i),
|
||||
mhz, (khz - mhz*1000), (hz - khz*1000));
|
||||
}
|
||||
|
||||
lcd_update();
|
||||
} while(get_action(CONTEXT_STD, HZ) != ACTION_STD_CANCEL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dbg_gpios_show_state(void)
|
||||
{
|
||||
const char portname[] = "ABCD";
|
||||
for(int i = 0; i < 4; ++i)
|
||||
lcd_putsf(0, i, "GPIO %c: %08x", portname[i], REG_GPIO_PIN(i));
|
||||
}
|
||||
|
||||
static void dbg_gpios_show_config(void)
|
||||
{
|
||||
const char portname[] = "ABCD";
|
||||
int line = 0;
|
||||
for(int i = 0; i < 4; ++i) {
|
||||
uint32_t intr = REG_GPIO_INT(i);
|
||||
uint32_t mask = REG_GPIO_MSK(i);
|
||||
uint32_t pat0 = REG_GPIO_PAT0(i);
|
||||
uint32_t pat1 = REG_GPIO_PAT1(i);
|
||||
lcd_putsf(0, line++, "GPIO %c", portname[i]);
|
||||
lcd_putsf(2, line++, " int %08lx", intr);
|
||||
lcd_putsf(2, line++, " msk %08lx", mask);
|
||||
lcd_putsf(2, line++, "pat0 %08lx", pat0);
|
||||
lcd_putsf(2, line++, "pat1 %08lx", pat1);
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
static bool dbg_gpios(void)
|
||||
{
|
||||
enum { STATE, CONFIG, NUM_SCREENS };
|
||||
const int timeouts[NUM_SCREENS] = { 1, HZ };
|
||||
int screen = STATE;
|
||||
|
||||
while(1) {
|
||||
lcd_clear_display();
|
||||
switch(screen) {
|
||||
case CONFIG:
|
||||
dbg_gpios_show_config();
|
||||
break;
|
||||
case STATE:
|
||||
dbg_gpios_show_state();
|
||||
break;
|
||||
}
|
||||
|
||||
lcd_update();
|
||||
|
||||
switch(get_action(CONTEXT_STD, timeouts[screen])) {
|
||||
case ACTION_STD_CANCEL:
|
||||
return false;
|
||||
case ACTION_STD_PREV:
|
||||
case ACTION_STD_PREVREPEAT:
|
||||
screen -= 1;
|
||||
if(screen < 0)
|
||||
screen = NUM_SCREENS - 1;
|
||||
break;
|
||||
case ACTION_STD_NEXT:
|
||||
case ACTION_STD_NEXTREPEAT:
|
||||
screen += 1;
|
||||
if(screen >= NUM_SCREENS)
|
||||
screen = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern volatile unsigned aic_tx_underruns;
|
||||
|
||||
static bool dbg_audio(void)
|
||||
{
|
||||
do {
|
||||
lcd_clear_display();
|
||||
lcd_putsf(0, 0, "TX underruns: %u", aic_tx_underruns);
|
||||
lcd_update();
|
||||
} while(get_action(CONTEXT_STD, HZ) != ACTION_STD_CANCEL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool dbg_cpuidle(void)
|
||||
{
|
||||
do {
|
||||
lcd_clear_display();
|
||||
lcd_putsf(0, 0, "CPU idle time: %d.%01d%%",
|
||||
__cpu_idle_cur/10, __cpu_idle_cur%10);
|
||||
lcd_putsf(0, 1, "CPU frequency: %d.%03d MHz",
|
||||
FREQ/1000000, (FREQ%1000000)/1000);
|
||||
lcd_update();
|
||||
} while(get_action(CONTEXT_STD, HZ) != ACTION_STD_CANCEL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FIIO_M3K
|
||||
extern bool dbg_fiiom3k_touchpad(void);
|
||||
extern bool axp173_debug_menu(void);
|
||||
#endif
|
||||
|
||||
/* Menu definition */
|
||||
static const struct {
|
||||
const char* name;
|
||||
bool(*function)(void);
|
||||
} menuitems[] = {
|
||||
{"Clocks", &dbg_clocks},
|
||||
{"GPIOs", &dbg_gpios},
|
||||
{"CPU idle", &dbg_cpuidle},
|
||||
{"Audio", &dbg_audio},
|
||||
#ifdef FIIO_M3K
|
||||
{"Touchpad", &dbg_fiiom3k_touchpad},
|
||||
{"Power stats", &axp173_debug_menu},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int hw_info_menu_action_cb(int btn, struct gui_synclist* lists)
|
||||
{
|
||||
if(btn == ACTION_STD_OK) {
|
||||
int sel = gui_synclist_get_sel_pos(lists);
|
||||
FOR_NB_SCREENS(i)
|
||||
viewportmanager_theme_enable(i, false, NULL);
|
||||
|
||||
lcd_setfont(FONT_SYSFIXED);
|
||||
lcd_set_foreground(LCD_WHITE);
|
||||
lcd_set_background(LCD_BLACK);
|
||||
|
||||
if(menuitems[sel].function())
|
||||
btn = SYS_USB_CONNECTED;
|
||||
else
|
||||
btn = ACTION_REDRAW;
|
||||
|
||||
lcd_setfont(FONT_UI);
|
||||
|
||||
FOR_NB_SCREENS(i)
|
||||
viewportmanager_theme_undo(i, false);
|
||||
}
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
static const char* hw_info_menu_get_name(int item, void* data,
|
||||
char* buffer, size_t buffer_len)
|
||||
{
|
||||
(void)buffer;
|
||||
(void)buffer_len;
|
||||
(void)data;
|
||||
return menuitems[item].name;
|
||||
}
|
||||
|
||||
bool dbg_hw_info(void)
|
||||
{
|
||||
struct simplelist_info info;
|
||||
simplelist_info_init(&info, MODEL_NAME " debug menu",
|
||||
ARRAYLEN(menuitems), NULL);
|
||||
info.action_callback = hw_info_menu_action_cb;
|
||||
info.get_name = hw_info_menu_get_name;
|
||||
return simplelist_show_list(&info);
|
||||
}
|
||||
|
||||
bool dbg_ports(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
91
firmware/target/mips/ingenic_x1000/dma-x1000.c
Normal file
91
firmware/target/mips/ingenic_x1000/dma-x1000.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "dma-x1000.h"
|
||||
#include "irq-x1000.h"
|
||||
#include "x1000/cpm.h"
|
||||
#include "panic.h"
|
||||
|
||||
static dma_cb_func dma_callbacks[DMA_NUM_USED_CHANNELS];
|
||||
|
||||
static void dma_no_cb(int event)
|
||||
{
|
||||
(void)event;
|
||||
panicf("Unhandled DMA channel interrupt");
|
||||
}
|
||||
|
||||
void dma_init(void)
|
||||
{
|
||||
for(int i = 0; i < DMA_NUM_USED_CHANNELS; ++i)
|
||||
dma_callbacks[i] = dma_no_cb;
|
||||
|
||||
jz_writef(CPM_CLKGR, PDMA(0));
|
||||
jz_writef(DMA_CTRL, ENABLE(1), HALT(0), AR(0));
|
||||
jz_writef(DMA_CTRL, FMSC(1), FSSI(1), FTSSI(1), FUART(1), FAIC(1));
|
||||
system_enable_irq(IRQ_PDMA);
|
||||
system_enable_irq(IRQ_PDMAD);
|
||||
}
|
||||
|
||||
void dma_set_callback(int chn, dma_cb_func cb)
|
||||
{
|
||||
dma_callbacks[chn] = cb != NULL ? cb : dma_no_cb;
|
||||
}
|
||||
|
||||
void PDMA(void)
|
||||
{
|
||||
/* This is called when the last descriptor completes, or if the
|
||||
* channel hits an error.
|
||||
*/
|
||||
unsigned pending = REG_DMA_IRQP;
|
||||
for(int i = 0; i < DMA_NUM_USED_CHANNELS; ++i) {
|
||||
if((pending & (1 << i)) == 0)
|
||||
continue;
|
||||
|
||||
int evt;
|
||||
if(REG_DMA_CHN_CS(i) & jz_orm(DMA_CHN_CS, AR, HLT))
|
||||
evt = DMA_EVENT_ERROR;
|
||||
else
|
||||
evt = DMA_EVENT_COMPLETE;
|
||||
|
||||
REG_DMA_CHN_CS(i) = 0;
|
||||
dma_callbacks[i](evt);
|
||||
}
|
||||
|
||||
/* Clear any errors and clear interrupts */
|
||||
jz_writef(DMA_CTRL, HALT(0), AR(0));
|
||||
REG_DMA_IRQP = 0;
|
||||
}
|
||||
|
||||
void PDMAD(void)
|
||||
{
|
||||
/* Called when TIE is set on a non-final descriptor */
|
||||
unsigned pending = REG_DMA_DIP;
|
||||
for(int i = 0; i < DMA_NUM_USED_CHANNELS; ++i) {
|
||||
if((pending & (1 << i)) == 0)
|
||||
continue;
|
||||
|
||||
dma_callbacks[i](DMA_EVENT_INTERRUPT);
|
||||
}
|
||||
|
||||
/* This does not operate like other clear registers */
|
||||
REG_DMA_DIC &= ~pending;
|
||||
}
|
69
firmware/target/mips/ingenic_x1000/dma-x1000.h
Normal file
69
firmware/target/mips/ingenic_x1000/dma-x1000.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __DMA_X1000_H__
|
||||
#define __DMA_X1000_H__
|
||||
|
||||
#include "x1000/dma.h"
|
||||
#include "x1000/dma_chn.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Events passed to DMA callbacks */
|
||||
#define DMA_EVENT_NONE 0 /* Not used by DMA code but can be used as
|
||||
* a sentinel value to indicate "no event" */
|
||||
#define DMA_EVENT_INTERRUPT 1 /* Interrupt on a non-final descriptor */
|
||||
#define DMA_EVENT_COMPLETE 2 /* Completed the final descriptor */
|
||||
#define DMA_EVENT_ERROR 3 /* Some kind of error occurred */
|
||||
|
||||
/* All DMA channels which use interrupts must be statically defined here.
|
||||
* The channel numbering should be contiguous, and lower channel numbers
|
||||
* will have lower interrupt latency because they're serviced first.
|
||||
*
|
||||
* Channels >= DMA_NUM_USED_CHANNELS will NOT have interrupts serviced!
|
||||
* Due to the possibility of address error interrupts that can occur even
|
||||
* if no interrupts are requested on the channel, the unallocated channels
|
||||
* cannot be used safely.
|
||||
*/
|
||||
#define DMA_CHANNEL_AUDIO 0
|
||||
#define DMA_CHANNEL_FBCOPY 1
|
||||
#define DMA_NUM_USED_CHANNELS 2
|
||||
|
||||
struct dma_desc {
|
||||
uint32_t cm; /* meaning and layout same as DMA_CHN_CM */
|
||||
uint32_t sa; /* source address */
|
||||
uint32_t ta; /* target address */
|
||||
uint32_t tc; /* low 24 bits: transfer count
|
||||
* upper 8 bits: offset to next descriptor
|
||||
*/
|
||||
uint32_t sd; /* same as DMA_CHN_SD */
|
||||
uint32_t rt; /* request type, same as DMA_CHN_RT */
|
||||
uint32_t pad0;
|
||||
uint32_t pad1;
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
typedef struct dma_desc dma_desc;
|
||||
|
||||
typedef void(*dma_cb_func)(int event);
|
||||
|
||||
extern void dma_init(void);
|
||||
extern void dma_set_callback(int chn, dma_cb_func cb);
|
||||
|
||||
#endif /* __DMA_X1000_H__ */
|
0
firmware/target/mips/ingenic_x1000/fiiom3k/adc-target.h
Normal file
0
firmware/target/mips/ingenic_x1000/fiiom3k/adc-target.h
Normal file
81
firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c
Normal file
81
firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "audiohw.h"
|
||||
#include "system.h"
|
||||
#include "pcm_sampr.h"
|
||||
#include "logf.h"
|
||||
#include "aic-x1000.h"
|
||||
#include "i2c-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "x1000/aic.h"
|
||||
#include "x1000/cpm.h"
|
||||
|
||||
void audiohw_init(void)
|
||||
{
|
||||
/* Configure AIC for I2S operation */
|
||||
jz_writef(CPM_CLKGR, AIC(0));
|
||||
gpio_config(GPIO_B, 0x1f, GPIO_DEVICE(1));
|
||||
jz_writef(AIC_I2SCR, STPBK(1));
|
||||
|
||||
/* Operate as I2S master, use external codec */
|
||||
jz_writef(AIC_CFG, AUSEL(1), ICDC(0), BCKD(1), SYNCD(1), LSMP(1));
|
||||
jz_writef(AIC_I2SCR, ESCLK(1), AMSL(0));
|
||||
|
||||
/* Stereo audio, packed 16 bit samples */
|
||||
jz_writef(AIC_CCR, PACK16(1), CHANNEL(1), OSS(1));
|
||||
|
||||
/* Initialize DAC */
|
||||
i2c_x1000_set_freq(AK4376_BUS, I2C_FREQ_400K);
|
||||
ak4376_init();
|
||||
}
|
||||
|
||||
void audiohw_postinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
void audiohw_close(void)
|
||||
{
|
||||
ak4376_close();
|
||||
}
|
||||
|
||||
void ak4376_set_pdn_pin(int level)
|
||||
{
|
||||
gpio_config(GPIO_A, 1 << 16, GPIO_OUTPUT(level ? 1 : 0));
|
||||
}
|
||||
|
||||
int ak4376_set_mclk_freq(int hw_freq, bool enabled)
|
||||
{
|
||||
/* Get the multiplier */
|
||||
int freq = hw_freq_sampr[hw_freq];
|
||||
int mult = freq >= SAMPR_176 ? 128 : 256;
|
||||
|
||||
if(enabled) {
|
||||
/* Set the new frequency; clock is enabled afterward */
|
||||
if(aic_i2s_set_mclk(X1000_CLK_SCLK_A, freq, mult))
|
||||
logf("WARNING: unachievable audio rate %d x %d!?", freq, mult);
|
||||
} else {
|
||||
/* Shut off the clock */
|
||||
jz_writef(AIC_I2SCR, STPBK(1));
|
||||
}
|
||||
|
||||
return mult;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "backlight.h"
|
||||
#include "backlight-target.h"
|
||||
#include "lcd.h"
|
||||
#include "pwm-x1000.h"
|
||||
|
||||
#define BL_LCD_CHN 0
|
||||
#define BL_LCD_PERIOD 33000
|
||||
|
||||
#define BL_BTN_CHN 4
|
||||
#define BL_BTN_PERIOD 100000
|
||||
|
||||
static int backlight_calc_duty(int period, int min_duty, int brightness)
|
||||
{
|
||||
return min_duty + (period - min_duty) * brightness / MAX_BRIGHTNESS_SETTING;
|
||||
}
|
||||
|
||||
bool backlight_hw_init(void)
|
||||
{
|
||||
pwm_init(BL_LCD_CHN);
|
||||
pwm_init(BL_BTN_CHN);
|
||||
pwm_enable(BL_LCD_CHN);
|
||||
pwm_enable(BL_BTN_CHN);
|
||||
backlight_hw_brightness(MAX_BRIGHTNESS_SETTING);
|
||||
buttonlight_hw_brightness(MAX_BRIGHTNESS_SETTING);
|
||||
/* TODO: avoid buttonlight flicker when powering up the machine */
|
||||
return true;
|
||||
}
|
||||
|
||||
void backlight_hw_on(void)
|
||||
{
|
||||
pwm_enable(BL_LCD_CHN);
|
||||
#ifdef HAVE_LCD_ENABLE
|
||||
lcd_enable(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void backlight_hw_off(void)
|
||||
{
|
||||
pwm_disable(BL_LCD_CHN);
|
||||
#ifdef HAVE_LCD_ENABLE
|
||||
lcd_enable(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void backlight_hw_brightness(int brightness)
|
||||
{
|
||||
int duty_ns = backlight_calc_duty(BL_LCD_PERIOD, 0, brightness);
|
||||
pwm_set_period(BL_LCD_CHN, BL_LCD_PERIOD, duty_ns);
|
||||
}
|
||||
|
||||
void buttonlight_hw_on(void)
|
||||
{
|
||||
pwm_enable(BL_BTN_CHN);
|
||||
}
|
||||
|
||||
void buttonlight_hw_off(void)
|
||||
{
|
||||
pwm_disable(BL_BTN_CHN);
|
||||
}
|
||||
|
||||
void buttonlight_hw_brightness(int brightness)
|
||||
{
|
||||
/* Duty cycle below 11% seems to turn the buttonlight off entirely,
|
||||
* so we need to rescale the range */
|
||||
int duty_ns = backlight_calc_duty(BL_BTN_PERIOD, BL_BTN_PERIOD*11/100, brightness);
|
||||
pwm_set_period(BL_BTN_CHN, BL_BTN_PERIOD, duty_ns);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __BACKLIGHT_TARGET_H__
|
||||
#define __BACKLIGHT_TARGET_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern bool backlight_hw_init(void);
|
||||
|
||||
extern void backlight_hw_on(void);
|
||||
extern void backlight_hw_off(void);
|
||||
extern void backlight_hw_brightness(int brightness);
|
||||
|
||||
extern void buttonlight_hw_on(void);
|
||||
extern void buttonlight_hw_off(void);
|
||||
extern void buttonlight_hw_brightness(int brightness);
|
||||
|
||||
#endif /* __BACKLIGHT_TARGET_H__ */
|
503
firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
Normal file
503
firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
Normal file
|
@ -0,0 +1,503 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "button.h"
|
||||
#include "kernel.h"
|
||||
#include "backlight.h"
|
||||
#include "panic.h"
|
||||
#include "lcd.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "i2c-x1000.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
# include "font.h"
|
||||
#endif
|
||||
|
||||
#define FT_RST_PIN (1 << 15)
|
||||
#define FT_INT_PIN (1 << 12)
|
||||
#define ft_interrupt GPIOB12
|
||||
|
||||
/* Touch event types */
|
||||
#define EVENT_NONE (-1)
|
||||
#define EVENT_PRESS 0
|
||||
#define EVENT_RELEASE 1
|
||||
#define EVENT_CONTACT 2
|
||||
|
||||
/* FSM states */
|
||||
#define STATE_IDLE 0
|
||||
#define STATE_PRESS 1
|
||||
#define STATE_REPORT 2
|
||||
#define STATE_SCROLL_PRESS 3
|
||||
#define STATE_SCROLLING 4
|
||||
|
||||
/* Assume there's no active touch if no event is reported in this time */
|
||||
#define AUTORELEASE_TIME (10000 * OST_TICKS_PER_US)
|
||||
|
||||
/* If there's no significant motion on the scrollbar for this time,
|
||||
* then report it as a button press instead */
|
||||
#define SCROLL_PRESS_TIME (100000 * OST_TICKS_PER_US)
|
||||
|
||||
/* If a press on the scrollbar moves more than this during SCROLL_PRESS_TIME,
|
||||
* then we enter scrolling mode. */
|
||||
#define MIN_SCROLL_THRESH 15
|
||||
|
||||
/* If OST tick a is after OST tick b, then returns the number of ticks
|
||||
* in the interval between a and b; otherwise undefined. */
|
||||
#define TICKS_SINCE(a, b) ((a) - (b))
|
||||
|
||||
/* Number of touch samples to smooth before reading */
|
||||
#define TOUCH_SAMPLES 3
|
||||
|
||||
static struct ft_driver {
|
||||
int i2c_cookie;
|
||||
i2c_descriptor i2c_desc;
|
||||
uint8_t raw_data[6];
|
||||
bool active;
|
||||
|
||||
/* Number of pixels squared which must be moved before
|
||||
* a scrollbar pulse is generated */
|
||||
int scroll_thresh_sqr;
|
||||
} ftd;
|
||||
|
||||
static struct ft_state_machine {
|
||||
/* Current button state, used by button_read_device() */
|
||||
int buttons;
|
||||
|
||||
/* FSM state */
|
||||
int state;
|
||||
|
||||
/* Time of the last touch event, as 32-bit OST timestamp. The kernel
|
||||
* tick is simply too low-resolution to work reliably, especially as
|
||||
* we handle touchpad events asynchronously. */
|
||||
uint32_t last_event_t;
|
||||
|
||||
/* Time of entering the SCROLL_PRESS state, used to differentiate
|
||||
* between a press, hold, or scrolling motion */
|
||||
uint32_t scroll_press_t;
|
||||
|
||||
/* Number of CONTACT events sampled in the PRESS state.
|
||||
* Must reach TOUCH_SAMPLES before we move forward. */
|
||||
int samples;
|
||||
|
||||
/* Filter for smoothing touch points */
|
||||
int sum_x, sum_y;
|
||||
|
||||
/* Position of the original touch */
|
||||
int orig_x, orig_y;
|
||||
|
||||
/* Current touch position */
|
||||
int cur_x, cur_y;
|
||||
} fsm;
|
||||
|
||||
static int touch_to_button(int x, int y)
|
||||
{
|
||||
if(x == 900) {
|
||||
/* Right strip */
|
||||
if(y == 80)
|
||||
return BUTTON_BACK;
|
||||
else if(y == 240)
|
||||
return BUTTON_RIGHT;
|
||||
else
|
||||
return 0;
|
||||
} else if(x < 80) {
|
||||
/* Left strip */
|
||||
if(y < 80)
|
||||
return BUTTON_MENU;
|
||||
else if(y > 190)
|
||||
return BUTTON_LEFT;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
/* Middle strip */
|
||||
if(y < 100)
|
||||
return BUTTON_UP;
|
||||
else if(y > 220)
|
||||
return BUTTON_DOWN;
|
||||
else
|
||||
return BUTTON_SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ft_accum_touch(uint32_t t, int tx, int ty)
|
||||
{
|
||||
/* Record event time */
|
||||
fsm.last_event_t = t;
|
||||
|
||||
if(fsm.samples < TOUCH_SAMPLES) {
|
||||
/* Continue "priming" the filter */
|
||||
fsm.sum_x += tx;
|
||||
fsm.sum_y += ty;
|
||||
fsm.samples += 1;
|
||||
|
||||
/* Return if filter is not ready */
|
||||
if(fsm.samples < TOUCH_SAMPLES)
|
||||
return false;
|
||||
} else {
|
||||
/* Update filter */
|
||||
fsm.sum_x += tx - fsm.sum_x / TOUCH_SAMPLES;
|
||||
fsm.sum_y += ty - fsm.sum_y / TOUCH_SAMPLES;
|
||||
}
|
||||
|
||||
/* Filter is ready, so read the point */
|
||||
fsm.cur_x = fsm.sum_x / TOUCH_SAMPLES;
|
||||
fsm.cur_y = fsm.sum_y / TOUCH_SAMPLES;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ft_go_idle(void)
|
||||
{
|
||||
/* Null out the touch state */
|
||||
fsm.buttons = 0;
|
||||
fsm.samples = 0;
|
||||
fsm.sum_x = fsm.sum_y = 0;
|
||||
fsm.state = STATE_IDLE;
|
||||
}
|
||||
|
||||
static void ft_start_report(void)
|
||||
{
|
||||
/* Report the button bit */
|
||||
fsm.buttons = touch_to_button(fsm.cur_x, fsm.cur_y);
|
||||
fsm.orig_x = fsm.cur_x;
|
||||
fsm.orig_y = fsm.cur_y;
|
||||
fsm.state = STATE_REPORT;
|
||||
}
|
||||
|
||||
static void ft_start_report_or_scroll(void)
|
||||
{
|
||||
ft_start_report();
|
||||
|
||||
/* If the press occurs on the scrollbar, then we need to
|
||||
* wait an additional delay before reporting it in case
|
||||
* this is the beginning of a scrolling motion */
|
||||
if(fsm.buttons & (BUTTON_UP|BUTTON_DOWN|BUTTON_SELECT)) {
|
||||
fsm.buttons = 0;
|
||||
fsm.scroll_press_t = __ost_read32();
|
||||
fsm.state = STATE_SCROLL_PRESS;
|
||||
}
|
||||
}
|
||||
|
||||
static void ft_step_state(uint32_t t, int evt, int tx, int ty)
|
||||
{
|
||||
/* Generate a release event automatically in case we missed it */
|
||||
if(evt == EVENT_NONE) {
|
||||
if(TICKS_SINCE(t, fsm.last_event_t) >= AUTORELEASE_TIME) {
|
||||
evt = EVENT_RELEASE;
|
||||
tx = fsm.cur_x;
|
||||
ty = fsm.cur_y;
|
||||
}
|
||||
}
|
||||
|
||||
switch(fsm.state) {
|
||||
case STATE_IDLE: {
|
||||
if(evt == EVENT_PRESS || evt == EVENT_CONTACT) {
|
||||
/* Move to REPORT or PRESS state */
|
||||
if(ft_accum_touch(t, tx, ty))
|
||||
ft_start_report_or_scroll();
|
||||
else
|
||||
fsm.state = STATE_PRESS;
|
||||
}
|
||||
} break;
|
||||
|
||||
case STATE_PRESS: {
|
||||
if(evt == EVENT_RELEASE) {
|
||||
/* Ignore if the number of samples is too low */
|
||||
ft_go_idle();
|
||||
} else if(evt == EVENT_PRESS || evt == EVENT_CONTACT) {
|
||||
/* Accumulate the touch position in the filter */
|
||||
if(ft_accum_touch(t, tx, ty))
|
||||
ft_start_report_or_scroll();
|
||||
}
|
||||
} break;
|
||||
|
||||
case STATE_REPORT: {
|
||||
if(evt == EVENT_RELEASE)
|
||||
ft_go_idle();
|
||||
else if(evt == EVENT_PRESS || evt == EVENT_CONTACT)
|
||||
ft_accum_touch(t, tx, ty);
|
||||
} break;
|
||||
|
||||
case STATE_SCROLL_PRESS: {
|
||||
if(evt == EVENT_RELEASE) {
|
||||
/* This _should_ synthesize a button press.
|
||||
*
|
||||
* - ft_start_report() will set the button bit based on the
|
||||
* current touch position and enter the REPORT state, which
|
||||
* will automatically hold the bit high
|
||||
*
|
||||
* - The next button_read_device() will see the button bit
|
||||
* and report it back to Rockbox, then step the FSM with
|
||||
* EVENT_NONE.
|
||||
*
|
||||
* - The EVENT_NONE stepping will eventually autogenerate a
|
||||
* RELEASE event and restore the button state back to 0
|
||||
*
|
||||
* - There's a small logic hole in the REPORT state which
|
||||
* could cause it to miss an immediately repeated PRESS
|
||||
* that occurs before the autorelease timeout kicks in.
|
||||
* FIXME: We might want to special-case that.
|
||||
*/
|
||||
ft_start_report();
|
||||
break;
|
||||
}
|
||||
|
||||
if(evt == EVENT_PRESS || evt == EVENT_CONTACT)
|
||||
ft_accum_touch(t, tx, ty);
|
||||
|
||||
int dx = fsm.cur_x - fsm.orig_x;
|
||||
int dy = fsm.cur_y - fsm.orig_y;
|
||||
int dp = (dx*dx) + (dy*dy);
|
||||
if(dp >= MIN_SCROLL_THRESH*MIN_SCROLL_THRESH) {
|
||||
/* Significant motion: enter SCROLLING state */
|
||||
fsm.state = STATE_SCROLLING;
|
||||
} else if(TICKS_SINCE(t, fsm.scroll_press_t) >= SCROLL_PRESS_TIME) {
|
||||
/* No significant motion: report it as a press */
|
||||
fsm.cur_x = fsm.orig_x;
|
||||
fsm.cur_y = fsm.orig_y;
|
||||
ft_start_report();
|
||||
}
|
||||
} break;
|
||||
|
||||
case STATE_SCROLLING: {
|
||||
if(evt == EVENT_RELEASE) {
|
||||
ft_go_idle();
|
||||
break;
|
||||
}
|
||||
|
||||
if(evt == EVENT_PRESS || evt == EVENT_CONTACT)
|
||||
ft_accum_touch(t, tx, ty);
|
||||
|
||||
int dx = fsm.cur_x - fsm.orig_x;
|
||||
int dy = fsm.cur_y - fsm.orig_y;
|
||||
int dp = (dx*dx) + (dy*dy);
|
||||
if(dp >= ftd.scroll_thresh_sqr) {
|
||||
if(dy < 0) {
|
||||
queue_post(&button_queue, BUTTON_SCROLL_BACK, 0);
|
||||
} else {
|
||||
queue_post(&button_queue, BUTTON_SCROLL_FWD, 0);
|
||||
}
|
||||
|
||||
/* Poke the backlight */
|
||||
backlight_on();
|
||||
buttonlight_on();
|
||||
|
||||
fsm.orig_x = fsm.cur_x;
|
||||
fsm.orig_y = fsm.cur_y;
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
panicf("ft6x06: unhandled state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ft_i2c_callback(int status, i2c_descriptor* desc)
|
||||
{
|
||||
(void)desc;
|
||||
if(status != I2C_STATUS_OK)
|
||||
return;
|
||||
|
||||
/* The panel is oriented such that its X axis is vertical,
|
||||
* so swap the axes for reporting */
|
||||
int evt = ftd.raw_data[1] >> 6;
|
||||
int ty = ftd.raw_data[2] | ((ftd.raw_data[1] & 0xf) << 8);
|
||||
int tx = ftd.raw_data[4] | ((ftd.raw_data[3] & 0xf) << 8);
|
||||
|
||||
/* TODO: convert the touch positions to linear positions.
|
||||
*
|
||||
* Points reported by the touch controller are distorted and non-linear,
|
||||
* ideally we'd like to correct these values. There's more precision in
|
||||
* the middle of the touchpad than on the edges, so scrolling feels slow
|
||||
* in the middle and faster near the edge.
|
||||
*/
|
||||
|
||||
ft_step_state(__ost_read32(), evt, tx, ty);
|
||||
}
|
||||
|
||||
void ft_interrupt(void)
|
||||
{
|
||||
/* We don't care if this fails */
|
||||
i2c_async_queue(FT6x06_BUS, TIMEOUT_NOBLOCK, I2C_Q_ONCE,
|
||||
ftd.i2c_cookie, &ftd.i2c_desc);
|
||||
}
|
||||
|
||||
static void ft_init(void)
|
||||
{
|
||||
/* Initialize the driver state */
|
||||
ftd.i2c_cookie = i2c_async_reserve_cookies(FT6x06_BUS, 1);
|
||||
ftd.i2c_desc.slave_addr = FT6x06_ADDR;
|
||||
ftd.i2c_desc.bus_cond = I2C_START | I2C_STOP;
|
||||
ftd.i2c_desc.tran_mode = I2C_READ;
|
||||
ftd.i2c_desc.buffer[0] = &ftd.raw_data[5];
|
||||
ftd.i2c_desc.count[0] = 1;
|
||||
ftd.i2c_desc.buffer[1] = &ftd.raw_data[0];
|
||||
ftd.i2c_desc.count[1] = 5;
|
||||
ftd.i2c_desc.callback = ft_i2c_callback;
|
||||
ftd.i2c_desc.arg = 0;
|
||||
ftd.i2c_desc.next = NULL;
|
||||
ftd.raw_data[5] = 0x02;
|
||||
ftd.active = true;
|
||||
touchpad_set_sensitivity(DEFAULT_TOUCHPAD_SENSITIVITY_SETTING);
|
||||
|
||||
/* Initialize the state machine */
|
||||
fsm.buttons = 0;
|
||||
fsm.state = STATE_IDLE;
|
||||
fsm.last_event_t = 0;
|
||||
fsm.scroll_press_t = 0;
|
||||
fsm.samples = 0;
|
||||
fsm.sum_x = fsm.sum_y = 0;
|
||||
fsm.orig_x = fsm.orig_y = 0;
|
||||
fsm.cur_x = fsm.cur_y = 0;
|
||||
|
||||
/* Bring up I2C bus */
|
||||
i2c_x1000_set_freq(FT6x06_BUS, I2C_FREQ_400K);
|
||||
|
||||
/* Reset chip */
|
||||
gpio_config(GPIO_B, FT_RST_PIN|FT_INT_PIN, GPIO_OUTPUT(0));
|
||||
mdelay(5);
|
||||
gpio_out_level(GPIO_B, FT_RST_PIN, 1);
|
||||
gpio_config(GPIO_B, FT_INT_PIN, GPIO_IRQ_EDGE(0));
|
||||
gpio_enable_irq(GPIO_B, FT_INT_PIN);
|
||||
}
|
||||
|
||||
void touchpad_set_sensitivity(int level)
|
||||
{
|
||||
int pixels = 40;
|
||||
pixels -= level;
|
||||
ftd.scroll_thresh_sqr = pixels * pixels;
|
||||
}
|
||||
|
||||
void touchpad_enable_device(bool en)
|
||||
{
|
||||
i2c_reg_write1(FT6x06_BUS, FT6x06_ADDR, 0xa5, en ? 0 : 3);
|
||||
ftd.active = en;
|
||||
}
|
||||
|
||||
/* Value of headphone detect register */
|
||||
static uint8_t hp_detect_reg = 0x00;
|
||||
|
||||
/* Interval to poll the register */
|
||||
#define HPD_POLL_TIME (HZ/2)
|
||||
|
||||
static int hp_detect_tmo_cb(struct timeout* tmo)
|
||||
{
|
||||
i2c_descriptor* d = (i2c_descriptor*)tmo->data;
|
||||
i2c_async_queue(AXP173_BUS, TIMEOUT_NOBLOCK, I2C_Q_ADD, 0, d);
|
||||
return HPD_POLL_TIME;
|
||||
}
|
||||
|
||||
static void hp_detect_init(void)
|
||||
{
|
||||
static struct timeout tmo;
|
||||
static const uint8_t gpio_reg = 0x94;
|
||||
static i2c_descriptor desc = {
|
||||
.slave_addr = AXP173_ADDR,
|
||||
.bus_cond = I2C_START | I2C_STOP,
|
||||
.tran_mode = I2C_READ,
|
||||
.buffer[0] = (void*)&gpio_reg,
|
||||
.count[0] = 1,
|
||||
.buffer[1] = &hp_detect_reg,
|
||||
.count[1] = 1,
|
||||
.callback = NULL,
|
||||
.arg = 0,
|
||||
.next = NULL,
|
||||
};
|
||||
|
||||
/* Headphone detect is wired to an undocumented GPIO on the AXP173.
|
||||
* This sets it to input mode so we can see the pin state. */
|
||||
i2c_reg_write1(AXP173_BUS, AXP173_ADDR, 0x93, 0x01);
|
||||
|
||||
/* Get an initial reading before startup */
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, gpio_reg);
|
||||
if(r >= 0)
|
||||
hp_detect_reg = r;
|
||||
|
||||
/* Poll the register every second */
|
||||
timeout_register(&tmo, &hp_detect_tmo_cb, HPD_POLL_TIME, (intptr_t)&desc);
|
||||
}
|
||||
|
||||
/* Rockbox interface */
|
||||
void button_init_device(void)
|
||||
{
|
||||
/* Configure physical button GPIOs */
|
||||
gpio_config(GPIO_A, (1 << 17) | (1 << 19), GPIO_INPUT);
|
||||
gpio_config(GPIO_B, (1 << 28) | (1 << 31), GPIO_INPUT);
|
||||
|
||||
/* Initialize touchpad */
|
||||
ft_init();
|
||||
|
||||
/* Set up headphone detect polling */
|
||||
hp_detect_init();
|
||||
}
|
||||
|
||||
int button_read_device(void)
|
||||
{
|
||||
int r = fsm.buttons;
|
||||
ft_step_state(__ost_read32(), EVENT_NONE, 0, 0);
|
||||
|
||||
/* Read GPIOs for physical buttons */
|
||||
uint32_t a = REG_GPIO_PIN(GPIO_A);
|
||||
uint32_t b = REG_GPIO_PIN(GPIO_B);
|
||||
|
||||
/* All buttons are active low */
|
||||
if((a & (1 << 17)) == 0) r |= BUTTON_PLAY;
|
||||
if((a & (1 << 19)) == 0) r |= BUTTON_VOL_UP;
|
||||
if((b & (1 << 28)) == 0) r |= BUTTON_VOL_DOWN;
|
||||
if((b & (1 << 31)) == 0) r |= BUTTON_POWER;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool headphones_inserted()
|
||||
{
|
||||
return hp_detect_reg & 0x40 ? true : false;
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
static int getbtn(void)
|
||||
{
|
||||
int btn;
|
||||
do {
|
||||
btn = button_get_w_tmo(1);
|
||||
} while(btn & (BUTTON_REL|BUTTON_REPEAT));
|
||||
return btn;
|
||||
}
|
||||
|
||||
bool dbg_fiiom3k_touchpad(void)
|
||||
{
|
||||
static const char* fsm_statenames[] = {
|
||||
"IDLE", "PRESS", "REPORT", "SCROLL_PRESS", "SCROLLING"
|
||||
};
|
||||
|
||||
do {
|
||||
int line = 0;
|
||||
lcd_clear_display();
|
||||
lcd_putsf(0, line++, "state: %s", fsm_statenames[fsm.state]);
|
||||
lcd_putsf(0, line++, "button: %08x", fsm.buttons);
|
||||
lcd_putsf(0, line++, "pos x: %4d orig x: %4d", fsm.cur_x, fsm.orig_x);
|
||||
lcd_putsf(0, line++, "pos y: %4d orig y: %4d", fsm.cur_y, fsm.orig_y);
|
||||
lcd_update();
|
||||
} while(getbtn() != BUTTON_POWER);
|
||||
return false;
|
||||
}
|
||||
#endif
|
54
firmware/target/mips/ingenic_x1000/fiiom3k/button-target.h
Normal file
54
firmware/target/mips/ingenic_x1000/fiiom3k/button-target.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __BUTTON_TARGET_H__
|
||||
#define __BUTTON_TARGET_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BUTTON_POWER 0x00000001
|
||||
#define BUTTON_PLAY 0x00000002
|
||||
#define BUTTON_VOL_UP 0x00000004
|
||||
#define BUTTON_VOL_DOWN 0x00000008
|
||||
#define BUTTON_UP 0x00000010
|
||||
#define BUTTON_DOWN 0x00000020
|
||||
#define BUTTON_LEFT 0x00000040
|
||||
#define BUTTON_RIGHT 0x00000080
|
||||
#define BUTTON_SELECT 0x00000100
|
||||
#define BUTTON_BACK 0x00000200
|
||||
#define BUTTON_MENU 0x00000400
|
||||
#define BUTTON_SCROLL_FWD 0x00000800
|
||||
#define BUTTON_SCROLL_BACK 0x00001000
|
||||
|
||||
#define BUTTON_MAIN (BUTTON_POWER|BUTTON_VOL_UP|BUTTON_VOL_DOWN|\
|
||||
BUTTON_PLAY|BUTTON_TOUCHPAD)
|
||||
|
||||
#define BUTTON_TOUCHPAD (BUTTON_UP|BUTTON_DOWN|BUTTON_LEFT|BUTTON_RIGHT|\
|
||||
BUTTON_SELECT|BUTTON_BACK|BUTTON_MENU|\
|
||||
BUTTON_SCROLL_FWD|BUTTON_SCROLL_BACK)
|
||||
|
||||
#define POWEROFF_BUTTON BUTTON_POWER
|
||||
#define POWEROFF_COUNT 30
|
||||
|
||||
extern void touchpad_set_sensitivity(int level);
|
||||
extern void touchpad_enable_device(bool en);
|
||||
|
||||
#endif /* __BUTTON_TARGET_H__ */
|
37
firmware/target/mips/ingenic_x1000/fiiom3k/i2c-target.h
Normal file
37
firmware/target/mips/ingenic_x1000/fiiom3k/i2c-target.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __I2C_TARGET_H__
|
||||
#define __I2C_TARGET_H__
|
||||
|
||||
#define I2C_ASYNC_BUS_COUNT 3
|
||||
#define I2C_ASYNC_QUEUE_SIZE 4
|
||||
|
||||
#define AK4376_BUS 0
|
||||
#define AK4376_ADDR 0x10
|
||||
|
||||
#define FT6x06_BUS 1
|
||||
#define FT6x06_ADDR 0x38
|
||||
|
||||
#define AXP173_BUS 2
|
||||
#define AXP173_ADDR 0x34
|
||||
|
||||
#endif /* __I2C_TARGET_H__ */
|
195
firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
Normal file
195
firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "installer.h"
|
||||
#include "nand-x1000.h"
|
||||
#include "core_alloc.h"
|
||||
#include "file.h"
|
||||
|
||||
#define INSTALL_SUCCESS 0
|
||||
#define ERR_FLASH_OPEN_FAILED (-1)
|
||||
#define ERR_FLASH_ENABLE_WP_FAILED (-2)
|
||||
#define ERR_FLASH_DISABLE_WP_FAILED (-3)
|
||||
#define ERR_FLASH_ERASE_FAILED (-4)
|
||||
#define ERR_FLASH_WRITE_FAILED (-5)
|
||||
#define ERR_FLASH_READ_FAILED (-6)
|
||||
#define ERR_OUT_OF_MEMORY (-7)
|
||||
#define ERR_CANNOT_READ_FILE (-8)
|
||||
#define ERR_CANNOT_WRITE_FILE (-9)
|
||||
#define ERR_WRONG_SIZE (-10)
|
||||
|
||||
#define BOOT_IMAGE_SIZE (128 * 1024)
|
||||
|
||||
static int install_from_buffer(const void* buf)
|
||||
{
|
||||
if(nand_open())
|
||||
return ERR_FLASH_OPEN_FAILED;
|
||||
|
||||
int status = INSTALL_SUCCESS;
|
||||
|
||||
if(nand_enable_writes(true)) {
|
||||
status = ERR_FLASH_DISABLE_WP_FAILED;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if(nand_erase_block(0)) {
|
||||
status = ERR_FLASH_ERASE_FAILED;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if(nand_write_bytes(0, BOOT_IMAGE_SIZE, buf)) {
|
||||
status = ERR_FLASH_WRITE_FAILED;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if(nand_enable_writes(false)) {
|
||||
status = ERR_FLASH_ENABLE_WP_FAILED;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
_exit:
|
||||
nand_close();
|
||||
return status;
|
||||
}
|
||||
|
||||
static int dump_to_buffer(void* buf)
|
||||
{
|
||||
if(nand_open())
|
||||
return ERR_FLASH_OPEN_FAILED;
|
||||
|
||||
int status = INSTALL_SUCCESS;
|
||||
|
||||
if(nand_read_bytes(0, BOOT_IMAGE_SIZE, buf)) {
|
||||
status = ERR_FLASH_READ_FAILED;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
_exit:
|
||||
nand_close();
|
||||
return status;
|
||||
}
|
||||
|
||||
int install_bootloader(const char* path)
|
||||
{
|
||||
/* Allocate memory to hold image */
|
||||
int handle = core_alloc("boot_image", BOOT_IMAGE_SIZE);
|
||||
if(handle < 0)
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
|
||||
int status = INSTALL_SUCCESS;
|
||||
void* buffer = core_get_data(handle);
|
||||
|
||||
/* Open the boot image */
|
||||
int fd = open(path, O_RDONLY);
|
||||
if(fd < 0) {
|
||||
status = ERR_CANNOT_READ_FILE;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* Check file size */
|
||||
off_t fsize = filesize(fd);
|
||||
if(fsize != BOOT_IMAGE_SIZE) {
|
||||
status = ERR_WRONG_SIZE;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* Read the file into the buffer */
|
||||
ssize_t cnt = read(fd, buffer, BOOT_IMAGE_SIZE);
|
||||
if(cnt != BOOT_IMAGE_SIZE) {
|
||||
status = ERR_CANNOT_READ_FILE;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* Perform the installation */
|
||||
status = install_from_buffer(buffer);
|
||||
|
||||
_exit:
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
core_free(handle);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Dump the current bootloader to a file */
|
||||
int dump_bootloader(const char* path)
|
||||
{
|
||||
/* Allocate memory to hold image */
|
||||
int handle = core_alloc("boot_image", BOOT_IMAGE_SIZE);
|
||||
if(handle < 0)
|
||||
return -1;
|
||||
|
||||
/* Read data from flash */
|
||||
int fd = -1;
|
||||
void* buffer = core_get_data(handle);
|
||||
int status = dump_to_buffer(buffer);
|
||||
if(status)
|
||||
goto _exit;
|
||||
|
||||
/* Open file */
|
||||
fd = open(path, O_CREAT|O_TRUNC|O_WRONLY);
|
||||
if(fd < 0) {
|
||||
status = ERR_CANNOT_WRITE_FILE;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* Write data to file */
|
||||
ssize_t cnt = write(fd, buffer, BOOT_IMAGE_SIZE);
|
||||
if(cnt != BOOT_IMAGE_SIZE) {
|
||||
status = ERR_CANNOT_WRITE_FILE;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
_exit:
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
core_free(handle);
|
||||
return status;
|
||||
}
|
||||
|
||||
const char* installer_strerror(int rc)
|
||||
{
|
||||
switch(rc) {
|
||||
case INSTALL_SUCCESS:
|
||||
return "Success";
|
||||
case ERR_FLASH_OPEN_FAILED:
|
||||
return "Can't open flash device";
|
||||
case ERR_FLASH_ENABLE_WP_FAILED:
|
||||
return "Couldn't re-enable write protect";
|
||||
case ERR_FLASH_DISABLE_WP_FAILED:
|
||||
return "Can't disable write protect";
|
||||
case ERR_FLASH_ERASE_FAILED:
|
||||
return "Flash erase failed";
|
||||
case ERR_FLASH_WRITE_FAILED:
|
||||
return "Flash write error";
|
||||
case ERR_FLASH_READ_FAILED:
|
||||
return "Flash read error";
|
||||
case ERR_OUT_OF_MEMORY:
|
||||
return "Out of memory";
|
||||
case ERR_CANNOT_READ_FILE:
|
||||
return "Error reading file";
|
||||
case ERR_CANNOT_WRITE_FILE:
|
||||
return "Error writing file";
|
||||
case ERR_WRONG_SIZE:
|
||||
return "Wrong file size";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
192
firmware/target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
Normal file
192
firmware/target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "lcd.h"
|
||||
#include "kernel.h"
|
||||
#include "lcd-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "system.h"
|
||||
|
||||
#define CS_PIN (1 << 18)
|
||||
#define RD_PIN (1 << 16)
|
||||
|
||||
static const uint32_t fiio_lcd_cmd_enable[] = {
|
||||
/* Software reset */
|
||||
LCD_INSTR_CMD, 0x01,
|
||||
LCD_INSTR_UDELAY, 120000,
|
||||
/* Sleep out */
|
||||
LCD_INSTR_CMD, 0x11,
|
||||
LCD_INSTR_UDELAY, 5000,
|
||||
/* Memory access order */
|
||||
LCD_INSTR_CMD, 0x36,
|
||||
LCD_INSTR_DAT, 0x00,
|
||||
/* Row and column address set */
|
||||
LCD_INSTR_CMD, 0x2a,
|
||||
LCD_INSTR_DAT, 0x00,
|
||||
LCD_INSTR_DAT, 0x00,
|
||||
LCD_INSTR_DAT, (LCD_WIDTH >> 8) & 0xff,
|
||||
LCD_INSTR_DAT, (LCD_WIDTH & 0xff),
|
||||
LCD_INSTR_CMD, 0x2b,
|
||||
LCD_INSTR_DAT, 0x00,
|
||||
LCD_INSTR_DAT, 0x00,
|
||||
LCD_INSTR_DAT, (LCD_HEIGHT >> 8) & 0xff,
|
||||
LCD_INSTR_DAT, (LCD_HEIGHT & 0xff),
|
||||
/* Interface pixel format */
|
||||
LCD_INSTR_CMD, 0x3a,
|
||||
LCD_INSTR_DAT, 0x05,
|
||||
/* Enable display inversion */
|
||||
LCD_INSTR_CMD, 0x21,
|
||||
/* Porch setting */
|
||||
LCD_INSTR_CMD, 0xb2,
|
||||
LCD_INSTR_DAT, 0x0c,
|
||||
LCD_INSTR_DAT, 0x0c,
|
||||
LCD_INSTR_DAT, 0x00,
|
||||
LCD_INSTR_DAT, 0x33,
|
||||
LCD_INSTR_DAT, 0x33,
|
||||
/* Gate control */
|
||||
LCD_INSTR_CMD, 0xb7,
|
||||
LCD_INSTR_DAT, 0x35,
|
||||
/* VCOM setting */
|
||||
LCD_INSTR_CMD, 0xbb,
|
||||
LCD_INSTR_DAT, 0x1f,
|
||||
/* Backlight control 5 */
|
||||
LCD_INSTR_CMD, 0xbc,
|
||||
LCD_INSTR_DAT, 0xec,
|
||||
/* Backlight control 6 */
|
||||
LCD_INSTR_CMD, 0xbd,
|
||||
LCD_INSTR_DAT, 0xfe,
|
||||
/* Voltage settings */
|
||||
LCD_INSTR_CMD, 0xc2,
|
||||
LCD_INSTR_DAT, 0x01,
|
||||
LCD_INSTR_CMD, 0xc3,
|
||||
LCD_INSTR_DAT, 0x19,
|
||||
LCD_INSTR_CMD, 0xc4,
|
||||
LCD_INSTR_DAT, 0x20,
|
||||
/* Frame rate control */
|
||||
LCD_INSTR_CMD, 0xc6,
|
||||
LCD_INSTR_DAT, 0x0f, /* = 60 fps */
|
||||
/* Power control 1 */
|
||||
LCD_INSTR_CMD, 0xd0,
|
||||
LCD_INSTR_DAT, 0xa4,
|
||||
LCD_INSTR_DAT, 0xa1,
|
||||
/* d6 Unknown */
|
||||
LCD_INSTR_CMD, 0xd6,
|
||||
LCD_INSTR_DAT, 0xa1,
|
||||
/* Positive gamma correction */
|
||||
LCD_INSTR_CMD, 0xe0,
|
||||
LCD_INSTR_DAT, 0xd0,
|
||||
LCD_INSTR_DAT, 0x06,
|
||||
LCD_INSTR_DAT, 0x0c,
|
||||
LCD_INSTR_DAT, 0x0a,
|
||||
LCD_INSTR_DAT, 0x09,
|
||||
LCD_INSTR_DAT, 0x0a,
|
||||
LCD_INSTR_DAT, 0x32,
|
||||
LCD_INSTR_DAT, 0x33,
|
||||
LCD_INSTR_DAT, 0x49,
|
||||
LCD_INSTR_DAT, 0x19,
|
||||
LCD_INSTR_DAT, 0x14,
|
||||
LCD_INSTR_DAT, 0x15,
|
||||
LCD_INSTR_DAT, 0x2b,
|
||||
LCD_INSTR_DAT, 0x34,
|
||||
/* Negative gamma correction */
|
||||
LCD_INSTR_CMD, 0xe1,
|
||||
LCD_INSTR_DAT, 0xd0,
|
||||
LCD_INSTR_DAT, 0x06,
|
||||
LCD_INSTR_DAT, 0x0c,
|
||||
LCD_INSTR_DAT, 0x0a,
|
||||
LCD_INSTR_DAT, 0x09,
|
||||
LCD_INSTR_DAT, 0x11,
|
||||
LCD_INSTR_DAT, 0x37,
|
||||
LCD_INSTR_DAT, 0x33,
|
||||
LCD_INSTR_DAT, 0x49,
|
||||
LCD_INSTR_DAT, 0x19,
|
||||
LCD_INSTR_DAT, 0x14,
|
||||
LCD_INSTR_DAT, 0x15,
|
||||
LCD_INSTR_DAT, 0x2d,
|
||||
LCD_INSTR_DAT, 0x34,
|
||||
/* Tearing effect line ON, mode=0 (vsync signal) */
|
||||
LCD_INSTR_CMD, 0x35,
|
||||
LCD_INSTR_DAT, 0x00,
|
||||
/* Display ON */
|
||||
LCD_INSTR_CMD, 0x29,
|
||||
LCD_INSTR_END,
|
||||
};
|
||||
|
||||
static const uint32_t fiio_lcd_cmd_sleep[] = {
|
||||
/* Display OFF */
|
||||
LCD_INSTR_CMD, 0x28,
|
||||
/* Sleep IN */
|
||||
LCD_INSTR_CMD, 0x10,
|
||||
LCD_INSTR_UDELAY, 5000,
|
||||
LCD_INSTR_END,
|
||||
};
|
||||
|
||||
static const uint32_t fiio_lcd_cmd_wake[] = {
|
||||
/* Sleep OUT */
|
||||
LCD_INSTR_CMD, 0x11,
|
||||
LCD_INSTR_UDELAY, 5000,
|
||||
/* Display ON */
|
||||
LCD_INSTR_CMD, 0x29,
|
||||
LCD_INSTR_END,
|
||||
};
|
||||
|
||||
static const uint8_t __attribute__((aligned(64)))
|
||||
fiio_lcd_dma_wr_cmd[] = {0x00, 0x00, 0x00, 0x2c};
|
||||
|
||||
const struct lcd_tgt_config lcd_tgt_config = {
|
||||
.bus_width = 16,
|
||||
.cmd_width = 8,
|
||||
.use_6800_mode = 0,
|
||||
.use_serial = 0,
|
||||
.clk_polarity = 0,
|
||||
.dc_polarity = 0,
|
||||
.wr_polarity = 1,
|
||||
.te_enable = 1,
|
||||
.te_polarity = 1,
|
||||
.te_narrow = 0,
|
||||
.dma_wr_cmd_buf = &fiio_lcd_dma_wr_cmd,
|
||||
.dma_wr_cmd_size = sizeof(fiio_lcd_dma_wr_cmd),
|
||||
};
|
||||
|
||||
void lcd_tgt_enable(bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
gpio_config(GPIO_A, 0xffff, GPIO_DEVICE(1));
|
||||
gpio_config(GPIO_B, 0x1f << 16, GPIO_DEVICE(1));
|
||||
gpio_config(GPIO_B, CS_PIN|RD_PIN, GPIO_OUTPUT(1));
|
||||
mdelay(5);
|
||||
gpio_out_level(GPIO_B, CS_PIN, 0);
|
||||
lcd_set_clock(X1000_CLK_SCLK_A, 30000000);
|
||||
lcd_exec_commands(&fiio_lcd_cmd_enable[0]);
|
||||
} else {
|
||||
lcd_exec_commands(&fiio_lcd_cmd_sleep[0]);
|
||||
mdelay(115); /* ensure we wait a total of 120ms before power off */
|
||||
gpio_config(GPIO_B, CS_PIN|RD_PIN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_tgt_sleep(bool sleep)
|
||||
{
|
||||
if(sleep)
|
||||
lcd_exec_commands(&fiio_lcd_cmd_sleep[0]);
|
||||
else
|
||||
lcd_exec_commands(&fiio_lcd_cmd_wake[0]);
|
||||
}
|
53
firmware/target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c
Normal file
53
firmware/target/mips/ingenic_x1000/fiiom3k/nand-fiiom3k.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "nand-x1000.h"
|
||||
#include "nand-target.h"
|
||||
#include "sfc-x1000.h"
|
||||
|
||||
/* Unbelievably FiiO has completely disabled the use of ECC for this chip
|
||||
* in their Linux kernel, even though it has perfectly good spare areas.
|
||||
* There's no internal ECC either.
|
||||
*
|
||||
* Using nanddump to read the spare areas reveals they're filled with 0xff,
|
||||
* and the publicly released Linux source has the ecc_strength set to 0.
|
||||
*/
|
||||
static const nand_chip_data ato25d1ga = {
|
||||
.name = "ATO25D1GA",
|
||||
.mf_id = 0x9b,
|
||||
.dev_id = 0x12,
|
||||
.dev_conf = NAND_INIT_SFC_DEV_CONF,
|
||||
/* XXX: datasheet says 104 MHz but FiiO seems to run this at 150 MHz.
|
||||
* Didn't find any issues doing this so might as well keep the behavior.
|
||||
*/
|
||||
.clock_freq = NAND_INIT_CLOCK_SPEED,
|
||||
.block_size = 64,
|
||||
.page_size = 2048,
|
||||
.spare_size = 64,
|
||||
.rowaddr_width = 3,
|
||||
.coladdr_width = 2,
|
||||
.flags = NANDCHIP_FLAG_QUAD,
|
||||
};
|
||||
|
||||
const nand_chip_desc target_nand_chip_descs[] = {
|
||||
{&ato25d1ga, &nand_chip_ops_std},
|
||||
{NULL, NULL},
|
||||
};
|
42
firmware/target/mips/ingenic_x1000/fiiom3k/nand-target.h
Normal file
42
firmware/target/mips/ingenic_x1000/fiiom3k/nand-target.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __NAND_TARGET_H__
|
||||
#define __NAND_TARGET_H__
|
||||
|
||||
/* The max page size (main + spare) of all NAND chips used by this target */
|
||||
#define NAND_MAX_PAGE_SIZE (2048 + 64)
|
||||
|
||||
/* The clock source to use for the SFC controller. Note the SPL has special
|
||||
* handling which ignores this choice, so it only applies to bootloader & app.
|
||||
*/
|
||||
#define NAND_CLOCK_SOURCE X1000_CLK_SCLK_A
|
||||
|
||||
/* The clock speed to use for the SFC controller during chip identification */
|
||||
#define NAND_INIT_CLOCK_SPEED 150000000
|
||||
|
||||
/* Initial value to program SFC_DEV_CONF register with */
|
||||
#define NAND_INIT_SFC_DEV_CONF \
|
||||
jz_orf(SFC_DEV_CONF, CE_DL(1), HOLD_DL(1), WP_DL(1), \
|
||||
CPHA(0), CPOL(0), TSH(7), TSETUP(0), THOLD(0), \
|
||||
STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), SMP_DELAY(1))
|
||||
|
||||
#endif /* __NAND_TARGET_H__ */
|
97
firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
Normal file
97
firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "power.h"
|
||||
#include "adc.h"
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "axp173.h"
|
||||
#include "i2c-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
|
||||
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
3470
|
||||
};
|
||||
|
||||
/* the OF shuts down at this voltage */
|
||||
const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
3400
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
|
||||
const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
|
||||
{
|
||||
{ 3400, 3639, 3697, 3723, 3757, 3786, 3836, 3906, 3980, 4050, 4159 }
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
|
||||
const unsigned short const percent_to_volt_charge[11] =
|
||||
{
|
||||
3485, 3780, 3836, 3857, 3890, 3930, 3986, 4062, 4158, 4185, 4196
|
||||
};
|
||||
|
||||
#define AXP173_IRQ_PORT GPIO_B
|
||||
#define AXP173_IRQ_PIN (1 << 10)
|
||||
|
||||
void power_init(void)
|
||||
{
|
||||
/* Initialize driver */
|
||||
i2c_x1000_set_freq(2, I2C_FREQ_400K);
|
||||
axp173_init();
|
||||
|
||||
/* Set lowest sample rate */
|
||||
axp173_adc_set_rate(AXP173_ADC_RATE_25HZ);
|
||||
|
||||
/* Ensure battery voltage ADC is enabled */
|
||||
int bits = axp173_adc_get_enabled();
|
||||
bits |= (1 << ADC_BATTERY_VOLTAGE);
|
||||
axp173_adc_set_enabled(bits);
|
||||
|
||||
/* Turn on all power outputs */
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x12, 0, 0x5f, NULL);
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x80, 0, 0xc0, NULL);
|
||||
|
||||
/* Short delay to give power outputs time to stabilize */
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
void adc_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void power_off(void)
|
||||
{
|
||||
/* Set the shutdown bit */
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0x32, 7, 1, NULL);
|
||||
while(1);
|
||||
}
|
||||
|
||||
bool charging_state(void)
|
||||
{
|
||||
return axp173_battery_status() == AXP173_BATT_CHARGING;
|
||||
}
|
||||
|
||||
int _battery_voltage(void)
|
||||
{
|
||||
return axp173_adc_read(ADC_BATTERY_VOLTAGE);
|
||||
}
|
84
firmware/target/mips/ingenic_x1000/gpio-x1000.c
Normal file
84
firmware/target/mips/ingenic_x1000/gpio-x1000.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "gpio-x1000.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#ifndef BOOTLOADER_SPL
|
||||
struct mutex gpio_z_mutex;
|
||||
#endif
|
||||
|
||||
void gpio_init(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_SPL
|
||||
mutex_init(&gpio_z_mutex);
|
||||
#endif
|
||||
|
||||
/* Set all pins to input state */
|
||||
for(int i = 0; i < 4; ++i) {
|
||||
jz_clr(GPIO_INT(GPIO_Z), 0xffffffff);
|
||||
jz_set(GPIO_MSK(GPIO_Z), 0xffffffff);
|
||||
jz_set(GPIO_PAT1(GPIO_Z), 0xffffffff);
|
||||
jz_clr(GPIO_PAT0(GPIO_Z), 0xffffffff);
|
||||
REG_GPIO_Z_GID2LD = i;
|
||||
}
|
||||
|
||||
/* Clear flag and disable pull resistor */
|
||||
for(int i = 0; i < 4; ++i) {
|
||||
jz_clr(GPIO_FLAG(i), 0xffffffff);
|
||||
jz_set(GPIO_PULL(i), 0xffffffff);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_lock(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_SPL
|
||||
mutex_lock(&gpio_z_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gpio_unlock(void)
|
||||
{
|
||||
#ifndef BOOTLOADER_SPL
|
||||
mutex_unlock(&gpio_z_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gpio_config(int port, unsigned pinmask, int func)
|
||||
{
|
||||
unsigned intr = REG_GPIO_INT(port);
|
||||
unsigned mask = REG_GPIO_MSK(port);
|
||||
unsigned pat1 = REG_GPIO_PAT1(port);
|
||||
unsigned pat0 = REG_GPIO_PAT0(port);
|
||||
|
||||
gpio_lock();
|
||||
if(func & 8) jz_set(GPIO_INT(GPIO_Z), (intr & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_INT(GPIO_Z), (~intr & pinmask) ^ pinmask);
|
||||
if(func & 4) jz_set(GPIO_MSK(GPIO_Z), (mask & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_MSK(GPIO_Z), (~mask & pinmask) ^ pinmask);
|
||||
if(func & 2) jz_set(GPIO_PAT1(GPIO_Z), (pat1 & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_PAT1(GPIO_Z), (~pat1 & pinmask) ^ pinmask);
|
||||
if(func & 1) jz_set(GPIO_PAT0(GPIO_Z), (pat0 & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_PAT0(GPIO_Z), (~pat0 & pinmask) ^ pinmask);
|
||||
REG_GPIO_Z_GID2LD = port;
|
||||
gpio_unlock();
|
||||
gpio_set_pull(port, pinmask, func & 16);
|
||||
}
|
110
firmware/target/mips/ingenic_x1000/gpio-x1000.h
Normal file
110
firmware/target/mips/ingenic_x1000/gpio-x1000.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __GPIO_X1000_H__
|
||||
#define __GPIO_X1000_H__
|
||||
|
||||
/* GPIO API
|
||||
* --------
|
||||
*
|
||||
* To assign a new function to a GPIO, call gpio_config(). This uses the
|
||||
* hardware's GPIO Z facility to atomically most GPIO registers at once,
|
||||
* so it can be used to make any state transition safely. Since GPIO Z is
|
||||
* protected by a mutex, you can't call gpio_config() from interrupt context.
|
||||
*
|
||||
* If you need to use GPIO Z directly, then use gpio_lock() and gpio_unlock()
|
||||
* to acquire the mutex.
|
||||
*
|
||||
* Depending on the current GPIO state, certain state transitions are safe to
|
||||
* perform without locking, as they only change one register:
|
||||
*
|
||||
* - for pins in GPIO_OUTPUT state:
|
||||
* - use gpio_out_level() to change the output level
|
||||
*
|
||||
* - for pins in GPIO_IRQ_LEVEL or GPIO_IRQ_EDGE state:
|
||||
* - use gpio_irq_level() to change the trigger level
|
||||
* - use gpio_irq_mask() to mask/unmask the IRQ
|
||||
*
|
||||
* - for pins in GPIO_DEVICE or GPIO_INPUT state:
|
||||
* - no special transitions allowed
|
||||
*
|
||||
* - in all states:
|
||||
* - use gpio_set_pull() to change the pull-up/pull-down state
|
||||
*/
|
||||
|
||||
#include "x1000/gpio.h"
|
||||
|
||||
/* GPIO port numbers */
|
||||
#define GPIO_A 0
|
||||
#define GPIO_B 1
|
||||
#define GPIO_C 2
|
||||
#define GPIO_D 3
|
||||
#define GPIO_Z 7
|
||||
|
||||
/* GPIO function bits */
|
||||
#define GPIO_F_PULL 16
|
||||
#define GPIO_F_INT 8
|
||||
#define GPIO_F_MASK 4
|
||||
#define GPIO_F_PAT1 2
|
||||
#define GPIO_F_PAT0 1
|
||||
|
||||
/* GPIO function numbers */
|
||||
#define GPIO_DEVICE(i) ((i)&3)
|
||||
#define GPIO_OUTPUT(i) (0x4|((i)&1))
|
||||
#define GPIO_INPUT 0x16
|
||||
#define GPIO_IRQ_LEVEL(i) (0x1c|((i)&1))
|
||||
#define GPIO_IRQ_EDGE(i) (0x1e|((i)&1))
|
||||
|
||||
extern void gpio_init(void);
|
||||
extern void gpio_lock(void);
|
||||
extern void gpio_unlock(void);
|
||||
extern void gpio_config(int port, unsigned pinmask, int func);
|
||||
|
||||
static inline void gpio_out_level(int port, unsigned pinmask, int level)
|
||||
{
|
||||
if(level)
|
||||
jz_set(GPIO_PAT0(port), pinmask);
|
||||
else
|
||||
jz_clr(GPIO_PAT0(port), pinmask);
|
||||
}
|
||||
|
||||
#define gpio_irq_level gpio_out_level
|
||||
|
||||
static inline void gpio_irq_mask(int port, unsigned pinmask, int masked)
|
||||
{
|
||||
if(masked)
|
||||
jz_set(GPIO_MSK(port), pinmask);
|
||||
else
|
||||
jz_clr(GPIO_MSK(port), pinmask);
|
||||
}
|
||||
|
||||
#define gpio_enable_irq(port, pinmask) gpio_irq_mask((port), (pinmask), 0)
|
||||
#define gpio_disable_irq(port, pinmask) gpio_irq_mask((port), (pinmask), 1)
|
||||
|
||||
static inline void gpio_set_pull(int port, unsigned pinmask, int state)
|
||||
{
|
||||
if(state)
|
||||
jz_set(GPIO_PULL(port), pinmask);
|
||||
else
|
||||
jz_clr(GPIO_PULL(port), pinmask);
|
||||
}
|
||||
|
||||
#endif /* __GPIO_X1000_H__ */
|
478
firmware/target/mips/ingenic_x1000/i2c-x1000.c
Normal file
478
firmware/target/mips/ingenic_x1000/i2c-x1000.c
Normal file
|
@ -0,0 +1,478 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* #define LOGF_ENABLE */
|
||||
#include "i2c-x1000.h"
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "panic.h"
|
||||
#include "logf.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "clk-x1000.h"
|
||||
#include "irq-x1000.h"
|
||||
#include "x1000/i2c.h"
|
||||
#include "x1000/cpm.h"
|
||||
|
||||
#if I2C_ASYNC_BUS_COUNT != 3
|
||||
# error "Wrong I2C_ASYNC_BUS_COUNT (should be 3)"
|
||||
#endif
|
||||
|
||||
#define FIFO_SIZE 64 /* Size of data FIFOs */
|
||||
#define FIFO_TX_THRESH 16 /* Wake up when TX FIFO gets to this level */
|
||||
#define FIFO_RX_SLACK 2 /* Slack space to leave, avoids RX FIFO overflow */
|
||||
|
||||
typedef struct i2c_x1000_bus {
|
||||
/* Hardware channel, this is just equal to i2c-async bus number. */
|
||||
int chn;
|
||||
|
||||
/* Buffer/count usage depends on what phase the bus is processing:
|
||||
*
|
||||
* - Phase1: writing out descriptor's buffer[0] for both READs and WRITEs.
|
||||
* - Phase2: writing out descriptor's buffer[1] for WRITEs, or issuing a
|
||||
* series of read requests for READs.
|
||||
*
|
||||
* In phase1, buffer[1] and count[1] are equal to the descriptor's copy.
|
||||
* buffer[0] and count[0] get incremented/decremented as we send bytes.
|
||||
* Phase1 is only visited if we actually need to send bytes; if there
|
||||
* would be no data in this phase then __i2c_async_submit() sets up the
|
||||
* driver to go directly to phase2.
|
||||
*
|
||||
* Phase2 begins after phase1 writes out its last byte, or if phase1 was
|
||||
* skipped at submit time. For WRITEs phase2 is identical to phase1 so we
|
||||
* copy over buffer[1] and count[1] to buffer[0] and count[0], and zero
|
||||
* out buffer[1] and count[1].
|
||||
*
|
||||
* For READs phase2 sets buffer[0] to NULL and count[0] equal to count[1].
|
||||
* Now count[0] counts the number of bytes left to request, and count[1]
|
||||
* counts the number of bytes left to receive. i2c_x1000_fifo_write() sees
|
||||
* that buffer[0] is NULL and sends read requests instead of data bytes.
|
||||
* buffer[1] is advanced by i2c_x1000_fifo_read() we receive bytes.
|
||||
*/
|
||||
unsigned char* buffer[2];
|
||||
int count[2];
|
||||
bool phase1;
|
||||
|
||||
/* Copied fields from descriptor */
|
||||
uint8_t bus_cond;
|
||||
uint8_t tran_mode;
|
||||
|
||||
/* Counter to keep track of when to send end conditions */
|
||||
int byte_cnt;
|
||||
int byte_cnt_end;
|
||||
|
||||
/* Current bus frequency, used to calculate timeout durations */
|
||||
long freq;
|
||||
|
||||
/* Timeout to reset the bus in case of buggy devices */
|
||||
struct timeout tmo;
|
||||
|
||||
/* Flag used to indicate a reset is processing */
|
||||
int resetting;
|
||||
} i2c_x1000_bus;
|
||||
|
||||
static i2c_x1000_bus i2c_x1000_busses[3];
|
||||
|
||||
static void i2c_x1000_fifo_write(i2c_x1000_bus* bus)
|
||||
{
|
||||
int tx_free, tx_n;
|
||||
|
||||
/* Get free space in FIFO */
|
||||
tx_free = FIFO_SIZE - REG_I2C_TXFLR(bus->chn);
|
||||
|
||||
_again:
|
||||
/* Leave some slack space when reading. If we submit a full FIFO's worth
|
||||
* of read requests, there's a small chance that a byte "on the wire" is
|
||||
* unaccounted for and causes an RX FIFO overrun. Slack space is meant to
|
||||
* avoid this situation.
|
||||
*/
|
||||
if(bus->tran_mode == I2C_READ) {
|
||||
tx_free -= FIFO_RX_SLACK;
|
||||
if(tx_free <= 0)
|
||||
goto _end;
|
||||
}
|
||||
|
||||
/* Calculate number of bytes needed to send/request */
|
||||
tx_n = MIN(tx_free, bus->count[0]);
|
||||
|
||||
/* Account for bytes we're about to send/request */
|
||||
bus->count[0] -= tx_n;
|
||||
tx_free -= tx_n;
|
||||
|
||||
for(; tx_n > 0; --tx_n) {
|
||||
bus->byte_cnt += 1;
|
||||
|
||||
/* Read data byte or set read request bit */
|
||||
uint32_t dc = bus->buffer[0] ? *bus->buffer[0]++ : jz_orm(I2C_DC, CMD);
|
||||
|
||||
/* Check for first byte & apply RESTART.
|
||||
* Note the HW handles RESTART automatically when changing the
|
||||
* direction of the transfer, so we don't need to check for that.
|
||||
*/
|
||||
if(bus->byte_cnt == 1 && (bus->bus_cond & I2C_RESTART))
|
||||
dc |= jz_orm(I2C_DC, RESTART);
|
||||
|
||||
/* Check for last byte & apply STOP */
|
||||
if(bus->byte_cnt == bus->byte_cnt_end && (bus->bus_cond & I2C_STOP))
|
||||
dc |= jz_orm(I2C_DC, STOP);
|
||||
|
||||
/* Add entry to FIFO */
|
||||
REG_I2C_DC(bus->chn) = dc;
|
||||
}
|
||||
|
||||
/* FIFO full and current phase still has data to send.
|
||||
* Configure interrupt to fire when there's a good amount of free space.
|
||||
*/
|
||||
if(bus->count[0] > 0) {
|
||||
_end:
|
||||
REG_I2C_TXTL(bus->chn) = FIFO_TX_THRESH;
|
||||
jz_writef(I2C_INTMSK(bus->chn), TXEMP(1), RXFL(0));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advance to second phase if needed */
|
||||
if(bus->phase1 && bus->count[1] > 0) {
|
||||
bus->buffer[0] = bus->tran_mode == I2C_WRITE ? bus->buffer[1] : NULL;
|
||||
bus->count[0] = bus->count[1];
|
||||
bus->phase1 = false;
|
||||
|
||||
/* Submit further data if possible; else wait for TX space */
|
||||
if(tx_free > 0)
|
||||
goto _again;
|
||||
else
|
||||
goto _end;
|
||||
}
|
||||
|
||||
/* All phases are done. Now we just need to wake up when the whole
|
||||
* operation is complete, either by waiting for TX to drain or RX to
|
||||
* fill to the appropriate level. */
|
||||
if(bus->tran_mode == I2C_WRITE) {
|
||||
REG_I2C_TXTL(bus->chn) = 0;
|
||||
jz_writef(I2C_INTMSK(bus->chn), TXEMP(1), RXFL(0));
|
||||
} else {
|
||||
REG_I2C_RXTL(bus->chn) = bus->count[1] - 1;
|
||||
jz_writef(I2C_INTMSK(bus->chn), TXEMP(0), RXFL(1));
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_x1000_fifo_read(i2c_x1000_bus* bus)
|
||||
{
|
||||
/* Get number of bytes in the RX FIFO */
|
||||
int rx_n = REG_I2C_RXFLR(bus->chn);
|
||||
|
||||
/* Shouldn't happen, but check just in case */
|
||||
if(rx_n > bus->count[1]) {
|
||||
panicf("i2c_x1000(%d): expected %d bytes in RX fifo, got %d",
|
||||
bus->chn, bus->count[1], rx_n);
|
||||
}
|
||||
|
||||
/* Fill buffer with data from FIFO */
|
||||
bus->count[1] -= rx_n;
|
||||
for(; rx_n != 0; --rx_n) {
|
||||
*bus->buffer[1]++ = jz_readf(I2C_DC(bus->chn), DAT);
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_x1000_interrupt(i2c_x1000_bus* bus)
|
||||
{
|
||||
int intr = REG_I2C_INTST(bus->chn);
|
||||
int status = I2C_STATUS_OK;
|
||||
|
||||
/* Bus error; we can't prevent this from happening. As I understand
|
||||
* it, we cannot get a TXABT when the bus is idle, so it should be
|
||||
* safe to leave this interrupt unmasked all the time.
|
||||
*/
|
||||
if(intr & jz_orm(I2C_INTST, TXABT)) {
|
||||
logf("i2c_x1000(%d): got TXABT (%08lx)",
|
||||
bus->chn, REG_I2C_ABTSRC(bus->chn));
|
||||
|
||||
REG_I2C_CTXABT(bus->chn);
|
||||
status = I2C_STATUS_ERROR;
|
||||
goto _done;
|
||||
}
|
||||
|
||||
/* FIFO errors shouldn't occur unless driver did something dumb */
|
||||
if(intr & jz_orm(I2C_INTST, RXUF, TXOF, RXOF)) {
|
||||
#if 1
|
||||
panicf("i2c_x1000(%d): fifo error (%08x)", bus->chn, intr);
|
||||
#else
|
||||
/* This is how the error condition would be cleared */
|
||||
REG_I2C_CTXOF(bus->chn);
|
||||
REG_I2C_CRXOF(bus->chn);
|
||||
REG_I2C_CRXUF(bus->chn);
|
||||
status = I2C_STATUS_ERROR;
|
||||
goto _done;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Read from FIFO on reads, and check if we have sent/received
|
||||
* the expected amount of data. If so, complete the descriptor. */
|
||||
if(bus->tran_mode == I2C_READ) {
|
||||
i2c_x1000_fifo_read(bus);
|
||||
if(bus->count[1] == 0)
|
||||
goto _done;
|
||||
} else if(bus->count[0] == 0) {
|
||||
goto _done;
|
||||
}
|
||||
|
||||
/* Still need to send or request data -- issue commands to FIFO */
|
||||
i2c_x1000_fifo_write(bus);
|
||||
return;
|
||||
|
||||
_done:
|
||||
jz_writef(I2C_INTMSK(bus->chn), TXEMP(0), RXFL(0));
|
||||
timeout_cancel(&bus->tmo);
|
||||
__i2c_async_complete_callback(bus->chn, status);
|
||||
}
|
||||
|
||||
void I2C0(void)
|
||||
{
|
||||
i2c_x1000_interrupt(&i2c_x1000_busses[0]);
|
||||
}
|
||||
|
||||
void I2C1(void)
|
||||
{
|
||||
i2c_x1000_interrupt(&i2c_x1000_busses[1]);
|
||||
}
|
||||
|
||||
void I2C2(void)
|
||||
{
|
||||
i2c_x1000_interrupt(&i2c_x1000_busses[2]);
|
||||
}
|
||||
|
||||
static int i2c_x1000_bus_timeout(struct timeout* tmo)
|
||||
{
|
||||
/* Buggy device is preventing the operation from completing, so we
|
||||
* can't do much except reset the bus and hope for the best. Device
|
||||
* drivers can aid us by detecting the TIMEOUT status we return and
|
||||
* resetting the device to get it out of a bugged state. */
|
||||
|
||||
i2c_x1000_bus* bus = (i2c_x1000_bus*)tmo->data;
|
||||
switch(bus->resetting) {
|
||||
default:
|
||||
/* Start of reset. Disable the controller */
|
||||
REG_I2C_INTMSK(bus->chn) = 0;
|
||||
bus->resetting = 1;
|
||||
jz_writef(I2C_ENABLE(bus->chn), ACTIVE(0));
|
||||
return 1;
|
||||
case 1:
|
||||
/* Check if controller is disabled yet */
|
||||
if(jz_readf(I2C_ENBST(bus->chn), ACTIVE))
|
||||
return 1;
|
||||
|
||||
/* Wait 10 ms after disabling to give time for bus to clear */
|
||||
bus->resetting = 2;
|
||||
return HZ/100;
|
||||
case 2:
|
||||
/* Re-enable the controller */
|
||||
bus->resetting = 3;
|
||||
jz_writef(I2C_ENABLE(bus->chn), ACTIVE(1));
|
||||
return 1;
|
||||
case 3:
|
||||
/* Check that controller is enabled */
|
||||
if(jz_readf(I2C_ENBST(bus->chn), ACTIVE) == 0)
|
||||
return 1;
|
||||
|
||||
/* Reset complete */
|
||||
bus->resetting = 0;
|
||||
jz_overwritef(I2C_INTMSK(bus->chn), RXFL(0), TXEMP(0),
|
||||
TXABT(1), TXOF(1), RXOF(1), RXUF(1));
|
||||
__i2c_async_complete_callback(bus->chn, I2C_STATUS_TIMEOUT);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void __i2c_async_submit(int busnr, i2c_descriptor* desc)
|
||||
{
|
||||
i2c_x1000_bus* bus = &i2c_x1000_busses[busnr];
|
||||
|
||||
if(desc->tran_mode == I2C_READ) {
|
||||
if(desc->count[0] > 0) {
|
||||
/* Handle initial write as phase1 */
|
||||
bus->buffer[0] = desc->buffer[0];
|
||||
bus->count[0] = desc->count[0];
|
||||
bus->phase1 = true;
|
||||
} else {
|
||||
/* No initial write, skip directly to phase2 */
|
||||
bus->buffer[0] = NULL;
|
||||
bus->count[0] = desc->count[1];
|
||||
bus->phase1 = false;
|
||||
}
|
||||
|
||||
/* Set buffer/count for phase2 read */
|
||||
bus->buffer[1] = desc->buffer[1];
|
||||
bus->count[1] = desc->count[1];
|
||||
} else {
|
||||
/* Writes always have to have buffer[0] populated; buffer[1] is
|
||||
* allowed to be NULL (and thus count[1] = 0). This matches our
|
||||
* phase logic so no need for anything special
|
||||
*/
|
||||
bus->buffer[0] = desc->buffer[0];
|
||||
bus->count[0] = desc->count[0];
|
||||
bus->buffer[1] = desc->buffer[1];
|
||||
bus->count[1] = desc->count[1];
|
||||
bus->phase1 = true;
|
||||
}
|
||||
|
||||
/* Save bus condition and transfer mode */
|
||||
bus->bus_cond = desc->bus_cond;
|
||||
bus->tran_mode = desc->tran_mode;
|
||||
|
||||
/* Byte counter is used to check for first and last byte and apply
|
||||
* the requested end mode */
|
||||
bus->byte_cnt = 0;
|
||||
bus->byte_cnt_end = desc->count[0] + desc->count[1];
|
||||
|
||||
/* Ensure interrupts are cleared */
|
||||
REG_I2C_CINT(busnr);
|
||||
|
||||
/* Program target address */
|
||||
jz_overwritef(I2C_TAR(busnr), ADDR(desc->slave_addr & ~I2C_10BIT_ADDR),
|
||||
10BITS(desc->slave_addr & I2C_10BIT_ADDR ? 1 : 0));
|
||||
|
||||
/* Do the initial FIFO fill; this sets up the needed interrupts. */
|
||||
i2c_x1000_fifo_write(bus);
|
||||
|
||||
/* Software timeout to deal with buggy slave devices that pull the bus
|
||||
* high forever and leave us hanging. Use 100ms + whatever time should
|
||||
* be needed to handle data transmission. Account for 9 bits per byte
|
||||
* because of the ACKs necessary after each byte.
|
||||
*/
|
||||
long ticks = (HZ/10) + (HZ * 9 * bus->byte_cnt_end / bus->freq);
|
||||
timeout_register(&bus->tmo, i2c_x1000_bus_timeout, ticks, (intptr_t)bus);
|
||||
}
|
||||
|
||||
void i2c_init(void)
|
||||
{
|
||||
/* Initialize core */
|
||||
__i2c_async_init();
|
||||
|
||||
/* Initialize our bus data structures */
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
i2c_x1000_busses[i].chn = i;
|
||||
i2c_x1000_busses[i].freq = 0;
|
||||
i2c_x1000_busses[i].resetting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stuff only required during initialization is below, basically the same as
|
||||
* the old driver except for how the IRQs are initially set up. */
|
||||
|
||||
static const struct {
|
||||
int port;
|
||||
unsigned pins;
|
||||
int func;
|
||||
} i2c_x1000_gpio_data[] = {
|
||||
{GPIO_B, 3 << 23, GPIO_DEVICE(0)},
|
||||
{GPIO_C, 3 << 26, GPIO_DEVICE(0)},
|
||||
/* Note: I2C1 is also on the following pins (normally used by LCD) */
|
||||
/* {GPIO_A, 3 << 0, GPIO_DEVICE(2)}, */
|
||||
{GPIO_D, 3 << 0, GPIO_DEVICE(1)},
|
||||
};
|
||||
|
||||
static void i2c_x1000_gate(int chn, int gate)
|
||||
{
|
||||
switch(chn) {
|
||||
case 0: jz_writef(CPM_CLKGR, I2C0(gate)); break;
|
||||
case 1: jz_writef(CPM_CLKGR, I2C1(gate)); break;
|
||||
case 2: jz_writef(CPM_CLKGR, I2C2(gate)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_x1000_enable(int chn)
|
||||
{
|
||||
/* Enable controller */
|
||||
jz_writef(I2C_ENABLE(chn), ACTIVE(1));
|
||||
while(jz_readf(I2C_ENBST(chn), ACTIVE) == 0);
|
||||
|
||||
/* Set up interrutpts */
|
||||
jz_overwritef(I2C_INTMSK(chn), RXFL(0), TXEMP(0),
|
||||
TXABT(1), TXOF(1), RXOF(1), RXUF(1));
|
||||
system_enable_irq(IRQ_I2C(chn));
|
||||
}
|
||||
|
||||
static void i2c_x1000_disable(int chn)
|
||||
{
|
||||
/* Disable interrupts */
|
||||
system_disable_irq(IRQ_I2C(chn));
|
||||
REG_I2C_INTMSK(chn) = 0;
|
||||
|
||||
/* Disable controller */
|
||||
jz_writef(I2C_ENABLE(chn), ACTIVE(0));
|
||||
while(jz_readf(I2C_ENBST(chn), ACTIVE));
|
||||
}
|
||||
|
||||
void i2c_x1000_set_freq(int chn, int freq)
|
||||
{
|
||||
/* Store frequency */
|
||||
i2c_x1000_busses[chn].freq = freq;
|
||||
|
||||
/* Disable the channel if previously active */
|
||||
i2c_x1000_gate(chn, 0);
|
||||
if(jz_readf(I2C_ENBST(chn), ACTIVE) == 1)
|
||||
i2c_x1000_disable(chn);
|
||||
|
||||
/* Request to shut down the channel */
|
||||
if(freq == 0) {
|
||||
i2c_x1000_gate(chn, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate timing parameters */
|
||||
unsigned pclk = clk_get(X1000_CLK_PCLK);
|
||||
unsigned t_SU_DAT = pclk / (freq * 8);
|
||||
unsigned t_HD_DAT = pclk / (freq * 12);
|
||||
unsigned t_LOW = pclk / (freq * 2);
|
||||
unsigned t_HIGH = pclk / (freq * 2);
|
||||
if(t_SU_DAT > 1) t_SU_DAT -= 1;
|
||||
if(t_SU_DAT > 255) t_SU_DAT = 255;
|
||||
if(t_SU_DAT == 0) t_SU_DAT = 0;
|
||||
if(t_HD_DAT > 0xffff) t_HD_DAT = 0xfff;
|
||||
if(t_LOW < 8) t_LOW = 8;
|
||||
if(t_HIGH < 6) t_HIGH = 6;
|
||||
|
||||
/* Control register setting */
|
||||
unsigned reg = jz_orf(I2C_CON, SLVDIS(1), RESTART(1), MD(1));
|
||||
if(freq <= I2C_FREQ_100K)
|
||||
reg |= jz_orf(I2C_CON, SPEED_V(100K));
|
||||
else
|
||||
reg |= jz_orf(I2C_CON, SPEED_V(400K));
|
||||
|
||||
/* Write the new controller settings */
|
||||
jz_write(I2C_CON(chn), reg);
|
||||
jz_write(I2C_SDASU(chn), t_SU_DAT);
|
||||
jz_write(I2C_SDAHD(chn), t_HD_DAT);
|
||||
if(freq <= I2C_FREQ_100K) {
|
||||
jz_write(I2C_SLCNT(chn), t_LOW);
|
||||
jz_write(I2C_SHCNT(chn), t_HIGH);
|
||||
} else {
|
||||
jz_write(I2C_FLCNT(chn), t_LOW);
|
||||
jz_write(I2C_FHCNT(chn), t_HIGH);
|
||||
}
|
||||
|
||||
/* Claim pins */
|
||||
gpio_config(i2c_x1000_gpio_data[chn].port,
|
||||
i2c_x1000_gpio_data[chn].pins,
|
||||
i2c_x1000_gpio_data[chn].func);
|
||||
|
||||
/* Enable the controller */
|
||||
i2c_x1000_enable(chn);
|
||||
}
|
44
firmware/target/mips/ingenic_x1000/i2c-x1000.h
Normal file
44
firmware/target/mips/ingenic_x1000/i2c-x1000.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __I2C_X1000_H__
|
||||
#define __I2C_X1000_H__
|
||||
|
||||
#include "i2c-async.h"
|
||||
|
||||
#define I2C_FREQ_100K 100000
|
||||
#define I2C_FREQ_400K 400000
|
||||
|
||||
extern void i2c_init(void);
|
||||
|
||||
/* Configure the I2C controller prior to use.
|
||||
*
|
||||
* - freq: frequency of SCL, should be <= 400 KHz and >= 25 KHz
|
||||
* - use I2C_FREQ_100K for 100 KHz
|
||||
* - use I2C_FREQ_400K for 400 Khz
|
||||
* - use 0 to disable the controller completely
|
||||
* - frequencies below 25 KHz will violate timing constraints
|
||||
*
|
||||
* TODO: move this to the i2c-async API, it's simple enough
|
||||
*/
|
||||
extern void i2c_x1000_set_freq(int chn, int freq);
|
||||
|
||||
#endif /* __I2C_X1000_H__ */
|
115
firmware/target/mips/ingenic_x1000/irq-x1000.h
Normal file
115
firmware/target/mips/ingenic_x1000/irq-x1000.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 __IRQ_X1000_H__
|
||||
#define __IRQ_X1000_H__
|
||||
|
||||
/* INTC(0) interrupts */
|
||||
#define IRQ0_DMIC 0
|
||||
#define IRQ0_AIC 1
|
||||
#define IRQ0_SFC 7
|
||||
#define IRQ0_SSI 8
|
||||
#define IRQ0_PDMA 10
|
||||
#define IRQ0_PDMAD 11
|
||||
#define IRQ0_GPIO3 14
|
||||
#define IRQ0_GPIO2 15
|
||||
#define IRQ0_GPIO1 16
|
||||
#define IRQ0_GPIO0 17
|
||||
#define IRQ0_OTG 21
|
||||
#define IRQ0_AES 23
|
||||
#define IRQ0_TCU2 25
|
||||
#define IRQ0_TCU1 26
|
||||
#define IRQ0_TCU0 27
|
||||
#define IRQ0_CIM 30
|
||||
#define IRQ0_LCD 31
|
||||
|
||||
/* INTC(1) interrupts */
|
||||
#define IRQ1_RTC 0
|
||||
#define IRQ1_MSC1 4
|
||||
#define IRQ1_MSC0 5
|
||||
#define IRQ1_SCC 6
|
||||
#define IRQ1_PCM 8
|
||||
#define IRQ1_HARB2 12
|
||||
#define IRQ1_HARB0 14
|
||||
#define IRQ1_CPM 15
|
||||
#define IRQ1_UART2 17
|
||||
#define IRQ1_UART1 18
|
||||
#define IRQ1_UART0 19
|
||||
#define IRQ1_DDR 20
|
||||
#define IRQ1_EFUSE 22
|
||||
#define IRQ1_MAC 23
|
||||
#define IRQ1_I2C2 26
|
||||
#define IRQ1_I2C1 27
|
||||
#define IRQ1_I2C0 28
|
||||
#define IRQ1_I2C(c) (28 - (c))
|
||||
#define IRQ1_PDMAM 29
|
||||
#define IRQ1_JPEG 30
|
||||
|
||||
/* Unified IRQ numbers */
|
||||
#define IRQ_DMIC IRQ0_DMIC
|
||||
#define IRQ_AIC IRQ0_AIC
|
||||
#define IRQ_SFC IRQ0_SFC
|
||||
#define IRQ_SSI IRQ0_SSI
|
||||
#define IRQ_PDMA IRQ0_PDMA
|
||||
#define IRQ_PDMAD IRQ0_PDMAD
|
||||
#define IRQ_GPIO3 IRQ0_GPIO3
|
||||
#define IRQ_GPIO2 IRQ0_GPIO2
|
||||
#define IRQ_GPIO1 IRQ0_GPIO1
|
||||
#define IRQ_GPIO0 IRQ0_GPIO0
|
||||
#define IRQ_OTG IRQ0_OTG
|
||||
#define IRQ_AES IRQ0_AES
|
||||
#define IRQ_TCU2 IRQ0_TCU2
|
||||
#define IRQ_TCU1 IRQ0_TCU1
|
||||
#define IRQ_TCU0 IRQ0_TCU0
|
||||
#define IRQ_CIM IRQ0_CIM
|
||||
#define IRQ_LCD IRQ0_LCD
|
||||
#define IRQ_RTC (32+IRQ1_RTC)
|
||||
#define IRQ_MSC1 (32+IRQ1_MSC1)
|
||||
#define IRQ_MSC0 (32+IRQ1_MSC0)
|
||||
#define IRQ_SCC (32+IRQ1_SCC)
|
||||
#define IRQ_PCM (32+IRQ1_PCM)
|
||||
#define IRQ_HARB2 (32+IRQ1_HARB2)
|
||||
#define IRQ_HARB0 (32+IRQ1_HARB0)
|
||||
#define IRQ_CPM (32+IRQ1_CPM)
|
||||
#define IRQ_UART2 (32+IRQ1_UART2)
|
||||
#define IRQ_UART1 (32+IRQ1_UART1)
|
||||
#define IRQ_UART0 (32+IRQ1_UART0)
|
||||
#define IRQ_DDR (32+IRQ1_DDR)
|
||||
#define IRQ_EFUSE (32+IRQ1_EFUSE)
|
||||
#define IRQ_MAC (32+IRQ1_MAC)
|
||||
#define IRQ_I2C2 (32+IRQ1_I2C2)
|
||||
#define IRQ_I2C1 (32+IRQ1_I2C1)
|
||||
#define IRQ_I2C0 (32+IRQ1_I2C0)
|
||||
#define IRQ_I2C(c) (32+IRQ1_I2C(c))
|
||||
#define IRQ_PDMAM (32+IRQ1_PDMAM)
|
||||
#define IRQ_JPEG (32+IRQ1_JPEG)
|
||||
#define IRQ_GPIO(port, pin) (64 + 32*(port) + (pin))
|
||||
|
||||
#define IRQ_IS_GROUP0(irq) (((irq) & 0xffffff20) == 0x00)
|
||||
#define IRQ_IS_GROUP1(irq) (((irq) & 0xffffff20) == 0x20)
|
||||
#define IRQ_IS_GPIO(irq) ((irq) >= 64)
|
||||
|
||||
#define IRQ_TO_GROUP0(irq) (irq)
|
||||
#define IRQ_TO_GROUP1(irq) ((irq) - 32)
|
||||
#define IRQ_TO_GPIO_PORT(irq) (((irq) - 64) >> 5)
|
||||
#define IRQ_TO_GPIO_PIN(irq) (((irq) - 64) & 0x1f)
|
||||
|
||||
#endif /* __IRQ_X1000_H__ */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue