summaryrefslogtreecommitdiffstats
path: root/rbutil/mkamsboot/dualboot/dualboot.S
blob: 8bb2059d789253ea1d0fb32ce0b0fd4dc89e0d58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2008 Rafaël Carré
 *
 * 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.
 *
 ****************************************************************************/

.text

/* AS3525 hardware registers */
.set GPIOA,     0xC80B0000
.set GPIOB,     0xC80C0000
.set GPIOC,     0xC80D0000
.set GPIOD,     0xC80E0000
.set CGU_PERI,  0xC80F0014
.set I2C_BASE,  0xC8070000
.set I2C_DATA,  0x00
.set I2C_SLAD0, 0x04
.set I2C_CNTRL, 0x0c
.set I2C_DACNT, 0x10
.set I2C_CPSR0, 0x1c
.set I2C_CPSR1, 0x20
.set I2C_IMR,   0x24
.set I2C_SR,    0x30
.set I2C_SADDR, 0x44
.set AS3514_I2C_ADDR, 0x46
.set AS3514_IRQ_ENRD0, 0x25
.set PCLK, 24000000
.set I2C_CLK, 400000
.set I2C_PRESCALER, ((PCLK + I2C_CLK -1) / I2C_CLK)
.set I2C_PRESCALER_LOW, (I2C_PRESCALER & 0xff)
.set I2C_PRESCALER_HIGH, (I2C_PRESCALER >> 8)
#if I2C_PRESCALER_HIGH > 3
#error i2c prescaler too big!
#endif

/* Vectors */

        ldr   pc, =start    /* reset vector */
        /* next vectors are unused, halt cpu */
1:      b 1b
1:      b 1b
1:      b 1b
1:      b 1b
1:      b 1b
1:      b 1b
1:      b 1b


/* These values are filled in by mkamsboot - don't move them from offset 0x20 */

uclunpack_end:   .word   0 /* End of the ucl_unpack function */
uclunpack_size:  .word   0 /* Size in bytes of the ucl_unpack function */

ucl_of_end:      .word   0 /* End of the ucl-compressed OF image */
ucl_of_size:     .word   0 /* Size in bytes of the compressed OF image */

ucl_rb_end:      .word   0 /* End of the ucl-compressed RB image */
ucl_rb_size:     .word   0 /* Size in bytes of the compressed RB image */

ucl_dest:        .word   0 /* End of our destination buffer (end of memory) */

start:
        /* First copy the UCL unpack function to the end of RAM */
        ldr     r0, uclunpack_end   /* Source */
        ldr     r1, uclunpack_size  /* Source length */
        sub     r2, r0, r1          /* Source start - 1*/

        ldr     r3, ucl_dest        /* Destination end */

uclcopy:
        ldrb    r4, [r0], #-1
        strb    r4, [r3], #-1
        cmp     r2, r0
        bne     uclcopy

        /* store the new destination buffer */
        str     r3, ucl_dest

        /* enable gpio clock */
        ldr     r0, =CGU_PERI
        ldr     r1, [r0]
        orr     r1, r1, #(1<<16)
        str     r1, [r0]


/* TODO : M200V4 ? */
#if defined(SANSA_CLIP) || defined(SANSA_CLIPV2)
#define USB_PIN 6
#elif defined(SANSA_FUZE) || defined(SANSA_E200V2) || defined(SANSA_FUZEV2)
#define USB_PIN 3
#endif

#ifdef USB_PIN  /* TODO : remove this check when we'll have an USB driver */
        ldr     r0, =GPIOA
        mov     r1, #0
        str     r1, [r0, #0x400]
        ldr     r1, [r0, #(4*(1<<USB_PIN))]
        cmp     r1, #0
        bne     boot_of
#endif
#if defined(SANSA_C200V2)
        /* Instead of checking the GPIO, check the audio master IRQ_ENRD0
         * USB_STATUS bit on C200V2 */

        ldr     r0, =CGU_PERI
        ldr     r1, [r0]
        /* enable i2c audio master clock */
        orr     r1, r1, #(1<<17)
        /* make sure 24MHz clk_main is selected */
        bic     r1, r1, #0x7f
        str     r1, [r0]

        ldr     r0, =I2C_BASE
        /* disable i2c interrupts */
        mov     r1, #0
        str     r1, [r0, #I2C_IMR]
        /* setup prescaler */
        mov     r1, #I2C_PRESCALER_LOW
        str     r1, [r0, #I2C_CPSR0]
        mov     r1, #I2C_PRESCALER_HIGH
        str     r1, [r0, #I2C_CPSR1]
        /* setup i2c slave address */
        mov     r1, #(AS3514_I2C_ADDR << 1)
        str     r1, [r0, #I2C_SLAD0]
        mov     r2, #0x51
        str     r2, [r0, #I2C_CNTRL]

        /* wait for not busy */
1:
        ldr     r1, [r0, #I2C_SR]
        tst     r1, #1
        bne 1b

        /* start read of irq_enrd0 */
        mov     r1, #AS3514_IRQ_ENRD0
        str     r1, [r0, #I2C_SADDR]
        orr     r2, r2, #(1 << 1)
        str     r2, [r0, #I2C_CNTRL]
        mov     r1, #1
        str     r1, [r0, #I2C_DACNT]

        /* wait for transfer to finish */
1:
        ldr     r1, [r0, #I2C_DACNT]
        cmp     r1, #0
        bne     1b

        /* load result and test USB_STATUS bit */
        ldr     r1, [r0, #I2C_DATA]
        tst     r1, #(1 << 3)
        bne     boot_of
#endif

        /* Here are model specific tests, for dual boot without a computer */
        /* All models use left button */
        /* /!\ Right button for c200v2 (left button is unkwown) */

#ifdef SANSA_CLIP
.set row, (1<<5) /* enable output on C5 */
.set col, (1<<0) /* read keyscan column B0 */

        ldr     r0, =GPIOC
        mov     r1, #row
        str     r1, [r0, #0x400]
        str     r1, [r0, #(4*row)]

        ldr     r0, =GPIOB
        mov     r1, #0
        str     r1, [r0, #0x400]
        ldr     r1, [r0, #(4*col)]

        cmp     r1, #0
        bne     boot_of
#elif defined(SANSA_CLIPV2)
.set row, (1<<4) /* enable output on D4 */
.set col, (1<<0) /* read keyscan column D0 */

        ldr     r0, =GPIOD
        mov     r1, #((1<<5)|(1<<4)|(1<<3)) /* all rows as output */
        str     r1, [r0, #0x400]

        /* all rows high */
        mov     r1, #(1<<3)
        str     r1, [r0, #(4*(1<<3))]
        mov     r1, #(1<<4)
        str     r1, [r0, #(4*(1<<4))]
        mov     r1, #(1<<5)
        str     r1, [r0, #(4*(1<<5))]

        mov     r1, #0                      /* button row low */
        str     r1, [r0, #(4*row)]

        mov     r1, #5                      /* small delay */
1:      subs    r1, r1, #1
        bne     1b

        ldr     r1, [r0, #(4*col)]

        cmp     r1, #0
        beq     boot_of
#elif defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_FUZEV2)
        ldr     r0, =GPIOC
        mov     r1, #0
        str     r1, [r0, #0x400]
        ldr     r1, [r0, #0x20]    /* read pin C3 */

        cmp     r1, #0             /* C3 = #0 means button pressed */
#ifdef SANSA_FUZEV2
        /* the logic is reversed on the fuzev2 */
        bne     boot_of
#else
        beq     boot_of
#endif /* SANSA_FUZEV2 */

#elif defined(SANSA_CLIPPLUS)
        @ read pins
        ldr     r0, =GPIOC
        ldr     r1, [r0, #4*(1<<3)] @ read pin C3 "|<<"

        ldr     r0, =GPIOA
        ldr     r2, [r0, #4*(1<<1)] @ read pin A1 "Home"

        orr     r2, r2, r1          @ c3 || A1

        cmp     r2, #0              @ test input from pins
        bne     boot_of             @ branch directly to OF if either pin high
#elif defined(SANSA_C200V2)
        /* check for RIGHT on C6, should changed to LEFT as soon as it
         * known in which pin that is in order for consistency  */
        ldr     r0, =GPIOC
        mov     r1, #0
        str     r1, [r0, #0x400]      /* set pin to output */

        ldr     r1, [r0, #256]        /* 1<<(6+2) */
        cmp     r1, #0                /* C6 low means button pressed */
        beq     boot_of
#elif defined(SANSA_M200V4)
.set row, (1<<5) /* enable output on A5 */
.set col, (1<<0) /* read keyscan column A0 */

        ldr     r0, =GPIOA
        mov     r1, #row
        str     r1, [r0, #0x400]
        str     r1, [r0, #(4*row)]

        ldr     r2, [r0, #(4*col)]

        /* check value read (1 means button pressed) */
        cmp     r2, #0
        bne     boot_of
#else
        #error No target-specific key check defined!
#endif


        /* The dualboot button was not held, so we boot rockbox */
        ldr     r0, ucl_rb_end      /* Address of compressed image */
        ldr     r1, ucl_rb_size     /* Compressed size */
        b       decompress

boot_of:
        ldr     r0, ucl_of_end      /* Address of compressed image */
        ldr     r1, ucl_of_size     /* Compressed size */


decompress:
        /* At this point:                                              */
        /* r0 = source_end for UCL image to copy                       */
        /* r1 = size of UCL image to copy                              */

        ldr     r3, ucl_dest
        add     r5, r3, #2      /* r5 is entry point of copy of uclunpack */
                                /* function, plus one (for thumb mode */

        sub     r4, r3, r1      /* r4 := destination_start - 1 */

fw_copy:
        ldrb    r2, [r0], #-1
        strb    r2, [r3], #-1
        cmp     r3, r4          /* Stop when we reached dest_start-1 */
        bne     fw_copy

        /* Call the ucl decompress function, which will branch to 0x0 */
        /* on completion */
        add     r0, r3, #1      /* r0 := Start of compressed image */
                                /* r1 already contains compressed size */
        mov     r2, #0          /* r2 := Destination for unpacking */
        bx      r5              /* Branch to uclunpack, switching to thumb */

        /* never reached : uclunpack will branch to the reset vector (0x0) */