diff options
-rw-r--r-- | arch/arm/include/asm/arch-tegra/tegra.h | 5 | ||||
-rw-r--r-- | arch/arm/lib/board.c | 8 | ||||
-rw-r--r-- | board/toradex/common/Makefile | 1 | ||||
-rw-r--r-- | board/toradex/common/tegra2_partitions.c | 342 | ||||
-rw-r--r-- | board/toradex/common/tegra2_partitions.h | 38 |
5 files changed, 394 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch-tegra/tegra.h b/arch/arm/include/asm/arch-tegra/tegra.h index c51a8014e01..db00ebf167d 100644 --- a/arch/arm/include/asm/arch-tegra/tegra.h +++ b/arch/arm/include/asm/arch-tegra/tegra.h @@ -78,6 +78,11 @@ struct timerus { unsigned int cntr_1us; }; +#define NVBOOTINFOTABLE_BCTSIZE 0x38 /* BCT size in BIT in IRAM */ +#define NVBOOTINFOTABLE_BCTPTR 0x3C /* BCT pointer in BIT in IRAM */ +#define BCT_PTINFO_OFFSET 3820 + +/* These are the available SKUs (product types) for Tegra */ enum { SKU_ID_T20 = 0x8, SKU_ID_T25SE = 0x14, diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 10ef2c81288..c6a12463e03 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -87,6 +87,10 @@ extern void rtl8019_get_enetaddr (uchar * addr); #include <i2c.h> #endif +#ifdef CONFIG_COLIBRI_T20 +extern void tegra_partition_init(void); +#endif + /************************************************************************ * Coloured LED functionality @@ -594,6 +598,10 @@ void board_init_r (gd_t *id, ulong dest_addr) onenand_init(); #endif +#ifdef CONFIG_COLIBRI_T20 + tegra_partition_init(); +#endif + #ifdef CONFIG_GENERIC_MMC puts("MMC: "); mmc_initialize(bd); diff --git a/board/toradex/common/Makefile b/board/toradex/common/Makefile index e3a6dbf9382..8d160d50e90 100644 --- a/board/toradex/common/Makefile +++ b/board/toradex/common/Makefile @@ -27,6 +27,7 @@ LIB = $(obj)lib$(VENDOR).o COBJS-y += board.o COBJS-$(CONFIG_TEGRA2_NAND) += tegra2_nand.o +COBJS-$(CONFIG_TEGRA2_NAND) += tegra2_partitions.o COBJS-$(CONFIG_USB_EHCI_TEGRA) += ulpi_linux.o COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o diff --git a/board/toradex/common/tegra2_partitions.c b/board/toradex/common/tegra2_partitions.c new file mode 100644 index 00000000000..b8d8bf29ba1 --- /dev/null +++ b/board/toradex/common/tegra2_partitions.c @@ -0,0 +1,342 @@ +#include <common.h> +#include <asm/io.h> +#include <nand.h> +#include <malloc.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/gpio.h> +#include <asm/arch-tegra/ap20.h> +#include <asm/errno.h> +#include <fdt_decode.h> +#include "tegra2_nand.h" +#include "tegra2_partitions.h" + +#define DEBUG 0 + +DECLARE_GLOBAL_DATA_PTR; + +/** + * nvtegra_print_partition_table - prints partition table info + * @param pt: nvtegra_parttable_t structure + */ +void nvtegra_print_partition_table(nvtegra_parttable_t * pt) +{ + int i; + nvtegra_partinfo_t *p; + + // sanity check + if (!pt) { + printf("%s: Error! pt arg is NULL\n", __FUNCTION__); + return; + } + + p = &(pt->partinfo[0]); + printf("\n------ NVTEGRA Partitions ------\n"); + +#if DEBUG > 1 + printf("UNK:\n"); + for (i = 0; i < 18; i++) { + if (pt->_unknown[i] > 1000000) + printf("0x%08X\t", pt->_unknown[i]); + else + printf("%u\t", pt->_unknown[i]); + if ((i + 1) % 6 == 0) + printf("\n"); + } + printf("\n"); +#endif + + for (i = 0; (p->id < 128) && (i < TEGRA_MAX_PARTITIONS); i++) { + printf + ("\n[%u]\tPart:\tID=%u\tNAME=%s\tNAME2=%s\n\t\tTYPE=%u\tALLOC_POLICY=%u\tFS_TYPE=%u\n\t\tVIRTUAL START SEC=%u\tVIRTUAL SIZE=%u\n", + i, p->id, p->name, p->name2, p->type, p->allocation_policy, + p->filesystem_type, p->virtual_start_sector, + p->virtual_size); + printf("\t\tSTART SEC=%u\tEND SEC=%u\tTOTAL=%u\n", + p->start_sector, p->end_sector, + p->end_sector + 1 - p->start_sector); + +#if DEBUG > 1 + printf("\t\tUNK1=%u\t%u\n", p->_unknown1[0], p->_unknown1[1]); + printf("\t\tUNK2=%u\t%u\t0x%08x\n", p->_unknown2[0], + p->_unknown2[1], p->_unknown2[2]); + printf("\t\tUNK3=%u\n", p->_unknown3); + printf("\t\tUNK4=%u\n", p->_unknown4); + printf("\t\tUNK5=%u\n", p->_unknown5); + printf("\t\tUNK6=%u\t%u\n", p->_unknown6[0], p->_unknown6[1]); +#endif + + p++; + } + printf("--------------------------------\n"); +} + +/** + * nvtegra_read_partition_table - reads nvidia's partition table + * @return: + * 1 - Success + * 0 - Error + */ +int nvtegra_read_partition_table(nvtegra_parttable_t * pt) +{ + size_t size; + int i; + nvtegra_partinfo_t *p; + u32 bct_start, pt_logical, pt_offset; + + // sanity check + if (!pt) { + printf("%s: Error! pt arg is NULL\n", __FUNCTION__); + return 0; + } + + /* + * Partition table offset is stored in the BCT in IRAM by the BootROM. + * The BCT start and size are stored in the BIT in IRAM. + * Read the data @ bct_start + (bct_size - 260). This works + * on T20 and T30 BCTs, which are locked down. If this changes + * in new chips (T114, etc.), we can revisit this algorithm. + */ + bct_start = readl(AP20_BASE_PA_SRAM + NVBOOTINFOTABLE_BCTPTR); +#if DEBUG > 1 + printf("bct_start=0x%08x\n", bct_start); +#endif + pt_logical = readw(bct_start + BCT_PTINFO_OFFSET); + /* In case we are running with a recovery BCT missing the partition + table offset information */ + if (pt_logical == 0) { + /* BCT partition size is 3 M in our default layout */ + pt_logical = 3 * 1024 * 1024 / nand_info->writesize; + } + /* StartLogicalSector * PageSize + 4 * BlockSize */ + pt_offset = pt_logical * nand_info->writesize + 4 * nand_info->erasesize; +#if DEBUG > 1 + printf("logical=0x%08x writesize=0x%08x erasesize=0x%08x\n", readw(bct_start + BCT_PTINFO_OFFSET), nand_info->writesize, nand_info->erasesize); + printf("pt_offset=0x%08x\n", pt_offset); +#endif + + size = sizeof(nvtegra_parttable_t); + i = nand_read_skip_bad(&nand_info[0], pt_offset, &size, + (unsigned char *)pt); + if ((i != 0) || (size != sizeof(nvtegra_parttable_t))) { + printf + ("%s: Error! nand_read_skip_bad failed. nand_info->writesize=%d ret=%d\n", + __FUNCTION__, nand_info->writesize, i); + return 0; + } + + /* some heuristics */ + p = &(pt->partinfo[0]); + if ((p->id != 2) || memcmp(p->name, "BCT\0", 4) + || memcmp(p->name2, "BCT\0", 4) || (p->virtual_start_sector != 0)) { + printf + ("%s: Error! Partition table offset is probably incorrect. name='%s'\n", + __FUNCTION__, p->name); + return 0; + } + + return 1; +} + +/** + * nvtegra_find_partition - parse nvidia partition table + * @param pt: nvtegra_parttable_t structure + * @param name: partition name + * @param partinfo: output pointer to nvtegra_partinfo_t structure + * @return: + * 1 - Success, partinfo contains partition info + * 0 - Not found or error + */ +int nvtegra_find_partition(nvtegra_parttable_t * pt, const char *name, + nvtegra_partinfo_t ** partinfo) +{ + int i, l; + nvtegra_partinfo_t *p; + + // sanity checks + if (!pt) { + printf("%s: Error! pt arg is NULL\n", __FUNCTION__); + return 0; + } + if (!name) { + printf("%s: Error! name arg is NULL\n", __FUNCTION__); + return 0; + } + if (!partinfo) { + printf("%s: Error! partinfo arg is NULL\n", __FUNCTION__); + return 0; + } + + p = &(pt->partinfo[0]); + l = strlen(name) + 1; // string length + \0 + for (i = 0; (p->id < 128) && (i < TEGRA_MAX_PARTITIONS); i++) { + if (memcmp(p->name, name, l) == 0 + || memcmp(p->name2, name, l) == 0) { + *partinfo = p; + return 1; + } + p++; + } + + printf("%s: Error! Partition '%s' not found.\n", __FUNCTION__, name); + return 0; +} + +int nvtegra_mtdparts_string(char *output, int size) +{ + int i, j = 0; + nvtegra_parttable_t *pt; + nvtegra_partinfo_t *p, *usr; + char buffer[512]; + + // sanity checks + if (!output) { + printf("%s: Error! output arg is NULL.\n", __FUNCTION__); + return 0; + } + if (size > 256) { + printf + ("%s: Error! size is too large. Increase buffer size here.\n", + __FUNCTION__); + return 0; + } + // parse nvidia partition table + pt = malloc(sizeof(nvtegra_parttable_t)); + if (!pt) { + printf("%s: Error calling malloc(%d)\n", __FUNCTION__, + sizeof(nvtegra_parttable_t)); + return 0; + } + + if (!nvtegra_read_partition_table(pt)) { + free(pt); + return 0; + } + // make rootfs partition the first in the list + if (nvtegra_find_partition(pt, "USR", &p)) { + sprintf(buffer + j, "%uK@%uK(USR)", + p->virtual_size * nand_info->writesize / 1024, + p->start_sector * nand_info->writesize / 1024); + j += strlen(buffer + j); + } + usr = p; + + p = &(pt->partinfo[0]); + for (i = 0; (p->id < 128) && (i < TEGRA_MAX_PARTITIONS); i++) { + if (p != usr) { + if (strlen(p->name)) + sprintf(buffer + j, ",%uK@%uK(%s)", + p->virtual_size * + nand_info->writesize / 1024, + p->start_sector * + nand_info->writesize / 1024, p->name); + else + sprintf(buffer + j, ",%uK@%uK", + p->virtual_size * + nand_info->writesize / 1024, + p->start_sector * + nand_info->writesize / 1024); + + j += strlen(buffer + j); + } + if (strlen(buffer) >= size) + break; + p++; + } + + memcpy(output, buffer, (j < size ? j + 1 : size)); + free(pt); + return 1; +} + +void tegra_partition_init(void) +{ + nvtegra_parttable_t *pt; + nvtegra_partinfo_t *partinfo; + + // parse nvidia partition table + pt = malloc(sizeof(nvtegra_parttable_t)); + if (!pt) { + printf("%s: Error calling malloc(%d)\n", __FUNCTION__, + sizeof(nvtegra_parttable_t)); + return; + } + //copy partition information to global data + if (!nvtegra_read_partition_table(pt)) { + free(pt); + return; + } + + if (nvtegra_find_partition(pt, "ENV", &partinfo)) { + gd->env_offset = + partinfo->start_sector * nand_info->writesize; +#if DEBUG > 1 + printf + ("\nPart:\tID=%u\tNAME=%s\tNAME2=%s\n\t\tTYPE=%u\tALLOC_POLICY=%u\tFS_TYPE=%u\n\t\tVIRTUAL START SEC=%u\tVIRTUAL SIZE=%u\n", + partinfo->id, partinfo->name, partinfo->name2, + partinfo->type, partinfo->allocation_policy, + partinfo->filesystem_type, partinfo->virtual_start_sector, + partinfo->virtual_size); + printf("\t\tSTART SEC=%u\tEND SEC=%u\tTOTAL=%u\n", + partinfo->start_sector, partinfo->end_sector, + partinfo->end_sector + 1 - partinfo->start_sector); +#endif + } + + if (nvtegra_find_partition(pt, "ARG", &partinfo)) { + gd->conf_blk_offset = + partinfo->start_sector * nand_info->writesize; +#if DEBUG > 1 + printf + ("\nPart:\tID=%u\tNAME=%s\tNAME2=%s\n\t\tTYPE=%u\tALLOC_POLICY=%u\tFS_TYPE=%u\n\t\tVIRTUAL START SEC=%u\tVIRTUAL SIZE=%u\n", + partinfo->id, partinfo->name, partinfo->name2, + partinfo->type, partinfo->allocation_policy, + partinfo->filesystem_type, partinfo->virtual_start_sector, + partinfo->virtual_size); + printf("\t\tSTART SEC=%u\tEND SEC=%u\tTOTAL=%u\n", + partinfo->start_sector, partinfo->end_sector, + partinfo->end_sector + 1 - partinfo->start_sector); +#endif + } + + if (nvtegra_find_partition(pt, "LNX", &partinfo)) { + gd->kernel_offset = + partinfo->start_sector * nand_info->writesize; +#if DEBUG > 1 + printf + ("\nPart:\tID=%u\tNAME=%s\tNAME2=%s\n\t\tTYPE=%u\tALLOC_POLICY=%u\tFS_TYPE=%u\n\t\tVIRTUAL START SEC=%u\tVIRTUAL SIZE=%u\n", + partinfo->id, partinfo->name, partinfo->name2, + partinfo->type, partinfo->allocation_policy, + partinfo->filesystem_type, partinfo->virtual_start_sector, + partinfo->virtual_size); + printf("\t\tSTART SEC=%u\tEND SEC=%u\tTOTAL=%u\n", + partinfo->start_sector, partinfo->end_sector, + partinfo->end_sector + 1 - partinfo->start_sector); +#endif + } + + if (nvtegra_find_partition(pt, "USR", &partinfo)) { +#if DEBUG > 1 + printf + ("\nPart:\tID=%u\tNAME=%s\tNAME2=%s\n\t\tTYPE=%u\tALLOC_POLICY=%u\tFS_TYPE=%u\n\t\tVIRTUAL START SEC=%u\tVIRTUAL SIZE=%u\n", + partinfo->id, partinfo->name, partinfo->name2, + partinfo->type, partinfo->allocation_policy, + partinfo->filesystem_type, partinfo->virtual_start_sector, + partinfo->virtual_size); + printf("\t\tSTART SEC=%u\tEND SEC=%u\tTOTAL=%u\n", + partinfo->start_sector, partinfo->end_sector, + partinfo->end_sector + 1 - partinfo->start_sector); +#endif + } +#if DEBUG > 1 + printf("gd->env_offset=%u\n", gd->env_offset); + printf("gd->conf_blk_offset=%u\n", gd->conf_blk_offset); + printf("gd->kernel_offset=%u\n", gd->kernel_offset); +#endif + +#if DEBUG > 0 + nvtegra_print_partition_table(pt); +#endif + + free(pt); +} + diff --git a/board/toradex/common/tegra2_partitions.h b/board/toradex/common/tegra2_partitions.h new file mode 100644 index 00000000000..504cd1a5cf4 --- /dev/null +++ b/board/toradex/common/tegra2_partitions.h @@ -0,0 +1,38 @@ +#ifndef _TEGRA2_PARTITIONS_H_ +#define _TEGRA2_PARTITIONS_H_ + +#define TEGRA_MAX_PARTITIONS 24 + +typedef struct { + unsigned id; + char name[4]; + unsigned allocation_policy; + unsigned _unknown1[2]; + char name2[4]; + unsigned filesystem_type; + unsigned _unknown2[3]; + unsigned virtual_start_sector; + unsigned _unknown3; + unsigned virtual_size; + unsigned _unknown4; + unsigned start_sector; + unsigned _unknown5; + unsigned end_sector; + unsigned _unknown6[2]; + unsigned type; +} __attribute__ ((packed)) nvtegra_partinfo_t; + +typedef struct { + unsigned _unknown[18]; + nvtegra_partinfo_t partinfo[TEGRA_MAX_PARTITIONS]; +} __attribute__ ((packed)) nvtegra_parttable_t; + +void nvtegra_print_partition_table(nvtegra_parttable_t * pt); +int nvtegra_read_partition_table(nvtegra_parttable_t * pt); +int nvtegra_find_partition(nvtegra_parttable_t * pt, const char *name, + nvtegra_partinfo_t ** partinfo); +int nvtegra_mtdparts_string(char *output, int size); +void tegra_partition_init(void); + +#endif /* _TEGRA2_PARTITIONS_H_ */ + |