summaryrefslogtreecommitdiff
path: root/utils/mkzenboot/dualboot/dualboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mkzenboot/dualboot/dualboot.c')
-rw-r--r--utils/mkzenboot/dualboot/dualboot.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/utils/mkzenboot/dualboot/dualboot.c b/utils/mkzenboot/dualboot/dualboot.c
new file mode 100644
index 0000000000..0b32772afb
--- /dev/null
+++ b/utils/mkzenboot/dualboot/dualboot.c
@@ -0,0 +1,136 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2013 by Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "regs-pinctrl.h"
22#include "regs-power.h"
23#include "regs-lradc.h"
24#include "regs-digctl.h"
25
26typedef unsigned long uint32_t;
27
28// target specific boot decision
29enum boot_t
30{
31 BOOT_STOP, /* power down */
32 BOOT_ROCK, /* boot to Rockbox */
33 BOOT_OF, /* boot to OF */
34};
35
36/**
37 * Helper functions
38 */
39
40static inline int __attribute__((always_inline)) read_gpio(int bank, int pin)
41{
42 return (HW_PINCTRL_DINn(bank) >> pin) & 1;
43}
44
45static inline int __attribute__((always_inline)) read_pswitch(void)
46{
47#if IMX233_SUBTARGET >= 3700
48 return BF_RD(POWER_STS, PSWITCH);
49#else
50 return BF_RD(DIGCTL_STATUS, PSWITCH);
51#endif
52}
53
54/* only works for channels <=7, always divide by 2, never accumulates */
55static inline void __attribute__((always_inline)) setup_lradc(int src)
56{
57 BF_CLR(LRADC_CTRL0, SFTRST);
58 BF_CLR(LRADC_CTRL0, CLKGATE);
59 /* don't bother changing the source, we are early enough at boot so that
60 * channel x is mapped to source x */
61 HW_LRADC_CHn_CLR(src) = BM_OR2(LRADC_CHn, NUM_SAMPLES, ACCUMULATE);
62 BF_SETV(LRADC_CTRL2, DIVIDE_BY_TWO, 1 << src);
63}
64
65#define BP_LRADC_CTRL1_LRADCx_IRQ(x) (x)
66#define BM_LRADC_CTRL1_LRADCx_IRQ(x) (1 << (x))
67
68static inline int __attribute__((always_inline)) read_lradc(int src)
69{
70 BF_CLR(LRADC_CTRL1, LRADCx_IRQ(src));
71 BF_SETV(LRADC_CTRL0, SCHEDULE, 1 << src);
72 while(!BF_RD(LRADC_CTRL1, LRADCx_IRQ(src)));
73 return BF_RDn(LRADC_CHn, src, VALUE);
74}
75
76static inline void __attribute__((noreturn)) power_down()
77{
78 /* power down */
79 HW_POWER_RESET = BM_OR2(POWER_RESET, UNLOCK, PWD);
80 while(1);
81}
82
83/**
84 * Boot decision functions
85 */
86
87#if defined(CREATIVE_ZENMOZAIC) || defined(CREATIVE_ZEN) || defined(CREATIVE_ZENXFI) \
88 || defined(CREATIVE_ZENV)
89static enum boot_t boot_decision()
90{
91 setup_lradc(0); // setup LRADC channel 0 to read keys
92 /* make a decision */
93 /* read keys */
94 int val = read_lradc(0);
95 /* if back is pressed, boot to OF
96 * otherwise boot to RB */
97 if(val >= 2650 && val < 2750) // conveniently, all players use the same value
98 return BOOT_OF;
99 return BOOT_ROCK;
100}
101#else
102#warning You should define a target specific boot decision function
103static int boot_decision()
104{
105 return BOOT_ROCK;
106}
107#endif
108
109static int main(uint32_t rb_addr, uint32_t of_addr)
110{
111 switch(boot_decision())
112 {
113 case BOOT_ROCK:
114 return rb_addr;
115 case BOOT_OF:
116 /* fix back the loading address
117 /* NOTE: see mkzenboot for more details */
118 *(uint32_t *)0x20 = of_addr;
119 return 0;
120 case BOOT_STOP:
121 default:
122 power_down();
123 }
124}
125
126/** Glue for the linker mostly */
127
128extern uint32_t of_vector;
129extern uint32_t rb_vector;
130extern uint32_t boot_arg;
131
132void __attribute__((section(".start"))) start()
133{
134 uint32_t addr = main(rb_vector, of_vector);
135 ((void (*)(uint32_t))addr)(boot_arg);
136}