| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright © 2010 by 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. |
| * |
| ****************************************************************************/ |
| #include "config.h" |
| #include "cpu.h" |
| |
| #define CACHE_NONE 0 |
| #define CACHE_ALL 0x0C |
| #define UNCACHED_ADDR(a) (a + 0x10000000) |
| |
| #if defined(SANSA_CLIP) || defined(SANSA_M200V4) || defined(SANSA_C200V2) |
| /* 16 bits external bus, low power SDRAM, 16 Mbits = 2 Mbytes */ |
| #define MEMORY_MODEL 0x21 |
| |
| #elif defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_CLIPV2) \ |
| || defined(SANSA_CLIPPLUS) || defined(SANSA_FUZEV2) |
| /* 16 bits external bus, high performance SDRAM, 64 Mbits = 8 Mbytes */ |
| #define MEMORY_MODEL 0x5 |
| |
| #else |
| #error "The external memory in your player is unknown" |
| #endif |
| |
| .global memory_init |
| .text |
| |
| memory_init: |
| |
| #ifdef BOOTLOADER |
| |
| ldr r2, =0xC80F0014 @ CGU_PERI |
| ldr r1, [r2] |
| orr r1, r1, #(CGU_EXTMEM_CLOCK_ENABLE|CGU_EXTMEMIF_CLOCK_ENABLE) |
| str r1, [r2] |
| |
| ldr r3, =0xC6030000 @ MPMC_BASE |
| |
| mov r2, #1 @ enable MPMC |
| str r2, [r3] @ MPMC_CONTROL |
| ldr r2, =0x183 @ SDRAM NOP, all clocks high |
| str r2, [r3, #0x20] @ MPMC_DYNAMIC_CONTROL |
| ldr r2, =0x103 @ SDRAM PALL, all clocks high |
| str r2, [r3, #0x20] @ MPMC_DYNAMIC_CONTROL |
| ldr r1, =0x138 @ 0x138 * 16 HCLK ticks between SDRAM refresh cycles |
| str r1, [r3, #0x24] @ MPMC_DYNAMIC_REFRESH |
| mov r2, #0 @ little endian, HCLK:MPMCCLKOUT[3:0] ratio = 1:1 |
| str r2, [r3, #8] @ MPMC_CONFIG |
| |
| ldr r2, [r3, #0xfe8] @ MPMC_PERIPH_ID2 |
| tst r2, #0xf0 |
| movne r2, #1 @ command delayed, clock out not delayed |
| strne r2, [r3, #0x28] @ MPMC_DYNAMIC_READ_CONFIG |
| |
| mov r1, #2 |
| mov r0, #5 |
| mov ip, #4 |
| mov r2, #0 |
| str r1, [r3, #0x30] @ tRP |
| str ip, [r3, #0x34] @ tRAS |
| str r0, [r3, #0x38] @ tSREX |
| str r2, [r3, #0x3c] @ tAPR |
| str ip, [r3, #0x40] @ tDAL |
| str r1, [r3, #0x44] @ tWR |
| str r0, [r3, #0x48] @ tRC |
| str r0, [r3, #0x4c] @ tRFC |
| str r0, [r3, #0x50] @ tXSR |
| str r1, [r3, #0x54] @ tRRD |
| str r1, [r3, #0x58] @ tMRD |
| mov ip, #(MEMORY_MODEL << 7) |
| str ip, [r3, #0x100] @ MPMC_DYNAMIC_CONFIG_CONFIG_0 |
| orr r1, r1, #(2<<8) @ CAS & RAS latency = 2 clock cycle |
| str r1, [r3, #0x104] @ MPMC_DYNAMIC_CONFIG_RASCAS_0 |
| |
| str r2, [r3, #0x120] @ MPMC_DYNAMIC_CONFIG_CONFIG_1 |
| str r2, [r3, #0x124] @ MPMC_DYNAMIC_CONFIG_RASCAS_1 |
| str r2, [r3, #0x140] @ MPMC_DYNAMIC_CONFIG_CONFIG_2 |
| str r2, [r3, #0x144] @ MPMC_DYNAMIC_CONFIG_RASCAS_2 |
| str r2, [r3, #0x160] @ MPMC_DYNAMIC_CONFIG_CONFIG_3 |
| str r2, [r3, #0x164] @ MPMC_DYNAMIC_CONFIG_RASCAS_3 |
| |
| mov r1, #0x82 @ SDRAM MODE, MPMCCLKOUT runs continuously |
| str r1, [r3, #0x20] @ MPMC_DYNAMIC_CONTROL |
| |
| ldr r1, =DRAM_ORIG+(0x2300*MEMORYSIZE) |
| ldr r1, [r1] |
| |
| str r2, [r3, #0x20] @ MPMC_DYNAMIC_CONTROL= SDRAM NORMAL, |
| @ MPMCCLKOUT stopped when SDRAM is idle |
| |
| ldr r2, [r3, #0x100] @ MPMC_DYNAMIC_CONFIG_0 |
| orr r2, r2, #(1<<19) @ buffer enable |
| str r2, [r3, #0x100] |
| |
| #endif /* BOOTLOADER */ |
| |
| @ XXX: to avoid using the stack, we rely on the fact that: |
| @ - ttb_init |
| @ - map_section |
| @ - enable_mmu |
| @ do not modify ip (r12) |
| mov ip, lr |
| |
| /* Setup MMU */ |
| |
| bl ttb_init |
| |
| mov r0, #0 @ physical address |
| mov r1, #0 @ virtual address |
| mov r2, #0x1000 @ size (all memory) |
| mov r3, #CACHE_NONE |
| bl map_section |
| |
| mov r0, #0 @ physical address |
| ldr r1, =IRAM_ORIG @ virtual address |
| mov r2, #1 @ size : 1MB |
| mov r3, #CACHE_ALL |
| bl map_section |
| |
| mov r0, #0 @ physical address |
| ldr r1, =UNCACHED_ADDR(IRAM_ORIG) @ virtual address |
| mov r2, #1 @ size : 1MB |
| mov r3, #CACHE_NONE |
| bl map_section |
| |
| mov r0, #0x30000000 @ physical address |
| mov r1, #DRAM_ORIG @ virtual address |
| mov r2, #MEMORYSIZE @ size |
| mov r3, #CACHE_ALL |
| bl map_section |
| |
| mov r0, #0x30000000 @ physical address |
| mov r1, #UNCACHED_ADDR(DRAM_ORIG) @ virtual address |
| mov r2, #MEMORYSIZE @ size |
| mov r3, #CACHE_NONE |
| bl map_section |
| |
| /* map 1st mbyte of RAM at 0x0 to have exception vectors available */ |
| #ifdef BOOTLOADER |
| mov r0, #0x81000000 @ physical address |
| #else |
| mov r0, #0x30000000 @ physical address |
| #endif |
| mov r1, #0 @ virtual address |
| mov r2, #1 @ size |
| mov r3, #CACHE_ALL |
| bl map_section |
| |
| bl enable_mmu |
| |
| bx ip |