forked from len0rd/rockbox
New port: FiiO M3K on bare metal
Change-Id: I7517e7d5459e129dcfc9465c6fbd708619888fbe
This commit is contained in:
parent
83fcbedc65
commit
3ec66893e3
143 changed files with 16585 additions and 24 deletions
|
|
@ -89,4 +89,11 @@ show_logo.c
|
|||
#elif defined(SANSA_CONNECT)
|
||||
sansaconnect.c
|
||||
show_logo.c
|
||||
#elif defined(FIIO_M3K)
|
||||
#ifdef BOOTLOADER_SPL
|
||||
x1000-spl.c
|
||||
fiiom3k-spl.c
|
||||
#else
|
||||
fiiom3k.c
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
204
bootloader/fiiom3k-spl.c
Normal file
204
bootloader/fiiom3k-spl.c
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "nand-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "mmu-mips.h"
|
||||
#include <string.h>
|
||||
|
||||
/* "fiio" in little endian */
|
||||
#define BOOTMAGIC 0x6f696966
|
||||
|
||||
/* Argument structure needed by Linux */
|
||||
struct linux_kargs {
|
||||
void* arg0;
|
||||
void* arg1;
|
||||
};
|
||||
|
||||
#define LINUX_KARGSADDR 0x80004000
|
||||
|
||||
static const char recovery_cmdline[] = "mem=xxM@0x0\
|
||||
no_console_suspend\
|
||||
console=ttyS2,115200n8\
|
||||
lpj=5009408\
|
||||
ip=off";
|
||||
|
||||
static const char normal_cmdline[] = "mem=64M@0x0\
|
||||
no_console_suspend\
|
||||
console=ttyS2,115200n8\
|
||||
lpj=5009408\
|
||||
ip=off\
|
||||
init=/linuxrc\
|
||||
ubi.mtd=3\
|
||||
root=ubi0:rootfs\
|
||||
ubi.mtd=4\
|
||||
rootfstype=ubifs\
|
||||
rw\
|
||||
loglevel=8";
|
||||
|
||||
#define BOOTOPTION_ROCKBOX 0
|
||||
#define BOOTOPTION_FIIOLINUX 1
|
||||
#define BOOTOPTION_RECOVERY 2
|
||||
#define NUM_BOOTOPTIONS 3
|
||||
|
||||
static const struct bootoption {
|
||||
uint32_t nand_addr;
|
||||
uint32_t nand_size;
|
||||
unsigned long load_addr;
|
||||
unsigned long exec_addr;
|
||||
const char* cmdline;
|
||||
} boot_options[NUM_BOOTOPTIONS] = {
|
||||
{
|
||||
/* Rockbox: the first unused NAND page is 26 KiB in, and the
|
||||
* remainder of the block is unused, giving us 102 KiB to use.
|
||||
*/
|
||||
.nand_addr = 0x6800,
|
||||
.nand_size = 0x19800,
|
||||
.load_addr = 0x80003ff8, /* first 8 bytes are bootloader ID */
|
||||
.exec_addr = 0x80004000,
|
||||
.cmdline = NULL,
|
||||
},
|
||||
{
|
||||
/* Original firmware */
|
||||
.nand_addr = 0x20000,
|
||||
.nand_size = 0x400000,
|
||||
.load_addr = 0x80efffc0,
|
||||
.exec_addr = 0x80f00000,
|
||||
.cmdline = normal_cmdline,
|
||||
},
|
||||
{
|
||||
/* Recovery image */
|
||||
.nand_addr = 0x420000,
|
||||
.nand_size = 0x500000,
|
||||
.load_addr = 0x80efffc0,
|
||||
.exec_addr = 0x80f00000,
|
||||
.cmdline = recovery_cmdline,
|
||||
},
|
||||
};
|
||||
|
||||
/* Simple diagnostic if something goes wrong -- a little nicer than wondering
|
||||
* what's going on when the machine hangs
|
||||
*/
|
||||
void die(void)
|
||||
{
|
||||
const int pin = (1 << 24);
|
||||
|
||||
/* Turn on button light */
|
||||
jz_clr(GPIO_INT(GPIO_C), pin);
|
||||
jz_set(GPIO_MSK(GPIO_C), pin);
|
||||
jz_clr(GPIO_PAT1(GPIO_C), pin);
|
||||
jz_set(GPIO_PAT0(GPIO_C), pin);
|
||||
|
||||
while(1) {
|
||||
/* Turn it off */
|
||||
mdelay(100);
|
||||
jz_set(GPIO_PAT0(GPIO_C), pin);
|
||||
|
||||
/* Turn it on */
|
||||
mdelay(100);
|
||||
jz_clr(GPIO_PAT0(GPIO_C), pin);
|
||||
}
|
||||
}
|
||||
|
||||
/* Boot select button state must remain stable for this duration
|
||||
* before the choice will be accepted. Currently 100ms.
|
||||
*/
|
||||
#define BTN_STABLE_TIME (100 * (X1000_EXCLK_FREQ / 4000))
|
||||
|
||||
int get_boot_option(void)
|
||||
{
|
||||
const uint32_t pinmask = (1 << 17) | (1 << 19);
|
||||
|
||||
uint32_t pin = 1, lastpin = 0;
|
||||
uint32_t deadline = 0;
|
||||
|
||||
/* Configure the button GPIOs as inputs */
|
||||
gpio_config(GPIO_A, pinmask, GPIO_INPUT);
|
||||
|
||||
/* Poll the pins for a short duration to detect a keypress */
|
||||
do {
|
||||
lastpin = pin;
|
||||
pin = ~REG_GPIO_PIN(GPIO_A) & pinmask;
|
||||
if(pin != lastpin) {
|
||||
/* This will always be set on the first iteration */
|
||||
deadline = __ost_read32() + BTN_STABLE_TIME;
|
||||
}
|
||||
} while(__ost_read32() < deadline);
|
||||
|
||||
/* Play button boots original firmware */
|
||||
if(pin == (1 << 17))
|
||||
return BOOTOPTION_FIIOLINUX;
|
||||
|
||||
/* Volume up boots recovery */
|
||||
if(pin == (1 << 19))
|
||||
return BOOTOPTION_RECOVERY;
|
||||
|
||||
/* Default is to boot Rockbox */
|
||||
return BOOTOPTION_ROCKBOX;
|
||||
}
|
||||
|
||||
void spl_main(void)
|
||||
{
|
||||
/* Get user boot option */
|
||||
int booti = get_boot_option();
|
||||
const struct bootoption* opt = &boot_options[booti];
|
||||
|
||||
/* Load selected firmware from flash */
|
||||
if(nand_open())
|
||||
die();
|
||||
if(nand_read_bytes(opt->nand_addr, opt->nand_size, (void*)opt->load_addr))
|
||||
die();
|
||||
|
||||
if(booti == BOOTOPTION_ROCKBOX) {
|
||||
/* If bootloader is not installed, return back to boot ROM.
|
||||
* Also read in the first eraseblock of NAND flash so it can be
|
||||
* dumped back over USB.
|
||||
*/
|
||||
if(*(unsigned*)(opt->load_addr + 4) != BOOTMAGIC) {
|
||||
nand_read_bytes(0, 128 * 1024, (void*)0x80000000);
|
||||
commit_discard_idcache();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Linux boot not implemented yet
|
||||
*
|
||||
* - Have to initialize UART2, as it's used for the serial console
|
||||
* - Must initialize APLL and change clocks over
|
||||
* - There are some other clocks which need to be initialized
|
||||
* - We should turn off OST since the OF SPL does not turn it on
|
||||
*/
|
||||
die();
|
||||
}
|
||||
|
||||
if(boot_options[booti].cmdline) {
|
||||
/* Handle Linux command line arguments */
|
||||
struct linux_kargs* kargs = (struct linux_kargs*)LINUX_KARGSADDR;
|
||||
kargs->arg0 = 0;
|
||||
kargs->arg1 = (void*)boot_options[booti].cmdline;
|
||||
}
|
||||
|
||||
/* Flush caches and jump to address */
|
||||
void* execaddr = (void*)opt->exec_addr;
|
||||
commit_discard_idcache();
|
||||
__asm__ __volatile__ ("jr %0" :: "r"(execaddr));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
96
bootloader/fiiom3k.c
Normal file
96
bootloader/fiiom3k.c
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "kernel/kernel-internal.h"
|
||||
#include "i2c.h"
|
||||
#include "power.h"
|
||||
#include "lcd.h"
|
||||
#include "backlight.h"
|
||||
#include "button.h"
|
||||
#include "storage.h"
|
||||
#include "file_internal.h"
|
||||
#include "disk.h"
|
||||
#include "rb-loader.h"
|
||||
#include "loader_strerror.h"
|
||||
|
||||
/* Load address where the binary needs to be placed */
|
||||
extern unsigned char loadaddress[];
|
||||
|
||||
/* Fixed buffer to contain the loaded binary in memory */
|
||||
extern unsigned char loadbuffer[];
|
||||
extern unsigned char loadbufferend[];
|
||||
#define MAX_LOAD_SIZE (loadbufferend - loadbuffer)
|
||||
|
||||
void exec(void* dst, const void* src, int bytes)
|
||||
__attribute__((noreturn, section(".icode")));
|
||||
|
||||
void exec(void* dst, const void* src, int bytes)
|
||||
{
|
||||
memcpy(dst, src, bytes);
|
||||
commit_discard_idcache();
|
||||
__asm__ __volatile__ ("jr %0" :: "r"(dst));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static void error(const char* msg)
|
||||
{
|
||||
/* Initialization of the LCD/buttons only if needed */
|
||||
lcd_init();
|
||||
backlight_init();
|
||||
button_init();
|
||||
|
||||
lcd_clear_display();
|
||||
lcd_puts(0, 0, msg);
|
||||
lcd_puts(0, 2, "Press POWER to power off");
|
||||
lcd_update();
|
||||
|
||||
while(button_get(true) != BUTTON_POWER);
|
||||
power_off();
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
system_init();
|
||||
kernel_init();
|
||||
i2c_init();
|
||||
power_init();
|
||||
enable_irq();
|
||||
|
||||
if(storage_init() < 0)
|
||||
error("Storage initialization failed");
|
||||
|
||||
filesystem_init();
|
||||
|
||||
if(!storage_present(0))
|
||||
error("No SD card present");
|
||||
|
||||
if(disk_mount_all() <= 0)
|
||||
error("Unable to mount filesystem");
|
||||
|
||||
int loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE);
|
||||
if(loadsize <= 0)
|
||||
error(loader_strerror(loadsize));
|
||||
|
||||
disable_irq();
|
||||
|
||||
exec(loadaddress, loadbuffer, loadsize);
|
||||
}
|
||||
230
bootloader/x1000-spl.c
Normal file
230
bootloader/x1000-spl.c
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2021 Aidan MacDonald
|
||||
*
|
||||
* 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 "system.h"
|
||||
#include "clk-x1000.h"
|
||||
#include "x1000/cpm.h"
|
||||
#include "x1000/ost.h"
|
||||
#include "x1000/ddrc.h"
|
||||
#include "x1000/ddrc_apb.h"
|
||||
#include "x1000/ddrphy.h"
|
||||
|
||||
#ifdef FIIO_M3K
|
||||
# define DDR_USE_AUTOSR 1
|
||||
# define DDR_NEED_BYPASS 1
|
||||
# define DDR_MEMORYSIZE 64
|
||||
#else
|
||||
# error "Please add DDR definitions for new target!"
|
||||
#endif
|
||||
|
||||
#define hang() do { } while(1)
|
||||
|
||||
/* Target-specific routine to load & execute the Rockbox bootloader */
|
||||
extern void spl_main(void);
|
||||
|
||||
/* Note: This is based purely on disassembly of the SPL from the FiiO M3K.
|
||||
* The code there is somewhat generic and corresponds roughly to Ingenic's
|
||||
* U-Boot code, but isn't entirely the same.
|
||||
*
|
||||
* I converted all the runtime conditionals to compile-time ones in order to
|
||||
* save code space, since they should be constant for any given target.
|
||||
*
|
||||
* I haven't bothered to decode all the register fields. Some of the values
|
||||
* written are going to bits documented as "Reserved" by Ingenic, but their
|
||||
* documentation doesn't seem completely reliable, so either these are bits
|
||||
* which _do_ have a purpose, or they're only defined on other Ingenic CPUs.
|
||||
*
|
||||
* The DDR PHY registers appear to be from Synopsys "PHY Utility Block Lite".
|
||||
* These aren't documented by Ingenic, but the addresses and names can be found
|
||||
* in their U-Boot code.
|
||||
*/
|
||||
static void ddr_init(void)
|
||||
{
|
||||
REG_CPM_DRCG = 0x73;
|
||||
mdelay(3);
|
||||
REG_CPM_DRCG = 0x71;
|
||||
mdelay(3);
|
||||
REG_DDRC_APB_PHYRST_CFG = 0x1a00001;
|
||||
mdelay(3);
|
||||
REG_DDRC_APB_PHYRST_CFG = 0;
|
||||
mdelay(3);
|
||||
REG_DDRC_CTRL = 0xf00000;
|
||||
mdelay(3);
|
||||
REG_DDRC_CTRL = 0;
|
||||
mdelay(3);
|
||||
|
||||
REG_DDRC_CFG = 0xa468a6c;
|
||||
REG_DDRC_CTRL = 2;
|
||||
REG_DDRPHY_DTAR = 0x150000;
|
||||
REG_DDRPHY_DCR = 0;
|
||||
REG_DDRPHY_MR0 = 0x42;
|
||||
REG_DDRPHY_MR2 = 0x98;
|
||||
REG_DDRPHY_PTR0 = 0x21000a;
|
||||
REG_DDRPHY_PTR1 = 0xa09c40;
|
||||
REG_DDRPHY_PTR2 = 0x280014;
|
||||
REG_DDRPHY_DTPR0 = 0x1a69444a;
|
||||
REG_DDRPHY_DTPR1 = 0x180090;
|
||||
REG_DDRPHY_DTPR2 = 0x1ff99428;
|
||||
REG_DDRPHY_DXGCR(0) = 0x90881;
|
||||
REG_DDRPHY_DXGCR(1) = 0x90881;
|
||||
REG_DDRPHY_DXGCR(2) = 0x90e80;
|
||||
REG_DDRPHY_DXGCR(3) = 0x90e80;
|
||||
REG_DDRPHY_PGCR = 0x1042e03;
|
||||
REG_DDRPHY_ACIOCR = 0x30c00813;
|
||||
REG_DDRPHY_DXCCR = 0x4912;
|
||||
|
||||
int i = 10000;
|
||||
while(i > 0 && REG_DDRPHY_PGSR != 7 && REG_DDRPHY_PGSR != 0x1f)
|
||||
i -= 1;
|
||||
if(i == 0)
|
||||
hang();
|
||||
|
||||
#if DDR_NEED_BYPASS
|
||||
REG_DDRPHY_ACDLLCR = 0x80000000;
|
||||
REG_DDRPHY_DSGCR &= ~0x10;
|
||||
REG_DDRPHY_DLLGCR |= 0x800000;
|
||||
REG_DDRPHY_PIR = 0x20020041;
|
||||
#else
|
||||
REG_DDRPHY_PIR = 0x41;
|
||||
#endif
|
||||
|
||||
while(i > 0 && REG_DDRPHY_PGSR != 0xf && REG_DDRPHY_PGSR != 0x1f)
|
||||
i -= 1;
|
||||
if(i == 0)
|
||||
hang();
|
||||
|
||||
REG_DDRC_APB_PHYRST_CFG = 0x400000;
|
||||
mdelay(3);
|
||||
REG_DDRC_APB_PHYRST_CFG = 0;
|
||||
mdelay(3);
|
||||
|
||||
REG_DDRC_CFG = 0xa468aec;
|
||||
REG_DDRC_CTRL = 2;
|
||||
#if DDR_NEED_BYPASS
|
||||
REG_DDRPHY_PIR = 0x20020081;
|
||||
#else
|
||||
REG_DDRPHY_PIR = 0x85;
|
||||
#endif
|
||||
|
||||
i = 500000;
|
||||
while(REG_DDRPHY_PGSR != 0x1f) {
|
||||
if(REG_DDRPHY_PGSR & 0x70)
|
||||
break;
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
if(i == 0)
|
||||
hang();
|
||||
|
||||
if((REG_DDRPHY_PGSR & 0x60) != 0 && REG_DDRPHY_PGSR != 0)
|
||||
hang();
|
||||
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CTRL = 10;
|
||||
REG_DDRC_CTRL = 0;
|
||||
REG_DDRC_CFG = 0xa468a6c;
|
||||
REG_DDRC_TIMING1 = 0x2050501;
|
||||
REG_DDRC_TIMING2 = 0x4090404;
|
||||
REG_DDRC_TIMING3 = 0x2704030d;
|
||||
REG_DDRC_TIMING4 = 0xb7a0251;
|
||||
REG_DDRC_TIMING5 = 0xff090200;
|
||||
REG_DDRC_TIMING6 = 0xa0a0202;
|
||||
#if DDR_MEMORYSIZE == 64
|
||||
REG_DDRC_MMAP0 = 0x20fc;
|
||||
REG_DDRC_MMAP1 = 0x2400;
|
||||
#elif DDR_MEMORYSIZE == 32
|
||||
REG_DDRC_MMAP0 = 0x20fe;
|
||||
REG_DDRC_MMAP1 = 0x2200;
|
||||
#else
|
||||
# error "Unsupported DDR_MEMORYSIZE"
|
||||
#endif
|
||||
REG_DDRC_CTRL = 10;
|
||||
REG_DDRC_REFCNT = 0x2f0003;
|
||||
REG_DDRC_CTRL = 0xc91e;
|
||||
|
||||
#if DDR_MEMORYSIZE == 64
|
||||
REG_DDRC_REMAP1 = 0x03020c0b;
|
||||
REG_DDRC_REMAP2 = 0x07060504;
|
||||
REG_DDRC_REMAP3 = 0x000a0908;
|
||||
REG_DDRC_REMAP4 = 0x0f0e0d01;
|
||||
REG_DDRC_REMAP5 = 0x13121110;
|
||||
#elif DDR_MEMORYSIZE == 32
|
||||
REG_DDRC_REMAP1 = 0x03020b0a;
|
||||
REG_DDRC_REMAP2 = 0x07060504;
|
||||
REG_DDRC_REMAP3 = 0x01000908;
|
||||
REG_DDRC_REMAP4 = 0x0f0e0d0c;
|
||||
REG_DDRC_REMAP5 = 0x13121110;
|
||||
#else
|
||||
# error "Unsupported DDR_MEMORYSIZE"
|
||||
#endif
|
||||
|
||||
REG_DDRC_STATUS &= ~0x40;
|
||||
|
||||
#if DDR_USE_AUTOSR
|
||||
#if DDR_NEED_BYPASS
|
||||
jz_writef(CPM_DDRCDR, GATE_EN(1));
|
||||
REG_DDRC_APB_CLKSTP_CFG = 0x9000000f;
|
||||
#else
|
||||
REG_DDRC_DLP = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
REG_DDRC_AUTOSR_EN = DDR_USE_AUTOSR;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
/* from original firmware SPL */
|
||||
REG_CPM_PSWC0ST = 0x00;
|
||||
REG_CPM_PSWC1ST = 0x10;
|
||||
REG_CPM_PSWC2ST = 0x18;
|
||||
REG_CPM_PSWC3ST = 0x08;
|
||||
|
||||
/* enable MPLL */
|
||||
#if X1000_EXCLK_FREQ == 24000000
|
||||
/* 24 * (24+1) = 600 MHz */
|
||||
jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(24), PLLOD(0));
|
||||
#elif X1000_EXCLK_FREQ == 26000000
|
||||
/* 26 * (22+1) = 598 MHz */
|
||||
jz_writef(CPM_MPCR, ENABLE(1), BS(1), PLLN(0), PLLM(22), PLLOD(0));
|
||||
#else
|
||||
# error "unknown EXCLK frequency"
|
||||
#endif
|
||||
while(jz_readf(CPM_MPCR, ON) == 0);
|
||||
|
||||
/* set DDR clock to MPLL/3 = 200 MHz */
|
||||
jz_writef(CPM_CLKGR, DDR(0));
|
||||
clk_set_ddr(X1000_CLK_MPLL, 3);
|
||||
|
||||
/* start OST so we can use mdelay/udelay */
|
||||
jz_writef(CPM_CLKGR, OST(0));
|
||||
jz_writef(OST_CTRL, PRESCALE2_V(BY_4));
|
||||
jz_writef(OST_CLEAR, OST2(1));
|
||||
jz_write(OST_2CNTH, 0);
|
||||
jz_write(OST_2CNTL, 0);
|
||||
jz_setf(OST_ENABLE, OST2);
|
||||
|
||||
/* init DDR memory */
|
||||
ddr_init();
|
||||
|
||||
/* jump to the target's main routine */
|
||||
spl_main();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue