| /* 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*/ |
| |