@@ -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
@@ -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;
+}
new file mode 100644
@@ -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"
new file mode 100644
@@ -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"
@@ -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;
@@ -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);
@@ -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)
@@ -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: