blob: 324ee1cd85c0af5cb89c2e9dad637ca07145e13e [file] [log] [blame]
/* This file contains the PRISM specific commands.
* The commands are organized as a tree format.
*
* prism ------- diag ---- pon ---- help
* | | |
* | | |------- loopback
* | | |
* | | |------- prbs_rx
* | | |
* | | -------- prbs_rx
* | |
* | ------ gbe ---- help
* | | |
* | | ------- loopback
* | |
* | ------ sff ---- help
* | | |
* | | ------- vbi
* | | |
* | | ------- vei
* | | |
* | | ------- csum
* | | |
* | | ------- vcc
* | |
* | ------ leds ---- help
* | |
* | -------- off
* | |
* | -------- on
* | |
* | -------- blink
* | |
* | -------- list
* |
* ---- help
*
* For help command, you don't need explicit definition, it is automatically
* taken care of by the framework.
*
* Add a new leaf command.
* =======================
* 1. Add the command definition
*
* PRISM_CMD_LEAF(parent, new_command,
* "Your command description", "Your syntax, e.g. <param1> <param2>");
*
* 2. Append the new_command to the parent's sub commands.
*
* static const struct prism_cmd_entry *parent_sub_cmds[] =
* {
* &parent_old_command1,
* &parent_old_command2,
* &parent_new_command,
* NULL
* };
*
* Add a new command group.
* ========================
* 1. Add all leafs and command group belonging to this command group.
*
* 2. Add all new commands to sub_commands.
* static const struct prism_cmd_entry *sub_cmds[] =
* {
* &leaf_command1,
* &leaf_command2,
* &leaf_command3,
* NULL
* };
*
* 3. Add the command group definition
*
* PRISM_CMD_PHONY(parent, new_command_group,
* "Your command description", "Your syntax, e.g. <param1> <param2>",
* sub_commands);
*
*
* 4. Append the new_command_group to the parent's sub commands.
*
* static const struct prism_cmd_entry *parent_sub_cmds[] =
* {
* &parent_old_command1,
* &parent_old_command2,
* &parent_new_command_group,
* NULL
* };
*/
#include <config.h>
#include <common.h>
#include <command.h>
#include <pci.h>
#include <net.h>
#include "mvTypes.h"
#include "mvCtrlEnvLib.h"
#include "boardEnv/mvBoardEnvLib.h"
#include "gpp/mvGpp.h"
#if defined(MV_INCLUDE_UNM_ETH) || defined(MV_INCLUDE_GIG_ETH)
#include "eth-phy/mvEthPhy.h"
#endif
#if defined(CONFIG_MV_ETH_LEGACY)
#include "eth/mvEth.h"
#include "eth/gbe/mvEthDebug.h"
#else
#include "neta/gbe/mvNeta.h"
#endif /* CONFIG_MV_ETH_LEGACY */
#if defined(CONFIG_CMD_PRISM)
#include "prism_sff.h"
#include "prism_gbe.h"
#define FOUR_SPACE " "
typedef int (*exec_func_t) (int level, int argc, char *argv[]);
struct prism_cmd_entry {
const char *name;
const char *desc;
const char *syntax;
exec_func_t exec_func;
const struct prism_cmd_entry **sub_cmds;
};
static void do_help(int level, int argc, char *argv[],
const struct prism_cmd_entry *cmd);
/* Generic MACRO to add a command */
#define PRISM_CMD(parent, name, desc, syntax, sub_cmds) \
static int do_##parent##_##name(int level, int argc, char *argv[]); \
static const struct prism_cmd_entry parent##_##name = \
{#name, desc, syntax, do_##parent##_##name, sub_cmds}
/* MACRO for adding a leaf command. */
#define PRISM_CMD_LEAF(parent, name, desc, syntax) \
PRISM_CMD(parent, name, desc, syntax, NULL)
/* MACRO for adding a command without syntax, usually a command group. */
#define PRISM_CMD_PHONY(parent, name, desc, syntax, sub_cmds) \
static const struct prism_cmd_entry parent##_##name = {#name, desc, syntax, NULL, sub_cmds}
/* SFF field info */
typedef struct sff_field_info_ {
char *name; /* field name */
uint start_daddr; /* starting data address of the section */
uint off; /* offset */
uchar dlen; /* data length */
int (*func)(char *, uchar *); /* ptr of function */
} sff_field_info;
/* diag sff commands */
PRISM_CMD_LEAF(prism_diag_sff, vbi,
"prism board list sfp basic id (0-63) of 0xA0 addr", NULL);
PRISM_CMD_LEAF(prism_diag_sff, vei,
"prism board list sfp extended id (64-95) of 0xA0 addr", NULL);
PRISM_CMD_LEAF(prism_diag_sff, csum,
"prism board sff verifying checksum verification\n"
"ccb - verify CC_BASE at offset 63 of 0xA0 addr\n"
"cce - verify CC_EXT at offset 95 of 0xA0 addr\n"
"ccd - verify CC_DMI at offset 95 of 0xA2 addr",
"<checksum types - ccb cce ccd>\n");
PRISM_CMD_LEAF(prism_diag_sff, vcc,
"internally measured supply voltage in transceiver", NULL);
static const struct prism_cmd_entry *prism_diag_sff_sub_cmds[] =
{
&prism_diag_sff_vbi,
&prism_diag_sff_vei,
&prism_diag_sff_csum,
&prism_diag_sff_vcc,
NULL
};
PRISM_CMD_PHONY(prism_diag, sff,
"prism board SFF diagnostics",
NULL, prism_diag_sff_sub_cmds);
/* diag pon commands */
PRISM_CMD_LEAF(prism_diag_pon, loopback,
"prism board PON loopback diagnostics", NULL);
PRISM_CMD_LEAF(prism_diag_pon, prbs_rx,
"prism board prbx RX diagnostics",
"<prbs pattern - 7, 15, 23> "
"<lock count> <time out>\n");
PRISM_CMD_LEAF(prism_diag_pon, prbs_tx,
"prism board prbx TX diagnostics",
"<prbs patter - 7, 15, 23>");
static const struct prism_cmd_entry *prism_diag_pon_sub_cmds[] =
{
&prism_diag_pon_loopback,
&prism_diag_pon_prbs_rx,
&prism_diag_pon_prbs_tx,
NULL
};
PRISM_CMD_PHONY(prism_diag, pon,
"prism board PON diagnostics",
NULL, prism_diag_pon_sub_cmds);
/* diag gbe commands */
PRISM_CMD_LEAF(prism_diag_gbe, loopback,
"prism board GbE loopback diagnostics\n"
#ifdef GBE_CMD_DBG
"port - port number to test <range: 0 - 1>\n"
"opt - lpbk or ro\n"
"example\n"
" loopback 0 lpbk",
"<port> <opt>\n");
#else
"port - port number to test <range: 0 - 1>",
"<port>\n");
#endif
static const struct prism_cmd_entry *prism_diag_gbe_sub_cmds[] =
{
&prism_diag_gbe_loopback,
NULL
};
PRISM_CMD_PHONY(prism_diag, gbe,
"prism board GbE diagnostics",
NULL, prism_diag_gbe_sub_cmds);
/* diag leds command */
PRISM_CMD_LEAF(prism_diag, leds,
"prism board leds diagnostics",
"<mode - off, on, blink, list> [<name>] [<hz>]\n");
/* diag commands */
static const struct prism_cmd_entry *prism_diag_sub_cmds[] =
{
&prism_diag_gbe,
&prism_diag_pon,
&prism_diag_sff,
&prism_diag_leds,
NULL
};
PRISM_CMD_PHONY(prism, diag,
"prism board diagnostics",
NULL, prism_diag_sub_cmds);
/* root command */
static const struct prism_cmd_entry *prism_sub_cmds[] =
{
&prism_diag,
NULL
};
PRISM_CMD_PHONY(root, prism,
"prism specific commands",
NULL, prism_sub_cmds);
void do_help(int level, int argc, char *argv[],
const struct prism_cmd_entry *cmd)
{
int i;
if (argc < level)
{
return;
}
for (i = 0; i < level; ++i)
{
printf("%s ", argv[i]);
}
if (cmd->desc)
printf("- %s", cmd->desc);
printf("\n");
if (cmd->syntax || cmd->sub_cmds) {
printf("Syntax:\n");
if (cmd->syntax)
{
printf(FOUR_SPACE"%s", cmd->syntax);
}
if (cmd->sub_cmds)
{
for (i = 0; cmd->sub_cmds[i]; ++i) {
printf(FOUR_SPACE"[%s]\n", cmd->sub_cmds[i]->name);
}
}
}
}
static int do_execute_cmd(int level, int argc, char *argv[],
const struct prism_cmd_entry *cmd)
{
int i;
if (argc < level)
{
return 1;
}
if (argc == level)
{
if (cmd->exec_func)
{
return cmd->exec_func(level, argc, argv);
}
else
{
do_help(level, argc, argv, cmd);
}
return 0;
}
if (strcmp(argv[level], "help") == 0)
{
do_help(level, argc, argv, cmd);
return 0;
}
if (cmd->sub_cmds)
{
for (i = 0; cmd->sub_cmds[i]; ++i) {
if (strcmp(cmd->sub_cmds[i]->name, argv[level]) == 0) {
return do_execute_cmd(
level+1, argc, argv,
cmd->sub_cmds[i]);
}
}
}
if (cmd->exec_func)
{
return cmd->exec_func(level, argc, argv);
}
else
{
do_help(level, argc, argv, cmd);
}
return 0;
}
static int do_prism(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
do_execute_cmd(1, argc, argv, &root_prism);
return 1;
}
static int do_prism_diag_pon_loopback(int level, int argc, char *argv[])
{
// TODO(kedong) Fill the register sequences.
printf("do_prism_diag_pon_loopback\n");
return 0;
}
static int do_prism_diag_pon_prbs_rx(int level, int argc, char *argv[])
{
// TODO(kedong) Fill the register sequences.
printf("do_prism_diag_pon_prbs_rx\n");
return 0;
}
static int do_prism_diag_pon_prbs_tx(int level, int argc, char *argv[])
{
// TODO(kedong) Fill the register sequences.
printf("do_prism_diag_pon_prbs_tx\n");
return 0;
}
#ifdef GBE_CMD_DBG
#define MAX_GBE_LPBK_PARAMS 6
#else
#define MAX_GBE_LPBK_PARAMS 5
#endif
static int do_prism_diag_gbe_loopback(int level, int argc, char *argv[])
{
int ret = 1;
int port;
char *pport_str = argv[4];
char *pcmd_opt = argv[5];
do {
if (argc > MAX_GBE_LPBK_PARAMS) {
printf("Error - too many input parameters\n");
break;
}
PRISM_DBG("do_prism_diag_gbe_loopback - port=%s, opt=%s", argv[4], argv[5]);
/* validate the port number */
if ((strlen(pport_str) != 1) || (*pport_str < '0') || (*pport_str > '1')) {
printf("Error - invalid port number (port=%s)\n", pport_str);
break;
}
/* get port number */
port = *pport_str - '0';
#ifdef GBE_CMD_DBG
if (strcmp(pcmd_opt, "lpbk") == 0) {
/* gbe loopback test */
ret = gbe_loopback_test(port, MV_TRUE);
} else if (strcmp(pcmd_opt, "ro") == 0) {
/* gbe receive-only test */
ret = gbe_loopback_test(port, MV_FALSE);
} else {
printf("Error - invalid opt (opt=%s)\n", argv[5]);
}
#else
ret = gbe_loopback_test(port, MV_TRUE);
#endif
} while (0);
printf("%s: gbe loopback test %s\n", __func__, (ret == 0)? "success" : "fail");
return ret;
}
static int sff_print_digits(char *pentry, uchar *pbuf)
{
int i;
sff_field_info *pfield = (sff_field_info *)pentry;
int addr = pfield->start_daddr + pfield->off;
printf("%03d/0x%02X %s:", addr, addr, pfield->name);
for (i = 0; i < pfield->dlen; i++) {
printf(" 0x%02X", pbuf[i]);
}
printf("\n");
return(0);
}
#define SFF_STR_MAX_LEN 40
static int sff_print_str(char *pentry, uchar *pbuf)
{
sff_field_info *pfield = (sff_field_info *)pentry;
int addr = pfield->start_daddr + pfield->off;
uchar sff_str[SFF_STR_MAX_LEN];
if (pfield->dlen < SFF_STR_MAX_LEN) {
memcpy(sff_str, pbuf, pfield->dlen);
sff_str[pfield->dlen] = '\0';
printf("%03d/0x%02X %s: %s\n", addr, addr, pfield->name, sff_str);
}
else
printf("dlen is > %d (dlen=%d)\n", SFF_STR_MAX_LEN, pfield->dlen);
return(0);
}
static int sff_read_print_group(
sff_addr *psff_addr, sff_field_info *pfields, int entries)
{
uchar sff_buf[SFF_BUF_LEN];
sff_field_info *pfield;
int i, ret;
/* read and print the vendor general information.
* buffer all read data, so we can make sure data is read only once.
*/
ret = i2c_read(
psff_addr->chip, psff_addr->daddr, SFF_ADDR_LEN,
sff_buf, psff_addr->nbytes);
if (ret != 0) {
printf("Error - failed to access the sff addr.\n");
return(ret);
}
/* print out the field data per table setting */
for (i = 0, pfield = &pfields[0]; i < entries; i++, pfield++) {
/* pass the staring addr of the field to calling routine */
(pfield->func)((char *)pfield, (sff_buf + pfield->off));
}
return(ret);
} /* end of sff_read_print_group */
static int do_prism_diag_sff_vbi(int level, int argc, char *argv[])
{
int ret;
sff_addr sff_info = {"vbi", SFF_ADDR_A0, SFF_A0_BASE_ID, A0_BASE_ID_L};
static const sff_field_info sfp_serial_id[] = {
{"id", SFF_A0_BASE_ID, 0, 1, sff_print_digits},
{"ext id", SFF_A0_BASE_ID, 1, 1, sff_print_digits},
{"conn", SFF_A0_BASE_ID, 2, 1, sff_print_digits},
{"ven name", SFF_A0_BASE_ID, 20, 16, sff_print_str},
{"ven pn", SFF_A0_BASE_ID, 40, 16, sff_print_str},
{"ven rev", SFF_A0_BASE_ID, 56, 4, sff_print_str}
};
PRISM_DBG("%s\n", __func__);
ret = sff_read_print_group(&sff_info,
(sff_field_info *)sfp_serial_id,
(sizeof(sfp_serial_id)/sizeof(sff_field_info)));
return(ret);
}
static int do_prism_diag_sff_vei(int level, int argc, char *argv[])
{
int ret;
sff_addr sff_info = {"vei", SFF_ADDR_A0, SFF_A0_EXT_ID, A0_EXT_ID_L};
static const sff_field_info sfp_ext_id[] = {
{"ven sn", SFF_A0_EXT_ID, 4, 16, sff_print_str},
{"date code", SFF_A0_EXT_ID, 20, 8, sff_print_str}
};
PRISM_DBG("%s\n", __func__);
ret = sff_read_print_group(&sff_info,
(sff_field_info *)sfp_ext_id,
(sizeof(sfp_ext_id)/sizeof(sff_field_info)));
return(ret);
}
static int do_prism_diag_sff_csum(int level, int argc, char *argv[])
{
int ret;
PRISM_DBG("%s: argc=%d, argv[0]=%s\n", __func__, argc, argv[4]);
ret = sff_read_verify_checksum(argv[4]);
return(ret);
}
static int do_prism_diag_sff_vcc(int level, int argc, char *argv[])
{
int ret;
u16 vcc;
ret = i2c_read(SFF_ADDR_A2, 98, 1, &vcc, sizeof(vcc));
if (!ret)
printf("%hu\n", __be16_to_cpu(vcc));
return ret;
}
enum {
LEDS_MODE_OFF,
LEDS_MODE_ON,
LEDS_MODE_BLINK,
LEDS_MODE_LIST,
};
static void config_led(MV_U8 gpio, MV_U8 polarity,
int mode /* 0 = off, 1 = on, 2 = blink */, int hz)
{
int shift = gpio % 32;
MV_U32 mask = 1 << shift;
MV_U32 group = gpio / 32;
switch (mode) {
case LEDS_MODE_OFF:
mvGppValueSet(group, mask, !polarity << shift);
mvGppBlinkEn(group, mask, 0);
break;
case LEDS_MODE_ON:
mvGppValueSet(group, mask, polarity << shift);
mvGppBlinkEn(group, mask, 0);
break;
case LEDS_MODE_BLINK:
if (hz > 0)
mvGppBlinkCntrSet(MV_GPP_BLINK_CNTR_A,
mvBoardTclkGet() / (hz * 2),
mvBoardTclkGet() / (hz * 2));
mvGppBlinkEn(group, mask, mask);
break;
}
}
static void mux_led(MV_U8 mpp)
{
MV_U32 reg = mvCtrlMppRegGet(mpp / 8);
MV_U32 val = MV_REG_READ(reg);
val &= ~(0xf << ((mpp % 8) * 4));
MV_REG_WRITE(reg, val);
}
static int do_prism_diag_leds(int level, int argc, char *argv[])
{
int hz = 1;
int mode;
MV_U32 i;
const char *name = NULL;
MV_BOARD_INFO *info = mvBoardInfoGet();
MV_BOARD_GPP_INFO *gpp;
if (argc == level) {
printf("Error - no mode specified\n");
return(1);
}
if (!strcmp(argv[level], "off"))
mode = LEDS_MODE_OFF;
else if (!strcmp(argv[level], "on"))
mode = LEDS_MODE_ON;
else if (!strcmp(argv[level], "blink")) {
mode = LEDS_MODE_BLINK;
if (argc > level + 2)
hz = simple_strtol(argv[level + 2], NULL, 0);
}
else if (!strcmp(argv[level], "list"))
mode = LEDS_MODE_LIST;
else {
printf("Error - invalid mode\n");
return(1);
}
if (argc > level + 1)
name = argv[level + 1];
for (i = 0; i < info->numBoardGppInfo; i++) {
gpp = &info->pBoardGppInfo[i];
if ((gpp->devClass == BOARD_GPP_LED)
&& (!name || (gpp->name && !strcmp(name, gpp->name)))) {
if (mode == LEDS_MODE_LIST)
printf("%s\n", gpp->name);
else {
mux_led(gpp->gppPinNum);
config_led(gpp->gppPinNum, !gpp->activeLow,
mode, hz);
}
}
}
return(0);
}
U_BOOT_CMD(
prism,
/* Don't forget to check maxargs when new commands are added. */
14, 0, do_prism,
"prism - prism specific commands\n",
"prism - prism specific commands\n"
);
#endif /*CFG_CMD_PRISM*/