#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 */
#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 */
#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 */
#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 */
#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__
/*
#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);
#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__
/*
#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.
*/
#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;
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;
}
}
-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);
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 {
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;
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)
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
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;
}
#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)
#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 */
#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)
#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)
{
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;
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];
#include <addr_map.h>
#endif
+#include <linux/log2.h>
+
DECLARE_GLOBAL_DATA_PTR;
void invalidate_tlb(u8 tlb)
#include <linux/compiler.h>
#include <asm/fsl_law.h>
#include <asm/io.h>
+#include <linux/log2.h>
DECLARE_GLOBAL_DATA_PTR;
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;
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;
#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);
#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__
/*
#define _FSL_LAW_H_
#include <asm/io.h>
+#include <linux/log2.h>
#define LAW_EN 0x80000000
#ifndef _FSL_SRIO_H_
#define _FSL_SRIO_H_
+#include <linux/log2.h>
+
enum atmu_size {
ATMU_SIZE_4K = 0xb,
ATMU_SIZE_8K,
#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__
#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 */
#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 */
* 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
#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
*
__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
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;
return 0;
}
+#endif
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
static int setup_board_part2(void)
{
bd_t *bd = gd->bd;
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
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,
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);
"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
);
#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>
#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)
/* 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);
#include <spi_flash.h>
#include <watchdog.h>
#include <linux/compiler.h>
+#include <linux/log2.h>
#include "sf_internal.h"
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;
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;
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 */
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;
/*
#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>
#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"
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
#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))
# 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
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) */
--- /dev/null
+/* 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 */
* @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
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
}
#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);