2013-10-21 22:48:33 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013 by Amaury Pouly
|
|
|
|
*
|
|
|
|
* 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 "regs-pinctrl.h"
|
|
|
|
#include "regs-power.h"
|
|
|
|
#include "regs-lradc.h"
|
2013-11-18 20:07:02 +00:00
|
|
|
#include "regs-digctl.h"
|
2013-10-21 22:48:33 +00:00
|
|
|
|
|
|
|
typedef unsigned long uint32_t;
|
|
|
|
|
|
|
|
// target specific boot decision
|
|
|
|
enum boot_t
|
|
|
|
{
|
|
|
|
BOOT_STOP, /* power down */
|
|
|
|
BOOT_ROCK, /* boot to Rockbox */
|
|
|
|
BOOT_OF, /* boot to OF */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline int __attribute__((always_inline)) read_gpio(int bank, int pin)
|
|
|
|
{
|
|
|
|
return (HW_PINCTRL_DINn(bank) >> pin) & 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int __attribute__((always_inline)) read_pswitch(void)
|
|
|
|
{
|
|
|
|
#if IMX233_SUBTARGET >= 3700
|
|
|
|
return BF_RD(POWER_STS, PSWITCH);
|
|
|
|
#else
|
|
|
|
return BF_RD(DIGCTL_STATUS, PSWITCH);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only works for channels <=7, always divide by 2, never accumulates */
|
|
|
|
static inline void __attribute__((always_inline)) setup_lradc(int src)
|
|
|
|
{
|
|
|
|
BF_CLR(LRADC_CTRL0, SFTRST);
|
|
|
|
BF_CLR(LRADC_CTRL0, CLKGATE);
|
|
|
|
/* don't bother changing the source, we are early enough at boot so that
|
|
|
|
* channel x is mapped to source x */
|
|
|
|
HW_LRADC_CHn_CLR(src) = BM_OR2(LRADC_CHn, NUM_SAMPLES, ACCUMULATE);
|
|
|
|
BF_SETV(LRADC_CTRL2, DIVIDE_BY_TWO, 1 << src);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define BP_LRADC_CTRL1_LRADCx_IRQ(x) (x)
|
|
|
|
#define BM_LRADC_CTRL1_LRADCx_IRQ(x) (1 << (x))
|
|
|
|
|
|
|
|
static inline int __attribute__((always_inline)) read_lradc(int src)
|
|
|
|
{
|
|
|
|
BF_CLR(LRADC_CTRL1, LRADCx_IRQ(src));
|
|
|
|
BF_SETV(LRADC_CTRL0, SCHEDULE, 1 << src);
|
|
|
|
while(!BF_RD(LRADC_CTRL1, LRADCx_IRQ(src)));
|
|
|
|
return BF_RDn(LRADC_CHn, src, VALUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void __attribute__((noreturn)) power_down()
|
|
|
|
{
|
|
|
|
/* power down */
|
|
|
|
HW_POWER_RESET = BM_OR2(POWER_RESET, UNLOCK, PWD);
|
|
|
|
while(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Boot decision functions
|
|
|
|
*/
|
|
|
|
|
2013-11-18 20:07:02 +00:00
|
|
|
#if defined(CREATIVE_ZENMOZAIC) || defined(CREATIVE_ZEN) || defined(CREATIVE_ZENXFI) \
|
|
|
|
|| defined(CREATIVE_ZENV)
|
2013-10-21 22:48:33 +00:00
|
|
|
static enum boot_t boot_decision()
|
|
|
|
{
|
|
|
|
setup_lradc(0); // setup LRADC channel 0 to read keys
|
|
|
|
/* make a decision */
|
|
|
|
/* read keys */
|
|
|
|
int val = read_lradc(0);
|
|
|
|
/* if back is pressed, boot to OF
|
|
|
|
* otherwise boot to RB */
|
|
|
|
if(val >= 2650 && val < 2750) // conveniently, all players use the same value
|
|
|
|
return BOOT_OF;
|
|
|
|
return BOOT_ROCK;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#warning You should define a target specific boot decision function
|
|
|
|
static int boot_decision()
|
|
|
|
{
|
|
|
|
return BOOT_ROCK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int main(uint32_t rb_addr, uint32_t of_addr)
|
|
|
|
{
|
|
|
|
switch(boot_decision())
|
|
|
|
{
|
|
|
|
case BOOT_ROCK:
|
|
|
|
return rb_addr;
|
|
|
|
case BOOT_OF:
|
|
|
|
/* fix back the loading address
|
|
|
|
/* NOTE: see mkzenboot for more details */
|
|
|
|
*(uint32_t *)0x20 = of_addr;
|
|
|
|
return 0;
|
|
|
|
case BOOT_STOP:
|
|
|
|
default:
|
|
|
|
power_down();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Glue for the linker mostly */
|
|
|
|
|
|
|
|
extern uint32_t of_vector;
|
|
|
|
extern uint32_t rb_vector;
|
|
|
|
extern uint32_t boot_arg;
|
|
|
|
|
|
|
|
void __attribute__((section(".start"))) start()
|
|
|
|
{
|
|
|
|
uint32_t addr = main(rb_vector, of_vector);
|
|
|
|
((void (*)(uint32_t))addr)(boot_arg);
|
|
|
|
}
|