diff options
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-mtd-Add-RPC-HyperFlash-support.patch')
-rw-r--r-- | meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-mtd-Add-RPC-HyperFlash-support.patch | 727 |
1 files changed, 727 insertions, 0 deletions
diff --git a/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-mtd-Add-RPC-HyperFlash-support.patch b/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-mtd-Add-RPC-HyperFlash-support.patch new file mode 100644 index 0000000..8d34bce --- /dev/null +++ b/meta-rcar-gen3-adas/recipes-bsp/u-boot/u-boot/0022-mtd-Add-RPC-HyperFlash-support.patch @@ -0,0 +1,727 @@ +From 00ea5714ecc7ca61919cb3942d0edf20e8190160 Mon Sep 17 00:00:00 2001 +From: Valentine Barshak <valentine.barshak@cogentembedded.com> +Date: Mon, 4 Apr 2016 18:40:39 +0300 +Subject: [PATCH] mtd: Add RPC HyperFlash support + +This adds RCAR Gen3 RPC HyperFlash driver. + +Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com> +--- + drivers/mtd/Makefile | 1 + + drivers/mtd/rpc_hyperflash.c | 695 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 696 insertions(+) + create mode 100644 drivers/mtd/rpc_hyperflash.c + +diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile +index 5467a95..8e794a2 100644 +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -18,3 +18,4 @@ obj-$(CONFIG_FTSMC020) += ftsmc020.o + obj-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o + obj-$(CONFIG_MW_EEPROM) += mw_eeprom.o + obj-$(CONFIG_ST_SMI) += st_smi.o ++obj-$(CONFIG_RPC_HYPERFLASH) += rpc_hyperflash.o +diff --git a/drivers/mtd/rpc_hyperflash.c b/drivers/mtd/rpc_hyperflash.c +new file mode 100644 +index 0000000..fc67ecd +--- /dev/null ++++ b/drivers/mtd/rpc_hyperflash.c +@@ -0,0 +1,695 @@ ++/* ++ * Copyright (C) 2016 Renesas Electronics Corporation ++ * Copyright (C) 2016 Cogent Embedded, Inc. ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#include <asm/arch/rpc-flash.h> ++ ++#define RPC_HF_CMD_CA47 (0x1 << 7) /* Read */ ++#define RPC_HF_CMD_CA46 (0x1 << 6) /* Register space */ ++#define RPC_HF_CMD_CA45 (0x1 << 5) /* Liner burst */ ++ ++#define RPC_HF_CMD_READ_REG (RPC_HF_CMD_CA47 | RPC_HF_CMD_CA46) ++#define RPC_HF_CMD_READ_MEM RPC_HF_CMD_CA47 ++#define RPC_HF_CMD_WRITE_REG RPC_HF_CMD_CA46 ++#define RPC_HF_CMD_WRITE_MEM 0x0 ++ ++#define RPC_HF_ERASE_SIZE 0x40000 ++ ++#define RPC_CFI_STATUS_DRB (0x1 << 7) ++#define RPC_CFI_STATUS_ESSB (0x1 << 6) ++#define RPC_CFI_STATUS_ESB (0x1 << 5) ++#define RPC_CFI_STATUS_PSB (0x1 << 4) ++#define RPC_CFI_STATUS_WBASB (0x1 << 3) ++#define RPC_CFI_STATUS_PSSB (0x1 << 2) ++#define RPC_CFI_STATUS_SLSB (0x1 << 1) ++#define RPC_CFI_STATUS_ESTAT (0x1 << 0) ++ ++#define RPC_CFI_UNLOCK1 (0x555 << 1) ++#define RPC_CFI_UNLOCK2 (0x2AA << 1) ++ ++#define RPC_CFI_CMD_UNLOCK_START 0xAA ++#define RPC_CFI_CMD_UNLOCK_ACK 0x55 ++#define RPC_CFI_CMD_RESET 0xF0 ++#define RPC_CFI_CMD_READ_STATUS 0x70 ++#define RPC_CFI_CMD_READ_ID 0x90 ++#define RPC_CFI_CMD_WRITE 0xA0 ++#define RPC_CFI_CMD_ERASE_START 0x80 ++#define RPC_CFI_CMD_ERASE_SECTOR 0x30 ++ ++#define RPC_CFI_ID_MASK 0x000F ++#define RPC_CFI_ID_MAN_SPANSION 0x0001 ++#define RPC_CFI_ID_TYPE_HYPERFLASH 0x000E ++ ++enum rpc_hf_size { ++ RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8), ++ RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC), ++ RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF), ++}; ++ ++static inline u32 rpc_hf_flash_map(flash_info_t *info, int sector) ++{ ++ return info->start[sector] - CONFIG_SYS_RPC_FLASH_BASE; ++} ++ ++static inline int rpc_hf_flash_sector(flash_info_t *info, u32 addr) ++{ ++ return (addr - info->start[0]) / RPC_HF_ERASE_SIZE; ++} ++ ++static inline int rpc_hf_flash_sector_size(flash_info_t *info, int sector) ++{ ++ return RPC_HF_ERASE_SIZE; ++} ++ ++static void rpc_hf_mode_man(flash_info_t *info) ++{ ++ rpc_wait_tend(info); ++ ++ /* ++ * RPC_PHYCNT = 0x80000263 ++ * bit31 CAL = 1 : PHY calibration ++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash ++ */ ++ rpc_setl(info, RPC_PHYCNT, ++ ~(RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)), ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); ++ ++ /* ++ * RPC_CMNCR = 0x81FFF301 ++ * bit31 MD = 1 : Manual mode ++ * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash ++ */ ++ rpc_setl(info, RPC_CMNCR, ++ ~(RPC_CMNCR_MD | RPC_CMNCR_BSZ(3)), ++ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | ++ RPC_CMNCR_MD | RPC_CMNCR_BSZ(1)); ++} ++ ++static void rpc_hf_mode_ext(flash_info_t *info) ++{ ++ rpc_wait_tend(info); ++ ++ /* ++ * RPC_PHYCNT = 0x80000263 ++ * bit31 CAL = 1 : PHY calibration ++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash ++ */ ++ rpc_setl(info, RPC_PHYCNT, ++ ~(RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)), ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); ++ ++ /* ++ * RPC_CMNCR = 0x81FFF301 ++ * bit31 MD = 1 : Manual mode ++ * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash ++ */ ++ rpc_setl(info, RPC_CMNCR, ++ ~(RPC_CMNCR_MD | RPC_CMNCR_BSZ(3)), ++ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ | ++ RPC_CMNCR_BSZ(1)); ++ ++ /* ++ * RPC_DRCR = 0x001F0100 ++ * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units ++ * bit9 RCF = 1 : Clear cache ++ * bit8 RBE = 1 : Read burst enable ++ */ ++ rpc_writel(info, RPC_DRCR, ++ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE); ++ ++ rpc_writel(info, RPC_DRCMR, RPC_DRCMR_CMD(0xA0)); ++ rpc_writel(info, RPC_DRENR, ++ RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) | ++ RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) | ++ RPC_DRENR_CDE | RPC_DRENR_OCDE | RPC_DRENR_ADE(4)); ++ rpc_writel(info, RPC_DRDMCR, RPC_DRDMCR_DMCYC(0xE)); ++ rpc_writel(info, RPC_DRDRENR, ++ RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE); ++ ++ /* Dummy read */ ++ rpc_readl(info, RPC_DRCR); ++} ++ ++static void rpc_hf_xfer(flash_info_t *info, u32 addr, u16 *data, ++ enum rpc_hf_size size, u8 cmd) ++{ ++ u32 val; ++ ++ rpc_hf_mode_man(info); ++ ++ /* ++ * bit23-21 CMD[7:5] : CA47-45 ++ * CA47 = 0/1 : Write/Read ++ * CA46 = 0/1 : Memory Space/Register Space ++ * CA45 = 0/1 : Wrapped Burst/Linear Burst ++ */ ++ rpc_writel(info, RPC_SMCMR, RPC_SMCMR_CMD(cmd)); ++ ++ rpc_writel(info, RPC_SMADR, addr >> 1); ++ ++ rpc_writel(info, RPC_SMOPR, 0x0); ++ ++ /* ++ * RPC_SMDRENR = 0x00005101 ++ * bit14-12 HYPE = 101: Hyperflash mode ++ * bit8 ADDRE = 1 : Address DDR transfer ++ * bit0 SPIDRE = 1 : DATA DDR transfer ++ */ ++ rpc_writel(info, RPC_SMDRENR, ++ RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE); ++ ++ val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | ++ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | ++ RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size; ++ ++ if (cmd & RPC_HF_CMD_CA47) ++ goto read_transfer; ++ ++ /* ++ * RPC_SMENR = 0xA222540x ++ * bit31-30 CDB[1:0] = 10 : 4bit width command ++ * bit25-24 ADB[1:0] = 10 : 4bit width address ++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data ++ * bit15 DME = 0 : dummy cycle disable ++ * bit14 CDE = 1 : Command enable ++ * bit12 OCDE = 1 : Option Command enable ++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output ++ * bit7-4 OPDE[3:0] = 0000 : Option data disable ++ * bit3-0 SPIDE[3:0] = xxxx : Transfer size ++ */ ++ rpc_writel(info, RPC_SMENR, val); ++ ++ switch (size) { ++ case RPC_HF_SIZE_64BIT: ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 : ++ data[0] | data[1] << 16; ++ rpc_writel(info, RPC_SMWDR1, val); ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[2]) | cpu_to_be16(data[3]) << 16 : ++ data[2] | data[3] << 16; ++ break; ++ case RPC_HF_SIZE_32BIT: ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 : ++ data[0] | data[1] << 16; ++ break; ++ default: ++ val = cmd & RPC_HF_CMD_CA46 ? ++ cpu_to_be16(data[0]) << 16 : ++ data[0] << 16; ++ break; ++ } ++ ++ rpc_writel(info, RPC_SMWDR0, val); ++ /* ++ * RPC_SMCR = 0x00000003 ++ * bit1 SPIWE = 1 : Data write enable ++ * bit0 SPIE = 1 : SPI transfer start ++ */ ++ rpc_writel(info, RPC_SMCR, RPC_SMCR_SPIWE | RPC_SMCR_SPIE); ++ return; ++ ++read_transfer: ++ rpc_writel(info, RPC_SMDMCR, RPC_SMDMCR_DMCYC(0xE)); ++ val |= RPC_SMENR_DME; ++ ++ /* ++ * RPC_SMENR = 0xA222D40x ++ * bit31-30 CDB[1:0] = 10 : 4bit width command ++ * bit25-24 ADB[1:0] = 10 : 4bit width address ++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data ++ * bit15 DME = 1 : dummy cycle disable ++ * bit14 CDE = 1 : Command enable ++ * bit12 OCDE = 1 : Option Command enable ++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address) ++ * bit7-4 OPDE[3:0] = 0000 : Option data disable ++ * bit3-0 SPIDE[3:0] = xxxx : Transfer size ++ */ ++ rpc_writel(info, RPC_SMENR, val); ++ ++ /* ++ * RPC_SMCR = 0x00000005 ++ * bit2 SPIRE = 1 : Data read disable ++ * bit0 SPIE = 1 : SPI transfer start ++ */ ++ rpc_writel(info, RPC_SMCR, RPC_SMCR_SPIRE | RPC_SMCR_SPIE); ++ ++ rpc_wait_tend(info); ++ val = rpc_readl(info, RPC_SMRDR0); ++ ++ /* ++ * Read data from either register or memory space. ++ * Register space is always big-endian. ++ */ ++ switch (size) { ++ case RPC_HF_SIZE_64BIT: ++ if (cmd & RPC_HF_CMD_CA46) { ++ data[3] = be16_to_cpu((val >> 16) & 0xFFFF); ++ data[2] = be16_to_cpu(val & 0xFFFF); ++ } else { ++ data[3] = (val >> 16) & 0xFFFF; ++ data[2] = val & 0xFFFF; ++ } ++ val = rpc_readl(info, RPC_SMRDR1); ++ if (cmd & RPC_HF_CMD_CA46) { ++ data[1] = be16_to_cpu((val >> 16) & 0xFFFF); ++ data[0] = be16_to_cpu(val & 0xFFFF); ++ } else { ++ data[1] = (val >> 16) & 0xFFFF; ++ data[0] = val & 0xFFFF; ++ } ++ break; ++ case RPC_HF_SIZE_32BIT: ++ if (cmd & RPC_HF_CMD_CA46) { ++ data[1] = be16_to_cpu((val >> 16) & 0xFFFF); ++ data[0] = be16_to_cpu(val & 0xFFFF); ++ } else { ++ data[1] = (val >> 16) & 0xFFFF; ++ data[0] = val & 0xFFFF; ++ } ++ break; ++ default: ++ data[0] = cmd & RPC_HF_CMD_CA46 ? ++ be16_to_cpu((val >> 16) & 0xFFFF) : ++ (val >> 16) & 0xFFFF; ++ break; ++ } ++} ++ ++static void rpc_hf_wbuf_enable(flash_info_t *info, u32 addr) ++{ ++ rpc_wait_tend(info); ++ ++ /* ++ * RPC_PHYCNT = 0x80000277 ++ * bit31 CAL = 1 : PHY calibration ++ * bit4 WBUF2 = 1 : Write buffer enable 2 ++ * bit2 WBUF = 1 : Write buffer enable ++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash ++ */ ++ rpc_setl(info, RPC_PHYCNT, ++ ~(RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)), ++ RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); ++ ++ /* ++ * RPC_DRCR = 0x001F0100 ++ * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units ++ * bit9 RCF = 1 : Clear cache ++ * bit8 RBE = 1 : Read burst enable ++ */ ++ rpc_writel(info, RPC_DRCR, ++ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE); ++ ++ rpc_writel(info, RPC_SMCMR, RPC_SMCMR_CMD(RPC_HF_CMD_WRITE_MEM)); ++ ++ rpc_writel(info, RPC_SMADR, addr >> 1); ++ ++ rpc_writel(info, RPC_SMOPR, 0x0); ++ ++ /* ++ * RPC_SMDRENR = 0x00005101 ++ * bit14-12 HYPE = 101:Hyperflash mode ++ * bit8 ADDRE = 1 : Address DDR transfer ++ * bit0 SPIDRE = 1 : DATA DDR transfer ++ */ ++ rpc_writel(info, RPC_SMDRENR, ++ RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE); ++ ++ /* ++ * RPC_SMENR = 0xA222540F ++ * bit31-30 CDB[1:0] = 10 : 4bit width command ++ * bit25-24 ADB[1:0] = 10 : 4bit width address ++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data ++ * bit15 DME = 0 : dummy cycle disable ++ * bit14 CDE = 1 : Command enable ++ * bit12 OCDE = 1 : Option Command enable ++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address) ++ * bit7-4 OPDE[3:0] = 0000 : Option data disable ++ * bit3-0 SPIDE[3:0] = 1111 : 64-bit transfer size ++ */ ++ rpc_writel(info, RPC_SMENR, ++ RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) | ++ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) | ++ RPC_SMENR_CDE | RPC_SMENR_OCDE | ++ RPC_SMENR_ADE(4) | RPC_HF_SIZE_64BIT); ++ ++ /* Dummy read */ ++ rpc_readl(info, RPC_DRCR); ++} ++ ++static inline void rpc_hf_write_cmd(flash_info_t *info, u32 addr, u16 cmd) ++{ ++ rpc_hf_xfer(info, addr, &cmd, RPC_HF_SIZE_16BIT, RPC_HF_CMD_WRITE_REG); ++} ++ ++static inline void rpc_hf_read_reg(flash_info_t *info, u32 addr, u16 *data, ++ enum rpc_hf_size size) ++{ ++ rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_READ_REG); ++} ++ ++static inline void rpc_hf_write_reg(flash_info_t *info, u32 addr, u16 *data, ++ enum rpc_hf_size size) ++{ ++ rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_WRITE_REG); ++} ++ ++static inline void rpc_hf_read_mem(flash_info_t *info, u32 addr, u16 *data, ++ enum rpc_hf_size size) ++{ ++ rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_READ_MEM); ++} ++ ++static inline void rpc_hf_write_mem(flash_info_t *info, u32 addr, u16 *data, ++ enum rpc_hf_size size) ++{ ++ rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_WRITE_MEM); ++} ++ ++static void rpc_hf_wp(flash_info_t *info, int enable) ++{ ++ rpc_setl(info, RPC_PHYINT, ~RPC_PHYINT_WP, enable ? RPC_PHYINT_WP : 0); ++} ++ ++static void rpc_hf_unlock(flash_info_t *info, u32 addr) ++{ ++ rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, ++ RPC_CFI_CMD_UNLOCK_START); ++ rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK2, ++ RPC_CFI_CMD_UNLOCK_ACK); ++} ++ ++static inline int rpc_hf_status(flash_info_t *info, u32 addr, ++ int iterations, int delay) ++{ ++ int retval; ++ u16 status = 0; ++ ++ while (iterations-- > 0) { ++ rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, ++ RPC_CFI_CMD_READ_STATUS); ++ rpc_hf_read_reg(info, addr, &status, RPC_HF_SIZE_16BIT); ++ ++ if (status & RPC_CFI_STATUS_DRB) ++ break; ++ ++ if (delay) ++ udelay(delay); ++ } ++ ++ if (!(status & RPC_CFI_STATUS_DRB)) { ++ retval = ERR_TIMOUT; ++ goto out; ++ } ++ ++ if (status & RPC_CFI_STATUS_PSB) { ++ retval = ERR_PROG_ERROR; ++ goto out; ++ } ++ ++ if (status & RPC_CFI_STATUS_ESB) { ++ retval = ERR_NOT_ERASED; ++ goto out; ++ } ++ ++ return ERR_OK; ++ ++out: ++ rpc_hf_write_cmd(info, 0, RPC_CFI_CMD_RESET); ++ return retval; ++} ++ ++static int rpc_hf_sector_erase(flash_info_t *info, int sector) ++{ ++ u32 addr = rpc_hf_flash_map(info, sector); ++ ++ rpc_hf_unlock(info, addr); ++ rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, RPC_CFI_CMD_ERASE_START); ++ rpc_hf_unlock(info, addr); ++ rpc_hf_write_cmd(info, addr, RPC_CFI_CMD_ERASE_SECTOR); ++ ++ return rpc_hf_status(info, addr, 10000, 1000); ++} ++ ++static ulong rpc_hf_get_size(phys_addr_t base, int banknum) ++{ ++ flash_info_t *info = &flash_info[banknum]; ++ u16 data[2] = { 0, 0 }; ++ ulong id, size = 0; ++ ushort sectors, i; ++ ++ info->flash_id = FLASH_UNKNOWN; ++ info->sector_count = -1; ++ info->size = 0; ++ ++ rpc_hf_mode_ext(info); ++ ++ rpc_hf_wp(info, 0); ++ ++ rpc_hf_unlock(info, 0); ++ rpc_hf_write_cmd(info, RPC_CFI_UNLOCK1, RPC_CFI_CMD_READ_ID); ++ ++ rpc_hf_read_reg(info, 0x0, data, RPC_HF_SIZE_32BIT); ++ if ((data[0] & RPC_CFI_ID_MASK) != RPC_CFI_ID_MAN_SPANSION || ++ (data[1] & RPC_CFI_ID_MASK) != RPC_CFI_ID_TYPE_HYPERFLASH) ++ goto out; ++ ++ id = data[0] | data[1] << 16; ++ ++ rpc_hf_read_reg(info, 0x27 << 1, data, RPC_HF_SIZE_16BIT); ++ size = 1 << data[0]; ++ ++ if (size & (RPC_HF_ERASE_SIZE - 1)) ++ goto out; ++ ++ sectors = size / RPC_HF_ERASE_SIZE; ++ if (sectors < 1 || sectors > CONFIG_SYS_MAX_FLASH_SECT) ++ goto out; ++ ++ info->flash_id = id; ++ info->size = size; ++ info->sector_count = sectors; ++ ++ for (i = 0; i < sectors; i++) { ++ info->start[i] = base; ++ base += RPC_HF_ERASE_SIZE; ++ } ++ ++out: ++ rpc_hf_write_cmd(info, 0, RPC_CFI_CMD_RESET); ++ rpc_hf_mode_ext(info); ++ return info->size; ++} ++ ++/* ++ * Flash erase, returns: ++ * ERR_OK : OK ++ * ERR_ABORTED : Aborted by user ++ * ERR_PROTECTED : Protected sector ++ */ ++int flash_erase(flash_info_t *info, int s_first, int s_last) ++{ ++ int s, retval = ERR_OK; ++ ++ puts("Erasing Flash... "); ++ for (s = s_first; s <= s_last; s++) { ++ if (ctrlc()) { ++ printf("aborted sector %i\n", s); ++ retval = ERR_ABORTED; ++ goto out; ++ } ++ ++ if (info->protect[s]) { ++ printf("protected sector %i\n", s); ++ retval = ERR_PROTECTED; ++ goto out; ++ } ++ ++ putc('.'); ++ ++ retval = rpc_hf_sector_erase(info, s); ++ if (retval != ERR_OK) { ++ printf("error sector %i\n", s); ++ goto out; ++ } ++ } ++ puts("done\n"); ++ ++out: ++ rpc_hf_mode_ext(info); ++ return retval; ++} ++ ++/* ++ * Copy memory to flash, returns: ++ * ERR_OK : OK ++ * ERR_ABORTED : Aborted by user ++ * ERR_PROTECTED : Protected sector ++ */ ++int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt) ++{ ++ union { ++ u8 b[4]; ++ u16 w[2]; ++ u32 d; ++ } data; ++ ulong offset, size; ++ int sector, idx, retval; ++ u8 last; ++ ++ retval = ERR_OK; ++ idx = 0; ++ ++ /* Handle unaligned start */ ++ if (addr & 0x1) { ++ addr--; ++ data.b[idx] = readb(addr); ++ idx++; ++ } ++ ++ /* Handle unaligned end */ ++ offset = addr + idx + cnt; ++ last = offset & 0x1 ? readb(offset) : 0xFF; ++ ++ sector = rpc_hf_flash_sector(info, addr); ++ offset = addr - info->start[sector]; ++ size = rpc_hf_flash_sector_size(info, sector) - offset; ++ offset += rpc_hf_flash_map(info, sector); ++ ++ while (cnt) { ++ if (ctrlc()) { ++ retval = ERR_ABORTED; ++ goto out; ++ } ++ ++ if (info->protect[sector]) { ++ retval = ERR_PROTECTED; ++ goto out; ++ } ++ ++ if (size > cnt) ++ size = cnt; ++ ++ putc('.'); ++ ++ cnt -= size; ++ while (size) { ++ rpc_hf_unlock(info, info->start[sector]); ++ rpc_hf_write_cmd(info, ++ info->start[sector] + RPC_CFI_UNLOCK1, ++ RPC_CFI_CMD_WRITE); ++ ++ if (size > 0x7) { ++ u32 wbuf = RPC_WBUF; ++ int block = size >= RPC_WBUF_SIZE ? ++ RPC_WBUF_SIZE : size & ~0x7; ++ ++ rpc_hf_wbuf_enable(info, offset); ++ offset += block; ++ ++ block >>= 3; ++ while (block--) { ++ while (idx < 4) { ++ data.b[idx++] = *src++; ++ size--; ++ } ++ rpc_writel(info, wbuf, data.d); ++ wbuf += 4; ++ ++ idx = 0; ++ while (idx < 4) { ++ data.b[idx++] = *src++; ++ size--; ++ } ++ rpc_writel(info, wbuf, data.d); ++ wbuf += 4; ++ ++ idx = 0; ++ } ++ ++ rpc_writel(info, RPC_SMCR, ++ RPC_SMCR_SPIWE | RPC_SMCR_SPIE); ++ } else { ++ enum rpc_hf_size bits; ++ ++ while (idx < 4) { ++ data.b[idx++] = *src++; ++ size--; ++ ++ if (!size) ++ break; ++ } ++ ++ if (idx & 0x1) ++ data.b[idx++] = last; ++ ++ switch (idx) { ++ case 2: ++ bits = RPC_HF_SIZE_16BIT; ++ break; ++ default: ++ bits = RPC_HF_SIZE_32BIT; ++ break; ++ } ++ ++ rpc_hf_write_mem(info, offset, data.w, bits); ++ offset += idx; ++ idx = 0; ++ } ++ ++ rpc_wait_tend(info); ++ rpc_setl(info, RPC_PHYCNT, ++ ~(RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 | ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)), ++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)); ++ ++ retval = rpc_hf_status(info, info->start[sector], ++ 1000000, 10); ++ if (retval) ++ goto out; ++ } ++ ++ sector++; ++ offset = rpc_hf_flash_map(info, sector); ++ size = rpc_hf_flash_sector_size(info, sector); ++ } ++ ++out: ++ rpc_hf_mode_ext(info); ++ return retval; ++} ++ ++/* Print flash information */ ++void flash_print_info(flash_info_t *info) ++{ ++ if (info->flash_id == FLASH_UNKNOWN) ++ return; ++ ++ printf("HyperFlash Id: %lx\n", info->flash_id); ++ printf("Base Address: %lx\n", info->start[0]); ++ printf("Size: %lu MiB\n", info->size >> 20); ++ printf("Sectors: %u\n", info->sector_count); ++} ++ ++flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; ++ ++unsigned long flash_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) { ++ flash_info[i].flash_id = FLASH_UNKNOWN; ++ flash_info[i].sector_count = -1; ++ flash_info[i].size = 0; ++ } ++ ++ return rpc_hf_get_size(CONFIG_SYS_RPC_FLASH_BASE, 0); ++} +-- +1.9.3 + |