diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-11-14 10:59:37 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-11-14 10:59:37 +1100 |
commit | a05118a3f2d7d775cfc1f27d0cc53a4d7aba710c (patch) | |
tree | 4b2aa9579bcd2f41493d9e8914a348cb71b6b822 | |
parent | 3cf5a0962e64a0f63537ddeecf04058793fed936 (diff) | |
download | skiboot-a05118a3f2d7d775cfc1f27d0cc53a4d7aba710c.zip skiboot-a05118a3f2d7d775cfc1f27d0cc53a4d7aba710c.tar.gz skiboot-a05118a3f2d7d775cfc1f27d0cc53a4d7aba710c.tar.bz2 |
Import pflash 0.8.6
We share code, it's easier to maintain it this way
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | external/pflash/Makefile | 44 | ||||
-rw-r--r-- | external/pflash/TODO | 7 | ||||
-rw-r--r-- | external/pflash/arm_io.c | 139 | ||||
-rw-r--r-- | external/pflash/ast.h | 66 | ||||
-rw-r--r-- | external/pflash/config.h | 19 | ||||
-rwxr-xr-x | external/pflash/get_arch.sh | 11 | ||||
-rw-r--r-- | external/pflash/io.h | 121 | ||||
-rw-r--r-- | external/pflash/pflash.c | 793 | ||||
-rw-r--r-- | external/pflash/powerpc_io.c | 341 | ||||
-rw-r--r-- | external/pflash/progress.c | 79 | ||||
-rw-r--r-- | external/pflash/progress.h | 8 | ||||
-rw-r--r-- | external/pflash/sfc-ctrl.h | 9 | ||||
-rw-r--r-- | libflash/libflash.h | 17 |
13 files changed, 1645 insertions, 9 deletions
diff --git a/external/pflash/Makefile b/external/pflash/Makefile new file mode 100644 index 0000000..59db535 --- /dev/null +++ b/external/pflash/Makefile @@ -0,0 +1,44 @@ +ARCH=$(shell ./get_arch.sh $(CROSS_COMPILE)) + +ifeq ($(ARCH),ARCH_POWERPC) + ARCH_OBJS = powerpc_io.o sfc-ctrl.o +else +ifeq ($(ARCH),ARCH_ARM) + ARCH_OBJS = arm_io.o +else +error_arch: + $(error Unsupported architecture $(ARCH)) +endif +endif + +CFLAGS = -O2 -Wall -I. +LDFLAGS = -lrt +OBJS = pflash.o progress.o ast-sf-ctrl.o +OBJS += libflash/libflash.o libflash/libffs.o +OBJS += $(ARCH_OBJS) +EXE = pflash + +CC = $(CROSS_COMPILE)gcc + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +all: $(EXE) + +.PHONY: links +links: + ln -sf ../../libflash . + ln -sf ../../ccan . + ln -sf ../../hw/sfc-ctrl.c . + ln -sf ../../hw/ast-bmc/ast-sf-ctrl.c + +$(OBJS) : links + +$(EXE): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ + +clean: + rm -f $(OBJS) $(EXE) *.o *.d libflash/test/test_flash libflash/test/*.o +distclean: clean + rm -f *.c~ *.h~ *.sh~ Makefile~ config.mk~ libflash/*.c~ libflash/*.h~ + rm -f libflash ccan sfc-ctrl.c ast-sf-ctrl.c diff --git a/external/pflash/TODO b/external/pflash/TODO new file mode 100644 index 0000000..b30f36d --- /dev/null +++ b/external/pflash/TODO @@ -0,0 +1,7 @@ +- PCI backend for host +- Use proper GPIO APIs on ARM +- Use IPMI for lock/unlock on host +- Timeouts and flashing errors handling +- Lock handling +- Support pnor "update" mode which only update selected partitions + diff --git a/external/pflash/arm_io.c b/external/pflash/arm_io.c new file mode 100644 index 0000000..ad040c3 --- /dev/null +++ b/external/pflash/arm_io.c @@ -0,0 +1,139 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <byteswap.h> +#include <stdint.h> +#include <stdbool.h> +#include <getopt.h> +#include <limits.h> +#include <arpa/inet.h> +#include <assert.h> + +#include "io.h" + +void *ahb_reg_map; +void *ahb_flash_map; +uint32_t ahb_flash_base, ahb_flash_size; +void *gpio_ctrl; + +int ast_copy_to_ahb(uint32_t reg, const void *src, uint32_t len) +{ + if (reg < ahb_flash_base || + (reg + len) > (ahb_flash_base + ahb_flash_size)) + return -1; + reg -= ahb_flash_base; + + if (((reg | (unsigned long)src | len) & 3) == 0) { + while(len > 3) { + uint32_t val = *(uint32_t *)src; + writel(val, ahb_flash_map + reg); + src += 4; + reg += 4; + len -= 4; + } + } + + while(len--) { + uint8_t val = *(uint8_t *)src; + writeb(val, ahb_flash_map + reg++); + src += 1; + } + return 0; +} + + +int ast_copy_from_ahb(void *dst, uint32_t reg, uint32_t len) +{ + if (reg < ahb_flash_base || + (reg + len) > (ahb_flash_base + ahb_flash_size)) + return -1; + reg -= ahb_flash_base; + + if (((reg | (unsigned long)dst | len) & 3) == 0) { + while(len > 3) { + *(uint32_t *)dst = readl(ahb_flash_map + reg); + dst += 4; + reg += 4; + len -= 4; + } + } + + while(len--) { + *(uint8_t *)dst = readb(ahb_flash_map + reg++); + dst += 1; + } + return 0; +} + +/* + * GPIO stuff to be replaced by higher level accessors for + * controlling the flash write lock via sysfs + */ + +static inline uint32_t gpio_ctl_readl(uint32_t offset) +{ + return readl(gpio_ctrl + offset); +} + +static inline void gpio_ctl_writel(uint32_t val, uint32_t offset) +{ + writel(val, gpio_ctrl + offset); +} + + +bool set_wrprotect(bool protect) +{ + uint32_t reg; + bool was_protected; + + reg = gpio_ctl_readl(0x20); + was_protected = !!(reg & 0x00004000); + if (protect) + reg |= 0x00004000; /* GPIOF[6] value */ + else + reg &= ~0x00004000; /* GPIOF[6] value */ + gpio_ctl_writel(reg, 0x20); + reg = gpio_ctl_readl(0x24); + reg |= 0x00004000; /* GPIOF[6] direction */ + gpio_ctl_writel(reg, 0x24); + + return was_protected; +} + +void open_devs(bool use_lpc, bool bmc_flash) +{ + int fd; + + (void)use_lpc; + + fd = open("/dev/mem", O_RDWR | O_SYNC); + if (fd < 0) { + perror("can't open /dev/mem"); + exit(1); + } + ahb_reg_map = mmap(0, AHB_REGS_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, AHB_REGS_BASE); + if (ahb_reg_map == MAP_FAILED) { + perror("can't map AHB registers /dev/mem"); + exit(1); + } + gpio_ctrl = mmap(0, GPIO_CTRL_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, GPIO_CTRL_BASE); + if (gpio_ctrl == MAP_FAILED) { + perror("can't map GPIO control via /dev/mem"); + exit(1); + } + ahb_flash_base = bmc_flash ? BMC_FLASH_BASE : PNOR_FLASH_BASE; + ahb_flash_size = bmc_flash ? BMC_FLASH_SIZE : PNOR_FLASH_SIZE; + ahb_flash_map = mmap(0, ahb_flash_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, ahb_flash_base); + if (ahb_flash_map == MAP_FAILED) { + perror("can't map flash via /dev/mem"); + exit(1); + } +} diff --git a/external/pflash/ast.h b/external/pflash/ast.h new file mode 100644 index 0000000..92cafa4 --- /dev/null +++ b/external/pflash/ast.h @@ -0,0 +1,66 @@ +#ifndef __AST_H +#define __AST_H + +/* + * AHB bus registers + */ + +/* SPI Flash controller #1 (BMC) */ +#define BMC_SPI_FCTL_BASE 0x1E620000 +#define BMC_SPI_FCTL_CTRL (BMC_SPI_FCTL_BASE + 0x10) +#define BMC_SPI_FREAD_TIMING (BMC_SPI_FCTL_BASE + 0x94) +#define BMC_FLASH_BASE 0x20000000 + +/* SPI Flash controller #2 (PNOR) */ +#define PNOR_SPI_FCTL_BASE 0x1E630000 +#define PNOR_SPI_FCTL_CONF (PNOR_SPI_FCTL_BASE + 0x00) +#define PNOR_SPI_FCTL_CTRL (PNOR_SPI_FCTL_BASE + 0x04) +#define PNOR_SPI_FREAD_TIMING (PNOR_SPI_FCTL_BASE + 0x14) +#define PNOR_FLASH_BASE 0x30000000 + +/* LPC registers */ +#define LPC_BASE 0x1e789000 +#define LPC_HICR6 (LPC_BASE + 0x80) +#define LPC_HICR7 (LPC_BASE + 0x88) +#define LPC_HICR8 (LPC_BASE + 0x8c) + +/* SCU registers */ +#define SCU_BASE 0x1e6e2000 +#define SCU_HW_STRAPPING (SCU_BASE + 0x70) + +/* + * AHB Accessors + */ +#ifndef __SKIBOOT__ +#include "io.h" +#else + +/* + * Register accessors, return byteswapped values + * (IE. LE registers) + */ +void ast_ahb_writel(uint32_t val, uint32_t reg); +uint32_t ast_ahb_readl(uint32_t reg); + +/* + * copy to/from accessors. Cannot cross IDSEL boundaries (256M) + */ +int ast_copy_to_ahb(uint32_t reg, const void *src, uint32_t len); +int ast_copy_from_ahb(void *dst, uint32_t reg, uint32_t len); + +void ast_io_init(void); + +#endif /* __SKIBOOT__ */ + +/* + * SPI Flash controllers + */ +#define AST_SF_TYPE_PNOR 0 +#define AST_SF_TYPE_BMC 1 + +struct spi_flash_ctrl; +int ast_sf_open(uint8_t type, struct spi_flash_ctrl **ctrl); +void ast_sf_close(struct spi_flash_ctrl *ctrl); + + +#endif /* __AST_H */ diff --git a/external/pflash/config.h b/external/pflash/config.h new file mode 100644 index 0000000..a132a01 --- /dev/null +++ b/external/pflash/config.h @@ -0,0 +1,19 @@ +/* For CCAN */ + +#include <endian.h> +#include <byteswap.h> + +#define HAVE_TYPEOF 1 +#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1 + + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define HAVE_BIG_ENDIAN 0 +#define HAVE_LITTLE_ENDIAN 1 +#else +#define HAVE_BIG_ENDIAN 1 +#define HAVE_LITTLE_ENDIAN 0 +#endif + +#define HAVE_BYTESWAP_H 1 +#define HAVE_BSWAP_64 1 diff --git a/external/pflash/get_arch.sh b/external/pflash/get_arch.sh new file mode 100755 index 0000000..18a5cef --- /dev/null +++ b/external/pflash/get_arch.sh @@ -0,0 +1,11 @@ +#!/bin/sh +echo "#if defined(__powerpc__) +echo -n ARCH_POWERPC +#elif defined(__x86_64__) || defined(__i386__) +echo -n ARCH_X86 +#elif defined(__arm__) +echo -n ARCH_ARM +#else +echo -n ARCH_UNKNOWN +#endif" | $1cpp | sh + diff --git a/external/pflash/io.h b/external/pflash/io.h new file mode 100644 index 0000000..257cfd2 --- /dev/null +++ b/external/pflash/io.h @@ -0,0 +1,121 @@ +#ifndef __IO_H +#define __IO_H + +#include <assert.h> +#include <stdint.h> +#include <stdbool.h> + +#include <libflash/libflash.h> + +/* AST AHB register base */ +#define AHB_REGS_BASE 0x1E600000 +#define AHB_REGS_SIZE 0x00200000 + +/* AST GPIO control regs */ +#define GPIO_CTRL_BASE 0x1E780000 +#define GPIO_CTRL_SIZE 0x1000 + +/* AST AHB mapping of PNOR */ +#define PNOR_FLASH_BASE 0x30000000 +#define PNOR_FLASH_SIZE 0x04000000 + +/* AST AHB mapping of BMC flash */ +#define BMC_FLASH_BASE 0x20000000 +#define BMC_FLASH_SIZE 0x04000000 + +/* Address of flash mapping on LPC FW space */ +#define LPC_FLASH_BASE 0x0e000000 +#define LPC_CTRL_BASE 0x1e789000 + +extern void open_devs(bool use_lpc, bool bmc_flash); +extern bool set_wrprotect(bool protect); + +#ifdef __powerpc__ + +extern void close_devs(void); + +/* AST access functions */ +extern uint32_t (*ast_ahb_readl)(uint32_t offset); +extern void (*ast_ahb_writel)(uint32_t val, uint32_t offset); +extern int (*ast_copy_to_ahb)(uint32_t reg, const void *src, uint32_t len); +extern int (*ast_copy_from_ahb)(void *dst, uint32_t reg, uint32_t len); + +/* SFC LPC access functions (big endian) */ +extern int lpc_fw_write32(uint32_t val, uint32_t addr); +extern int lpc_fw_read32(uint32_t *val, uint32_t addr); + +extern void check_platform(bool *has_sfc, bool *has_ast); + +#else + +static inline void close_devs(void) { } + +static inline uint8_t readb(void *addr) +{ + asm volatile("" : : : "memory"); + return *(volatile uint8_t *)addr; +} + +static inline uint16_t readw(void *addr) +{ + asm volatile("" : : : "memory"); + return *(volatile uint16_t *)addr; +} + +static inline uint32_t readl(void *addr) +{ + asm volatile("" : : : "memory"); + return *(volatile uint32_t *)addr; +} + +static inline void writeb(uint8_t val, void *addr) +{ + asm volatile("" : : : "memory"); + *(volatile uint8_t *)addr = val; +} + +static inline void writew(uint16_t val, void *addr) +{ + asm volatile("" : : : "memory"); + *(volatile uint16_t *)addr = val; +} + +static inline void writel(uint32_t val, void *addr) +{ + asm volatile("" : : : "memory"); + *(volatile uint32_t *)addr = val; +} + +/* + * AHB register and flash access + */ + +extern void *ahb_reg_map; + +static inline uint32_t ast_ahb_readl(uint32_t offset) +{ + assert(((offset ^ AHB_REGS_BASE) & ~(AHB_REGS_SIZE - 1)) == 0); + + return readl(ahb_reg_map + (offset - AHB_REGS_BASE)); +} + +static inline void ast_ahb_writel(uint32_t val, uint32_t offset) +{ + assert(((offset ^ AHB_REGS_BASE) & ~(AHB_REGS_SIZE - 1)) == 0); + + writel(val, ahb_reg_map + (offset - AHB_REGS_BASE)); +} + +extern int ast_copy_to_ahb(uint32_t reg, const void *src, uint32_t len); +extern int ast_copy_from_ahb(void *dst, uint32_t reg, uint32_t len); + +static inline void check_platform(bool *has_sfc, bool *has_ast) +{ + *has_sfc = false; + *has_ast = true; +} + +#endif + +#endif /* __IO_H */ + diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c new file mode 100644 index 0000000..908a41d --- /dev/null +++ b/external/pflash/pflash.c @@ -0,0 +1,793 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <byteswap.h> +#include <stdint.h> +#include <stdbool.h> +#include <getopt.h> +#include <limits.h> +#include <arpa/inet.h> +#include <assert.h> + +#include <libflash/libflash.h> +#include <libflash/libffs.h> +#include "progress.h" +#include "io.h" +#include "ast.h" +#include "sfc-ctrl.h" + +#define __aligned(x) __attribute__((aligned(x))) + +#define PFLASH_VERSION "0.8.6" + +static bool must_confirm = true; +static bool dummy_run; +static bool need_relock; +static bool bmc_flash; +#ifdef __powerpc__ +static bool using_sfc; +#endif + +#define FILE_BUF_SIZE 0x10000 +static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000); + +static struct spi_flash_ctrl *fl_ctrl; +static struct flash_chip *fl_chip; +static struct ffs_handle *ffsh; +static uint32_t fl_total_size, fl_erase_granule; +static const char *fl_name; +static int32_t ffs_index = -1; + +static void check_confirm(void) +{ + char yes[8], *p; + + if (!must_confirm) + return; + + printf("WARNING ! This will modify your %s flash chip content !\n", + bmc_flash ? "BMC" : "HOST"); + printf("Enter \"yes\" to confirm:"); + memset(yes, 0, sizeof(yes)); + if (!fgets(yes, 7, stdin)) + exit(1); + p = strchr(yes, 10); + if (p) + *p = 0; + p = strchr(yes, 13); + if (p) + *p = 0; + if (strcmp(yes, "yes")) { + printf("Operation cancelled !\n"); + exit(1); + } + must_confirm = false; +} + +static void print_flash_info(void) +{ + uint32_t i; + int rc; + + printf("Flash info:\n"); + printf("-----------\n"); + printf("Name = %s\n", fl_name); + printf("Total size = %dMB \n", fl_total_size >> 20); + printf("Erase granule = %dKB \n", fl_erase_granule >> 10); + + if (bmc_flash) + return; + + if (!ffsh) { + rc = ffs_open_flash(fl_chip, 0, 0, &ffsh); + if (rc) { + fprintf(stderr, "Error %d opening ffs !\n", rc); + ffsh = NULL; + } + } + if (!ffsh) + return; + + printf("\n"); + printf("Partitions:\n"); + printf("-----------\n"); + + for (i = 0;; i++) { + uint32_t start, size, act, end; + char *name; + + rc = ffs_part_info(ffsh, i, &name, &start, &size, &act); + if (rc == FFS_ERR_PART_NOT_FOUND) + break; + if (rc) { + fprintf(stderr, "Error %d scanning partitions\n", rc); + break; + } + end = start + size; + printf("ID=%02d %15s %08x..%08x (actual=%08x)\n", + i, name, start, end, act); + free(name); + } +} + +static void lookup_partition(const char *name) +{ + uint32_t index; + int rc; + + /* Open libffs if needed */ + if (!ffsh) { + rc = ffs_open_flash(fl_chip, 0, 0, &ffsh); + if (rc) { + fprintf(stderr, "Error %d opening ffs !\n", rc); + exit(1); + } + } + + /* Find partition */ + rc = ffs_lookup_part(ffsh, name, &index); + if (rc == FFS_ERR_PART_NOT_FOUND) { + fprintf(stderr, "Partition '%s' not found !\n", name); + exit(1); + } + if (rc) { + fprintf(stderr, "Error %d looking for partition '%s' !\n", + rc, name); + exit(1); + } + ffs_index = index; +} + +static void erase_chip(void) +{ + int rc; + + printf("About to erase chip !\n"); + check_confirm(); + + printf("Erasing... (may take a while !) "); + fflush(stdout); + + if (dummy_run) { + printf("skipped (dummy)\n"); + return; + } + + rc = flash_erase_chip(fl_chip); + if (rc) { + fprintf(stderr, "Error %d erasing chip\n", rc); + exit(1); + } + + printf("done !\n"); +} + +static void erase_range(uint32_t start, uint32_t size, bool will_program) +{ + uint32_t done = 0; + int rc; + + printf("About to erase 0x%08x..0x%08x !\n", start, start + size); + check_confirm(); + + if (dummy_run) { + printf("skipped (dummy)\n"); + return; + } + + printf("Erasing...\n"); + progress_init(size >> 8); + while(size) { + /* If aligned to 64k and at least 64k, use 64k erase */ + if ((start & 0xffff) == 0 && size >= 0x10000) { + rc = flash_erase(fl_chip, start, 0x10000); + if (rc) { + fprintf(stderr, "Error %d erasing 0x%08x\n", + rc, start); + exit(1); + } + start += 0x10000; + size -= 0x10000; + done += 0x10000; + } else { + rc = flash_erase(fl_chip, start, 0x1000); + if (rc) { + fprintf(stderr, "Error %d erasing 0x%08x\n", + rc, start); + exit(1); + } + start += 0x1000; + size -= 0x1000; + done += 0x1000; + } + progress_tick(done >> 8); + } + progress_end(); + + /* If this is a flash partition, mark it empty if we aren't + * going to program over it as well + */ + if (ffsh && ffs_index >= 0 && !will_program) { + printf("Updating actual size in partition header...\n"); + ffs_update_act_size(ffsh, ffs_index, 0); + } +} + +static void program_file(const char *file, uint32_t start, uint32_t size) +{ + int fd, rc; + ssize_t len; + uint32_t actual_size = 0; + + fd = open(file, O_RDONLY); + if (fd == -1) { + perror("Failed to open file"); + exit(1); + } + printf("About to program \"%s\" at 0x%08x..0x%08x !\n", + file, start, size); + check_confirm(); + + if (dummy_run) { + printf("skipped (dummy)\n"); + return; + } + + printf("Programming & Verifying...\n"); + progress_init(size >> 8); + while(size) { + len = read(fd, file_buf, FILE_BUF_SIZE); + if (len < 0) { + perror("Error reading file"); + exit(1); + } + if (len == 0) + break; + if (len > size) + len = size; + size -= len; + actual_size += len; + rc = flash_write(fl_chip, start, file_buf, len, true); + if (rc) { + if (rc == FLASH_ERR_VERIFY_FAILURE) + fprintf(stderr, "Verification failed for" + " chunk at 0x%08x\n", start); + else + fprintf(stderr, "Flash write error %d for" + " chunk at 0x%08x\n", rc, start); + exit(1); + } + start += len; + progress_tick(actual_size >> 8); + } + progress_end(); + close(fd); + + /* If this is a flash partition, adjust its size */ + if (ffsh && ffs_index >= 0) { + printf("Updating actual size in partition header...\n"); + ffs_update_act_size(ffsh, ffs_index, actual_size); + } +} + +static void do_read_file(const char *file, uint32_t start, uint32_t size) +{ + int fd, rc; + ssize_t len; + uint32_t done = 0; + + fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 00666); + if (fd == -1) { + perror("Failed to open file"); + exit(1); + } + printf("Reading to \"%s\" from 0x%08x..0x%08x !\n", + file, start, size); + + progress_init(size >> 8); + while(size) { + len = size > FILE_BUF_SIZE ? FILE_BUF_SIZE : size; + rc = flash_read(fl_chip, start, file_buf, len); + if (rc) { + fprintf(stderr, "Flash read error %d for" + " chunk at 0x%08x\n", rc, start); + exit(1); + } + rc = write(fd, file_buf, len); + if (rc < 0) { + perror("Error writing file"); + exit(1); + } + start += len; + size -= len; + done += len; + progress_tick(done >> 8); + } + progress_end(); + close(fd); +} + +static void enable_4B_addresses(void) +{ + int rc; + + printf("Switching to 4-bytes address mode\n"); + + rc = flash_force_4b_mode(fl_chip, true); + if (rc) { + fprintf(stderr, "Error %d enabling 4b mode\n", rc); + exit(1); + } +} + +static void disable_4B_addresses(void) +{ + int rc; + + printf("Switching to 3-bytes address mode\n"); + + rc = flash_force_4b_mode(fl_chip, false); + if (rc) { + fprintf(stderr, "Error %d disabling 4b mode\n", rc); + exit(1); + } +} + +static void flash_access_cleanup_bmc(void) +{ + if (ffsh) + ffs_close(ffsh); + flash_exit(fl_chip); + ast_sf_close(fl_ctrl); + close_devs(); +} + +static void flash_access_setup_bmc(bool use_lpc, bool need_write) +{ + int rc; + + /* Open and map devices */ + open_devs(use_lpc, true); + + /* Create the AST flash controller */ + rc = ast_sf_open(AST_SF_TYPE_BMC, &fl_ctrl); + if (rc) { + fprintf(stderr, "Failed to open controller\n"); + exit(1); + } + + /* Open flash chip */ + rc = flash_init(fl_ctrl, &fl_chip); + if (rc) { + fprintf(stderr, "Failed to open flash chip\n"); + exit(1); + } + + /* Setup cleanup function */ + atexit(flash_access_cleanup_bmc); +} + +static void flash_access_cleanup_pnor(void) +{ + /* Re-lock flash */ + if (need_relock) + set_wrprotect(true); + + if (ffsh) + ffs_close(ffsh); + flash_exit(fl_chip); +#ifdef __powerpc__ + if (using_sfc) + sfc_close(fl_ctrl); + else + ast_sf_close(fl_ctrl); +#else + ast_sf_close(fl_ctrl); +#endif + close_devs(); +} + +static void flash_access_setup_pnor(bool use_lpc, bool use_sfc, bool need_write) +{ + int rc; + + /* Open and map devices */ + open_devs(use_lpc, false); + +#ifdef __powerpc__ + if (use_sfc) { + /* Create the SFC flash controller */ + rc = sfc_open(&fl_ctrl); + if (rc) { + fprintf(stderr, "Failed to open controller\n"); + exit(1); + } + using_sfc = true; + } else { +#endif + /* Create the AST flash controller */ + rc = ast_sf_open(AST_SF_TYPE_PNOR, &fl_ctrl); + if (rc) { + fprintf(stderr, "Failed to open controller\n"); + exit(1); + } +#ifdef __powerpc__ + } +#endif + + /* Open flash chip */ + rc = flash_init(fl_ctrl, &fl_chip); + if (rc) { + fprintf(stderr, "Failed to open flash chip\n"); + exit(1); + } + + /* Unlock flash (PNOR only) */ + if (need_write) + need_relock = set_wrprotect(false); + + /* Setup cleanup function */ + atexit(flash_access_cleanup_pnor); +} + +static void print_version(void) +{ + printf("Palmetto Flash tool " PFLASH_VERSION "\n"); +} + +static void print_help(const char *pname) +{ + printf("Usage: %s [options] commands...\n\n", pname); + printf(" Options:\n"); + printf("\t-a address, --address=address\n"); + printf("\t\tSpecify the start address for erasing, reading\n"); + printf("\t\tor flashing\n\n"); + printf("\t-s size, --size=size\n"); + printf("\t\tSpecify the size in bytes for erasing, reading\n"); + printf("\t\tor flashing\n\n"); + printf("\t-P part_name, --partition=part_name\n"); + printf("\t\tSpecify the partition whose content is to be erased\n"); + printf("\t\tprogrammed or read. This is an alternative to -a and -s\n"); + printf("\t\tif both -P and -s are specified, the smallest of the\n"); + printf("\t\ttwo will be used\n\n"); + printf("\t-f, --force\n"); + printf("\t\tDon't ask for confirmation before erasing or flashing\n\n"); + printf("\t-d, --dummy\n"); + printf("\t\tDon't write to flash\n\n"); +#ifdef __powerpc__ + printf("\t-l, --lpc\n"); + printf("\t\tUse LPC accesses instead of PCI\n\n"); +#endif + printf("\t-b, --bmc\n"); + printf("\t\tTarget BMC flash instead of host flash\n\n"); + printf(" Commands:\n"); + printf("\t-4, --enable-4B\n"); + printf("\t\tSwitch the flash and controller to 4-bytes address\n"); + printf("\t\tmode (no confirmation needed).\n\n"); + printf("\t-3, --disable-4B\n"); + printf("\t\tSwitch the flash and controller to 3-bytes address\n"); + printf("\t\tmode (no confirmation needed).\n\n"); + printf("\t-r file, --read=file\n"); + printf("\t\tRead flash content from address into file, use -s\n"); + printf("\t\tto specify the size to read (or it will use the source\n"); + printf("\t\tfile size if used in conjunction with -p and -s is not\n"); + printf("\t\tspecified). When using -r together with -e or -p, the\n"); + printf("\t\tread will be peformed first\n\n"); + printf("\t-E, --erase-all\n"); + printf("\t\tErase entire flash chip\n"); + printf("\t\t(Not supported on all chips/controllers)\n\n"); + printf("\t-e, --erase\n"); + printf("\t\tErase the specified region. If size or address are not\n"); + printf("\t\tspecified, but \'--program\' is used, then the file\n"); + printf("\t\tsize will be used (rounded to an erase block) and the\n"); + printf("\t\taddress defaults to 0.\n\n"); + printf("\t-p file, --program=file\n"); + printf("\t\tWill program the file to flash. If the address is not\n"); + printf("\t\tspecified, it will use 0. If the size is not specified\n"); + printf("\t\tit will use the file size. Otherwise it will limit to\n"); + printf("\t\tthe specified size (whatever is smaller). If used in\n"); + printf("\t\tconjunction with any erase command, the erase will\n"); + printf("\t\ttake place first.\n\n"); + printf("\t-t, --tune\n"); + printf("\t\tJust tune the flash controller & access size\n"); + printf("\t\t(Implicit for all other operations)\n\n"); + printf("\t-i, --info\n"); + printf("\t\tDisplay some information about the flash.\n\n"); + printf("\t-h, --help\n"); + printf("\t\tThis message.\n\n"); +} + +int main(int argc, char *argv[]) +{ + const char *pname = argv[0]; + uint32_t address = 0, read_size = 0, write_size = 0; + uint32_t erase_start = 0, erase_size = 0; + bool erase = false; + bool program = false, erase_all = false, info = false, do_read = false; + bool enable_4B = false, disable_4B = false, use_lpc = true; + bool show_help = false, show_version = false; + bool has_sfc = false, has_ast = false; + bool no_action = false, tune = false; + char *write_file = NULL, *read_file = NULL, *part_name = NULL; + int rc; + + while(1) { + static struct option long_opts[] = { + {"address", required_argument, NULL, 'a'}, + {"size", required_argument, NULL, 's'}, + {"partition", required_argument, NULL, 'P'}, + {"lpc", no_argument, NULL, 'l'}, + {"bmc", no_argument, NULL, 'b'}, + {"enable-4B", no_argument, NULL, '4'}, + {"disable-4B", no_argument, NULL, '3'}, + {"read", required_argument, NULL, 'r'}, + {"erase-all", no_argument, NULL, 'E'}, + {"erase", no_argument, NULL, 'e'}, + {"program", required_argument, NULL, 'p'}, + {"force", no_argument, NULL, 'f'}, + {"info", no_argument, NULL, 'i'}, + {"tune", no_argument, NULL, 't'}, + {"dummy", no_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {"debug", no_argument, NULL, 'g'}, + }; + int c, oidx = 0; + + c = getopt_long(argc, argv, "a:s:P:r:43Eep:fdihlvbtg", + long_opts, &oidx); + if (c == EOF) + break; + switch(c) { + case 'a': + address = strtoul(optarg, NULL, 0); + break; + case 's': + read_size = write_size = strtoul(optarg, NULL, 0); + break; + case 'P': + part_name = strdup(optarg); + break; + case '4': + enable_4B = true; + break; + case '3': + disable_4B = true; + break; + case 'r': + do_read = true; + read_file = strdup(optarg); + break; + case 'E': + erase_all = erase = true; + break; + case 'e': + erase = true; + break; + case 'p': + program = true; + write_file = strdup(optarg); + break; + case 'f': + must_confirm = false; + break; + case 'd': + must_confirm = false; + dummy_run = true; + break; + case 'i': + info = true; + break; + case 'l': + use_lpc = true; + break; + case 'b': + bmc_flash = true; + break; + case 't': + tune = true; + break; + case 'v': + show_version = true; + break; + case 'h': + show_help = show_version = true; + break; + case 'g': + libflash_debug = true; + break; + default: + exit(1); + } + } + + /* Check if we need to access the flash at all (which will + * also tune them as a side effect + */ + no_action = !erase && !program && !info && !do_read && + !enable_4B && !disable_4B && !tune; + + /* Nothing to do, if we didn't already, print usage */ + if (no_action && !show_version) + show_help = show_version = true; + + if (show_version) + print_version(); + if (show_help) + print_help(pname); + + if (no_action) + return 0; + + /* --enable-4B and --disable-4B are mutually exclusive */ + if (enable_4B && disable_4B) { + fprintf(stderr, "--enable-4B and --disable-4B are mutually" + " exclusive !\n"); + exit(1); + } + + /* 4B not supported on BMC flash */ + if (enable_4B && bmc_flash) { + fprintf(stderr, "--enable-4B not supported on BMC flash !\n"); + exit(1); + } + + /* partitions not supported on BMC flash */ + if (part_name && bmc_flash) { + fprintf(stderr, "--partition not supported on BMC flash !\n"); + exit(1); + } + + /* part-name and erase-all make no sense together */ + if (part_name && erase_all) { + fprintf(stderr, "--partition and --erase-all are mutually" + " exclusive !\n"); + exit(1); + } + + /* Read command should always come with a file */ + if (do_read && !read_file) { + fprintf(stderr, "Read with no file specified !\n"); + exit(1); + } + + /* Program command should always come with a file */ + if (program && !write_file) { + fprintf(stderr, "Program with no file specified !\n"); + exit(1); + } + + /* If both partition and address specified, error out */ + if (address && part_name) { + fprintf(stderr, "Specify partition or address, not both !\n"); + exit(1); + } + + /* If file specified but not size, get size from file + */ + if (write_file && !write_size) { + struct stat stbuf; + + if (stat(write_file, &stbuf)) { + perror("Failed to get file size"); + exit(1); + } + write_size = stbuf.st_size; + } + + /* Check platform */ + check_platform(&has_sfc, &has_ast); + + /* Prepare for access */ + if (bmc_flash) { + if (!has_ast) { + fprintf(stderr, "No BMC on this platform\n"); + exit(1); + } + flash_access_setup_bmc(use_lpc, erase || program); + } else { + if (!has_ast && !has_sfc) { + fprintf(stderr, "No BMC nor SFC on this platform\n"); + exit(1); + } + flash_access_setup_pnor(use_lpc, has_sfc, erase || program); + } + + rc = flash_get_info(fl_chip, &fl_name, + &fl_total_size, &fl_erase_granule); + if (rc) { + fprintf(stderr, "Error %d getting flash info\n", rc); + exit(1); + } + + /* If -t is passed, then print a nice message */ + if (tune) + printf("Flash and controller tuned\n"); + + /* If read specified and no read_size, use flash size */ + if (do_read && !read_size && !part_name) + read_size = fl_total_size; + + /* We have a partition specified, grab the details */ + if (part_name) + lookup_partition(part_name); + + /* We have a partition, adjust read/write size if needed */ + if (ffsh && ffs_index >= 0) { + uint32_t pstart, pmaxsz, pactsize; + int rc; + + rc = ffs_part_info(ffsh, ffs_index, NULL, + &pstart, &pmaxsz, &pactsize); + if (rc) { + fprintf(stderr,"Failed to get partition info\n"); + exit(1); + } + + /* Read size is obtained from partition "actual" size */ + if (!read_size) + read_size = pactsize; + + /* Write size is max size of partition */ + if (!write_size) + write_size = pmaxsz; + + /* Crop write size to partition size */ + if (write_size > pmaxsz) { + printf("WARNING: Size (%d bytes) larger than partition" + " (%d bytes), cropping to fit\n", + write_size, pmaxsz); + write_size = pmaxsz; + } + + /* If erasing, check partition alignment */ + if (erase && ((pstart | pmaxsz) & 0xfff)) { + fprintf(stderr,"Partition not aligned properly\n"); + exit(1); + } + + /* Set address */ + address = pstart; + } + + /* Align erase boundaries */ + if (erase && !erase_all) { + uint32_t mask = 0xfff; + uint32_t erase_end; + + /* Dummy size for erase, will be adjusted later */ + if (!write_size) + write_size = 1; + erase_start = address & ~mask; + erase_end = ((address + write_size) + mask) & ~mask; + erase_size = erase_end - erase_start; + + if (erase_start != address || erase_size != write_size) + fprintf(stderr, "WARNING: Erase region adjusted" + " to 0x%08x..0x%08x\n", + erase_start, erase_end); + } + + /* Process commands */ + if (enable_4B) + enable_4B_addresses(); + if (disable_4B) + disable_4B_addresses(); + if (info) + print_flash_info(); + if (do_read) + do_read_file(read_file, address, read_size); + if (erase_all) + erase_chip(); + else if (erase) + erase_range(erase_start, erase_size, program); + if (program) + program_file(write_file, address, write_size); + + return 0; +} diff --git a/external/pflash/powerpc_io.c b/external/pflash/powerpc_io.c new file mode 100644 index 0000000..7678161 --- /dev/null +++ b/external/pflash/powerpc_io.c @@ -0,0 +1,341 @@ +#define _GNU_SOURCE /* for strcasestr */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <byteswap.h> +#include <stdint.h> +#include <stdbool.h> +#include <getopt.h> +#include <limits.h> +#include <arpa/inet.h> +#include <assert.h> + +#include "io.h" + +/* Big endian warning/note: + * + * The register accessors return byteswapped data for registers + */ +uint32_t (*ast_ahb_readl)(uint32_t offset); +void (*ast_ahb_writel)(uint32_t val, uint32_t offset); +int (*ast_copy_to_ahb)(uint32_t reg, const void *src, uint32_t len); +int (*ast_copy_from_ahb)(void *dst, uint32_t reg, uint32_t len); + +static enum ppc_platform { + plat_unknown, + plat_rhesus, + plat_ast_bmc, +} ppc_platform; + +static int lpc_io_fd = -1, lpc_fw_fd = -1; +static uint32_t lpc_old_flash_reg; +static uint32_t ahb_flash_base, ahb_flash_size, lpc_flash_offset; + +static void lpc_outb(uint8_t val, uint16_t port) +{ + int rc; + + lseek(lpc_io_fd, port, SEEK_SET); + rc = write(lpc_io_fd, &val, 1); + if (rc != 1) { + perror("Can't write to LPC IO"); + exit(1); + } +} + +static uint8_t lpc_inb(uint16_t port) +{ + uint8_t val; + int rc; + + lseek(lpc_io_fd, port, SEEK_SET); + rc = read(lpc_io_fd, &val, 1); + if (rc != 1) { + perror("Can't read from LPC IO"); + exit(1); + } + return val; +} + +int lpc_fw_write32(uint32_t val, uint32_t addr) +{ + int rc; + + /* The value passed in is in big endian always */ + lseek(lpc_fw_fd, addr, SEEK_SET); + rc = write(lpc_fw_fd, &val, 4); + if (rc != 4) { + perror("Can't write to LPC FW"); + exit(1); + } + return 0; +} + +int lpc_fw_read32(uint32_t *val, uint32_t addr) +{ + int rc; + + lseek(lpc_fw_fd, addr, SEEK_SET); + rc = read(lpc_fw_fd, val, 4); + if (rc != 4) { + perror("Can't read from LPC FW"); + exit(1); + } + return 0; +} + +static void lpc_sio_outb(uint8_t val, uint8_t reg) +{ + lpc_outb(reg, 0x2e); + lpc_outb(val, 0x2f); +} + +static uint8_t lpc_sio_inb(uint8_t reg) +{ + lpc_outb(reg, 0x2e); + return lpc_inb(0x2f); +} + +static void lpc_ahb_prep(uint32_t reg, uint8_t type) +{ + /* Address */ + lpc_sio_outb((reg >> 24) & 0xff, 0xf0); + lpc_sio_outb((reg >> 16) & 0xff, 0xf1); + lpc_sio_outb((reg >> 8) & 0xff, 0xf2); + lpc_sio_outb((reg ) & 0xff, 0xf3); + + /* 4 bytes cycle */ + lpc_sio_outb(type, 0xf8); +} + +static void lpc_ahb_writel(uint32_t val, uint32_t reg) +{ + lpc_ahb_prep(reg, 2); + + /* Write data */ + lpc_sio_outb(val >> 24, 0xf4); + lpc_sio_outb(val >> 16, 0xf5); + lpc_sio_outb(val >> 8, 0xf6); + lpc_sio_outb(val , 0xf7); + + /* Trigger */ + lpc_sio_outb(0xcf, 0xfe); +} + +static uint32_t lpc_ahb_readl(uint32_t reg) +{ + uint32_t val = 0; + + lpc_ahb_prep(reg, 2); + + /* Trigger */ + lpc_sio_inb(0xfe); + + /* Read results */ + val = (val << 8) | lpc_sio_inb(0xf4); + val = (val << 8) | lpc_sio_inb(0xf5); + val = (val << 8) | lpc_sio_inb(0xf6); + val = (val << 8) | lpc_sio_inb(0xf7); + + return val; +} + +static void lpc_ahb_init(bool bmc_flash) +{ + uint32_t b; + + /* Send SuperIO password */ + lpc_outb(0xa5, 0x2e); + lpc_outb(0xa5, 0x2e); + + /* Select logical dev d */ + lpc_sio_outb(0x0d, 0x07); + + /* Enable iLPC->AHB */ + lpc_sio_outb(0x01, 0x30); + + /* Save flash base */ + lpc_old_flash_reg = b = lpc_ahb_readl(LPC_CTRL_BASE + 0x88); + /* Upate flash base */ + if (bmc_flash) { + ahb_flash_base = BMC_FLASH_BASE; + ahb_flash_size = BMC_FLASH_SIZE; + } else { + ahb_flash_base = PNOR_FLASH_BASE; + ahb_flash_size = PNOR_FLASH_SIZE; + } + lpc_flash_offset = 0x0e000000; + b = (b & 0x0000ffff) | ahb_flash_base; + lpc_ahb_writel(b, LPC_CTRL_BASE + 0x88); + b = lpc_ahb_readl(LPC_CTRL_BASE + 0x88); +} + +static int lpc_ast_copy_from_ahb(void *dst, uint32_t reg, uint32_t len) +{ + int rc; + + if (reg < ahb_flash_base || + (reg + len) > (ahb_flash_base + ahb_flash_size)) + return -1; + reg = (reg - ahb_flash_base) + lpc_flash_offset; + + lseek(lpc_fw_fd, reg, SEEK_SET); + rc = read(lpc_fw_fd, dst, len); + if (rc != len) { + perror("Can't read bulk from LPC FW"); + exit(1); + } + return 0; +} + +static int lpc_ast_copy_to_ahb(uint32_t reg, const void *src, uint32_t len) +{ + int rc; + + if (reg < ahb_flash_base || + (reg + len) > (ahb_flash_base + ahb_flash_size)) + return -1; + reg = (reg - ahb_flash_base) + lpc_flash_offset; + + lseek(lpc_fw_fd, reg, SEEK_SET); + rc = write(lpc_fw_fd, src, len); + if (rc != len) { + perror("Can't write bulk from LPC FW"); + exit(1); + } + return 0; +} + +/* + * Write protect: TODO use custom IPMI to control lock from BMC + */ +static uint32_t lpc_gpio_ctl_readl(uint32_t offset) +{ + return lpc_ahb_readl(GPIO_CTRL_BASE + offset); +} + +static void lpc_gpio_ctl_writel(uint32_t val, uint32_t offset) +{ + lpc_ahb_writel(val, GPIO_CTRL_BASE + offset); +} + +bool set_wrprotect(bool protect) +{ + uint32_t reg; + bool was_protected; + + if (ppc_platform != plat_ast_bmc) + return false; + + reg = lpc_gpio_ctl_readl(0x20); + was_protected = !!(reg & 0x00004000); + if (protect) + reg |= 0x00004000; /* GPIOF[6] value */ + else + reg &= ~0x00004000; /* GPIOF[6] value */ + lpc_gpio_ctl_writel(reg, 0x20); + reg = lpc_gpio_ctl_readl(0x24); + reg |= 0x00004000; /* GPIOF[6] direction */ + lpc_gpio_ctl_writel(reg, 0x24); + + return was_protected; +} + +static void open_lpc(bool bmc_flash) +{ + lpc_fw_fd = open("/sys/kernel/debug/powerpc/lpc/fw", O_RDWR); + if (lpc_fw_fd < 0) { + perror("can't open LPC MEM"); + exit(1); + } + + if (ppc_platform != plat_ast_bmc) + return; + + lpc_io_fd = open("/sys/kernel/debug/powerpc/lpc/io", O_RDWR); + if (lpc_io_fd < 0) { + perror("can't open LPC IO"); + exit(1); + } + + ast_ahb_readl = lpc_ahb_readl; + ast_ahb_writel = lpc_ahb_writel; + ast_copy_to_ahb = lpc_ast_copy_to_ahb; + ast_copy_from_ahb = lpc_ast_copy_from_ahb; + + lpc_ahb_init(bmc_flash); +} + +void close_devs(void) +{ + if (lpc_io_fd < 0 || lpc_fw_fd < 0) + return; + + if (ppc_platform != plat_ast_bmc) + return; + + /* Restore flash base */ + lpc_ahb_writel(lpc_old_flash_reg, LPC_CTRL_BASE + 0x88); +} + +static void open_pci(bool bmc_flash) +{ + /* XXX */ + fprintf(stderr, "WARNING: PCI access method not implemented !\n"); + fprintf(stderr, " Use -l or --lpc\n"); + exit(1); +} + +static void identify_platform(void) +{ + FILE *cpuinfo; + char *lptr = NULL; + size_t lsize = 0; + bool found = false; + + ppc_platform = plat_unknown; + + cpuinfo = fopen("/proc/cpuinfo", "r"); + if (!cpuinfo) { + perror("Can't open /proc/cpuinfo"); + exit(1); + } + while(!found && getline(&lptr, &lsize, cpuinfo) >= 0) { + if (!strncmp(lptr, "model", 5)) { + if (strcasestr(lptr, "rhesus")) + ppc_platform = plat_rhesus; + else if (strcasestr(lptr, "palmetto")) + ppc_platform = plat_ast_bmc; + found = true; + } + free(lptr); + lptr = NULL; + lsize = 0; + } +} + +void open_devs(bool use_lpc, bool bmc_flash) +{ + if (ppc_platform == plat_unknown) { + fprintf(stderr, "Unsupported platform !\n"); + exit(1); + } + + if (use_lpc) + open_lpc(bmc_flash); + else + open_pci(bmc_flash); +} + +void check_platform(bool *has_sfc, bool *has_ast) +{ + identify_platform(); + + *has_sfc = ppc_platform == plat_rhesus; + *has_ast = ppc_platform == plat_ast_bmc; +} diff --git a/external/pflash/progress.c b/external/pflash/progress.c new file mode 100644 index 0000000..1f98502 --- /dev/null +++ b/external/pflash/progress.c @@ -0,0 +1,79 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <time.h> + +static unsigned long progress_max; +static unsigned int progress_pcent; +static unsigned long progress_n_upd; +static unsigned int progress_prevsec; +static struct timespec progress_start; + +#define PROGRESS_CHARS 50 + +void progress_init(unsigned long count) +{ + unsigned int i; + + progress_max = count; + progress_pcent = 0; + progress_n_upd = ULONG_MAX; + progress_prevsec = UINT_MAX; + + printf("\r["); + for (i = 0; i < PROGRESS_CHARS; i++) + printf(" "); + printf("] 0%%"); + fflush(stdout); + clock_gettime(CLOCK_MONOTONIC, &progress_start);} + +void progress_tick(unsigned long cur) +{ + unsigned int pcent, i, pos, sec; + struct timespec now; + + pcent = (cur * 100) / progress_max; + if (progress_pcent == pcent && cur < progress_n_upd && + cur < progress_max) + return; + progress_pcent = pcent; + pos = (pcent * PROGRESS_CHARS) / 101; + clock_gettime(CLOCK_MONOTONIC, &now); + + printf("\r["); + for (i = 0; i <= pos; i++) + printf("="); + for (; i < PROGRESS_CHARS; i++) + printf(" "); + printf("] %d%%", pcent); + + sec = now.tv_sec - progress_start.tv_sec; + if (sec >= 5 && pcent > 0) { + unsigned int persec = cur / sec; + unsigned int rem_sec; + + if (!persec) + persec = 1; + progress_n_upd = cur + persec; + rem_sec = ((sec * 100) + (pcent / 2)) / pcent - sec; + if (rem_sec > progress_prevsec) + rem_sec = progress_prevsec; + progress_prevsec = rem_sec; + if (rem_sec < 60) + printf(" ETA:%ds ", rem_sec); + else { + printf(" ETA:%d:%02d:%02d ", + rem_sec / 3600, + (rem_sec / 60) % 60, + rem_sec % 60); + } + } + + fflush(stdout); +} + +void progress_end(void) +{ + printf("\n"); +} diff --git a/external/pflash/progress.h b/external/pflash/progress.h new file mode 100644 index 0000000..673b495 --- /dev/null +++ b/external/pflash/progress.h @@ -0,0 +1,8 @@ +#ifndef __PROGRESS_H +#define __PROGRESS_H + +void progress_init(unsigned long count); +void progress_tick(unsigned long cur); +void progress_end(void); + +#endif /* __PROGRESS_H */ diff --git a/external/pflash/sfc-ctrl.h b/external/pflash/sfc-ctrl.h new file mode 100644 index 0000000..6c30759 --- /dev/null +++ b/external/pflash/sfc-ctrl.h @@ -0,0 +1,9 @@ +#ifndef SFC_CTRL_H +#define SFC_CTRL_H + +struct spi_flash_ctrl; + +extern int sfc_open(struct spi_flash_ctrl **ctrl); +extern void sfc_close(struct spi_flash_ctrl *ctrl); + +#endif /* SFC_CTRL_H */ diff --git a/libflash/libflash.h b/libflash/libflash.h index e8d357b..31d3562 100644 --- a/libflash/libflash.h +++ b/libflash/libflash.h @@ -19,16 +19,15 @@ #include <stdint.h> #include <stdbool.h> -#ifndef FL_INF +#ifdef __SKIBOOT__ +#include <skiboot.h> +#define FL_INF(fmt...) do { prlog(PR_INFO, fmt); } while(0) +#define FL_DBG(fmt...) do { prlog(PR_DEBUG, fmt); } while(0) +#define FL_ERR(fmt...) do { prlog(PR_ERR, fmt); } while(0) +#else +extern bool libflash_debug; +#define FL_DBG(fmt...) do { if (libflash_debug) printf(fmt); } while(0) #define FL_INF(fmt...) do { printf(fmt); } while(0) -#endif - -#ifndef FL_DBG -//#define FL_DBG(fmt...) do { printf(fmt); } while(0) -#define FL_DBG(fmt...) do { } while(0) -#endif - -#ifndef FL_ERR #define FL_ERR(fmt...) do { printf(fmt); } while(0) #endif |