Merge branch 'master' of git://git.denx.de/u-boot-nios
authorTom Rini <trini@konsulko.com>
Fri, 6 Nov 2015 14:21:33 +0000 (09:21 -0500)
committerTom Rini <trini@konsulko.com>
Fri, 6 Nov 2015 14:21:33 +0000 (09:21 -0500)
38 files changed:
arch/arc/include/asm/bitops.h
arch/arm/include/asm/bitops.h
arch/arm/mach-mvebu/mbus.c
arch/avr32/include/asm/bitops.h
arch/blackfin/include/asm/bitops.h
arch/m68k/include/asm/bitops.h
arch/microblaze/include/asm/bitops.h
arch/mips/include/asm/bitops.h
arch/mips/lib/bootm.c
arch/nds32/include/asm/bitops.h
arch/nios2/include/asm/bitops.h
arch/openrisc/include/asm/bitops.h
arch/powerpc/cpu/mpc83xx/law.c
arch/powerpc/cpu/mpc85xx/tlb.c
arch/powerpc/cpu/mpc8xxx/law.c
arch/powerpc/include/asm/bitops.h
arch/powerpc/include/asm/fsl_law.h
arch/powerpc/include/asm/fsl_srio.h
arch/sandbox/include/asm/bitops.h
arch/sh/include/asm/bitops.h
arch/sparc/include/asm/bitops.h
arch/x86/include/asm/bitops.h
common/board_f.c
common/cmd_sf.c
drivers/mtd/mtdcore.c
drivers/mtd/spi/sf_internal.h
drivers/mtd/spi/sf_ops.c
drivers/mtd/spi/sf_probe.c
drivers/mtd/ubi/build.c
fs/ubifs/super.c
include/asm-generic/bitops/__ffs.h [new file with mode: 0644]
include/asm-generic/bitops/__fls.h [new file with mode: 0644]
include/asm-generic/bitops/fls.h [new file with mode: 0644]
include/asm-generic/bitops/fls64.h [new file with mode: 0644]
include/linux/bitops.h
include/linux/compat.h
include/linux/log2.h [new file with mode: 0644]
include/spi_flash.h

index 85721aa..370cb46 100644 (file)
@@ -16,4 +16,9 @@
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
 #endif /* __ASM_ARC_BITOPS_H */
index 9b78043..d479a38 100644 (file)
@@ -190,4 +190,9 @@ found_middle:
 
 #endif /* __KERNEL__ */
 
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+
 #endif /* _ARM_BITOPS_H */
index 771cce6..346278e 100644 (file)
@@ -52,7 +52,7 @@
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
-#include <linux/compat.h>
+#include <linux/log2.h>
 #include <linux/mbus.h>
 
 /* DDR target is the same on all platforms */
index 0ec6784..0d425c2 100644 (file)
@@ -6,4 +6,9 @@
 #ifndef __ASM_AVR32_BITOPS_H
 #define __ASM_AVR32_BITOPS_H
 
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
 #endif /* __ASM_AVR32_BITOPS_H */
index cd7e356..6cde6db 100644 (file)
 
 #include <asm/byteorder.h>
 #include <asm/system.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
 
 #ifdef __KERNEL__
 /*
index f9c434b..69ea26a 100644 (file)
@@ -6,6 +6,10 @@
 #define _M68K_BITOPS_H
 
 #include <asm/byteorder.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
 
 extern void set_bit(int nr, volatile void *addr);
 extern void clear_bit(int nr, volatile void *addr);
index 0ac78d7..d24f2cf 100644 (file)
@@ -7,6 +7,10 @@
 
 #include <asm/byteorder.h>     /* swab32 */
 #include <asm/system.h>                /* save_flags */
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
 
 #ifdef __KERNEL__
 /*
index b5c2a63..c31ff6e 100644 (file)
 #include <asm/sgidefs.h>
 #include <asm/system.h>
 
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
index 9c647aa..eed159c 100644 (file)
@@ -15,24 +15,6 @@ DECLARE_GLOBAL_DATA_PTR;
 #define        LINUX_MAX_ENVS          256
 #define        LINUX_MAX_ARGS          256
 
-#if defined(CONFIG_MALTA)
-#define mips_boot_malta                1
-#else
-#define mips_boot_malta                0
-#endif
-
-#if defined(CONFIG_MIPS_BOOT_CMDLINE_LEGACY)
-#define mips_boot_cmdline_legacy       1
-#else
-#define mips_boot_cmdline_legacy       0
-#endif
-
-#if defined(CONFIG_MIPS_BOOT_ENV_LEGACY)
-#define mips_boot_env_legacy   1
-#else
-#define mips_boot_env_legacy   0
-#endif
-
 static int linux_argc;
 static char **linux_argv;
 static char *linux_argp;
@@ -62,50 +44,6 @@ void arch_lmb_reserve(struct lmb *lmb)
        lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp);
 }
 
-static int boot_setup_linux(bootm_headers_t *images)
-{
-       int ret;
-       ulong rd_len;
-
-       rd_len = images->rd_end - images->rd_start;
-       ret = boot_ramdisk_high(&images->lmb, images->rd_start,
-               rd_len, &images->initrd_start, &images->initrd_end);
-       if (ret)
-               return ret;
-
-#if defined(CONFIG_MIPS_BOOT_FDT) && defined(CONFIG_OF_LIBFDT)
-       if (images->ft_len) {
-               boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
-
-               ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
-                       &images->ft_len);
-               if (ret)
-                       return ret;
-       }
-#endif
-
-       return 0;
-}
-
-static void boot_setup_fdt(bootm_headers_t *images)
-{
-#if defined(CONFIG_MIPS_BOOT_FDT) && defined(CONFIG_OF_LIBFDT)
-       u64 mem_start = 0;
-       u64 mem_size = gd->ram_size;
-
-       debug("## setup FDT\n");
-
-       fdt_chosen(images->ft_addr);
-       fdt_fixup_memory_banks(images->ft_addr, &mem_start, &mem_size, 1);
-       fdt_fixup_ethernet(images->ft_addr);
-       fdt_initrd(images->ft_addr, images->initrd_start, images->initrd_end);
-
-#if defined(CONFIG_OF_BOARD_SETUP)
-       ft_board_setup(images->ft_addr, gd->bd);
-#endif
-#endif
-}
-
 static void linux_cmdline_init(void)
 {
        linux_argc = 1;
@@ -197,18 +135,6 @@ static void linux_cmdline_append(bootm_headers_t *images)
        }
 }
 
-static void boot_cmdline_linux(bootm_headers_t *images)
-{
-       if (mips_boot_cmdline_legacy && !images->ft_len) {
-               linux_cmdline_legacy(images);
-
-               if (!mips_boot_env_legacy)
-                       linux_cmdline_append(images);
-
-               linux_cmdline_dump();
-       }
-}
-
 static void linux_env_init(void)
 {
        linux_env = (char **)(((ulong) linux_argp + 15) & ~15);
@@ -225,7 +151,7 @@ static void linux_env_set(const char *env_name, const char *env_val)
                strcpy(linux_env_p, env_name);
                linux_env_p += strlen(env_name);
 
-               if (mips_boot_malta) {
+               if (CONFIG_IS_ENABLED(MALTA)) {
                        linux_env_p++;
                        linux_env[++linux_env_idx] = linux_env_p;
                } else {
@@ -246,14 +172,15 @@ static void linux_env_legacy(bootm_headers_t *images)
        const char *cp;
        ulong rd_start, rd_size;
 
-#ifdef CONFIG_MEMSIZE_IN_BYTES
-       sprintf(env_buf, "%lu", (ulong)gd->ram_size);
-       debug("## Giving linux memsize in bytes, %lu\n", (ulong)gd->ram_size);
-#else
-       sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
-       debug("## Giving linux memsize in MB, %lu\n",
-             (ulong)(gd->ram_size >> 20));
-#endif /* CONFIG_MEMSIZE_IN_BYTES */
+       if (CONFIG_IS_ENABLED(MEMSIZE_IN_BYTES)) {
+               sprintf(env_buf, "%lu", (ulong)gd->ram_size);
+               debug("## Giving linux memsize in bytes, %lu\n",
+                     (ulong)gd->ram_size);
+       } else {
+               sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
+               debug("## Giving linux memsize in MB, %lu\n",
+                     (ulong)(gd->ram_size >> 20));
+       }
 
        rd_start = UNCACHED_SDRAM(images->initrd_start);
        rd_size = images->initrd_end - images->initrd_start;
@@ -282,19 +209,87 @@ static void linux_env_legacy(bootm_headers_t *images)
        if (cp)
                linux_env_set("eth1addr", cp);
 
-       if (mips_boot_malta) {
+       if (CONFIG_IS_ENABLED(MALTA)) {
                sprintf(env_buf, "%un8r", gd->baudrate);
                linux_env_set("modetty0", env_buf);
        }
 }
 
+static int boot_reloc_ramdisk(bootm_headers_t *images)
+{
+       ulong rd_len = images->rd_end - images->rd_start;
+
+       /*
+        * In case of legacy uImage's, relocation of ramdisk is already done
+        * by do_bootm_states() and should not repeated in 'bootm prep'.
+        */
+       if (images->state & BOOTM_STATE_RAMDISK) {
+               debug("## Ramdisk already relocated\n");
+               return 0;
+       }
+
+       return boot_ramdisk_high(&images->lmb, images->rd_start,
+               rd_len, &images->initrd_start, &images->initrd_end);
+}
+
+static int boot_reloc_fdt(bootm_headers_t *images)
+{
+       /*
+        * In case of legacy uImage's, relocation of FDT is already done
+        * by do_bootm_states() and should not repeated in 'bootm prep'.
+        */
+       if (images->state & BOOTM_STATE_FDT) {
+               debug("## FDT already relocated\n");
+               return 0;
+       }
+
+#if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
+       boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
+       return boot_relocate_fdt(&images->lmb, &images->ft_addr,
+               &images->ft_len);
+#else
+       return 0;
+#endif
+}
+
+int arch_fixup_memory_node(void *blob)
+{
+#if CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && CONFIG_IS_ENABLED(OF_LIBFDT)
+       u64 mem_start = 0;
+       u64 mem_size = gd->ram_size;
+
+       return fdt_fixup_memory_banks(blob, &mem_start, &mem_size, 1);
+#else
+       return 0;
+#endif
+}
+
+static int boot_setup_fdt(bootm_headers_t *images)
+{
+       return image_setup_libfdt(images, images->ft_addr, images->ft_len,
+               &images->lmb);
+}
+
 static void boot_prep_linux(bootm_headers_t *images)
 {
-       if (mips_boot_env_legacy && !images->ft_len)
-               linux_env_legacy(images);
+       boot_reloc_ramdisk(images);
 
-       if (images->ft_len)
+       if (CONFIG_IS_ENABLED(MIPS_BOOT_FDT) && images->ft_len) {
+               boot_reloc_fdt(images);
                boot_setup_fdt(images);
+       } else {
+               if (CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY))
+                       linux_env_legacy(images);
+
+               if (CONFIG_IS_ENABLED(MIPS_BOOT_CMDLINE_LEGACY)) {
+                       linux_cmdline_legacy(images);
+
+                       if (!CONFIG_IS_ENABLED(CONFIG_MIPS_BOOT_ENV_LEGACY))
+                               linux_cmdline_append(images);
+
+                       linux_cmdline_dump();
+               }
+       }
 }
 
 static void boot_jump_linux(bootm_headers_t *images)
@@ -307,13 +302,13 @@ static void boot_jump_linux(bootm_headers_t *images)
 
        bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 
-       if (mips_boot_malta)
+       if (CONFIG_IS_ENABLED(MALTA))
                linux_extra = gd->ram_size;
 
-#ifdef CONFIG_BOOTSTAGE_FDT
+#if CONFIG_IS_ENABLED(BOOTSTAGE_FDT)
        bootstage_fdt_add_report();
 #endif
-#ifdef CONFIG_BOOTSTAGE_REPORT
+#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
        bootstage_report();
 #endif
 
@@ -327,35 +322,28 @@ static void boot_jump_linux(bootm_headers_t *images)
 int do_bootm_linux(int flag, int argc, char * const argv[],
                        bootm_headers_t *images)
 {
-       int ret;
-
        /* No need for those on MIPS */
        if (flag & BOOTM_STATE_OS_BD_T)
                return -1;
 
-       if (flag & BOOTM_STATE_OS_CMDLINE) {
-               boot_cmdline_linux(images);
+       /*
+        * Cmdline init has been moved to 'bootm prep' because it has to be
+        * done after relocation of ramdisk to always pass correct values
+        * for rd_start and rd_size to Linux kernel.
+        */
+       if (flag & BOOTM_STATE_OS_CMDLINE)
                return 0;
-       }
 
        if (flag & BOOTM_STATE_OS_PREP) {
                boot_prep_linux(images);
                return 0;
        }
 
-       if (flag & BOOTM_STATE_OS_GO) {
+       if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
                boot_jump_linux(images);
                return 0;
        }
 
-       ret = boot_setup_linux(images);
-       if (ret)
-               return ret;
-
-       boot_cmdline_linux(images);
-       boot_prep_linux(images);
-       boot_jump_linux(images);
-
        /* does not return */
        return 1;
 }
index f1aa9a3..7ee37c3 100644 (file)
 #ifdef __KERNEL__
 
 #include <asm/system.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
 
 #define smp_mb__before_clear_bit()     do { } while (0)
 #define smp_mb__after_clear_bit()      do { } while (0)
index 3e17964..ee46f37 100644 (file)
@@ -13,4 +13,9 @@
 #include <asm/bitops/non-atomic.h>
 #include <asm/bitops/ffs.h>
 
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
 #endif /* __ASM_NIOS2_BITOPS_H */
index 6d0b57c..28c4658 100644 (file)
 #define PLATFORM_FFS
 #include <asm/bitops/ffs.h>
 
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
 #define hweight32(x) generic_hweight32(x)
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
index 66c88b6..262ae7f 100644 (file)
@@ -9,6 +9,7 @@
 #include <common.h>
 #include <asm/fsl_law.h>
 #include <asm/mmu.h>
+#include <linux/log2.h>
 
 int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
 {
@@ -20,7 +21,7 @@ int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
        if (start == 0)
                start_align = 1ull << (LAW_SIZE_2G + 1);
        else
-               start_align = 1ull << (ffs64(start) - 1);
+               start_align = 1ull << (__ffs64(start) - 1);
        law_sz = min(start_align, sz);
        law_sz_enc = __ilog2_u64(law_sz) - 1;
 
@@ -40,7 +41,7 @@ int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
        if (sz) {
                start += law_sz;
 
-               start_align = 1ull << (ffs64(start) - 1);
+               start_align = 1ull << (__ffs64(start) - 1);
                law_sz = min(start_align, sz);
                law_sz_enc = __ilog2_u64(law_sz) - 1;
                ecm = &immap->sysconf.ddrlaw[1];
index 8e0508f..cf31eb2 100644 (file)
@@ -14,6 +14,8 @@
 #include <addr_map.h>
 #endif
 
+#include <linux/log2.h>
+
 DECLARE_GLOBAL_DATA_PTR;
 
 void invalidate_tlb(u8 tlb)
index 33d53a8..24baad4 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/compiler.h>
 #include <asm/fsl_law.h>
 #include <asm/io.h>
+#include <linux/log2.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -187,7 +188,7 @@ int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
        if (start == 0)
                start_align = 1ull << (LAW_SIZE_32G + 1);
        else
-               start_align = 1ull << (ffs64(start) - 1);
+               start_align = 1ull << (__ffs64(start) - 1);
        law_sz = min(start_align, sz);
        law_sz_enc = __ilog2_u64(law_sz) - 1;
 
@@ -202,7 +203,7 @@ int set_ddr_laws(u64 start, u64 sz, enum law_trgt_if id)
        if (sz) {
                start += law_sz;
 
-               start_align = 1ull << (ffs64(start) - 1);
+               start_align = 1ull << (__ffs64(start) - 1);
                law_sz = min(start_align, sz);
                law_sz_enc = __ilog2_u64(law_sz) - 1;
 
index a6bcf3c..14217ef 100644 (file)
@@ -6,6 +6,7 @@
 #define _PPC_BITOPS_H
 
 #include <asm/byteorder.h>
+#include <asm-generic/bitops/__ffs.h>
 
 extern void set_bit(int nr, volatile void *addr);
 extern void clear_bit(int nr, volatile void *addr);
@@ -209,16 +210,6 @@ static inline int fls64(__u64 x)
 #error BITS_PER_LONG not 32 or 64
 #endif
 
-static inline int __ilog2_u64(u64 n)
-{
-       return fls64(n) - 1;
-}
-
-static inline int ffs64(u64 x)
-{
-       return __ilog2_u64(x & -x) + 1ull;
-}
-
 #ifdef __KERNEL__
 
 /*
index 3b50487..8e1d22a 100644 (file)
@@ -10,6 +10,7 @@
 #define _FSL_LAW_H_
 
 #include <asm/io.h>
+#include <linux/log2.h>
 
 #define LAW_EN 0x80000000
 
index e5aab2a..ec25e16 100644 (file)
@@ -7,6 +7,8 @@
 #ifndef _FSL_SRIO_H_
 #define _FSL_SRIO_H_
 
+#include <linux/log2.h>
+
 enum atmu_size {
        ATMU_SIZE_4K = 0xb,
        ATMU_SIZE_8K,
index f1a7aee..f27d5e9 100644 (file)
 
 #include <linux/compiler.h>
 #include <asm/system.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
 
 #ifdef __KERNEL__
 
index c57d628..8cb8385 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef __ASM_SH_BITOPS_H
 #define __ASM_SH_BITOPS_H
 
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
 #ifdef __KERNEL__
 #include <asm/irqflags.h>
 /* For __swab32 */
index fa39fa3..c66f730 100644 (file)
@@ -9,4 +9,9 @@
 #ifndef _SPARC_BITOPS_H
 #define _SPARC_BITOPS_H
 
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/__ffs.h>
+
 #endif                         /* _SPARC_BITOPS_H */
index 5a7e4cb..f97dc66 100644 (file)
  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
  */
 
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+
 #ifdef CONFIG_SMP
 #define LOCK_PREFIX "lock ; "
 #else
@@ -332,6 +336,20 @@ static __inline__ unsigned long ffz(unsigned long word)
 #ifdef __KERNEL__
 
 /**
+ * __ffs - find first set bit in word
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+       __asm__("rep; bsf %1,%0"
+               : "=r" (word)
+               : "rm" (word));
+       return word;
+}
+
+/**
  * ffs - find first bit set
  * @x: the word to search
  *
@@ -346,7 +364,8 @@ static __inline__ int ffs(int x)
        __asm__("bsfl %1,%0\n\t"
                "jnz 1f\n\t"
                "movl $-1,%0\n"
-               "1:" : "=r" (r) : "g" (x));
+               "1:" : "=r" (r) : "rm" (x));
+
        return r+1;
 }
 #define PLATFORM_FFS
index 94db06d..725eb18 100644 (file)
@@ -551,7 +551,7 @@ static int display_new_sp(void)
        return 0;
 }
 
-#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
 static int setup_board_part1(void)
 {
        bd_t *bd = gd->bd;
@@ -580,7 +580,9 @@ static int setup_board_part1(void)
 
        return 0;
 }
+#endif
 
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
 static int setup_board_part2(void)
 {
        bd_t *bd = gd->bd;
@@ -933,8 +935,10 @@ static init_fnc_t init_sequence_f[] = {
        reserve_stacks,
        setup_dram_config,
        show_dram_config,
-#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
        setup_board_part1,
+#endif
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
        INIT_FUNC_WATCHDOG_RESET
        setup_board_part2,
 #endif
index ac7f5df..42862d9 100644 (file)
@@ -348,6 +348,37 @@ static int do_spi_flash_erase(int argc, char * const argv[])
        return ret == 0 ? 0 : 1;
 }
 
+static int do_spi_protect(int argc, char * const argv[])
+{
+       int ret = 0;
+       loff_t start, len;
+       bool prot = false;
+
+       if (argc != 4)
+               return -1;
+
+       if (!str2off(argv[2], &start)) {
+               puts("start sector is not a valid number\n");
+               return 1;
+       }
+
+       if (!str2off(argv[3], &len)) {
+               puts("len is not a valid number\n");
+               return 1;
+       }
+
+       if (strcmp(argv[1], "lock") == 0)
+               prot = true;
+       else if (strcmp(argv[1], "unlock") == 0)
+               prot = false;
+       else
+               return -1;  /* Unknown parameter */
+
+       ret = spi_flash_protect(flash, start, len, prot);
+
+       return ret == 0 ? 0 : 1;
+}
+
 #ifdef CONFIG_CMD_SF_TEST
 enum {
        STAGE_ERASE,
@@ -540,6 +571,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc,
                ret = do_spi_flash_read_write(argc, argv);
        else if (strcmp(cmd, "erase") == 0)
                ret = do_spi_flash_erase(argc, argv);
+       else if (strcmp(cmd, "protect") == 0)
+               ret = do_spi_protect(argc, argv);
 #ifdef CONFIG_CMD_SF_TEST
        else if (!strcmp(cmd, "test"))
                ret = do_spi_flash_test(argc, argv);
@@ -579,5 +612,7 @@ U_BOOT_CMD(
        "sf update addr offset|partition len    - erase and write `len' bytes from memory\n"
        "                                         at `addr' to flash at `offset'\n"
        "                                         or to start of mtd `partition'\n"
+       "sf protect lock/unlock sector len      - protect/unprotect 'len' bytes starting\n"
+       "                                         at address 'sector'\n"
        SF_TEST_HELP
 );
index 2f2172b..e3f56e5 100644 (file)
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #else
-#include <linux/compat.h>
 #include <linux/err.h>
 #include <ubi_uboot.h>
 #endif
 
+#include <linux/log2.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
index 8a3e5ec..8793f18 100644 (file)
@@ -105,6 +105,9 @@ enum spi_nor_option_flags {
 #define STATUS_QEB_WINSPAN             (1 << 1)
 #define STATUS_QEB_MXIC                (1 << 6)
 #define STATUS_PEC                     (1 << 7)
+#define SR_BP0                         BIT(2)  /* Block protect 0 */
+#define SR_BP1                         BIT(3)  /* Block protect 1 */
+#define SR_BP2                         BIT(4)  /* Block protect 2 */
 
 /* Flash timeout values */
 #define SPI_FLASH_PROG_TIMEOUT         (2 * CONFIG_SYS_HZ)
@@ -173,6 +176,15 @@ int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs);
 /* Program the status register */
 int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws);
 
+/* Lock stmicro spi flash region */
+int stm_lock(struct spi_flash *flash, u32 ofs, size_t len);
+
+/* Unlock stmicro spi flash region */
+int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len);
+
+/* Check if a stmicro spi flash region is completely locked */
+int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len);
+
 /* Read the config register */
 int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc);
 
index f2a9244..d832464 100644 (file)
@@ -15,6 +15,7 @@
 #include <spi_flash.h>
 #include <watchdog.h>
 #include <linux/compiler.h>
+#include <linux/log2.h>
 
 #include "sf_internal.h"
 
@@ -267,6 +268,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
                return -1;
        }
 
+       if (flash->flash_is_locked(flash, offset, len) > 0) {
+               printf("offset 0x%x is protected and cannot be erased\n", offset);
+               return -EINVAL;
+       }
+
        cmd[0] = flash->erase_cmd;
        while (len) {
                erase_addr = offset;
@@ -309,6 +315,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
 
        page_size = flash->page_size;
 
+       if (flash->flash_is_locked(flash, offset, len) > 0) {
+               printf("offset 0x%x is protected and cannot be written\n", offset);
+               return -EINVAL;
+       }
+
        cmd[0] = flash->write_cmd;
        for (actual = 0; actual < len; actual += chunk_len) {
                write_addr = offset;
@@ -565,3 +576,172 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
        return ret;
 }
 #endif
+
+#ifdef CONFIG_SPI_FLASH_STMICRO
+static void stm_get_locked_range(struct spi_flash *flash, u8 sr, loff_t *ofs,
+                                u32 *len)
+{
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       int shift = ffs(mask) - 1;
+       int pow;
+
+       if (!(sr & mask)) {
+               /* No protection */
+               *ofs = 0;
+               *len = 0;
+       } else {
+               pow = ((sr & mask) ^ mask) >> shift;
+               *len = flash->size >> pow;
+               *ofs = flash->size - *len;
+       }
+}
+
+/*
+ * Return 1 if the entire region is locked, 0 otherwise
+ */
+static int stm_is_locked_sr(struct spi_flash *flash, u32 ofs, u32 len,
+                           u8 sr)
+{
+       loff_t lock_offs;
+       u32 lock_len;
+
+       stm_get_locked_range(flash, sr, &lock_offs, &lock_len);
+
+       return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
+}
+
+/*
+ * Check if a region of the flash is (completely) locked. See stm_lock() for
+ * more info.
+ *
+ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
+ * negative on errors.
+ */
+int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
+{
+       int status;
+       u8 sr;
+
+       status = spi_flash_cmd_read_status(flash, &sr);
+       if (status < 0)
+               return status;
+
+       return stm_is_locked_sr(flash, ofs, len, sr);
+}
+
+/*
+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
+ * Supports only the block protection bits BP{0,1,2} in the status register
+ * (SR). Does not support these features found in newer SR bitfields:
+ *   - TB: top/bottom protect - only handle TB=0 (top protect)
+ *   - SEC: sector/block protect - only handle SEC=0 (block protect)
+ *   - CMP: complement protect - only support CMP=0 (range is not complemented)
+ *
+ * Sample table portion for 8MB flash (Winbond w25q64fw):
+ *
+ *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
+ *  --------------------------------------------------------------------------
+ *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
+ *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
+ *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
+ *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
+ *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
+ *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
+ *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
+ *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
+ *
+ * Returns negative on errors, 0 on success.
+ */
+int stm_lock(struct spi_flash *flash, u32 ofs, size_t len)
+{
+       u8 status_old, status_new;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       u8 shift = ffs(mask) - 1, pow, val;
+
+       spi_flash_cmd_read_status(flash, &status_old);
+
+       /* SPI NOR always locks to the end */
+       if (ofs + len != flash->size) {
+               /* Does combined region extend to end? */
+               if (!stm_is_locked_sr(flash, ofs + len, flash->size - ofs - len,
+                                     status_old))
+                       return -EINVAL;
+               len = flash->size - ofs;
+       }
+
+       /*
+        * Need smallest pow such that:
+        *
+        *   1 / (2^pow) <= (len / size)
+        *
+        * so (assuming power-of-2 size) we do:
+        *
+        *   pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+        */
+       pow = ilog2(flash->size) - ilog2(len);
+       val = mask - (pow << shift);
+       if (val & ~mask)
+               return -EINVAL;
+
+       /* Don't "lock" with no region! */
+       if (!(val & mask))
+               return -EINVAL;
+
+       status_new = (status_old & ~mask) | val;
+
+       /* Only modify protection if it will not unlock other areas */
+       if ((status_new & mask) <= (status_old & mask))
+               return -EINVAL;
+
+       spi_flash_cmd_write_status(flash, status_new);
+
+       return 0;
+}
+
+/*
+ * Unlock a region of the flash. See stm_lock() for more info
+ *
+ * Returns negative on errors, 0 on success.
+ */
+int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len)
+{
+       uint8_t status_old, status_new;
+       u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+       u8 shift = ffs(mask) - 1, pow, val;
+
+       spi_flash_cmd_read_status(flash, &status_old);
+
+       /* Cannot unlock; would unlock larger region than requested */
+       if (stm_is_locked_sr(flash, status_old, ofs - flash->erase_size,
+                            flash->erase_size))
+               return -EINVAL;
+       /*
+        * Need largest pow such that:
+        *
+        *   1 / (2^pow) >= (len / size)
+        *
+        * so (assuming power-of-2 size) we do:
+        *
+        *   pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
+        */
+       pow = ilog2(flash->size) - order_base_2(flash->size - (ofs + len));
+       if (ofs + len == flash->size) {
+               val = 0; /* fully unlocked */
+       } else {
+               val = mask - (pow << shift);
+               /* Some power-of-two sizes are not supported */
+               if (val & ~mask)
+                       return -EINVAL;
+       }
+
+       status_new = (status_old & ~mask) | val;
+
+       /* Only modify protection if it will not lock other areas */
+       if ((status_new & mask) >= (status_old & mask))
+               return -EINVAL;
+
+       spi_flash_cmd_write_status(flash, status_new);
+
+       return 0;
+}
+#endif  /* CONFIG_SPI_FLASH_STMICRO */
index c000c53..bc05d30 100644 (file)
@@ -182,6 +182,19 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
        flash->read = spi_flash_cmd_read_ops;
 #endif
 
+       /* lock hooks are flash specific - assign them based on idcode0 */
+       switch (idcode[0]) {
+#ifdef CONFIG_SPI_FLASH_STMICRO
+       case SPI_FLASH_CFI_MFR_STMICRO:
+               flash->flash_lock = stm_lock;
+               flash->flash_unlock = stm_unlock;
+               flash->flash_is_locked = stm_is_locked;
+#endif
+               break;
+       default:
+               debug("SF: Lock ops not supported for %02x flash\n", idcode[0]);
+       }
+
        /* Compute the flash size */
        flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
        /*
index f0a3b67..f484e62 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/slab.h>
 #include <linux/major.h>
 #else
-#include <linux/compat.h>
+#include <linux/log2.h>
 #endif
 #include <linux/err.h>
 #include <ubi_uboot.h>
index c474313..abe861a 100644 (file)
@@ -31,7 +31,7 @@
 #include <common.h>
 #include <malloc.h>
 #include <memalign.h>
-#include <linux/compat.h>
+#include <linux/log2.h>
 #include <linux/stat.h>
 #include <linux/err.h>
 #include "ubifs.h"
diff --git a/include/asm-generic/bitops/__ffs.h b/include/asm-generic/bitops/__ffs.h
new file mode 100644 (file)
index 0000000..937d7c4
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _ASM_GENERIC_BITOPS___FFS_H_
+#define _ASM_GENERIC_BITOPS___FFS_H_
+
+#include <asm/types.h>
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __always_inline unsigned long __ffs(unsigned long word)
+{
+       int num = 0;
+
+#if BITS_PER_LONG == 64
+       if ((word & 0xffffffff) == 0) {
+               num += 32;
+               word >>= 32;
+       }
+#endif
+       if ((word & 0xffff) == 0) {
+               num += 16;
+               word >>= 16;
+       }
+       if ((word & 0xff) == 0) {
+               num += 8;
+               word >>= 8;
+       }
+       if ((word & 0xf) == 0) {
+               num += 4;
+               word >>= 4;
+       }
+       if ((word & 0x3) == 0) {
+               num += 2;
+               word >>= 2;
+       }
+       if ((word & 0x1) == 0)
+               num += 1;
+       return num;
+}
+
+#endif /* _ASM_GENERIC_BITOPS___FFS_H_ */
diff --git a/include/asm-generic/bitops/__fls.h b/include/asm-generic/bitops/__fls.h
new file mode 100644 (file)
index 0000000..a60a7cc
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _ASM_GENERIC_BITOPS___FLS_H_
+#define _ASM_GENERIC_BITOPS___FLS_H_
+
+#include <asm/types.h>
+
+/**
+ * __fls - find last (most-significant) set bit in a long word
+ * @word: the word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static __always_inline unsigned long __fls(unsigned long word)
+{
+       int num = BITS_PER_LONG - 1;
+
+#if BITS_PER_LONG == 64
+       if (!(word & (~0ul << 32))) {
+               num -= 32;
+               word <<= 32;
+       }
+#endif
+       if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
+               num -= 16;
+               word <<= 16;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
+               num -= 8;
+               word <<= 8;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
+               num -= 4;
+               word <<= 4;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
+               num -= 2;
+               word <<= 2;
+       }
+       if (!(word & (~0ul << (BITS_PER_LONG-1))))
+               num -= 1;
+       return num;
+}
+
+#endif /* _ASM_GENERIC_BITOPS___FLS_H_ */
diff --git a/include/asm-generic/bitops/fls.h b/include/asm-generic/bitops/fls.h
new file mode 100644 (file)
index 0000000..0576d1f
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _ASM_GENERIC_BITOPS_FLS_H_
+#define _ASM_GENERIC_BITOPS_FLS_H_
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+
+static __always_inline int fls(int x)
+{
+       int r = 32;
+
+       if (!x)
+               return 0;
+       if (!(x & 0xffff0000u)) {
+               x <<= 16;
+               r -= 16;
+       }
+       if (!(x & 0xff000000u)) {
+               x <<= 8;
+               r -= 8;
+       }
+       if (!(x & 0xf0000000u)) {
+               x <<= 4;
+               r -= 4;
+       }
+       if (!(x & 0xc0000000u)) {
+               x <<= 2;
+               r -= 2;
+       }
+       if (!(x & 0x80000000u)) {
+               x <<= 1;
+               r -= 1;
+       }
+       return r;
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FLS_H_ */
diff --git a/include/asm-generic/bitops/fls64.h b/include/asm-generic/bitops/fls64.h
new file mode 100644 (file)
index 0000000..b097cf8
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _ASM_GENERIC_BITOPS_FLS64_H_
+#define _ASM_GENERIC_BITOPS_FLS64_H_
+
+#include <asm/types.h>
+
+/**
+ * fls64 - find last set bit in a 64-bit word
+ * @x: the word to search
+ *
+ * This is defined in a similar way as the libc and compiler builtin
+ * ffsll, but returns the position of the most significant set bit.
+ *
+ * fls64(value) returns 0 if value is 0 or the position of the last
+ * set bit if value is nonzero. The last (most significant) bit is
+ * at position 64.
+ */
+#if BITS_PER_LONG == 32
+static __always_inline int fls64(__u64 x)
+{
+       __u32 h = x >> 32;
+       if (h)
+               return fls(h) + 32;
+       return fls(x);
+}
+#elif BITS_PER_LONG == 64
+static __always_inline int fls64(__u64 x)
+{
+       if (x == 0)
+               return 0;
+       return __fls(x) + 1;
+}
+#else
+#error BITS_PER_LONG not 32 or 64
+#endif
+
+#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */
index 7b4011f..1b2e491 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_BITOPS_H
 
 #include <asm/types.h>
+#include <linux/compiler.h>
 
 #define BIT(nr)                        (1UL << (nr))
 #define BIT_MASK(nr)           (1UL << ((nr) % BITS_PER_LONG))
@@ -139,6 +140,32 @@ static inline unsigned int generic_hweight8(unsigned int w)
 # define fls generic_fls
 #endif
 
+static inline unsigned fls_long(unsigned long l)
+{
+       if (sizeof(l) == 4)
+               return fls(l);
+       return fls64(l);
+}
+
+/**
+ * __ffs64 - find first set bit in a 64 bit word
+ * @word: The 64 bit word
+ *
+ * On 64 bit arches this is a synomyn for __ffs
+ * The result is not defined if no bits are set, so check that @word
+ * is non-zero before calling this.
+ */
+static inline unsigned long __ffs64(u64 word)
+{
+#if BITS_PER_LONG == 32
+       if (((u32)word) == 0UL)
+               return __ffs((u32)(word >> 32)) + 32;
+#elif BITS_PER_LONG != 64
+#error BITS_PER_LONG not 32 or 64
+#endif
+       return __ffs((unsigned long)word);
+}
+
 /**
  * __set_bit - Set a bit in memory
  * @nr: the bit to set
index 59937de..e561ee3 100644 (file)
@@ -130,12 +130,6 @@ static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {}
 static inline void led_trigger_event(struct led_trigger *trigger,
                                        enum led_brightness event) {}
 
-/* include/linux/log2.h */
-static inline int is_power_of_2(unsigned long n)
-{
-       return (n != 0 && ((n & (n - 1)) == 0));
-}
-
 /* uapi/linux/limits.h */
 #define XATTR_LIST_MAX 65536   /* size of extended attribute namelist (64k) */
 
diff --git a/include/linux/log2.h b/include/linux/log2.h
new file mode 100644 (file)
index 0000000..aa1de63
--- /dev/null
@@ -0,0 +1,205 @@
+/* Integer base 2 logarithm calculation
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _LINUX_LOG2_H
+#define _LINUX_LOG2_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+/*
+ * deal with unrepresentable constant logarithms
+ */
+extern __attribute__((const, noreturn))
+int ____ilog2_NaN(void);
+
+/*
+ * non-constant log of base 2 calculators
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ *   more efficiently than using fls() and fls64()
+ * - the arch is not required to handle n==0 if implementing the fallback
+ */
+#ifndef CONFIG_ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+       return fls(n) - 1;
+}
+#endif
+
+#ifndef CONFIG_ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+       return fls64(n) - 1;
+}
+#endif
+
+/*
+ *  Determine whether some value is a power of two, where zero is
+ * *not* considered a power of two.
+ */
+
+static inline __attribute__((const))
+bool is_power_of_2(unsigned long n)
+{
+       return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+/*
+ * round up to nearest power of two
+ */
+static inline __attribute__((const))
+unsigned long __roundup_pow_of_two(unsigned long n)
+{
+       return 1UL << fls_long(n - 1);
+}
+
+/*
+ * round down to nearest power of two
+ */
+static inline __attribute__((const))
+unsigned long __rounddown_pow_of_two(unsigned long n)
+{
+       return 1UL << (fls_long(n) - 1);
+}
+
+/**
+ * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
+ * @n - parameter
+ *
+ * constant-capable log of base 2 calculation
+ * - this can be used to initialise global variables from constant data, hence
+ *   the massive ternary operator construction
+ *
+ * selects the appropriately-sized optimised version depending on sizeof(n)
+ */
+#define ilog2(n)                               \
+(                                              \
+       __builtin_constant_p(n) ? (             \
+               (n) < 1 ? ____ilog2_NaN() :     \
+               (n) & (1ULL << 63) ? 63 :       \
+               (n) & (1ULL << 62) ? 62 :       \
+               (n) & (1ULL << 61) ? 61 :       \
+               (n) & (1ULL << 60) ? 60 :       \
+               (n) & (1ULL << 59) ? 59 :       \
+               (n) & (1ULL << 58) ? 58 :       \
+               (n) & (1ULL << 57) ? 57 :       \
+               (n) & (1ULL << 56) ? 56 :       \
+               (n) & (1ULL << 55) ? 55 :       \
+               (n) & (1ULL << 54) ? 54 :       \
+               (n) & (1ULL << 53) ? 53 :       \
+               (n) & (1ULL << 52) ? 52 :       \
+               (n) & (1ULL << 51) ? 51 :       \
+               (n) & (1ULL << 50) ? 50 :       \
+               (n) & (1ULL << 49) ? 49 :       \
+               (n) & (1ULL << 48) ? 48 :       \
+               (n) & (1ULL << 47) ? 47 :       \
+               (n) & (1ULL << 46) ? 46 :       \
+               (n) & (1ULL << 45) ? 45 :       \
+               (n) & (1ULL << 44) ? 44 :       \
+               (n) & (1ULL << 43) ? 43 :       \
+               (n) & (1ULL << 42) ? 42 :       \
+               (n) & (1ULL << 41) ? 41 :       \
+               (n) & (1ULL << 40) ? 40 :       \
+               (n) & (1ULL << 39) ? 39 :       \
+               (n) & (1ULL << 38) ? 38 :       \
+               (n) & (1ULL << 37) ? 37 :       \
+               (n) & (1ULL << 36) ? 36 :       \
+               (n) & (1ULL << 35) ? 35 :       \
+               (n) & (1ULL << 34) ? 34 :       \
+               (n) & (1ULL << 33) ? 33 :       \
+               (n) & (1ULL << 32) ? 32 :       \
+               (n) & (1ULL << 31) ? 31 :       \
+               (n) & (1ULL << 30) ? 30 :       \
+               (n) & (1ULL << 29) ? 29 :       \
+               (n) & (1ULL << 28) ? 28 :       \
+               (n) & (1ULL << 27) ? 27 :       \
+               (n) & (1ULL << 26) ? 26 :       \
+               (n) & (1ULL << 25) ? 25 :       \
+               (n) & (1ULL << 24) ? 24 :       \
+               (n) & (1ULL << 23) ? 23 :       \
+               (n) & (1ULL << 22) ? 22 :       \
+               (n) & (1ULL << 21) ? 21 :       \
+               (n) & (1ULL << 20) ? 20 :       \
+               (n) & (1ULL << 19) ? 19 :       \
+               (n) & (1ULL << 18) ? 18 :       \
+               (n) & (1ULL << 17) ? 17 :       \
+               (n) & (1ULL << 16) ? 16 :       \
+               (n) & (1ULL << 15) ? 15 :       \
+               (n) & (1ULL << 14) ? 14 :       \
+               (n) & (1ULL << 13) ? 13 :       \
+               (n) & (1ULL << 12) ? 12 :       \
+               (n) & (1ULL << 11) ? 11 :       \
+               (n) & (1ULL << 10) ? 10 :       \
+               (n) & (1ULL <<  9) ?  9 :       \
+               (n) & (1ULL <<  8) ?  8 :       \
+               (n) & (1ULL <<  7) ?  7 :       \
+               (n) & (1ULL <<  6) ?  6 :       \
+               (n) & (1ULL <<  5) ?  5 :       \
+               (n) & (1ULL <<  4) ?  4 :       \
+               (n) & (1ULL <<  3) ?  3 :       \
+               (n) & (1ULL <<  2) ?  2 :       \
+               (n) & (1ULL <<  1) ?  1 :       \
+               (n) & (1ULL <<  0) ?  0 :       \
+               ____ilog2_NaN()                 \
+                                  ) :          \
+       (sizeof(n) <= 4) ?                      \
+       __ilog2_u32(n) :                        \
+       __ilog2_u64(n)                          \
+ )
+
+/**
+ * roundup_pow_of_two - round the given value up to nearest power of two
+ * @n - parameter
+ *
+ * round the given value up to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two(n)                  \
+(                                              \
+       __builtin_constant_p(n) ? (             \
+               (n == 1) ? 1 :                  \
+               (1UL << (ilog2((n) - 1) + 1))   \
+                                  ) :          \
+       __roundup_pow_of_two(n)                 \
+ )
+
+/**
+ * rounddown_pow_of_two - round the given value down to nearest power of two
+ * @n - parameter
+ *
+ * round the given value down to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define rounddown_pow_of_two(n)                        \
+(                                              \
+       __builtin_constant_p(n) ? (             \
+               (1UL << ilog2(n))) :            \
+       __rounddown_pow_of_two(n)               \
+ )
+
+/**
+ * order_base_2 - calculate the (rounded up) base 2 order of the argument
+ * @n: parameter
+ *
+ * The first few values calculated by this routine:
+ *  ob2(0) = 0
+ *  ob2(1) = 0
+ *  ob2(2) = 1
+ *  ob2(3) = 2
+ *  ob2(4) = 2
+ *  ob2(5) = 3
+ *  ... and so on.
+ */
+
+#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+
+#endif /* _LINUX_LOG2_H */
index 4312d3d..0ae0062 100644 (file)
@@ -54,6 +54,9 @@ struct spi_slave;
  * @write_cmd:         Write cmd - page and quad program.
  * @dummy_byte:                Dummy cycles for read operation.
  * @memory_map:                Address of read-only SPI flash access
+ * @flash_lock:                lock a region of the SPI Flash
+ * @flash_unlock:      unlock a region of the SPI Flash
+ * @flash_is_locked:   check if a region of the SPI Flash is completely locked
  * @read:              Flash read ops: Read len bytes at offset into buf
  *                     Supported cmds: Fast Array Read
  * @write:             Flash write ops: Write len bytes from buf into offset
@@ -87,6 +90,10 @@ struct spi_flash {
        u8 dummy_byte;
 
        void *memory_map;
+
+       int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len);
+       int (*flash_unlock)(struct spi_flash *flash, u32 ofs, size_t len);
+       int (*flash_is_locked)(struct spi_flash *flash, u32 ofs, size_t len);
 #ifndef CONFIG_DM_SPI_FLASH
        /*
         * These are not strictly needed for driver model, but keep them here
@@ -227,6 +234,18 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
 }
 #endif
 
+static inline int spi_flash_protect(struct spi_flash *flash, u32 ofs, u32 len,
+                                       bool prot)
+{
+       if (!flash->flash_lock)
+               return -EOPNOTSUPP;
+
+       if (prot)
+               return flash->flash_lock(flash, ofs, len);
+       else
+               return flash->flash_unlock(flash, ofs, len);
+}
+
 void spi_boot(void) __noreturn;
 void spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst);