From: Patrick Delaunay <patrick.delau...@st.com>

Signed-off-by: Patrick Delaunay <patrick.delau...@st.com>
Signed-off-by: Patrick Delaunay <patrick.delauna...@gmail.com>
---

Changes in v2: None

 Kconfig            |  12 ++
 disk/part_efi.c    | 445 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 doc/README.gpt.mtd | 189 +++++++++++++++++++++++
 include/part.h     |  13 +-
 4 files changed, 657 insertions(+), 2 deletions(-)
 create mode 100644 doc/README.gpt.mtd

diff --git a/Kconfig b/Kconfig
index 529858a..1ce39d5 100644
--- a/Kconfig
+++ b/Kconfig
@@ -309,6 +309,18 @@ config ARCH_FIXUP_FDT
 
 endmenu                # Boot images
 
+config EFI_PARTITION_MTD
+       bool "Support GPT over MTD"
+       help
+         The GPT partition is normally defined only for block device with
+         built-in controller which manage flash translation layer
+         This option activate the GPT partition support over RAW device
+         using the MTD framework
+         - manage partition over MTD devices (as flash: NOR and NAND)
+         - extract MTD information
+         - update command gpt, mtdparts and part
+         NB: depends on EFI_PARTITION
+
 source "common/Kconfig"
 
 source "cmd/Kconfig"
diff --git a/disk/part_efi.c b/disk/part_efi.c
index a23c8ea..f409bb0 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -21,6 +21,10 @@
 #include <part_efi.h>
 #include <linux/ctype.h>
 
+#ifdef CONFIG_EFI_PARTITION_MTD
+#include <linux/mtd/mtd.h>
+#endif
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifdef HAVE_BLOCK_DEVICE
@@ -960,3 +964,444 @@ U_BOOT_PART_TYPE(a_efi) = {
        .test           = part_test_efi,
 };
 #endif
+
+#ifdef CONFIG_EFI_PARTITION_MTD
+static int is_primary_gpt_valid_mtd(struct mtd_info *mtd,
+                                     lbaint_t lba,
+                                   void **buf,
+                                   gpt_header **pgpt_head,
+                                   gpt_entry **pgpt_pte)
+{
+       gpt_header *gpt_h;
+       gpt_entry *gpt_e;
+       uint32_t size;
+       uint64_t offset;
+       int ret;
+       size_t retlen;
+       lbaint_t my_lba;
+       u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+                                 MTD_LBA_SIZE);
+
+       size = gpt_e_size + 2 * MTD_LBA_SIZE;
+       /* skip bad block */
+       offset = 0;
+       while (mtd_block_isbad(mtd, offset)) {
+               printf("bad block at 0x%llx\n", offset);
+               offset += mtd->erasesize;
+               if (offset >= mtd->size) {
+                       printf("*** ERROR: too many bad block ***\n");
+                       return -1;
+               }
+       }
+
+       debug("primary offset = 0x%llx\n", offset);
+       /* Read primary GPT from device */
+       ret = mtd_read(mtd, offset, size, &retlen, *buf);
+       if (ret || (retlen != size)) {
+               printf("*** ERROR: Can't read primary GPT ***\n");
+               return -1;
+       }
+
+       /* determine start of GPT Header & Entries in the buffer */
+       gpt_h = *buf + (1 * MTD_LBA_SIZE);
+       gpt_e = *buf + (2 * MTD_LBA_SIZE);
+       my_lba = lldiv(offset, MTD_LBA_SIZE) + GPT_PRIMARY_PARTITION_TABLE_LBA;
+
+       if (!validate_gpt_header(gpt_h, my_lba, lba) &&
+           !validate_gpt_entries(gpt_h, gpt_e)) {
+               *pgpt_head = gpt_h;
+               *pgpt_pte = gpt_e;
+               return 0;
+       }
+       return -1;
+}
+
+static int is_secondary_gpt_valid_mtd(struct mtd_info *mtd,
+                                     lbaint_t lba,
+                                     void **buf,
+                                     gpt_header **pgpt_head,
+                                     gpt_entry **pgpt_pte)
+{
+       gpt_header *gpt_h;
+       gpt_entry *gpt_e;
+       uint32_t size;
+       uint64_t offset;
+       int ret;
+       size_t retlen;
+       lbaint_t my_lba;
+       u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+                                 MTD_LBA_SIZE);
+
+       size = gpt_e_size + 2 * MTD_LBA_SIZE;
+       /* skip bad block */
+       offset = mtd->size;
+       while (mtd_block_isbad(mtd, offset - mtd->erasesize)) {
+               offset -= mtd->erasesize;
+               printf("bad block at 0x%llx\n", offset);
+               if (offset <= mtd->erasesize) {
+                       printf("*** ERROR: too many bad block ***\n");
+                       return -1;
+               }
+       }
+
+       /* Read backup GPT from device : end of the last valid block */
+       size = gpt_e_size + MTD_LBA_SIZE;
+       offset -= size;
+
+       debug("backup offset = 0x%llx\n", offset);
+       ret = mtd_read(mtd, offset, size, &retlen, *buf);
+       if (ret || (retlen != size)) {
+               printf("*** ERROR: Can't read backup GPT ***\n");
+               return -1;
+       }
+
+       /* determine start of GPT Header & Entries in the buffer */
+       gpt_h = *buf + gpt_e_size;
+       gpt_e = *buf;
+       my_lba = lldiv(offset, MTD_LBA_SIZE) - 1;
+
+       if (!validate_gpt_header(gpt_h, my_lba, lba) &&
+           !validate_gpt_entries(gpt_h, gpt_e)) {
+               *pgpt_head = gpt_h;
+               *pgpt_pte = gpt_e;
+               return 0;
+       }
+       return -1;
+}
+
+/**
+ * is_gpt_valid_mtd() - tests one GPT header and PTEs for validity
+ *
+ * lba is the logical block address of the GPT header to test
+ * pgpt_head is a GPT header ptr, filled on return.
+ * pgpt_pte is a PTEs ptr, filled on return.
+ *
+ * Description: returns 1 if valid,  0 on error.
+ * If valid, returns pointers to PTEs.
+ */
+
+static int is_gpt_valid_mtd(struct mtd_info *mtd,
+                           void **buf,
+                           gpt_header **pgpt_head,
+                           gpt_entry **pgpt_pte)
+{
+       u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+                                 MTD_LBA_SIZE);
+       lbaint_t lba;
+
+       if (!mtd || !pgpt_head || !pgpt_pte) {
+               printf("%s: Invalid Argument(s)\n", __func__);
+               return 0;
+       }
+       *pgpt_head = NULL;
+       *pgpt_pte = NULL;
+       *buf = malloc(gpt_e_size + 2 * MTD_LBA_SIZE);
+       lba = lldiv(mtd->size, MTD_LBA_SIZE);
+
+       if (!is_primary_gpt_valid_mtd(mtd, lba, buf, pgpt_head, pgpt_pte))
+               return 1;
+
+       printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+
+       if (!is_secondary_gpt_valid_mtd(mtd, lba, buf, pgpt_head, pgpt_pte)) {
+               printf("%s: *** Using Backup GPT ***\n", __func__);
+               return 1;
+       }
+       printf("%s: *** ERROR: Invalid Backup GPT ***\n", __func__);
+
+       free(*buf);
+       return 0;
+}
+
+
+static int gpt_fill_header_mtd(struct mtd_info *mtd, gpt_header *gpt_h,
+                              char *str_guid, int parts_count)
+{
+       uint32_t erasesize;
+       uint64_t offset_p_gpt, offset_s_gpt;
+       __le64 my_lba;
+       __le64 alternate_lba;
+       u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+                                 MTD_LBA_SIZE);
+
+       /* one mtd block is not enought for MBR and GPT */
+       if ((gpt_e_size + 2 * MTD_LBA_SIZE) > mtd->erasesize)
+               return -1;
+
+       erasesize = lldiv(mtd->erasesize, MTD_LBA_SIZE);
+
+       /* GPT location : skip bad block */
+       offset_p_gpt = 0;
+       while (mtd_block_isbad(mtd, offset_p_gpt)) {
+               printf("bad block at 0x%llx\n", offset_p_gpt);
+               offset_p_gpt += mtd->erasesize;
+               if (offset_p_gpt >= mtd->size)
+                       return -1;
+       }
+       /* primary GPT : 17 first LBA of last good block */
+       my_lba = lldiv(offset_p_gpt, MTD_LBA_SIZE) + 1;
+
+       offset_s_gpt = mtd->size;
+       while (mtd_block_isbad(mtd, offset_s_gpt - mtd->erasesize)) {
+               offset_s_gpt -= mtd->erasesize;
+               printf("bad block at 0x%llx\n", offset_s_gpt);
+               if (offset_s_gpt <= mtd->erasesize)
+                       return -1;
+       }
+       /* secondary GPT : 16 LBA of last good block */
+       alternate_lba = lldiv(offset_s_gpt, MTD_LBA_SIZE) - 1;
+
+       /* only one good block (primary and secondary on same block) */
+       if (offset_p_gpt == ((offset_s_gpt - mtd->erasesize)))
+               return -1;
+
+       gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
+       gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1);
+       gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
+       gpt_h->my_lba = cpu_to_le64(my_lba);
+       gpt_h->alternate_lba = cpu_to_le64(alternate_lba);
+       gpt_h->first_usable_lba = cpu_to_le64(my_lba - 1 + erasesize);
+       gpt_h->last_usable_lba = cpu_to_le64(alternate_lba - erasesize);
+       gpt_h->partition_entry_lba = cpu_to_le64(my_lba + 1);
+       gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS);
+       gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
+       gpt_h->header_crc32 = 0;
+       gpt_h->partition_entry_array_crc32 = 0;
+
+       if (uuid_str_to_bin(str_guid, gpt_h->disk_guid.b, UUID_STR_FORMAT_GUID))
+               return -1;
+
+       return 0;
+}
+
+static int mtd_erase_write_block(struct mtd_info *mtd,
+                                uint64_t offset,
+                                void *buf,
+                                size_t len)
+{
+       struct erase_info erase;
+       int ret;
+       size_t retlen;
+       u_char *verify_buf;
+
+       erase.mtd = mtd;
+       erase.len  = mtd->erasesize;
+       erase.addr = offset & ~(mtd->erasesize - 1); /* aligned erase offset */
+       erase.callback = NULL;
+
+       debug(" erase at 0x%llx\n", erase.addr);
+       ret = mtd_erase(mtd, &erase);
+       if (ret != 0) {
+               printf("** mark bad block 0x%llx on MTD device %s **\n",
+                      erase.addr, mtd->name);
+               ret = mtd_block_markbad(mtd, erase.addr);
+               if (ret)
+                       error("cannot mark bad at offset 0x%llx, error %d",
+                             offset, ret);
+               return -1;
+       }
+
+       /* mtd write */
+       ret = mtd_write(mtd, offset, len, &retlen, buf);
+       if (ret != 0 || retlen != len) {
+               error("Write error %d\n", ret);
+               return -2;
+       }
+
+       verify_buf = malloc(len);
+       ret = mtd_read(mtd, offset, len, &retlen, verify_buf);
+       if (ret) {
+               error("Read failed 0x%x, %d\n", (u32)offset, ret);
+               free(verify_buf);
+               return -3;
+       }
+
+       if (memcmp(buf, verify_buf, len)) {
+               error("Verify failed at 0x%x\n", (u32)offset);
+               return -4;
+       }
+
+       free(verify_buf);
+
+       return 0;
+}
+
+static void prepare_mbr_gpt_header_mtd(void *buf,
+                                      struct mtd_info *mtd,
+                                      gpt_header *gpt_h,
+                                      gpt_entry *gpt_e)
+{
+       legacy_mbr *p_mbr = buf;
+       u32 calc_crc32;
+
+       /* Generate CRC for the Primary GPT Header */
+       calc_crc32 = efi_crc32((const unsigned char *)gpt_e,
+                             le32_to_cpu(gpt_h->num_partition_entries) *
+                             le32_to_cpu(gpt_h->sizeof_partition_entry));
+       gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32);
+
+       calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
+                             le32_to_cpu(gpt_h->header_size));
+       gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+
+       /* Setup the Protective MBR */
+       p_mbr->signature = MSDOS_MBR_SIGNATURE;
+       p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
+       p_mbr->partition_record[0].start_sect = 1;
+       p_mbr->partition_record[0].nr_sects = (u32) lldiv(mtd->size,
+                                             MTD_LBA_SIZE) - 1;
+}
+
+
+static int write_gpt_table_mtd(struct mtd_info *mtd,
+                              gpt_header *gpt_h,
+                              gpt_entry *gpt_e)
+{
+       const int pte_blk_cnt = PAD_COUNT((gpt_h->num_partition_entries
+                                          * sizeof(gpt_entry)), MTD_LBA_SIZE);
+       uint64_t offset;
+       void *buf;
+       u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
+                                 MTD_LBA_SIZE);
+       u32 buf_size, p_size, s_size;
+
+       p_size = gpt_e_size + 2 * MTD_LBA_SIZE;
+       s_size = roundup(gpt_e_size + MTD_LBA_SIZE, mtd->writesize);
+       buf_size = max(p_size, s_size);
+       buf = malloc(buf_size);
+       memset(buf, 0x0, p_size);
+
+       prepare_mbr_gpt_header_mtd(buf, mtd, gpt_h, gpt_e);
+
+       /* GPT Header (1 block) */
+       memcpy(buf + (GPT_PRIMARY_PARTITION_TABLE_LBA * MTD_LBA_SIZE),
+              gpt_h, sizeof(*gpt_h));
+       memcpy(buf + ((GPT_PRIMARY_PARTITION_TABLE_LBA + 1) * MTD_LBA_SIZE),
+              gpt_e, sizeof(gpt_entry) * pte_blk_cnt);
+
+       offset = ALIGN(le64_to_cpu(gpt_h->my_lba -
+                                  GPT_PRIMARY_PARTITION_TABLE_LBA)
+                      * MTD_LBA_SIZE,
+                      mtd->erasesize);
+
+       debug("primary offset = 0x%llx\n", offset);
+
+       if (mtd_erase_write_block(mtd, offset, buf, p_size))
+               goto err;
+
+       prepare_backup_gpt_header(gpt_h);
+
+       memset(buf, 0x0, s_size);
+
+       offset = (le64_to_cpu(gpt_h->my_lba) + 1) * MTD_LBA_SIZE - s_size;
+       memcpy(buf + s_size - MTD_LBA_SIZE, gpt_h, sizeof(*gpt_h));
+       memcpy(buf + s_size - MTD_LBA_SIZE - gpt_e_size,
+              gpt_e, sizeof(gpt_entry) * pte_blk_cnt);
+
+
+       debug("backup offset = 0x%llx\n", offset);
+
+       if (mtd_erase_write_block(mtd, offset, buf, s_size))
+               goto err;
+
+       free(buf);
+       debug("GPT successfully written to MTD device!\n");
+       return 0;
+
+ err:
+       free(buf);
+       printf("** Can't write to MTD device %s **\n", mtd->name);
+       return -1;
+}
+
+/*
+ * Public Functions (include/part.h)
+ */
+
+int gpt_restore_mtd(struct mtd_info *mtd, char *str_disk_guid,
+                   disk_partition_t *partitions, int parts_count)
+{
+       int ret;
+       gpt_header *gpt_h = calloc(1, PAD_SIZE(sizeof(gpt_header),
+                                              MTD_LBA_SIZE));
+       gpt_entry *gpt_e;
+
+       if (gpt_h == NULL) {
+               printf("%s: calloc failed!\n", __func__);
+               return -1;
+       }
+
+       gpt_e = calloc(1, PAD_SIZE(GPT_ENTRY_NUMBERS
+                                  * sizeof(gpt_entry),
+                                  MTD_LBA_SIZE));
+       if (gpt_e == NULL) {
+               printf("%s: calloc failed!\n", __func__);
+               free(gpt_h);
+               return -1;
+       }
+
+       /* Generate Primary GPT header (LBA1) */
+       ret = gpt_fill_header_mtd(mtd, gpt_h, str_disk_guid, parts_count);
+       if (ret)
+               goto err;
+
+       /* Generate partition entries */
+       ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count);
+       if (ret)
+               goto err;
+
+       /* Write GPT partition table */
+       ret = write_gpt_table_mtd(mtd, gpt_h, gpt_e);
+
+err:
+       free(gpt_e);
+       free(gpt_h);
+       return ret;
+}
+
+void part_print_efi_mtd(struct mtd_info *mtd)
+{
+           void *buf;
+           gpt_header *gpt_head;
+           gpt_entry *gpt_pte;
+
+       if (!is_gpt_valid_mtd(mtd, &buf, &gpt_head, &gpt_pte))
+                       return;
+
+       part_print_gpt(gpt_head, gpt_pte);
+
+       /* Remember to free buffer */
+       free(buf);
+       return;
+}
+
+int part_get_info_efi_mtd(struct mtd_info *mtd, int part,
+                         disk_partition_t *info)
+{
+       void *buf;
+       gpt_header *gpt_head;
+       gpt_entry *gpt_pte;
+
+       if (!mtd || !info || part < 1) {
+               printf("%s: Invalid Argument(s)\n", __func__);
+               return -1;
+       }
+
+       if (!is_gpt_valid_mtd(mtd, &buf, &gpt_head, &gpt_pte))
+                       return -1;
+
+       if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
+           !is_pte_valid(&gpt_pte[part - 1])) {
+               debug("%s: *** ERROR: Invalid partition number %d ***\n",
+                     __func__, part);
+               free(buf);
+               return -1;
+       }
+
+       part_get_disk_info(part, MTD_LBA_SIZE, gpt_pte, info);
+
+       /* Remember to free buffer */
+       free(buf);
+       return 0;
+}
+#endif /* CONFIG_EFI_PARTITION_MTD */
diff --git a/doc/README.gpt.mtd b/doc/README.gpt.mtd
new file mode 100644
index 0000000..fbc8f82
--- /dev/null
+++ b/doc/README.gpt.mtd
@@ -0,0 +1,189 @@
+#
+#
+# SPDX-License-Identifier:     GPL-2.0+
+
+Glossary:
+========
+- GPT (GUID Partition Table) - it is the EFI standard part
+- MTD (Memory Technology Device) - abstraction layer for RAW flah device
+
+Introduction:
+=============
+This document describes the GPT support on MTD and usage of
+the associated command in U-Boot.
+
+The GPT is normally defined only for block device with built-in controller
+which manage flash translation layer (FTL) as MMC, SD, USB or ATA.
+
+For raw flash device, the MTD partionning are usally defined in U-Boot
+environment and provided to kernel (see mtdparts command).
+
+U-Boot support GPT for MTD device to save the partition informations of
+raw flash device directly in this device (usefull for CONFIG_ENV_IS_NOWHERE)
+and to use these informations to support MTD devices in DISTRO without
+hardcoded MTD partitioning in U-Boot environment
+
+The GPT support on top of MTD is defined under CONFIG_EFI_PARTITION_MTD.
+
+PS: DISTRO boot cmd is no yet updated
+
+GPT on MTD brief explanation:
+=============================
+
+The GPT standard is respected (header and field meaning).
+
+The GPT header and each partition need to be eraseblock-align to allow
+individual udpate for header or partiton.
+
+The primary and the backup GPT header are located in the first and
+the last -not bad- eraseblock.
+
+We assume that one eraseblock is enought for MBR and GPT header
+(size = 17 KB for 128 entry)
+
+So it not compatible with the feature CONFIG_SPI_FLASH_USE_4K_SECTORS
+
+       Layout:
+       -------
+
+       ----------------------------------------------------------
+       LBA 0-33       |Protective MBR + Primary GPT     | 1rst eraseblock
+       --------------------------------------------------
+       LBA 34         | (not used)                      |
+       LBA N-1        |                                 |
+       ----------------------------------------------------------
+       LBA N          |Partition 1                      | 2nd eraseblock
+                      |                                 | = first usable
+                      -----------------------------------
+                      |Partition 2                      |
+                      |                                 |
+                       ----------------------------------- last-1 eraseblock
+       LBA M          |Partition n                      | = last usable
+       ----------------------------------------------------------
+       LBA M+1        | (not used)                      | last eraseblock
+       LBA -35        |                                 |
+       --------------------------------------------------
+       LBA -1 to -34  |Backup GPT Header                |
+       ----------------------------------------------------------
+
+       NB: this layout change (LBA0 and LBA-1) if bad block are present
+
+       GPT header:
+       -----------
+
+       for details of GPT header, see README.gpt
+
+       "Current LBA" and "Backup LBA" give the location of the primary and
+       secondary GPT header.
+
+       All the bad block are detected and skipped when the GPT header is build.
+
+       For Primary GPT:
+
+       - Current LBA = 2nd LBA of the first good eraseblock
+
+       - Backup LBA = Last LBA of the last good block
+
+       - First usable LBA = First LBA of the first usable eraseblock
+                            i.e. the block after primary GPT one
+                            Current LBA - 1 + erase block size
+
+       - Last usable LBA = Last LBA of the last usable eraseblock
+                           i.e. the block before backup GPT one
+                           Backup LBA - erase block size
+
+       Bad Block management (NAND):
+       ---------------------------
+       As the bad blocks are skipped, Current LBA and Backup LBA give the real
+       location of primary and backup GPT header
+
+       warning: the first and the last usable LBA are not guarantee
+                to be in a good block
+
+
+       Typically, the last 4 erase blocks for NAND are used for the bad block
+       table (BBT, see bbt_options and NAND_BBT_USE_FLASH).
+       They are indicated bad by MTD framework and they are also skipped.
+       So the layout for NAND with bad :
+
+       NAND layout with bad blocks:
+       ----------------------------------------------------------
+       N * BAD (*)   |                                 | skipped bad
+       -----------------------------------------------------------
+                      |Protective MBR                   | 1rst good eraseblock
+                      |Primary GPT Header               |
+                      |                                 |
+                      -------------------------------------------
+                      |                                 | = first usable
+                      |                                 |
+                      |  Partitions                     |
+                      |                                 |
+                      |                                 | = last usable
+                      -------------------------------------------
+                      |                                 |
+                      |Backup GPT Header                | last good eraseblock
+       ----------------------------------------------------------
+       M * BAD (*)    |                                 | skipped bad
+       ----------------------------------------------------------
+       BBT => BAD (*) |                                 | skipped 4 blocks
+       ----------------------------------------------------------
+       (*) BBT and block marked bad are skipped
+
+
+Drawbacks:
+==========
+1.  2 eraseblocks are used in the device just to save the GPT headers
+    (primary and backup)
+
+2.  for device with back block (NAND), any read request can disturb the device
+    so the GPT header should be refreshed when one fixable bit-flip ECC error 
is
+    detected...
+    but it is not the case today
+
+3.  for gpt write the eraseblock for the primary or backup GPT header
+    (expected good) can become bad for the erase request
+
+    And then U-Boot will mark this block bad
+
+    In this case the first / last usable LBA need to change and to skip the new
+    bad block, so header need to be recomputed
+    => the requested gpt write command failed to force new request
+       PS: the next request will work (skip the new bad block)
+
+    And as the first / last usable LBA can change the same partionning after
+    the block is marked bad
+
+GPT on MTD commands:
+====================
+some command are modified to support GPT on MTD devices under 
CONFIG_EFI_PARTITION_MTD
+
+       Creating GPT on MTD partitions:
+       -------------------------------
+
+       1. Define partition layout in the environment.
+            "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+               name=kernel,size=60MiB,uuid=...;"
+
+       2. From U-Boot prompt type:
+          gpt write nand 0 $partitions
+          gpt write nor 0 $partitions
+
+       List GPT partition on MTD:
+       ---------------------------------
+       part list nand 0
+       part list nor 0
+
+       to find bootable partition (used for distro):
+
+       part list nand 0 -bootable nand_boot_part
+       part list nor 0 -bootable nor_boot_part
+
+       NB: bootable partition can be used with UBIFS
+
+       Generate MTD partitions from GPT:
+       ---------------------------------
+       mtdparts gpt nand0
+       mtdparts gpt nor0
+
+       Then to check mtd partition created with:
+       mtdparts
diff --git a/include/part.h b/include/part.h
index 0979005..0660c27 100644
--- a/include/part.h
+++ b/include/part.h
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <linux/mtd/mtd.h>
 
 struct block_drvr {
        char *name;
@@ -308,7 +309,6 @@ int gpt_fill_header(struct blk_desc *dev_desc, gpt_header 
*gpt_h,
  */
 int gpt_restore(struct blk_desc *dev_desc, char *str_disk_guid,
                disk_partition_t *partitions, const int parts_count);
-
 /**
  * is_valid_gpt_buf() - Ensure that the Primary GPT information is valid
  *
@@ -363,7 +363,16 @@ int gpt_verify_headers(struct blk_desc *dev_desc, 
gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
                          disk_partition_t *partitions, int parts,
                          gpt_header *gpt_head, gpt_entry **gpt_pte);
-#endif
+
+#ifdef CONFIG_EFI_PARTITION_MTD
+#define MTD_LBA_SIZE   512
+int gpt_restore_mtd(struct mtd_info *mtd, char *str_disk_guid,
+                   disk_partition_t *partitions, int parts_count);
+void part_print_efi_mtd(struct mtd_info *mtd_info);
+int part_get_info_efi_mtd(struct mtd_info *mtd, int part,
+                              disk_partition_t *info);
+#endif /* CONFIG_EFI_PARTITION_MTD */
+#endif /* CONFIG_EFI_PARTITION */
 
 #ifdef CONFIG_DOS_PARTITION
 /**
-- 
1.9.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to