255 lines
5.1 KiB
C
Executable File
255 lines
5.1 KiB
C
Executable File
/*
|
|
* Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
|
|
*/
|
|
|
|
|
|
#include "ddr_interface.h"
|
|
#include "ddr_training_impl.h"
|
|
|
|
#define __ddr_training_console__
|
|
#ifdef DDR_TRAINING_CONSOLE_CONFIG
|
|
|
|
#define DDR_UART_BASE_REG 0x12090000
|
|
#define UART_PL01x_FR 0x18 /* Flag register (Read only). */
|
|
#define UART_PL01x_FR_RXFE 0x10
|
|
#define UART_PL01x_DR 0x00 /* Data read or written from the interface. */
|
|
#define UART_PL01x_ECR 0x04 /* Error clear register (Write). */
|
|
|
|
#define isprint(c) ((c) >= ' ' && (c) <= '~')
|
|
#define isspace(c) ((c) == ' ' || ((c) >= '\t' && (c) <= '\r'))
|
|
#define isdigit(c) ((c) >= '0' && (c) <= '9')
|
|
#define isxdigit(c) (isdigit(c) \
|
|
|| ((c) >= 'A' && (c) <= 'F') \
|
|
|| ((c) >= 'a' && (c) <= 'f'))
|
|
#define CMD(_p, _c0, _c1, _do_cmd) \
|
|
if (_p[0] == _c0 && _p[1] == _c1) { \
|
|
if (!_do_cmd(_p + 2)) \
|
|
continue; \
|
|
}
|
|
|
|
/* DDR console get char */
|
|
static int ddr_console_getc(void)
|
|
{
|
|
unsigned int data;
|
|
|
|
/* Wait until there is data in the FIFO */
|
|
while (ddr_read(DDR_UART_BASE_REG + UART_PL01x_FR) & UART_PL01x_FR_RXFE) {
|
|
}
|
|
|
|
data = ddr_read(DDR_UART_BASE_REG + UART_PL01x_DR);
|
|
|
|
/* Check for an error flag */
|
|
if (data & 0xFFFFFF00) {
|
|
/* Clear the error */
|
|
ddr_write(0xFFFFFFFF, DDR_UART_BASE_REG + UART_PL01x_ECR);
|
|
return -1;
|
|
}
|
|
return (int) data;
|
|
}
|
|
|
|
/* DDR read line */
|
|
static char *ddr_readline(char *str, int len)
|
|
{
|
|
unsigned int c;
|
|
char *p = str;
|
|
while (len > 0) {
|
|
c = ddr_console_getc();
|
|
switch (c) {
|
|
case '\r':
|
|
case '\n':
|
|
*p = '\0';
|
|
DDR_PUTC('\r');
|
|
DDR_PUTC('\n');
|
|
return str;
|
|
case 0x08:
|
|
case 0x7F:
|
|
if (p > str) {
|
|
p--;
|
|
len++;
|
|
DDR_PUTC('\b');
|
|
DDR_PUTC(' ');
|
|
DDR_PUTC('\b');
|
|
}
|
|
break;
|
|
default:
|
|
if (isprint(c)) {
|
|
(*p++) = (char)c;
|
|
len--;
|
|
DDR_PUTC(c);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
(*--p) = '\0';
|
|
return str;
|
|
}
|
|
|
|
/* HEX to INT */
|
|
static int hex2int(char **ss, unsigned int *n)
|
|
{
|
|
unsigned char *s = (unsigned char *)(*ss);
|
|
|
|
while (isspace(*s)) s++;
|
|
|
|
if (!(*s))
|
|
return -1;
|
|
|
|
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
|
|
s += 2;
|
|
|
|
for ((*n) = 0; isxdigit(*s); s++) {
|
|
(*n) = ((*n) << 4);
|
|
if ((*s) >= '0' && (*s) <= '9')
|
|
(*n) |= ((*s) - '0');
|
|
else if ((*s) >= 'a' && (*s) <= 'f')
|
|
(*n) |= ((*s) + 10 - 'a');
|
|
else if ((*s) >= 'A' && (*s) <= 'F')
|
|
(*n) |= ((*s) + 10 - 'A');
|
|
}
|
|
|
|
if (isspace(*s) || !(*s)) {
|
|
while (isspace(*s)) s++;
|
|
(*ss) = (char *)s;
|
|
return 0;
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
/**
|
|
* DDR do memory write.
|
|
* mw address value [count]
|
|
*/
|
|
static int ddr_do_memory_write(char *cmd)
|
|
{
|
|
unsigned int address;
|
|
unsigned int value;
|
|
unsigned int count = 4;
|
|
|
|
if (hex2int(&cmd, &address))
|
|
return -1;
|
|
|
|
if (hex2int(&cmd, &value))
|
|
return -1;
|
|
|
|
if ((*cmd) && hex2int(&cmd, &count))
|
|
return -1;
|
|
|
|
if (address & 0x03 || count & 0x03) {
|
|
DDR_INFO("parameter should align with 4 bytes.\n");
|
|
return -1;
|
|
}
|
|
for (;count > 0; count -= 4, address += 4)
|
|
ddr_write(value, address);
|
|
return 0;
|
|
}
|
|
/**
|
|
* DDR do memory display.
|
|
* md address [count]
|
|
*/
|
|
static int ddr_do_memory_display(char *cmd)
|
|
{
|
|
unsigned int ix;
|
|
unsigned int loop;
|
|
unsigned int address;
|
|
unsigned int count = 64;
|
|
|
|
if (hex2int(&cmd, &address))
|
|
return -1;
|
|
|
|
if ((*cmd) && hex2int(&cmd, &count))
|
|
return -1;
|
|
|
|
if (count < 4)
|
|
count = 4;
|
|
|
|
address &= ~0x03;
|
|
loop = (count & ~0x03);
|
|
|
|
while (loop > 0) {
|
|
|
|
DDR_PUTC('0');
|
|
DDR_PUTC('x');
|
|
DDR_PUT_HEX(address);
|
|
DDR_PUTC(':');
|
|
|
|
for (ix = 0;
|
|
ix < 4 && loop > 0;
|
|
ix++, loop -= 4, address += 4) {
|
|
|
|
DDR_PUTC(' '); DDR_PUT_HEX(ddr_read(address));
|
|
}
|
|
DDR_PUTC('\r');
|
|
DDR_PUTC('\n');
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DDR_TRAINING_CMD
|
|
extern struct ddr_training_result_st ddrt_result_sram;
|
|
#endif
|
|
static int ddr_do_sw_training(char *cmd)
|
|
{
|
|
int result;
|
|
struct ddr_cfg_st ddr_cfg;
|
|
struct ddr_cfg_st *cfg = &ddr_cfg;
|
|
|
|
ddr_training_cfg_init(cfg);
|
|
#ifdef DDR_TRAINING_CMD
|
|
cfg->res_st = (void *)&ddrt_result_sram;
|
|
#endif
|
|
result = ddr_training_all(cfg);
|
|
|
|
result += ddr_dcc_training_func(cfg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ddr_do_hw_training(char *cmd)
|
|
{
|
|
int result;
|
|
|
|
result = ddr_hw_training_func();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Do DDR training console if sw training or hw training fail */
|
|
static int ddr_training_console(void *args)
|
|
{
|
|
char str[256];
|
|
char *p = NULL;
|
|
unsigned int cmd=0;
|
|
|
|
while (1) {
|
|
DDR_PUTC('d');
|
|
DDR_PUTC('d');
|
|
DDR_PUTC('r');
|
|
DDR_PUTC('#');
|
|
|
|
p = ddr_readline(str, sizeof(str));
|
|
|
|
while (isspace(*p)) p++;
|
|
if (p[0] == 'q')
|
|
break;
|
|
CMD(p, 'm', 'w', ddr_do_memory_write) else
|
|
CMD(p, 'm', 'd', ddr_do_memory_display) else
|
|
CMD(p, 's', 'w', ddr_do_sw_training) else
|
|
CMD(p, 'h', 'w', ddr_do_hw_training)
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
static int ddr_training_console(void *args)
|
|
{
|
|
DDR_WARNING("Not support DDR training console.");
|
|
return 0;
|
|
}
|
|
#endif /* DDR_TRAINING_CONSOLE_CONFIG */
|
|
|
|
int ddr_training_console_if(void *args)
|
|
{
|
|
return DDR_TRAINING_CONSOLE(args);
|
|
}
|