From: Allen Martin <amartin@xxxxxxxxxx> The Denver CPU in Tegra132 requires microcode to be loaded before CPU initialization. There are two microcode files required, "preboot" MTS and MTS proper. Add support for loading MTS from either the binary filenames or binary directory with default filenames from the command line. Signed-off-by: Allen Martin <amartin@xxxxxxxxxx> --- src/Makefile.am | 2 + src/main.c | 294 ++++++++++++++++++++++++++++++++-- src/miniloader/tegra132-mts.h | 12 ++ src/miniloader/tegra132-preboot-mts.h | 11 ++ src/nv3p.c | 19 +++ src/nv3p.h | 9 ++ src/rcm.h | 1 + src/tegrarcm.1.in | 7 + 8 files changed, 344 insertions(+), 11 deletions(-) create mode 100644 src/miniloader/tegra132-mts.h create mode 100644 src/miniloader/tegra132-preboot-mts.h diff --git a/src/Makefile.am b/src/Makefile.am index d0d45cad4fee..ba167f0dcc6c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,8 @@ tegrarcm_SOURCES = \ miniloader/tegra114-miniloader.h \ miniloader/tegra124-miniloader.h \ miniloader/tegra132-miniloader.h \ + miniloader/tegra132-preboot-mts.h \ + miniloader/tegra132-mts.h \ usb.h man_MANS = tegrarcm.1 diff --git a/src/main.c b/src/main.c index 24d3bf81191f..b173675d3944 100644 --- a/src/main.c +++ b/src/main.c @@ -63,16 +63,26 @@ // tegra132 miniloader #include "miniloader/tegra132-miniloader.h" +// tegra132 preboot mts +#include "miniloader/tegra132-preboot-mts.h" + +// tegra132 mts +#include "miniloader/tegra132-mts.h" + static int initialize_rcm(uint16_t devid, usb_device_t *usb); static int initialize_miniloader(uint16_t devid, usb_device_t *usb, char *mlfile, uint32_t mlentry); +static int initialize_preboot(usb_device_t *usb, char *pbfile, uint32_t pbentry, char *mtsdir); static int wait_status(nv3p_handle_t h3p); static int send_file(nv3p_handle_t h3p, const char *filename); -static int download_miniloader(usb_device_t *usb, uint8_t *miniloader, - uint32_t size, uint32_t entry); +static int send_buf(nv3p_handle_t h3p, uint8_t *buf, uint64_t total); +static int download_binary(uint32_t cmd, usb_device_t *usb, + uint8_t *miniloader, uint32_t size, uint32_t entry); static void dump_platform_info(nv3p_platform_info_t *info); static int download_bct(nv3p_handle_t h3p, char *filename); static int download_bootloader(nv3p_handle_t h3p, char *filename, uint32_t entry, uint32_t loadaddr); +static int download_mts(nv3p_handle_t h3p, char *filename, + uint32_t loadaddr, uint16_t devid, char *mtsdir); static int read_bct(nv3p_handle_t h3p, char *filename); enum cmdline_opts { @@ -84,6 +94,11 @@ enum cmdline_opts { OPT_VERSION, OPT_MINILOADER, OPT_MINIENTRY, + OPT_PREBOOT, + OPT_PREBOOTENTRY, + OPT_MTS, + OPT_MTSENTRY, + OPT_MTSDIR, OPT_END, }; @@ -117,6 +132,20 @@ static void usage(char *progname) fprintf(stderr, "\t\tminiloader\n"); fprintf(stderr, "\t--miniloader_entry=<mlentry>\n"); fprintf(stderr, "\t\tSpecify the entry point for the miniloader\n"); + fprintf(stderr, "\t--preboot=pbfile\n"); + fprintf(stderr, "\t\tRead the preboot mts ucode from file instead of using built-in\n"); + fprintf(stderr, "\t\tpreboot mts\n"); + fprintf(stderr, "\t--preboot-entry=<pbentry>\n"); + fprintf(stderr, "\t\tSpecify the entry point for the preboot ucode\n"); + fprintf(stderr, "\t--mts=mtsfile\n"); + fprintf(stderr, "\t\tRead the mts ucode from file instead of using built-in\n"); + fprintf(stderr, "\t\tmts\n"); + fprintf(stderr, "\t--mts-entry=<mtsentry>\n"); + fprintf(stderr, "\t\tSpecify the entry point for the cpu ucode\n"); + fprintf(stderr, "\t--mts-dir=full_mts_directory\n"); + fprintf(stderr, "\t\tRead the mts ucode from indicated location with pre-defined\n"); + fprintf(stderr, "\t\tfile name and entry point. mts-dir will take precedence\n"); + fprintf(stderr, "\t\tover mts and preboot options\n"); fprintf(stderr, "\n"); } @@ -139,6 +168,11 @@ int main(int argc, char **argv) int do_read = 0; char *mlfile = NULL; uint32_t mlentry = 0; + char *pbfile = NULL; + uint32_t pbentry = 0; + char *mtsfile = NULL; + uint32_t mtsentry = 0; + char *mtsdir = NULL; static struct option long_options[] = { [OPT_BCT] = {"bct", 1, 0, 0}, @@ -149,6 +183,11 @@ int main(int argc, char **argv) [OPT_VERSION] = {"version", 0, 0, 0}, [OPT_MINILOADER] = {"miniloader", 1, 0, 0}, [OPT_MINIENTRY] = {"miniloader_entry", 1, 0, 0}, + [OPT_PREBOOT] = {"preboot", 1, 0, 0}, + [OPT_PREBOOTENTRY] = {"preboot-entry", 1, 0, 0}, + [OPT_MTS] = {"mts", 1, 0, 0}, + [OPT_MTSENTRY] = {"mts-entry", 1, 0, 0}, + [OPT_MTSDIR] = {"mts-dir", 1, 0, 0}, [OPT_END] = {0, 0, 0, 0} }; @@ -184,6 +223,21 @@ int main(int argc, char **argv) case OPT_MINIENTRY: mlentry = strtoul(optarg, NULL, 0); break; + case OPT_PREBOOT: + pbfile = optarg; + break; + case OPT_PREBOOTENTRY: + pbentry = strtoul(optarg, NULL, 0); + break; + case OPT_MTS: + mtsfile = optarg; + break; + case OPT_MTSENTRY: + mtsentry = strtoul(optarg, NULL, 0); + break; + case OPT_MTSDIR: + mtsdir = optarg; + break; case OPT_HELP: default: usage(argv[0]); @@ -255,6 +309,13 @@ int main(int argc, char **argv) if (ret2) error(1, errno, "error initializing RCM protocol"); + // download the mts_preboot ucode + if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA132) { + ret2 = initialize_preboot(usb, pbfile, pbentry, mtsdir); + if (ret2) + error(1, errno, "error initializing preboot mts"); + } + // download the miniloader to start nv3p ret2 = initialize_miniloader(devid, usb, mlfile, mlentry); if (ret2) @@ -304,6 +365,13 @@ int main(int argc, char **argv) error(1, ret, "error downloading bct: %s", bctfile); } + // download mts + if ((devid & 0xff) == USB_DEVID_NVIDIA_TEGRA132) { + ret = download_mts(h3p, mtsfile, mtsentry, devid, mtsdir); + if (ret) + error(1, ret, "error downloading mts: %s", mtsfile); + } + // download the bootloader ret = download_bootloader(h3p, blfile, entryaddr, loadaddr); if (ret) @@ -377,6 +445,84 @@ static int initialize_rcm(uint16_t devid, usb_device_t *usb) return 0; } +static int initialize_preboot(usb_device_t *usb, char *pbfile, uint32_t pbentry, + char *mtsdir) +{ + int fd; + struct stat sb; + int ret; + uint8_t *preboot, *_preboot = NULL; + uint32_t pb_size; + uint32_t pb_entry; + char *_mtsdir = NULL; + + if (!mtsdir && !pbfile) { + mtsdir = _mtsdir = (char *)malloc(strlen(TEGRA132_MTS_DIR) + 1); + sprintf(mtsdir, "%s", TEGRA132_MTS_DIR); + } + + if (mtsdir) { + pbfile = (char *)malloc(strlen(mtsdir) + 2 + + strlen(TEGRA132_PREBOOT_MTS_FILE)); + sprintf(pbfile, "%s/%s", mtsdir, TEGRA132_PREBOOT_MTS_FILE); + pbentry = TEGRA132_PREBOOT_MTS_ENTRY; + } + + // use prebuilt preboot mts if not loading from a file + if (pbfile) { + fd = open(pbfile, O_RDONLY, 0); + if (fd < 0) { + fprintf(stderr, "error: %s\n", pbfile); + dprintf("error opening %s for reading\n", pbfile); + ret = errno; + goto done; + } + ret = fstat(fd, &sb); + if (ret) { + dprintf("error on fstat of %s\n", pbfile); + goto done; + } + pb_size = sb.st_size; + preboot = _preboot = (uint8_t *)malloc(pb_size); + if (!preboot) { + dprintf("error allocating %d bytes for preboot mts\n", pb_size); + ret = errno; + goto done; + } + if (read(fd, preboot, pb_size) != pb_size) { + dprintf("error reading from preboot mts file"); + ret = errno; + goto done; + } + pb_entry = pbentry; + } else { + dprintf("error opening %s for reading\n", pbfile); + ret = errno; + goto done; + } + + printf("downloading preboot mts to target at address 0x%x (%d bytes)...\n", + pb_entry, pb_size); + ret = download_binary(RCM_CMD_DL_MTS, usb, preboot, + pb_size, pb_entry); + if (ret) { + fprintf(stderr, "Error downloading preboot mts\n"); + goto done; + } + printf("preboot mts downloaded successfully\n"); +done: + if (_mtsdir) + free(_mtsdir); + + if (mtsdir && pbfile) + free(pbfile); + + if (_preboot) + free(_preboot); + + return ret; +} + static int initialize_miniloader(uint16_t devid, usb_device_t *usb, char *mlfile, uint32_t mlentry) { int fd; @@ -437,8 +583,8 @@ static int initialize_miniloader(uint16_t devid, usb_device_t *usb, char *mlfile } printf("downloading miniloader to target at address 0x%x (%d bytes)...\n", miniloader_entry, miniloader_size); - ret = download_miniloader(usb, miniloader, miniloader_size, - miniloader_entry); + ret = download_binary(RCM_CMD_DL_MINILOADER, usb, miniloader, + miniloader_size, miniloader_entry); if (ret) { fprintf(stderr, "Error downloading miniloader\n"); return ret; @@ -486,6 +632,44 @@ fail: /* +* send_buf: send data present in buffer to nv3p server +*/ +static int send_buf(nv3p_handle_t h3p, uint8_t *buf, uint64_t total) +{ + int ret = 0; + uint32_t size; + uint64_t count; + char *spinner = "-\\|/"; + int spin_idx = 0; + +#define NVFLASH_DOWNLOAD_CHUNK (1024 * 64) + + printf("sending data:\n"); + + count = 0; + while(count != total) { + size = (uint32_t)MIN(total - count, NVFLASH_DOWNLOAD_CHUNK); + + ret = nv3p_data_send(h3p, buf, size); + if (ret) + goto fail; + + count += size; + buf += size; + + printf("\r%c %" PRIu64 "/%" PRIu64" bytes sent", spinner[spin_idx], + count, total); + spin_idx = (spin_idx + 1) % 4; + } + printf("\ndata sent successfully\n"); + +#undef NVFLASH_DOWNLOAD_CHUNK + +fail: + return ret; +} + +/* * send_file: send data present in file "filename" to nv3p server. */ static int send_file(nv3p_handle_t h3p, const char *filename) @@ -561,29 +745,35 @@ fail: } -static int download_miniloader(usb_device_t *usb, uint8_t *miniloader, - uint32_t size, uint32_t entry) +static int download_binary(uint32_t cmd, usb_device_t *usb, + uint8_t *binary, uint32_t size, uint32_t entry) { uint8_t *msg_buff; int ret; uint32_t status; int actual_len; - // download the miniloader to the bootrom - rcm_create_msg(RCM_CMD_DL_MINILOADER, - (uint8_t *)&entry, sizeof(entry), miniloader, size, + // create download message + rcm_create_msg(cmd, + (uint8_t *)&entry, sizeof(entry), binary, size, &msg_buff); ret = usb_write(usb, msg_buff, rcm_get_msg_len(msg_buff)); - if (ret) + if (ret) { + dprintf("error sending %x command to target\n", cmd); goto fail; + } ret = usb_read(usb, (uint8_t *)&status, sizeof(status), &actual_len); - if (ret) + if (ret) { + dprintf("error reading status from target\n"); goto fail; + } if (actual_len < sizeof(status)) { + dprintf("short read of status\n"); ret = EIO; goto fail; } if (status != 0) { + dprintf("got bad status: %x\n", status); ret = EIO; goto fail; } @@ -807,3 +997,85 @@ static int download_bootloader(nv3p_handle_t h3p, char *filename, return 0; } + +static int download_mts(nv3p_handle_t h3p, char *filename, + uint32_t loadaddr, uint16_t devid, char *mtsdir) +{ + int ret; + nv3p_cmd_dl_mts_t arg; + int fd; + struct stat sb; + uint8_t *buf; + char *_mtsdir = NULL; + + if (!mtsdir && !filename) { + mtsdir = _mtsdir = (char *)malloc(strlen(TEGRA132_MTS_DIR) + 1); + sprintf(mtsdir, "%s", TEGRA132_MTS_DIR); + } + + if (mtsdir) { + filename = (char *)malloc(strlen(mtsdir) + 2 + + strlen(TEGRA132_MTS_FILE)); + sprintf(filename, "%s/%s", mtsdir, TEGRA132_MTS_FILE); + loadaddr = TEGRA132_MTS_ENTRY; + } + + if (filename) { + fd = open(filename, O_RDONLY, 0); + if (fd < 0) { + fprintf(stderr, "error: %s\n", filename); + dprintf("error opening %s for reading\n", filename); + ret = errno; + goto done; + } + + ret = fstat(fd, &sb); + if (ret) { + dprintf("error on fstat of %s\n", filename); + goto done; + } + close(fd); + + arg.length = sb.st_size; + arg.address = loadaddr; + } else { + dprintf("error opening %s for reading\n", filename); + ret = errno; + goto done; + } + + ret = nv3p_cmd_send(h3p, NV3P_CMD_DL_MTS, (uint8_t *)&arg); + if (ret) { + dprintf("error sending 3p mts download command\n"); + goto done; + } + + if (filename) { + // send the mts file + ret = send_file(h3p, filename); + if (ret) { + dprintf("error downloading mts\n"); + goto done; + } + } else { + ret = send_buf(h3p, buf, arg.length); + if (ret) { + dprintf("error downloading mts\n"); + goto done; + } + } + + ret = wait_status(h3p); + if (ret) { + dprintf("error waiting for status on mts dl\n"); + } + +done: + if (_mtsdir) + free(_mtsdir); + + if (mtsdir && filename) + free(filename); + + return ret; +} diff --git a/src/miniloader/tegra132-mts.h b/src/miniloader/tegra132-mts.h new file mode 100644 index 000000000000..9cbc4f0ac77e --- /dev/null +++ b/src/miniloader/tegra132-mts.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2014 NVIDIA CORPORATION. All Rights Reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ +#define TEGRA132_MTS_ENTRY 0x82000000 +#define TEGRA132_MTS_FILE "mts_cr.bin" +#define TEGRA132_MTS_DIR "/lib/firmware/nvidia/tegra132/denver-ucode" diff --git a/src/miniloader/tegra132-preboot-mts.h b/src/miniloader/tegra132-preboot-mts.h new file mode 100644 index 000000000000..b3145fe99d2c --- /dev/null +++ b/src/miniloader/tegra132-preboot-mts.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2014 NVIDIA CORPORATION. All Rights Reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ +#define TEGRA132_PREBOOT_MTS_ENTRY 0x4000f000 +#define TEGRA132_PREBOOT_MTS_FILE "preboot_cr.bin" diff --git a/src/nv3p.c b/src/nv3p.c index b2dff4286422..616485f4ce30 100644 --- a/src/nv3p.c +++ b/src/nv3p.c @@ -52,6 +52,7 @@ /* NV3P_CMD_DL_BCT */ /* NV3P_CMD_DL_BL */ /* NV3P_CMD_STATUS */ +/* NV3P_CMD_DL_MTS */ /*-----------------------------------*/ /* command arguments */ /* . */ @@ -346,6 +347,16 @@ static void nv3p_write_cmd(nv3p_handle_t h3p, uint32_t command, void *args, WRITE32(tmp, a->entry); break; } + case NV3P_CMD_DL_MTS: + { + nv3p_cmd_dl_mts_t *a = (nv3p_cmd_dl_mts_t *)args; + *length = sizeof(nv3p_cmd_dl_mts_t); + WRITE32(tmp, *length); + WRITE32(tmp, command); + WRITE32(tmp, a->length); + WRITE32(tmp, a->address); + break; + } default: dprintf("bad command: 0x%x\n", command); break; @@ -423,6 +434,7 @@ static int nv3p_get_cmd_return(nv3p_handle_t h3p, uint32_t command, void *args) break; case NV3P_CMD_DL_BCT: case NV3P_CMD_DL_BL: + case NV3P_CMD_DL_MTS: break; default: dprintf("unknown command: 0x%x\n", command); @@ -659,6 +671,13 @@ static int nv3p_get_args(nv3p_handle_t h3p, uint32_t command, void **args, READ32(tmp, a->entry); break; } + case NV3P_CMD_DL_MTS: + { + nv3p_cmd_dl_mts_t *a = (nv3p_cmd_dl_mts_t *)buf; + READ32(tmp, a->length); + READ32(tmp, a->address); + break; + } default: dprintf("unknown command: 0x%x\n", command); return EINVAL; diff --git a/src/nv3p.h b/src/nv3p.h index 6ee3ef3393a7..fd63f2824cbf 100644 --- a/src/nv3p.h +++ b/src/nv3p.h @@ -43,6 +43,7 @@ #define NV3P_CMD_DL_BCT 0x04 #define NV3P_CMD_DL_BL 0x06 #define NV3P_CMD_STATUS 0x0a +#define NV3P_CMD_DL_MTS 0x33 // nack codes #define NV3P_NACK_SUCCESS 0x1 @@ -188,6 +189,14 @@ typedef struct { uint32_t entry; // Execution entry point } nv3p_cmd_dl_bl_t; +/* + * nv3p_cmd_dl_mts_t: downloads the mts ucode. + */ +typedef struct { + uint32_t length; + uint32_t address; // Load address +} nv3p_cmd_dl_mts_t; + int nv3p_open(nv3p_handle_t *h3p, usb_device_t *usb); void nv3p_close(nv3p_handle_t h3p); int nv3p_cmd_send(nv3p_handle_t h3p, uint32_t command, void *args); diff --git a/src/rcm.h b/src/rcm.h index ab4bea2d8752..7a66045e245d 100644 --- a/src/rcm.h +++ b/src/rcm.h @@ -47,6 +47,7 @@ #define RCM_CMD_QUERY_BR_VERSION 0x5 #define RCM_CMD_QUERY_RCM_VERSION 0x6 #define RCM_CMD_QUERY_BD_VERSION 0x7 +#define RCM_CMD_DL_MTS 0xb // AES block size in bytes #define RCM_AES_BLOCK_SIZE (128 / 8) diff --git a/src/tegrarcm.1.in b/src/tegrarcm.1.in index e0c2cc38d656..23e484e1a4cd 100644 --- a/src/tegrarcm.1.in +++ b/src/tegrarcm.1.in @@ -81,6 +81,13 @@ built-in one. .TP .B \-\-miniloader_entry \fImlentry\fP Specify the entry address of the miniloader. +.TP +.B \-\-preboot \fIpbfile\fP +Read the preboot mts ucode from the specified file instead of using the +built-in one. +.TP +.B \-\-preboot_entry \fIpbentry\fP +Specify the entry address of the preboot mts ucode. .SH EXAMPLES To download u-boot firmware to a Tegra20 seaboard: -- 1.8.1.5 -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html