Travis Geiselbrecht | 1d0df69 | 2008-09-01 02:26:09 -0700 | [diff] [blame] | 1 | /* init_clock.S -- AT91SAM7 clock coldstart code |
| 2 | ** |
| 3 | ** Copyright 2006, Brian Swetland. All rights reserved. |
| 4 | ** See provided LICENSE file or http://frotz.net/LICENSE for details. |
| 5 | */ |
| 6 | |
| 7 | .globl init_clock |
| 8 | |
| 9 | init_clock: |
| 10 | /* init flash controller timing for 18.432MHz */ |
| 11 | mov r1, #0xffffff00 |
| 12 | ldr r0, =0x00340100 |
| 13 | str r0, [r1, #0x60] |
| 14 | |
| 15 | #define PMC_MOR 0x20 |
| 16 | #define PMC_MCFR 0x24 |
| 17 | #define PMC_PLLR 0x2c |
| 18 | #define PMC_MCKR 0x30 |
| 19 | #define PMC_SR 0x68 |
| 20 | |
| 21 | /* PMC_MOR */ |
| 22 | #define PMC_MOSCEN 0x01 |
| 23 | #define PMC_OSCBYPASS 0x02 |
| 24 | |
| 25 | /* PMC_MCFR */ |
| 26 | #define PMC_MAINRDY 0x00010000 |
| 27 | |
| 28 | /* PMC_SR */ |
| 29 | #define PMC_MOSCS 0x01 |
| 30 | #define PMC_LOCK 0x04 |
| 31 | #define PMC_MCKRDY 0x08 |
| 32 | |
| 33 | /* PMC_MCKR */ |
| 34 | #define PMC_CSS_SLOW 0x00 |
| 35 | #define PMC_CSS_MAIN 0x01 |
| 36 | #define PMC_CSS_PLL 0x03 |
| 37 | #define PMC_PRES_NONE 0x00 |
| 38 | #define PMC_PRES_DIV2 0x04 |
| 39 | #define PMC_PRES_DIV4 0x08 |
| 40 | |
| 41 | /* Oscillator Init Sequence based on the Atmel sample code |
| 42 | ** in cstartup_boot_SAM7S32_64.s |
| 43 | ** |
| 44 | ** I cleaned it up a bit -- why they use a temporary register, |
| 45 | ** AND and then CMP instead of just TSTing against an immediate |
| 46 | ** boggles my mind. I think this could be a bit simpler yet, |
| 47 | ** but debugging it is a pain, so Good Enough wins for now. |
| 48 | */ |
| 49 | ldr r1, =0xfffffc00 |
| 50 | |
| 51 | /* bypass main oscillator */ |
| 52 | mov r0, #PMC_OSCBYPASS |
| 53 | str r0, [r1, #PMC_MOR] |
| 54 | |
| 55 | /* compensate MAINRDY rising flag (45 SCLK) */ |
| 56 | mov r0, #45 |
| 57 | 1: subs r0, r0, #1 |
| 58 | bhi 1b |
| 59 | |
| 60 | /* if MAINRDY is set, we have an external oscillator */ |
| 61 | ldr r0, [r1, #PMC_MCFR] |
| 62 | tst r0, #PMC_MAINRDY |
| 63 | bne ext_osc_found |
| 64 | |
| 65 | /* reset MOSCS flag */ |
| 66 | mov r0, #0 |
| 67 | str r0, [r1, #PMC_MOR] |
| 68 | |
| 69 | /* enable main oscillator */ |
| 70 | ldr r0, =((0x40 << 8) | PMC_MOSCEN) |
| 71 | str r0, [r1, #PMC_MOR] |
| 72 | |
| 73 | /* wait for main oscillator to come online */ |
| 74 | 1: ldr r0, [r1, #PMC_SR] |
| 75 | tst r0, #PMC_MOSCS |
| 76 | beq 1b |
| 77 | |
| 78 | ext_osc_found: |
| 79 | /* select main oscillator, no prescaler for MCK */ |
| 80 | mov r0, #(PMC_CSS_MAIN | PMC_PRES_NONE) |
| 81 | str r0, [r1, #PMC_MCKR] |
| 82 | |
| 83 | /* wait until MCK settles to continue */ |
| 84 | 1: ldr r0, [r1, #PMC_SR] |
| 85 | tst r0, #PMC_MCKRDY |
| 86 | beq 1b |
| 87 | |
| 88 | /* this is a bit of voodoo for selecting a 96.109MHz PLL |
| 89 | ** freq (MUL=72, DIV=14, OUT=0, USBDIV=/1) from the 18.432MHz |
| 90 | ** main clock. |
| 91 | */ |
| 92 | ldr r0, =0x10483f0e |
| 93 | str r0, [r1, #PMC_PLLR] |
| 94 | |
| 95 | /* let the PLL lock before we continue */ |
| 96 | 1: ldr r0, [r1, #PMC_SR] |
| 97 | tst r0, #PMC_LOCK |
| 98 | beq 1b |
| 99 | |
| 100 | mov pc, lr |
| 101 | |