Commit 659ea493 authored by Angus Ainslie's avatar Angus Ainslie

imx8m_som/ddr : Add an option to use the M4 code to load the DDR training firmware

parent f5f73bb2
...@@ -6,3 +6,6 @@ config SYS_VENDOR ...@@ -6,3 +6,6 @@ config SYS_VENDOR
config SYS_CONFIG_NAME config SYS_CONFIG_NAME
default "imx8m_som" default "imx8m_som"
config M4_LOAD_DDR_TRAINING
bool "Use the M4 to load the DDR training firmware"
...@@ -6,26 +6,66 @@ ...@@ -6,26 +6,66 @@
#include <common.h> #include <common.h>
#include <spl.h> #include <spl.h>
#include <mmc.h>
#include <blk.h>
#include <asm/io.h> #include <asm/io.h>
#include <errno.h> #include <errno.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/arch/ddr_memory_map.h> #include <asm/arch/ddr_memory_map.h>
#include <asm/arch/clock.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/arch/sys_proto.h>
#include <fsl_wdog.h>
#include "ddr.h" #include "ddr.h"
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
#define OCRAM_BASE 0x900000
#define OCRAM_SIZE (128*1024)
#define TCML_BASE 0x7e0000
#define TCMU_BASE 0x800000
#define TCMU_SIZE 0x20000
#define TCMU_CMD_M4 (TCMU_BASE + TCMU_SIZE - 24) /* command mailbox */
#define TCMU_ARG_M4 (TCMU_BASE + TCMU_SIZE - 20) /* arg mailbox */
#define TCMU_ST_M4 (TCMU_BASE + TCMU_SIZE - 16) /* status mailbox */
#define TCMU_CMD_A53 (TCMU_BASE + TCMU_SIZE - 12) /* command mailbox */
#define TCMU_ARG_A53 (TCMU_BASE + TCMU_SIZE - 8) /* arg mailbox */
#define TCMU_ST_A53 (TCMU_BASE + TCMU_SIZE - 4) /* status mailbox */
#define CMD_NONE 0
#define CMD_READY 1
#define CMD_WRITE_FW 2
#define ST_NONE 0
#define ST_READY 1
#define ST_FAIL 2
#define ST_SUCCESS 3
#define ST_BUSY 4
#define ST_EXCEPT 5
#define IMEM_LEN 32768//23400 //byte #define IMEM_LEN 32768//23400 //byte
#define DMEM_LEN 16384//1720 //byte #define DMEM_LEN 16384//1720 //byte
#define IMEM_2D_OFFSET 49152 #define IMEM_2D_OFFSET 49152
#define FIRMWARE_BASE (OCRAM_BASE + OCRAM_SIZE / 2)
#define IMEM_OFFSET_ADDR 0x00050000 #define IMEM_OFFSET_ADDR 0x00050000
#define DMEM_OFFSET_ADDR 0x00054000 #define DMEM_OFFSET_ADDR 0x00054000
#define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0) #define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0)
struct aipstz_regs {
u32 mprot0;
u32 mprot1;
u32 rsvd[0xe];
u32 opacr0;
u32 opacr1;
u32 opacr2;
u32 opacr3;
u32 opacr4;
};
/* We need PHY iMEM PHY is 32KB padded */ /* We need PHY iMEM PHY is 32KB padded */
void ddr_load_train_code(enum fw_type type) void old_ddr_load_train_code(enum fw_type type)
{ {
u32 tmp32, i; u32 tmp32, i;
u32 error = 0; u32 error = 0;
...@@ -58,6 +98,7 @@ void ddr_load_train_code(enum fw_type type) ...@@ -58,6 +98,7 @@ void ddr_load_train_code(enum fw_type type)
i += 4; i += 4;
} }
printf("check ddr4_pmu_train_imem code\n");
pr_from32 = imem_start; pr_from32 = imem_start;
pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR; pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR;
for(i = 0x0; i < IMEM_LEN;){ for(i = 0x0; i < IMEM_LEN;){
...@@ -75,8 +116,11 @@ void ddr_load_train_code(enum fw_type type) ...@@ -75,8 +116,11 @@ void ddr_load_train_code(enum fw_type type)
} }
if(error){ if(error){
printf("check ddr4_pmu_train_imem code fail=%d\n",error); printf("check ddr4_pmu_train_imem code fail=%d\n",error);
}else{
printf("check ddr4_pmu_train_imem code pass\n");
} }
printf("check ddr4_pmu_train_dmem code\n");
pr_from32 = dmem_start; pr_from32 = dmem_start;
pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR; pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR;
for(i = 0x0; i < DMEM_LEN;){ for(i = 0x0; i < DMEM_LEN;){
...@@ -94,5 +138,306 @@ void ddr_load_train_code(enum fw_type type) ...@@ -94,5 +138,306 @@ void ddr_load_train_code(enum fw_type type)
if(error){ if(error){
printf("check ddr4_pmu_train_dmem code fail=%d",error); printf("check ddr4_pmu_train_dmem code fail=%d",error);
}else{
printf("check ddr4_pmu_train_dmem code pass\n");
}
}
void load_train_code_tcmu(enum fw_type type)
{
u32 tmp32, i;
unsigned long pr_to32, pr_from32;
unsigned long fw_offset = type ? IMEM_2D_OFFSET : 0;
unsigned long imem_start = (unsigned long)&_end + fw_offset;
unsigned long dmem_start = imem_start + IMEM_LEN;
printf("copying ddr4_pmu_train_imem code\n");
pr_from32 = imem_start;
pr_to32 = FIRMWARE_BASE;
for(i = 0x0; i < IMEM_LEN; ){
tmp32 = readl(pr_from32);
writel(tmp32, pr_to32);
pr_to32 += 4;
pr_from32 += 4;
i += 4;
}
printf("copying ddr4_pmu_train_dmem code\n");
pr_from32 = dmem_start;
pr_to32 = FIRMWARE_BASE+IMEM_LEN;
for(i = 0x0; i < DMEM_LEN;){
tmp32 = readl(pr_from32);
writel(tmp32, pr_to32);
pr_to32 += 4;
pr_from32 += 4;
i += 4;
}
}
extern int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device);
int is_mx8(void)
{
return 1;
}
void init_aips(void)
{
struct aipstz_regs *aips[4];
int num_aips = 2, i;
aips[0] = (struct aipstz_regs *)AIPS1_BASE_ADDR;
aips[1] = (struct aipstz_regs *)AIPS2_BASE_ADDR;
aips[2] = (struct aipstz_regs *)AIPS3_BASE_ADDR;
aips[3] = (struct aipstz_regs *)AIPS4_BASE_ADDR;
if (is_mx6ull() || is_mx6sx() || is_mx7())
num_aips = 3;
if(is_mx8())
num_aips = 4;
for( i=0; i<num_aips; i++) {
/*
* Set all MPROTx to be non-bufferable, trusted for R/W,
* not forced to user-mode.
*/
writel(0x77770700, &aips[i]->mprot0);
//writel(0x77777777, &aips[i]->mprot1);
/*
* Set all OPACRx to be non-bufferable, not require
* supervisor privilege level for access,allow for
* write access and untrusted master access.
*/
writel(0x00000000, &aips[i]->opacr0);
writel(0x00000000, &aips[i]->opacr1);
writel(0x00000000, &aips[i]->opacr2);
writel(0x00000000, &aips[i]->opacr3);
writel(0x00000000, &aips[i]->opacr4);
}
}
#define SRC_M4RCR 0x3039000C
void M4_load_firmware( enum fw_type type )
{
#if defined(CONFIG_M4_LOAD_DDR_TRAINING)
uint32_t status;
printf("Set A53 ready\n");
writel(CMD_READY, TCMU_CMD_A53);
printf("Wait for M4 cmd finished\n");
status = readl(TCMU_ST_M4);
while(status != ST_FAIL && status != ST_SUCCESS)
{
status = readl(TCMU_ST_M4);
/*if(status == ST_EXCEPT)
{
printf( "M4 Exception : %d\n", readl(TCMU_CMD_M4));
return;
}*/
}
printf("Clear A53 command\n");
writel(0, TCMU_CMD_A53);
while(status != ST_READY)
status = readl(TCMU_ST_M4);
printf("Cortex M4 synchronized\n");
load_train_code_tcmu(type);
writel(type, TCMU_ARG_A53);
writel(0, TCMU_ST_A53);
printf("Cmd write firmware\n");
writel(CMD_WRITE_FW, TCMU_CMD_A53);
status = readl(TCMU_ST_M4);
printf("Wait for M4 to complete\n");
while(status != ST_FAIL && status != ST_SUCCESS)
{
status = readl(TCMU_ST_M4);
/*if(status == ST_EXCEPT)
{
printf( "M4 Exception : %d\n", readl(TCMU_CMD_M4));
return;
}*/
}
/*
printf("ddr trainging code loaded - type 0x%x\n", type);
writel(0, TCMU_CMD_A53);
while(status != ST_READY)
status = readl(TCMU_ST_M4);
*/
#endif
}
void start_M4(void)
{
struct mmc *mmc;
struct blk_desc *block_dev;
void *vect_buffer = (void *)TCML_BASE;
void *buffer = (void *)OCRAM_BASE;
uint32_t status, reg, stack, pc;
int err, count;
int boot_device;
#if 0
/* use this wait to stop the code for the OpenOCD debugger */
volatile int i = 0;
printf("busy wait");
while( i==0 );
#endif
printf("Setting up AIPS\n");
init_aips();
printf("Finding MMC device\n");
boot_device = spl_boot_device();
if(0 == (err = spl_mmc_find_device(&mmc, boot_device)))
{
err = mmc_init(mmc);
if (err) {
printf("spl: mmc init failed with error: %d\n", err);
}
else
{
printf("Disabling Cortex M4 clock\n");
clock_enable(CCGR_M4, 0);
printf("Getting block device\n");
block_dev = mmc_get_blk_desc(mmc);
printf("Loading Cortex M4 firmware loader\n");
/* From 2k copy - blocks are 512 bytes each */
blk_dread(block_dev, 4, 64, buffer);
printf("Loading Cortex M4 exception vectors\n");
blk_dread(block_dev, 4, 1, vect_buffer);
printf("Starting Cortex M4 core\n");
stack = *(u32 *)buffer;
pc = *(u32 *)(buffer + 4);
/* Set the stack and pc to M4 bootROM */
writel(stack, M4_BOOTROM_BASE_ADDR);
writel(pc, M4_BOOTROM_BASE_ADDR + 4);
printf("Enabling Cortex M4 clock\n");
clock_enable(CCGR_M4, 1);
printf("reset M4 core\n");
reg = readl(SRC_M4RCR);
writel((reg & ~0xF)| 0xa, SRC_M4RCR);
status = readl(TCMU_ST_M4);
for(count = 0; count < 50000; count++)
{
status = readl(TCMU_ST_M4);
if( status == ST_READY )
break;
udelay( 10 );
}
if(status == ST_READY) {
printf("Cortex M4 ready\n");
}
else
{
printf("Cortex M4 NOT ready\n");
}
}
}
else
{
printf("spl: mmc find device failed with error: %d\n", err);
} }
} }
void ddr_load_train_code(enum fw_type type)
{
struct mmc *mmc;
struct blk_desc *block_dev;
void *vect_buffer = (void *)TCML_BASE;
void *buffer = (void *)OCRAM_BASE;
uint32_t status, reg, stack, pc;
int err, count;
int boot_device;
#if defined(CONFIG_M4_LOAD_DDR_TRAINING)
printf("Finding MMC device\n");
boot_device = spl_boot_device();
if(0 == (err = spl_mmc_find_device(&mmc, boot_device)))
{
err = mmc_init(mmc);
if (err) {
printf("spl: mmc init failed with error: %d\n", err);
}
else
{
printf("Disabling Cortex M4 clock\n");
clock_enable(CCGR_M4, 0);
printf("Getting block device\n");
block_dev = mmc_get_blk_desc(mmc);
printf("Loading Cortex M4 firmware loader\n");
/* From 2k copy - blocks are 512 bytes each */
blk_dread(block_dev, 4, 64, buffer);
printf("Loading Cortex M4 exception vectors\n");
blk_dread(block_dev, 4, 1, vect_buffer);
printf("Starting Cortex M4 core\n");
stack = *(u32 *)buffer;
pc = *(u32 *)(buffer + 4);
/* Set the stack and pc to M4 bootROM */
writel(stack, M4_BOOTROM_BASE_ADDR);
writel(pc, M4_BOOTROM_BASE_ADDR + 4);
printf("Enabling Cortex M4 clock\n");
clock_enable(CCGR_M4, 1);
printf("reset M4 core\n");
reg = readl(SRC_M4RCR);
writel((reg & ~0xF)| 0xa, SRC_M4RCR);
status = readl(TCMU_ST_M4);
for(count = 0; count < 50000; count++)
{
status = readl(TCMU_ST_M4);
if( status == ST_READY )
break;
udelay( 10 );
}
if(status == ST_READY) {
printf("Cortex M4 ready\n");
}
else
{
printf("Cortex M4 NOT ready\n");
}
//if( boot_M4() == ST_READY )
M4_load_firmware( type );
}
}
else
{
printf("spl: mmc find device failed with error: %d\n", err);
}
#else
old_ddr_load_train_code(type);
#endif
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment