summaryrefslogtreecommitdiffstats
path: root/rbutil/mkamsboot/dualboot/dualboot.S
blob: 4df69a45cce95b8cfa8e4b8ae604e59d6819d059 (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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/***************************************************************************
 *             __________               __   ___.
 *   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_PROC,  0xC80F0010
.set CGU_PERI,  0xC80F0014
.set CGU_DBOP,  0xC80F0038
.set DBOP,      0xC8120000
.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

        b start     @ skip our data

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

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]


#ifdef SANSA_CLIPV2 /* 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<<6))]
        cmp     r1, #0
        bne     boot_of
#endif
        /* Here are model specific tests for dual boot (test left button) */

#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)
        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 */
        beq     boot_of

#elif 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 */
        bne     boot_of

#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_CLIPZIP)
        @ read pins
        ldr     r0, =GPIOA
        ldr     r1, [r0, #4*(1<<6)] @ read GPIO A6 "vol-"

        cmp     r1, #0              @ test input from pins
        bne     boot_of             @ branch directly to OF if either pin high

#elif defined(SANSA_C200V2)
.set BUTTON_LEFT,      (1<< 2)
.set BUTTON_DOWN,      (1<< 3)
.set BUTTON_SELECT,    (1<< 4)
.set BUTTON_UP,        (1<< 5)
.set BUTTON_RIGHT,     (1<< 6)
.set BUTTON_HOLD,      (1<<12)

        ldr     r0, =CGU_DBOP
        mov     r1, #(1<<3)         @ DBOP freq = PCLK, clock enabled
        str     r1, [r0]

        @ AFSEL needs to be set for this to work
        ldr     r2, =GPIOB
        mov     r1, #0xc
        str     r1, [r2, #0x420]    @ GPIOB_AFSEL
        ldr     r2, =GPIOC
        mov     r1, #0xff
        str     r1, [r2, #0x420]    @ GPIOC_AFSEL

        ldr     r0, =DBOP
        @ TIMPOL doesn't matter here since we don't need
        @ the control signals.

        @ 16 bit data width
        @ enable write
        @ tri-state output
        ldr     r1, =0x00091000
        str     r1, [r0, #8]        @ DBOP_CTRL

        ldr     r1, =0xf0ff         @ precharge
        str     r1, [r0, #0x10]     @ DBOP_DOUT

2:      ldr     r1, [r0, #0xc]      @ DOBP_STAT
        ands    r1, r1, #(1<<10)
        beq     2b                  @ make sure fifo is empty

        @ 16 bit data width
        @ start read
        @ tri-state output
        @ strobe time 31
        ldr     r1, =0x0008901f
        str     r1, [r0, #8]        @ DBOP_CTRL

3:      ldr     r1, [r0, #0xc]      @ DOBP_STAT
        ands    r1, r1, #(1<<16)
        beq     3b                  @ wait for valid data

        ldrh    r1, [r0, #0x14]     @ DBOP_DIN

        tst     r1, #BUTTON_LEFT    @ boot of?
        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

#if defined(SANSA_CLIPPLUS) || defined(SANSA_FUZEV2)
        /* Check for USB after buttons because I trust more the GPIO code than
         * the i2c code.
         * Also it seems we need to wait a bit before detecting USB connection
         * on those models, but not on c200v2
         */


        ldr     r0, =CGU_PROC
        mov     r1, #0
        str     r1, [r0]    @ fclk = 24MHz

        ldr     r0, =CGU_PERI
        ldr     r1, [r0]
        /* enable i2c audio master clock */
        orr     r1, r1, #(1<<17)
        /* pclk = fclk = 24MHz */
        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

        /* wait a bit (~100ms) else detection fails */
        mov     r1, #0x80000
1:      subs    r1, 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


        /* 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) */