| /* init_clock.S -- AT91SAM7 clock coldstart code |
| ** |
| ** Copyright 2006, Brian Swetland. All rights reserved. |
| ** See provided LICENSE file or http://frotz.net/LICENSE for details. |
| */ |
| |
| .globl init_clock |
| |
| init_clock: |
| /* init flash controller timing for 18.432MHz */ |
| mov r1, #0xffffff00 |
| ldr r0, =0x00340100 |
| str r0, [r1, #0x60] |
| |
| #define PMC_MOR 0x20 |
| #define PMC_MCFR 0x24 |
| #define PMC_PLLR 0x2c |
| #define PMC_MCKR 0x30 |
| #define PMC_SR 0x68 |
| |
| /* PMC_MOR */ |
| #define PMC_MOSCEN 0x01 |
| #define PMC_OSCBYPASS 0x02 |
| |
| /* PMC_MCFR */ |
| #define PMC_MAINRDY 0x00010000 |
| |
| /* PMC_SR */ |
| #define PMC_MOSCS 0x01 |
| #define PMC_LOCK 0x04 |
| #define PMC_MCKRDY 0x08 |
| |
| /* PMC_MCKR */ |
| #define PMC_CSS_SLOW 0x00 |
| #define PMC_CSS_MAIN 0x01 |
| #define PMC_CSS_PLL 0x03 |
| #define PMC_PRES_NONE 0x00 |
| #define PMC_PRES_DIV2 0x04 |
| #define PMC_PRES_DIV4 0x08 |
| |
| /* Oscillator Init Sequence based on the Atmel sample code |
| ** in cstartup_boot_SAM7S32_64.s |
| ** |
| ** I cleaned it up a bit -- why they use a temporary register, |
| ** AND and then CMP instead of just TSTing against an immediate |
| ** boggles my mind. I think this could be a bit simpler yet, |
| ** but debugging it is a pain, so Good Enough wins for now. |
| */ |
| ldr r1, =0xfffffc00 |
| |
| /* bypass main oscillator */ |
| mov r0, #PMC_OSCBYPASS |
| str r0, [r1, #PMC_MOR] |
| |
| /* compensate MAINRDY rising flag (45 SCLK) */ |
| mov r0, #45 |
| 1: subs r0, r0, #1 |
| bhi 1b |
| |
| /* if MAINRDY is set, we have an external oscillator */ |
| ldr r0, [r1, #PMC_MCFR] |
| tst r0, #PMC_MAINRDY |
| bne ext_osc_found |
| |
| /* reset MOSCS flag */ |
| mov r0, #0 |
| str r0, [r1, #PMC_MOR] |
| |
| /* enable main oscillator */ |
| ldr r0, =((0x40 << 8) | PMC_MOSCEN) |
| str r0, [r1, #PMC_MOR] |
| |
| /* wait for main oscillator to come online */ |
| 1: ldr r0, [r1, #PMC_SR] |
| tst r0, #PMC_MOSCS |
| beq 1b |
| |
| ext_osc_found: |
| /* select main oscillator, no prescaler for MCK */ |
| mov r0, #(PMC_CSS_MAIN | PMC_PRES_NONE) |
| str r0, [r1, #PMC_MCKR] |
| |
| /* wait until MCK settles to continue */ |
| 1: ldr r0, [r1, #PMC_SR] |
| tst r0, #PMC_MCKRDY |
| beq 1b |
| |
| /* this is a bit of voodoo for selecting a 96.109MHz PLL |
| ** freq (MUL=72, DIV=14, OUT=0, USBDIV=/1) from the 18.432MHz |
| ** main clock. |
| */ |
| ldr r0, =0x10483f0e |
| str r0, [r1, #PMC_PLLR] |
| |
| /* let the PLL lock before we continue */ |
| 1: ldr r0, [r1, #PMC_SR] |
| tst r0, #PMC_LOCK |
| beq 1b |
| |
| mov pc, lr |
| |