in drivers/ddr/fsl/interactive.c [1888:2314]
unsigned long long fsl_ddr_interactive(fsl_ddr_info_t *pinfo, int var_is_set)
{
unsigned long long ddrsize;
const char *prompt = "FSL DDR>";
char buffer[CONFIG_SYS_CBSIZE];
char buffer2[CONFIG_SYS_CBSIZE];
char *p = NULL;
char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
int argc;
unsigned int next_step = STEP_GET_SPD;
const char *usage = {
"commands:\n"
"print print SPD and intermediate computed data\n"
"reset reboot machine\n"
"recompute reload SPD and options to default and recompute regs\n"
"edit modify spd, parameter, or option\n"
"compute recompute registers from current next_step to end\n"
"copy copy parameters\n"
"next_step shows current next_step\n"
"help this message\n"
"go program the memory controller and continue with u-boot\n"
};
if (var_is_set) {
if (env_get_f("ddr_interactive", buffer2,
CONFIG_SYS_CBSIZE) > 0)
p = buffer2;
else
var_is_set = 0;
}
/*
* The strategy for next_step is that it points to the next
* step in the computation process that needs to be done.
*/
while (1) {
if (var_is_set) {
char *pend = strchr(p, ';');
if (pend) {
/* found command separator, copy sub-command */
*pend = '\0';
strcpy(buffer, p);
p = pend + 1;
} else {
/* separator not found, copy whole string */
strcpy(buffer, p);
p = NULL;
var_is_set = 0;
}
} else {
/*
* No need to worry for buffer overflow here in
* this function; cli_readline() maxes out at
* CFG_CBSIZE
*/
cli_readline_into_buffer(prompt, buffer, 0);
}
argc = cli_simple_parse_line(buffer, argv);
if (argc == 0)
continue;
if (strcmp(argv[0], "help") == 0) {
puts(usage);
continue;
}
if (strcmp(argv[0], "next_step") == 0) {
printf("next_step = 0x%02X (%s)\n",
next_step,
step_to_string(next_step));
continue;
}
if (strcmp(argv[0], "copy") == 0) {
unsigned int error = 0;
unsigned int step_mask = 0;
unsigned int src_ctlr_mask = 0;
unsigned int src_dimm_mask = 0;
unsigned int dimm_number_required = 0;
unsigned int src_ctlr_num = 0;
unsigned int src_dimm_num = 0;
unsigned int dst_ctlr_num = -1;
unsigned int dst_dimm_num = -1;
unsigned int i, num_dest_parms;
if (argc == 1) {
printf("copy <src c#> <src d#> <spd|dimmparms|commonparms|opts|addresses|regs> <dst c#> <dst d#>\n");
continue;
}
error = fsl_ddr_parse_interactive_cmd(
argv, argc,
&step_mask,
&src_ctlr_mask,
&src_dimm_mask,
&dimm_number_required
);
/* XXX: only dimm_number_required and step_mask will
be used by this function. Parse the controller and
DIMM number separately because it is easier. */
if (error)
continue;
/* parse source destination controller / DIMM */
num_dest_parms = dimm_number_required ? 2 : 1;
for (i = 0; i < argc; i++) {
if (argv[i][0] == 'c') {
char c = argv[i][1];
if (isdigit(c)) {
src_ctlr_num = (c - '0');
break;
}
}
}
for (i = 0; i < argc; i++) {
if (argv[i][0] == 'd') {
char c = argv[i][1];
if (isdigit(c)) {
src_dimm_num = (c - '0');
break;
}
}
}
/* parse destination controller / DIMM */
for (i = argc - 1; i >= argc - num_dest_parms; i--) {
if (argv[i][0] == 'c') {
char c = argv[i][1];
if (isdigit(c)) {
dst_ctlr_num = (c - '0');
break;
}
}
}
for (i = argc - 1; i >= argc - num_dest_parms; i--) {
if (argv[i][0] == 'd') {
char c = argv[i][1];
if (isdigit(c)) {
dst_dimm_num = (c - '0');
break;
}
}
}
/* TODO: validate inputs */
debug("src_ctlr_num = %u, src_dimm_num = %u, dst_ctlr_num = %u, dst_dimm_num = %u, step_mask = %x\n",
src_ctlr_num, src_dimm_num, dst_ctlr_num, dst_dimm_num, step_mask);
switch (step_mask) {
case STEP_GET_SPD:
memcpy(&(pinfo->spd_installed_dimms[dst_ctlr_num][dst_dimm_num]),
&(pinfo->spd_installed_dimms[src_ctlr_num][src_dimm_num]),
sizeof(pinfo->spd_installed_dimms[0][0]));
break;
case STEP_COMPUTE_DIMM_PARMS:
memcpy(&(pinfo->dimm_params[dst_ctlr_num][dst_dimm_num]),
&(pinfo->dimm_params[src_ctlr_num][src_dimm_num]),
sizeof(pinfo->dimm_params[0][0]));
break;
case STEP_COMPUTE_COMMON_PARMS:
memcpy(&(pinfo->common_timing_params[dst_ctlr_num]),
&(pinfo->common_timing_params[src_ctlr_num]),
sizeof(pinfo->common_timing_params[0]));
break;
case STEP_GATHER_OPTS:
memcpy(&(pinfo->memctl_opts[dst_ctlr_num]),
&(pinfo->memctl_opts[src_ctlr_num]),
sizeof(pinfo->memctl_opts[0]));
break;
/* someday be able to have addresses to copy addresses... */
case STEP_COMPUTE_REGS:
memcpy(&(pinfo->fsl_ddr_config_reg[dst_ctlr_num]),
&(pinfo->fsl_ddr_config_reg[src_ctlr_num]),
sizeof(pinfo->memctl_opts[0]));
break;
default:
printf("unexpected step_mask value\n");
}
continue;
}
if (strcmp(argv[0], "edit") == 0) {
unsigned int error = 0;
unsigned int step_mask = 0;
unsigned int ctlr_mask = 0;
unsigned int dimm_mask = 0;
char *p_element = NULL;
char *p_value = NULL;
unsigned int dimm_number_required = 0;
unsigned int ctrl_num;
unsigned int dimm_num;
if (argc == 1) {
/* Only the element and value must be last */
printf("edit <c#> <d#> "
"<spd|dimmparms|commonparms|opts|"
"addresses|regs> <element> <value>\n");
printf("for spd, specify byte number for "
"element\n");
continue;
}
error = fsl_ddr_parse_interactive_cmd(
argv, argc - 2,
&step_mask,
&ctlr_mask,
&dimm_mask,
&dimm_number_required
);
if (error)
continue;
/* Check arguments */
/* ERROR: If no steps were found */
if (step_mask == 0) {
printf("Error: No valid steps were specified "
"in argument.\n");
continue;
}
/* ERROR: If multiple steps were found */
if (step_mask & (step_mask - 1)) {
printf("Error: Multiple steps specified in "
"argument.\n");
continue;
}
/* ERROR: Controller not specified */
if (ctlr_mask == 0) {
printf("Error: controller number not "
"specified or no element and "
"value specified\n");
continue;
}
if (ctlr_mask & (ctlr_mask - 1)) {
printf("Error: multiple controllers "
"specified, %X\n", ctlr_mask);
continue;
}
/* ERROR: DIMM number not specified */
if (dimm_number_required && dimm_mask == 0) {
printf("Error: DIMM number number not "
"specified or no element and "
"value specified\n");
continue;
}
if (dimm_mask & (dimm_mask - 1)) {
printf("Error: multipled DIMMs specified\n");
continue;
}
p_element = argv[argc - 2];
p_value = argv[argc - 1];
ctrl_num = __ilog2(ctlr_mask);
dimm_num = __ilog2(dimm_mask);
switch (step_mask) {
case STEP_GET_SPD:
{
unsigned int element_num;
unsigned int value;
element_num = simple_strtoul(p_element,
NULL, 0);
value = simple_strtoul(p_value,
NULL, 0);
fsl_ddr_spd_edit(pinfo,
ctrl_num,
dimm_num,
element_num,
value);
next_step = STEP_COMPUTE_DIMM_PARMS;
}
break;
case STEP_COMPUTE_DIMM_PARMS:
fsl_ddr_dimm_parameters_edit(
pinfo, ctrl_num, dimm_num,
p_element, p_value);
next_step = STEP_COMPUTE_COMMON_PARMS;
break;
case STEP_COMPUTE_COMMON_PARMS:
lowest_common_dimm_parameters_edit(pinfo,
ctrl_num, p_element, p_value);
next_step = STEP_GATHER_OPTS;
break;
case STEP_GATHER_OPTS:
fsl_ddr_options_edit(pinfo, ctrl_num,
p_element, p_value);
next_step = STEP_ASSIGN_ADDRESSES;
break;
case STEP_ASSIGN_ADDRESSES:
printf("editing of address assignment "
"not yet implemented\n");
break;
case STEP_COMPUTE_REGS:
{
fsl_ddr_regs_edit(pinfo,
ctrl_num,
p_element,
p_value);
next_step = STEP_PROGRAM_REGS;
}
break;
default:
printf("programming error\n");
while (1)
;
break;
}
continue;
}
if (strcmp(argv[0], "reset") == 0) {
/*
* Reboot machine.
* Args don't seem to matter because this
* doesn't return
*/
do_reset(NULL, 0, 0, NULL);
printf("Reset didn't work\n");
}
if (strcmp(argv[0], "recompute") == 0) {
/*
* Recalculate everything, starting with
* loading SPD EEPROM from DIMMs
*/
next_step = STEP_GET_SPD;
ddrsize = fsl_ddr_compute(pinfo, next_step, 0);
continue;
}
if (strcmp(argv[0], "compute") == 0) {
/*
* Compute rest of steps starting at
* the current next_step/
*/
ddrsize = fsl_ddr_compute(pinfo, next_step, 0);
continue;
}
if (strcmp(argv[0], "print") == 0) {
unsigned int error = 0;
unsigned int step_mask = 0;
unsigned int ctlr_mask = 0;
unsigned int dimm_mask = 0;
unsigned int dimm_number_required = 0;
if (argc == 1) {
printf("print [c<n>] [d<n>] [spd] [dimmparms] "
"[commonparms] [opts] [addresses] [regs]\n");
continue;
}
error = fsl_ddr_parse_interactive_cmd(
argv, argc,
&step_mask,
&ctlr_mask,
&dimm_mask,
&dimm_number_required
);
if (error)
continue;
/* If no particular controller was found, print all */
if (ctlr_mask == 0)
ctlr_mask = 0xFF;
/* If no particular dimm was found, print all dimms. */
if (dimm_mask == 0)
dimm_mask = 0xFF;
/* If no steps were found, print all steps. */
if (step_mask == 0)
step_mask = STEP_ALL;
fsl_ddr_printinfo(pinfo, ctlr_mask,
dimm_mask, step_mask);
continue;
}
if (strcmp(argv[0], "go") == 0) {
if (next_step)
ddrsize = fsl_ddr_compute(pinfo, next_step, 0);
break;
}
printf("unknown command %s\n", argv[0]);
}
debug("end of memory = %llu\n", (u64)ddrsize);
return ddrsize;
}