Commit 900fc692 authored by Hugo Grostabussiat's avatar Hugo Grostabussiat

imx8m: Add Purism Librem5 devkit board

This commit creates a new board for the Purism Librem5 devkit.

- The board code was copied from the emcraft/imx8m_som board, minus the
parts which were not relevant (other DDR configs).
- The Emcraft-specific preprocessor defines have been removed.
- A new librem5.h configuration file was created.
parent 5a34315e
......@@ -90,6 +90,12 @@ config TARGET_EMCRAFT_IMX8M_LPDDR4_800MHZ_2GB_SOM
endchoice
config TARGET_PURISM_LIBREM5_DEVKIT
bool "Purism Librem5 devkit"
select IMX8M
select IMX8MQ
select SUPPORT_SPL
config SYS_SOC
default "imx8m"
......@@ -99,5 +105,6 @@ source "board/freescale/imx8mq_arm2/Kconfig"
source "board/freescale/imx8mm_evk/Kconfig"
source "board/freescale/imx8mm_val/Kconfig"
source "board/emcraft/imx8m_som/Kconfig"
source "board/purism/librem5/Kconfig"
endif
../freescale/common
\ No newline at end of file
if TARGET_PURISM_LIBREM5_DEVKIT
config SYS_BOARD
default "librem5"
config SYS_VENDOR
default "purism"
config SYS_CONFIG_NAME
default "librem5"
config M4_LOAD_DDR_TRAINING
bool "Use the M4 to load the DDR training firmware"
endif
#
# Copyright 2016 Freescale Semiconductor
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += imx8m_som.o
ifdef CONFIG_SPL_BUILD
obj-y += spl.o
obj-y += ddr/lpddr4_3gb/ddr_init.o ddr/lpddr4_3gb/ddrphy_train.o \
ddr/lpddr4_3gb/helper.o
endif
/*
* Copyright 2017 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*/
enum fw_type {
FW_1D_IMAGE,
FW_2D_IMAGE,
};
void ddr_init(void);
void ddr_load_train_code(enum fw_type type);
void lpddr4_800M_cfg_phy(void);
static inline void reg32_write(unsigned long addr, u32 val)
{
writel(val, addr);
}
static inline uint32_t reg32_read(unsigned long addr)
{
return readl(addr);
}
static void inline dwc_ddrphy_apb_wr(unsigned long addr, u32 val)
{
writel(val, addr);
}
static inline void reg32setbit(unsigned long addr, u32 bit)
{
setbits_le32(addr, (1 << bit));
}
/*
* Copyright 2017 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*
* Generated code from MX8M_DDR_tool
*/
#include <common.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/ddr_memory_map.h>
#include <asm/arch/clock.h>
#include "ddr.h"
#ifdef CONFIG_ENABLE_DDR_TRAINING_DEBUG
#define ddr_printf(args...) printf(args)
#else
#define ddr_printf(args...)
#endif
#include "wait_ddrphy_training_complete.c"
#ifndef SRC_DDRC_RCR_ADDR
#define SRC_DDRC_RCR_ADDR SRC_IPS_BASE_ADDR +0x1000
#endif
#ifndef DDR_CSD1_BASE_ADDR
#define DDR_CSD1_BASE_ADDR 0x40000000
#endif
#define SILICON_TRAIN
void ddr_cfg_phy(void);
volatile unsigned int tmp, tmp_t, i;
void ddr_init(void)
{
/** Initialize DDR clock and DDRC registers **/
reg32_write(0x3038a088,0x7070000);
reg32_write(0x3038a084,0x4030000);
reg32_write(0x303a00ec,0xffff);
tmp=reg32_read(0x303a00f8);
tmp |= 0x20;
reg32_write(0x303a00f8,tmp);
reg32_write(0x30391000,0x8f000000);
reg32_write(0x30391004,0x8f000000);
reg32_write(0x30360068,0xece580);
tmp=reg32_read(0x30360060);
tmp &= ~0x80;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp |= 0x200;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp &= ~0x20;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp &= ~0x10;
reg32_write(0x30360060,tmp);
do{
tmp=reg32_read(0x30360060);
if(tmp&0x80000000) break;
}while(1);
reg32_write(0x30391000,0x8f000006);
reg32_write(0x3d400304,0x1);
reg32_write(0x3d400030,0x1);
reg32_write(0x3d400000,0xa3080020);
reg32_write(0x3d400028,0x0);
reg32_write(0x3d400020,0x203);
reg32_write(0x3d400024,0x186a000);
reg32_write(0x3d400064,0x6100e0);
reg32_write(0x3d4000d0,0xc003061c);
reg32_write(0x3d4000d4,0x9e0000);
reg32_write(0x3d4000dc,0xd4002d);
reg32_write(0x3d4000e0,0x310008);
reg32_write(0x3d4000e8,0x66004a);
reg32_write(0x3d4000ec,0x16004a);
reg32_write(0x3d400100,0x1a201b22);
reg32_write(0x3d400104,0x60633);
reg32_write(0x3d40010c,0xc0c000);
reg32_write(0x3d400110,0xf04080f);
reg32_write(0x3d400114,0x2040c0c);
reg32_write(0x3d400118,0x1010007);
reg32_write(0x3d40011c,0x401);
reg32_write(0x3d400130,0x20600);
reg32_write(0x3d400134,0xc100002);
reg32_write(0x3d400138,0xe6);
reg32_write(0x3d400144,0xa00050);
reg32_write(0x3d400180,0x3200018);
reg32_write(0x3d400184,0x28061a8);
reg32_write(0x3d400188,0x0);
reg32_write(0x3d400190,0x497820a);
reg32_write(0x3d400194,0x80303);
reg32_write(0x3d4001a0,0xe0400018);
reg32_write(0x3d4001a4,0xdf00e4);
reg32_write(0x3d4001a8,0x80000000);
reg32_write(0x3d4001b0,0x11);
reg32_write(0x3d4001b4,0x170a);
reg32_write(0x3d4001c0,0x1);
reg32_write(0x3d4001c4,0x1);
reg32_write(0x3d4000f4,0x639);
reg32_write(0x3d400108,0x70e1214);
reg32_write(0x3d400200,0x15);
reg32_write(0x3d40020c,0x0);
reg32_write(0x3d400210,0x1f1f);
reg32_write(0x3d400204,0x80808);
reg32_write(0x3d400214,0x7070707);
reg32_write(0x3d400218,0x48080707);
reg32_write(0x3d402020,0x1);
reg32_write(0x3d402024,0x518b00);
reg32_write(0x3d402050,0x20d040);
reg32_write(0x3d402064,0x14002f);
reg32_write(0x3d4020dc,0x940009);
reg32_write(0x3d4020e0,0x310000);
reg32_write(0x3d4020e8,0x66004a);
reg32_write(0x3d4020ec,0x16004a);
reg32_write(0x3d402100,0xb070508);
reg32_write(0x3d402104,0x3040b);
reg32_write(0x3d402108,0x305090c);
reg32_write(0x3d40210c,0x505000);
reg32_write(0x3d402110,0x4040204);
reg32_write(0x3d402114,0x2030303);
reg32_write(0x3d402118,0x1010004);
reg32_write(0x3d40211c,0x301);
reg32_write(0x3d402130,0x20300);
reg32_write(0x3d402134,0xa100002);
reg32_write(0x3d402138,0x31);
reg32_write(0x3d402144,0x220011);
reg32_write(0x3d402180,0xa70006);
reg32_write(0x3d402190,0x3858202);
reg32_write(0x3d402194,0x80303);
reg32_write(0x3d4021b4,0x502);
reg32_write(0x3d400244,0x0);
reg32_write(0x3d400250,0x29001505);
reg32_write(0x3d400254,0x2c);
reg32_write(0x3d40025c,0x5900575b);
reg32_write(0x3d400264,0x9);
reg32_write(0x3d40026c,0x2005574);
reg32_write(0x3d400300,0x16);
reg32_write(0x3d400304,0x0);
reg32_write(0x3d40030c,0x0);
reg32_write(0x3d400320,0x1);
reg32_write(0x3d40036c,0x11);
reg32_write(0x3d400400,0x111);
reg32_write(0x3d400404,0x10f3);
reg32_write(0x3d400408,0x72ff);
reg32_write(0x3d400490,0x1);
reg32_write(0x3d400494,0x1110d00);
reg32_write(0x3d400498,0x620790);
reg32_write(0x3d40049c,0x100001);
reg32_write(0x3d4004a0,0x41f);
reg32_write(0x30391000,0x8f000004);
reg32_write(0x30391000,0x8f000000);
reg32_write(0x3d400030,0xa8);
do{
tmp=reg32_read(0x3d400004);
if(tmp&0x223) break;
}while(1);
reg32_write(0x3d400320,0x0);
reg32_write(0x3d000000,0x1);
reg32_write(0x3d4001b0,0x10);
reg32_write(0x3c040280,0x0);
reg32_write(0x3c040284,0x1);
reg32_write(0x3c040288,0x2);
reg32_write(0x3c04028c,0x3);
reg32_write(0x3c040290,0x4);
reg32_write(0x3c040294,0x5);
reg32_write(0x3c040298,0x6);
reg32_write(0x3c04029c,0x7);
reg32_write(0x3c044280,0x0);
reg32_write(0x3c044284,0x1);
reg32_write(0x3c044288,0x2);
reg32_write(0x3c04428c,0x3);
reg32_write(0x3c044290,0x4);
reg32_write(0x3c044294,0x5);
reg32_write(0x3c044298,0x6);
reg32_write(0x3c04429c,0x7);
reg32_write(0x3c048280,0x0);
reg32_write(0x3c048284,0x1);
reg32_write(0x3c048288,0x2);
reg32_write(0x3c04828c,0x3);
reg32_write(0x3c048290,0x4);
reg32_write(0x3c048294,0x5);
reg32_write(0x3c048298,0x6);
reg32_write(0x3c04829c,0x7);
reg32_write(0x3c04c280,0x0);
reg32_write(0x3c04c284,0x1);
reg32_write(0x3c04c288,0x2);
reg32_write(0x3c04c28c,0x3);
reg32_write(0x3c04c290,0x4);
reg32_write(0x3c04c294,0x5);
reg32_write(0x3c04c298,0x6);
reg32_write(0x3c04c29c,0x7);
/* Configure DDR PHY's registers */
ddr_cfg_phy();
reg32_write(DDRC_RFSHCTL3(0), 0x00000000);
reg32_write(DDRC_SWCTL(0), 0x0000);
/*
* ------------------- 9 -------------------
* Set DFIMISC.dfi_init_start to 1
* -----------------------------------------
*/
reg32_write(DDRC_DFIMISC(0), 0x00000030);
reg32_write(DDRC_SWCTL(0), 0x0001);
/* wait DFISTAT.dfi_init_complete to 1 */
tmp_t = 0;
while(tmp_t==0){
tmp = reg32_read(DDRC_DFISTAT(0));
tmp_t = tmp & 0x01;
tmp = reg32_read(DDRC_MRSTAT(0));
}
reg32_write(DDRC_SWCTL(0), 0x0000);
/* clear DFIMISC.dfi_init_complete_en */
reg32_write(DDRC_DFIMISC(0), 0x00000010);
reg32_write(DDRC_DFIMISC(0), 0x00000011);
reg32_write(DDRC_PWRCTL(0), 0x00000088);
tmp = reg32_read(DDRC_CRCPARSTAT(0));
/*
* set SWCTL.sw_done to enable quasi-dynamic register
* programming outside reset.
*/
reg32_write(DDRC_SWCTL(0), 0x00000001);
/* wait SWSTAT.sw_done_ack to 1 */
while((reg32_read(DDRC_SWSTAT(0)) & 0x1) == 0)
;
/* wait STAT.operating_mode([1:0] for ddr3) to normal state */
while ((reg32_read(DDRC_STAT(0)) & 0x3) != 0x1)
;
reg32_write(DDRC_PWRCTL(0), 0x00000088);
/* reg32_write(DDRC_PWRCTL(0), 0x018a); */
tmp = reg32_read(DDRC_CRCPARSTAT(0));
/* enable port 0 */
reg32_write(DDRC_PCTRL_0(0), 0x00000001);
/* enable DDR auto-refresh mode */
tmp = reg32_read(DDRC_RFSHCTL3(0)) & ~0x1;
reg32_write(DDRC_RFSHCTL3(0), tmp);
}
\ No newline at end of file
/*
* Copyright 2017 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*
* Generated code from MX8M_DDR_tool
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/ddr_memory_map.h>
#include "ddr.h"
extern void wait_ddrphy_training_complete(void);
void ddr_cfg_phy(void) {
unsigned int tmp, tmp_t;
//Init DDRPHY register...
reg32_write(0x3c080440,0x2);
reg32_write(0x3c080444,0x3);
reg32_write(0x3c080448,0x4);
reg32_write(0x3c08044c,0x5);
reg32_write(0x3c080450,0x0);
reg32_write(0x3c080454,0x1);
reg32_write(0x3c04017c,0x1ff);
reg32_write(0x3c04057c,0x1ff);
reg32_write(0x3c04417c,0x1ff);
reg32_write(0x3c04457c,0x1ff);
reg32_write(0x3c04817c,0x1ff);
reg32_write(0x3c04857c,0x1ff);
reg32_write(0x3c04c17c,0x1ff);
reg32_write(0x3c04c57c,0x1ff);
reg32_write(0x3c44017c,0x1ff);
reg32_write(0x3c44057c,0x1ff);
reg32_write(0x3c44417c,0x1ff);
reg32_write(0x3c44457c,0x1ff);
reg32_write(0x3c44817c,0x1ff);
reg32_write(0x3c44857c,0x1ff);
reg32_write(0x3c44c17c,0x1ff);
reg32_write(0x3c44c57c,0x1ff);
reg32_write(0x3c000154,0x1ff);
reg32_write(0x3c004154,0x1ff);
reg32_write(0x3c008154,0x1ff);
reg32_write(0x3c00c154,0x1ff);
reg32_write(0x3c010154,0x1ff);
reg32_write(0x3c014154,0x1ff);
reg32_write(0x3c018154,0x1ff);
reg32_write(0x3c01c154,0x1ff);
reg32_write(0x3c020154,0x1ff);
reg32_write(0x3c024154,0x1ff);
reg32_write(0x3c080314,0x19);
reg32_write(0x3c480314,0x7);
reg32_write(0x3c0800b8,0x2);
reg32_write(0x3c4800b8,0x1);
reg32_write(0x3c240810,0x0);
reg32_write(0x3c640810,0x0);
reg32_write(0x3c080090,0xab);
reg32_write(0x3c0800e8,0x0);
reg32_write(0x3c480090,0xab);
reg32_write(0x3c0800e8,0x0);
reg32_write(0x3c080158,0x3);
reg32_write(0x3c480158,0xa);
reg32_write(0x3c040134,0xe00);
reg32_write(0x3c040534,0xe00);
reg32_write(0x3c044134,0xe00);
reg32_write(0x3c044534,0xe00);
reg32_write(0x3c048134,0xe00);
reg32_write(0x3c048534,0xe00);
reg32_write(0x3c04c134,0xe00);
reg32_write(0x3c04c534,0xe00);
reg32_write(0x3c440134,0xe00);
reg32_write(0x3c440534,0xe00);
reg32_write(0x3c444134,0xe00);
reg32_write(0x3c444534,0xe00);
reg32_write(0x3c448134,0xe00);
reg32_write(0x3c448534,0xe00);
reg32_write(0x3c44c134,0xe00);
reg32_write(0x3c44c534,0xe00);
reg32_write(0x3c040124,0xfbe);
reg32_write(0x3c040524,0xfbe);
reg32_write(0x3c044124,0xfbe);
reg32_write(0x3c044524,0xfbe);
reg32_write(0x3c048124,0xfbe);
reg32_write(0x3c048524,0xfbe);
reg32_write(0x3c04c124,0xfbe);
reg32_write(0x3c04c524,0xfbe);
reg32_write(0x3c440124,0xfbe);
reg32_write(0x3c440524,0xfbe);
reg32_write(0x3c444124,0xfbe);
reg32_write(0x3c444524,0xfbe);
reg32_write(0x3c448124,0xfbe);
reg32_write(0x3c448524,0xfbe);
reg32_write(0x3c44c124,0xfbe);
reg32_write(0x3c44c524,0xfbe);
reg32_write(0x3c00010c,0x63);
reg32_write(0x3c00410c,0x63);
reg32_write(0x3c00810c,0x63);
reg32_write(0x3c00c10c,0x63);
reg32_write(0x3c01010c,0x63);
reg32_write(0x3c01410c,0x63);
reg32_write(0x3c01810c,0x63);
reg32_write(0x3c01c10c,0x63);
reg32_write(0x3c02010c,0x63);
reg32_write(0x3c02410c,0x63);
reg32_write(0x3c080060,0x3);
reg32_write(0x3c0801d4,0x4);
reg32_write(0x3c080140,0x0);
reg32_write(0x3c080020,0x320);
reg32_write(0x3c480020,0xa7);
reg32_write(0x3c080220,0x9);
reg32_write(0x3c0802c8,0xdc);
reg32_write(0x3c04010c,0x5a1);
reg32_write(0x3c04050c,0x5a1);
reg32_write(0x3c04410c,0x5a1);
reg32_write(0x3c04450c,0x5a1);
reg32_write(0x3c04810c,0x5a1);
reg32_write(0x3c04850c,0x5a1);
reg32_write(0x3c04c10c,0x5a1);
reg32_write(0x3c04c50c,0x5a1);
reg32_write(0x3c4802c8,0xdc);
reg32_write(0x3c44010c,0x5a1);
reg32_write(0x3c44050c,0x5a1);
reg32_write(0x3c44410c,0x5a1);
reg32_write(0x3c44450c,0x5a1);
reg32_write(0x3c44810c,0x5a1);
reg32_write(0x3c44850c,0x5a1);
reg32_write(0x3c44c10c,0x5a1);
reg32_write(0x3c44c50c,0x5a1);
reg32_write(0x3c0803e8,0x1);
reg32_write(0x3c4803e8,0x1);
reg32_write(0x3c080064,0x1);
reg32_write(0x3c480064,0x1);
reg32_write(0x3c0803c0,0x0);
reg32_write(0x3c0803c4,0x0);
reg32_write(0x3c0803c8,0x4444);
reg32_write(0x3c0803cc,0x8888);
reg32_write(0x3c0803d0,0x5555);
reg32_write(0x3c0803d4,0x0);
reg32_write(0x3c0803d8,0x0);
reg32_write(0x3c0803dc,0xf000);
reg32_write(0x3c080094,0x0);
reg32_write(0x3c0800b4,0x0);
reg32_write(0x3c4800b4,0x0);
reg32_write(0x3c080180,0x2);
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 1D training image
ddr_load_train_code(FW_1D_IMAGE);
//configure DDRPHY-FW DMEM structure @clock0...
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
//set the PHY input clock to the desired frequency for pstate 0
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54004,0x2);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54006,0x11);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54008,0x131f);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54009,0xc8);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400b,0x2);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400d,0x100);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4a66);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4a66);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x6600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x6600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600);
//disable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
//Reset MPU and run
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
wait_ddrphy_training_complete();
//configure DDRPHY-FW DMEM structure @clock1...
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
//set the PHY input clock to the desired frequency for pstate 1
reg32_write(0x3038a088,0x7070000);
reg32_write(0x3038a084,0x4030000);
reg32_write(0x303a00ec,0xffff);
tmp=reg32_read(0x303a00f8);
tmp |= 0x20;
reg32_write(0x303a00f8,tmp);
reg32_write(0x30360068,0xf5a406);
tmp=reg32_read(0x30360060);
tmp &= ~0x80;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp |= 0x200;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp &= ~0x20;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp &= ~0x10;
reg32_write(0x30360060,tmp);
do{
tmp=reg32_read(0x30360060);
if(tmp&0x80000000) break;
}while(1);
reg32_write(0x30389808,0x1000000);
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
reg32_write(0x3c150008,0x1);
reg32_write(0x3c15000c,0x29c);
reg32_write(0x3c150020,0x121f);
reg32_write(0x3c150064,0x994);
reg32_write(0x3c150068,0x31);
reg32_write(0x3c15006c,0x4d46);
reg32_write(0x3c150070,0x4d08);
reg32_write(0x3c150074,0x0);
reg32_write(0x3c150078,0x15);
reg32_write(0x3c15007c,0x994);
reg32_write(0x3c150080,0x31);
reg32_write(0x3c150084,0x4d46);
reg32_write(0x3c150088,0x4d08);
reg32_write(0x3c15008c,0x0);
reg32_write(0x3c150090,0x15);
reg32_write(0x3c1500c8,0x9400);
reg32_write(0x3c1500cc,0x3109);
reg32_write(0x3c1500d0,0x4600);
reg32_write(0x3c1500d4,0x84d);
reg32_write(0x3c1500d8,0x4d);
reg32_write(0x3c1500dc,0x1500);
reg32_write(0x3c1500e0,0x9400);
reg32_write(0x3c1500e4,0x3109);
reg32_write(0x3c1500e8,0x4600);
reg32_write(0x3c1500ec,0x84d);
reg32_write(0x3c1500f0,0x4d);
reg32_write(0x3c1500f4,0x1500);
reg32_write(0x3c1500f8,0x0);
//disable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
//Reset MPU and run
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
wait_ddrphy_training_complete();
//set the PHY input clock to the desired frequency for pstate 0
reg32_write(0x3038a088,0x7070000);
reg32_write(0x3038a084,0x4030000);
reg32_write(0x303a00ec,0xffff);
tmp=reg32_read(0x303a00f8);
tmp |= 0x20;
reg32_write(0x303a00f8,tmp);
reg32_write(0x30360068,0xece580);
tmp=reg32_read(0x30360060);
tmp &= ~0x80;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp |= 0x200;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp &= ~0x20;
reg32_write(0x30360060,tmp);
tmp=reg32_read(0x30360060);
tmp &= ~0x10;
reg32_write(0x30360060,tmp);
do{
tmp=reg32_read(0x30360060);
if(tmp&0x80000000) break;
}while(1);
reg32_write(0x30389808,0x1000000);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//load the 2D training image
ddr_load_train_code(FW_2D_IMAGE);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54003,0xc80);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54006,0x11);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54008,0x61);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54009,0xc8);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400b,0x2);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5400f,0x100);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54010,0x1f7f);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54012,0x310);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54019,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401a,0x31);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401b,0x4a66);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401c,0x4a08);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401e,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5401f,0x2dd4);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54020,0x31);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54021,0x4a66);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54022,0x4a08);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54024,0x16);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402b,0x1000);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5402c,0x3);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54032,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54033,0x312d);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54034,0x6600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54035,0x84a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54036,0x4a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54037,0x1600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54038,0xd400);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x54039,0x312d);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403a,0x6600);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403b,0x84a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403c,0x4a);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0x5403d,0x1600);
//disable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x1);
//Reset MPU and run
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x9);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x0);
wait_ddrphy_training_complete();
//Halt MPU
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0099, 0x1);
//enable APB bus to access DDRPHY RAM
reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0000, 0x0);
//Load firmware PIE image
reg32_write(0x3c240000,0x10);
reg32_write(0x3c240004,0x400);
reg32_write(0x3c240008,0x10e);
reg32_write(0x3c24000c,0x0);
reg32_write(0x3c240010,0x0);
reg32_write(0x3c240014,0x8);
reg32_write(0x3c2400a4,0xb);
reg32_write(0x3c2400a8,0x480);
reg32_write(0x3c2400ac,0x109);
reg32_write(0x3c2400b0,0x8);
reg32_write(0x3c2400b4,0x448);
reg32_write(0x3c2400b8,0x139);
reg32_write(0x3c2400bc,0x8);
reg32_write(0x3c2400c0,0x478);
reg32_write(0x3c2400c4,0x109);
reg32_write(0x3c2400c8,0x0);
reg32_write(0x3c2400cc,0xe8);