Commit 11275e33 authored by Dmitry Konyshev's avatar Dmitry Konyshev

RT #83884 Implement SPI-FI support using the NPX's spifi_drv_M3.lib

parent 7d971406
......@@ -308,7 +308,13 @@ endif
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
ifeq ($(CONFIG_SYS_LPC18XX)$(CONFIG_SPIFI),yy)
SPIFILIB_DEP = cpu/arm_cortexm3/lpc18xx/spifilib/spifilib.bin
$(SPIFILIB_DEP): depend
$(MAKE) -C cpu/arm_cortexm3/lpc18xx/spifilib -f spifilib.mk
endif
$(obj)u-boot.bin: $(obj)u-boot $(SPIFILIB_DEP)
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
ifeq ($(CONFIG_LPC178X_FCG),y)
$(obj)tools/lpc178x_fcg $(obj)u-boot.bin $(obj)u-boot-lpc.bin
......@@ -318,6 +324,9 @@ ifeq ($(CONFIG_LPC18XX_BOOTHEADER),y)
$(obj)tools/lpc18xx_bootheader $(obj)u-boot.bin $(obj)u-boot-bootheader.bin
mv $(obj)u-boot-bootheader.bin $(obj)u-boot.bin
endif
ifeq ($(CONFIG_SYS_LPC18XX)$(CONFIG_SPIFI),yy)
dd if=cpu/arm_cortexm3/lpc18xx/spifilib/spifilib.bin of=u-boot.bin seek=112 bs=1024
endif
$(obj)u-boot.upgrade: $(obj)u-boot.bin
split -b 32768 -a 1 -d u-boot.bin u-boot.bin-
......
......@@ -28,6 +28,9 @@
#if defined(CONFIG_LPC_SPI)
#include <spi.h>
#endif
#if defined(CONFIG_SPIFI)
#include <spifi.h>
#endif
#include <asm/arch/lpc18xx_gpio.h>
#include <asm/arch/lpc18xx_scu.h>
......@@ -677,7 +680,11 @@ int checkboard(void)
#ifdef CONFIG_MISC_INIT_R
int misc_init_r(void)
{
/* TBD */
#if defined(CONFIG_SPIFI)
if (spifi_initialize()) {
return 1;
}
#endif
return 0;
}
#endif /* CONFIG_MISC_INIT_R */
......
......@@ -62,6 +62,7 @@ COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o
COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o
COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o
COBJS-$(CONFIG_ENV_IS_IN_SPIFI) += env_spifi.o
COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o
# command
......
......@@ -33,6 +33,9 @@
#include <dataflash.h>
#endif
#include <watchdog.h>
#ifdef CONFIG_SPIFI
#include <spifi.h>
#endif
#include <u-boot/md5.h>
#include <sha1.h>
......@@ -450,6 +453,20 @@ int do_mem_cp ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
}
#endif
#ifdef CONFIG_SPIFI
if (spifi_addr(dest)) {
if (spifi_addr(addr)) {
puts ("Cannot copy from SPIFI to SPIFI, aborting.\n\r");
return 1;
}
if (!spifi_addr(dest + count)) {
puts ("Cannot copy across SPIFI boundaries, aborting.\n\r");
return 1;
}
return spifi_write(dest, (void *)addr, count);
}
#endif
while (count-- > 0) {
if (size == 4)
*((ulong *)dest) = *((ulong *)addr);
......
......@@ -63,9 +63,10 @@ DECLARE_GLOBAL_DATA_PTR;
!defined(CONFIG_ENV_IS_IN_NVRAM) && \
!defined(CONFIG_ENV_IS_IN_ONENAND) && \
!defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \
!defined(CONFIG_ENV_IS_IN_SPIFI) && \
!defined(CONFIG_ENV_IS_NOWHERE)
# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\
SPI_FLASH|MG_DISK|NVRAM|NOWHERE}
SPI_FLASH|SPIFI|MG_DISK|NVRAM|NOWHERE}
#endif
#define XMK_STR(x) #x
......
/* LowLevel function for SPIFI environment support
*
* (C) Copyright 2012
*
* Dmitry Konyshev, Emcraft Systems, probables@emcraft.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
#include <common.h>
#include <command.h>
#include <environment.h>
#include <linux/stddef.h>
DECLARE_GLOBAL_DATA_PTR;
env_t *env_ptr = NULL;
char * env_name_spec = "spifi";
extern uchar default_environment[];
uchar env_get_char_spec (int index)
{
return *((uchar *)CONFIG_ENV_ADDR + index + offsetof(env_t,data));
}
void env_relocate_spec (void)
{
memcpy(env_ptr, (void *)CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
}
int saveenv(void)
{
/* env must be copied to do not alter env structure in memory*/
unsigned char temp[CONFIG_ENV_SIZE];
memcpy(temp, env_ptr, CONFIG_ENV_SIZE);
return spifi_write(CONFIG_ENV_ADDR, temp, CONFIG_ENV_SIZE);
}
/************************************************************************
* Initialize Environment use
*
* We are still running from ROM, so data use is limited
* Use a (moderately small) buffer on the stack
*/
int env_init(void)
{
ulong crc, len, new;
unsigned off;
uchar buf[64];
if (gd->env_valid == 0){
/* read old CRC */
memcpy((char *)&crc, (char *)CONFIG_ENV_ADDR + offsetof(env_t, crc),
sizeof(ulong));
new = 0;
len = ENV_SIZE;
off = offsetof(env_t,data);
while (len > 0) {
int n = (len > sizeof(buf)) ? sizeof(buf) : len;
memcpy((char *)buf, (char *)CONFIG_ENV_ADDR + off, n);
new = crc32 (new, buf, n);
len -= n;
off += n;
}
if (crc == new) {
gd->env_addr = offsetof(env_t,data);
gd->env_valid = 1;
} else {
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 0;
}
}
return (0);
}
......@@ -25,6 +25,10 @@
#include "wdt.h"
#include "clock.h"
#if defined (CONFIG_SYS_LPC18XX) && defined(CONFIG_SPIFI)
#include <spifi.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
#if defined(CONFIG_ARMCORTEXM3_SOC_INIT)
......@@ -134,6 +138,10 @@ void
#endif
#ifdef CONFIG_SYS_LPC18XX
#if defined(CONFIG_SPIFI)
/* LPC4350 errata 3.10 for booting from SPIFI */
spifi_cancel_mem_mode();
#endif
/*
* Use watchdog reset on LPC18xx/43xx
*/
......
......@@ -29,7 +29,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).a
COBJS := clock.o cpu.o envm.o wdt.o
COBJS := clock.o cpu.o envm.o wdt.o spifi.o
SOBJS :=
SRCS := $(COBJS:.o=.c)
......
/*
* (C) Copyright 2013
*
* Dmitry Konyshev, Emcraft Systems, probables@emcraft.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include "spifilib/spifilib.h"
#if defined(CONFIG_SPIFI)
static SPIFIobj spifi_obj;
const spifilib_header_t *spifilib_ram_hdr = NULL;
int spifi_initialize(void)
{
int ret;
if (spifilib_flash_hdr->signature == SPIFILIB_SIG) {
spifilib_ram_hdr = spifilib_flash_hdr->link_addr;
memcpy(spifilib_flash_hdr->link_addr, spifilib_flash_hdr,
spifilib_flash_hdr->lib_size);
if ((ret = spifilib_ram_hdr->init_func(&spifi_obj, 10, S_MODE3, 25))) {
spifilib_ram_hdr = NULL;
printf("SPIFI lib init failed with code %i\n", ret);
return 1;
}
} else {
puts("No SPIFI lib found\n");
return 1;
}
return 0;
}
int spifi_write(ulong offset, const void *buf, ulong len)
{
SPIFIopers ops = {
.dest = offset < CONFIG_SPIFI_BASE ? (char *)offset :
(char *)offset - CONFIG_SPIFI_BASE,
.length = len,
.scratch = NULL,
.protect = 0,
.options = 0,
};
if (!spifilib_ram_hdr) {
puts("SPIFI lib is not initialized!\n");
return 1;
}
return spifilib_ram_hdr->program_func(&spifi_obj, (char *)buf, &ops);
}
void spifi_cancel_mem_mode(void)
{
if (!spifilib_ram_hdr) {
puts("SPIFI lib is not initialized!\n");
return;
}
spifilib_ram_hdr->cancel_mem_mode_func(&spifi_obj);
}
#endif
/***********************************************************************
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors'
* relevant copyright in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
**********************************************************************/
#ifndef SPIFI_ROM_API_H
#define SPIFI_ROM_API_H
#include <stdint.h>
/* define the symbol TESTING in the environment if test output desired */
/* maintain LONGEST_PROT >= the length (in bytes) of the largest
protection block of any serial flash that this driver handles */
#define LONGEST_PROT 68
typedef uint8_t uc;
#ifndef NULL
#define NULL ((void *)0)
#endif
/* protection/sector descriptors */
typedef struct {
uint32_t base;
uc flags;
int8_t log2;
uint16_t rept;
} protEnt;
/* bits in the flags byte */
enum {RWPROT=1};
/* overall data structure includes # sectors, length of protection reg,
array of descriptors
typedef struct {
uint16_t sectors;
uint16_t protBytes;
protEnt *entries;
} protDesc; */
typedef union {
uint16_t hw;
uc byte[2];
}stat_t;
/* the object that init returns, and other routines use as an operand */
typedef struct {
uint32_t base, regbase, devSize, memSize;
uc mfger, devType, devID, busy;
stat_t stat;
uint16_t reserved;
uint16_t set_prot, write_prot;
uint32_t mem_cmd, prog_cmd;
uint16_t sectors, protBytes;
uint32_t opts, errCheck;
uc erase_shifts[4], erase_ops[4];
protEnt *protEnts;
char prot[LONGEST_PROT];
} SPIFIobj;
/* operands of program and erase */
typedef struct {
char *dest;
uint32_t length;
char *scratch;
int32_t protect;
uint32_t options;
} SPIFIopers;
/* instruction classes for wait_busy */
typedef enum {stat_inst, block_erase, prog_inst, chip_erase} inst_type;
/* bits in options operands (MODE3, RCVCLK, and FULLCLK
have the same relationship as in the Control register) */
#define S_MODE3 1
#define S_MODE0 0
#define S_MINIMAL 2
#define S_MAXIMAL 0
#define S_FORCE_ERASE 4
#define S_ERASE_NOT_REQD 8
#define S_CALLER_ERASE 8
#define S_ERASE_AS_REQD 0
#define S_VERIFY_PROG 0x10
#define S_VERIFY_ERASE 0x20
#define S_NO_VERIFY 0
#define S_RCVCLK 0x80
#define S_INTCLK 0
#define S_FULLCLK 0x40
#define S_HALFCLK 0
#define S_DUAL 0x100
#define S_CALLER_PROT 0x200
#define S_DRIVER_PROT 0
/* the following values in the first post-address memory command byte work
for all known quad devices that support "no opcode" operation */
#define NO_OPCODE_FOLLOWS 0xA5
#define OPCODE_FOLLOWS 0xFF
/* basic SPI commands for serial flash */
#define BASE_READ_CMD (CMD_RD<<OPCODE_SHIFT|4<<FRAMEFORM_SHIFT|UNL_DATA)
#define FAST_READ_CMD (CMD_READ_FAST<<OPCODE_SHIFT|4<<FRAMEFORM_SHIFT|1<<INTLEN_SHIFT|UNL_DATA)
#define BASE_PROG_CMD (CMD_PROG<<OPCODE_SHIFT|4<<FRAMEFORM_SHIFT|DOUT)
/* the length of a standard program command is 256 on all devices */
#define PROG_SIZE 256
/* options in obj->opts (mostly for setMulti) */
/* used by Winbond: send 0xA3 command so hardware can read faster */
#define OPT_SEND_A3 1
/* used by SST: send 0x38 command to enable quad and allow full command set */
#define OPT_SEND_38 2
/* used by Winbond and others: read status reg 2, check it,
if necessary write it back with Quad Enable set */
#define OPT_35_OR02_01 4
/* used by Atmel: read Configuration register, if necessary set Quad Enable */
#define OPT_3F_OR80_3E 8
/* used by Numonyx to set all-quad mode: only for parts that include RSTQIO */
#define OPT_65_CLR_C0_61 0x10
/* used by Numonyx: send 0x81 command to write Volatile Configuration Register
to set # dummy bytes and allow XIP mode */
#define OPT_81 0x20
/* set for devices without full device erase command (Numonyx type 0x40) */
#define OPT_NO_DEV_ERASE 0x40
/* used by Macronix: status reg 2 includes selection between write-protect
in status reg and command-based */
#define OPT_WPSEL 0x80
/* set when protection data has been read into the SPIFI object */
#define OPT_PROT_READ 0x100
/* set if device needs 4-byte address (and maybe 0x4B command = use 4-byte address) */
#define OPT_4BAD 0x200
/* set if setMulti should set the Dual bit in Control reg */
#define OPT_DUAL 0x400
/* send "# dummy bits" in C0 command to Winbond */
#define OPT_C0 0x800
/* set QE for Chingis */
#define OPT_05_OR40_01 0x1000
/* write status does not go busy */
#define OPT_01_NO_BUSY 0x2000
/* protection mode bits moved from protMode byte to opts Fri May 13 2011 */
#define OPT_PROT_STAT 0x4000
#define OPT_PROT_REG 0x8000
#define OPT_PROT_CMD3 0x10000
#define OPT_PROT_CMDE 0x20000
#define OPT_PROT_MASK 0x3C000
#define OPT_ALL_QUAD 0x40000
#ifndef OMIT_ROM_TABLE
/* interface to ROM API */
typedef struct {
int32_t (*spifi_init) (SPIFIobj *obj, uint32_t csHigh, uint32_t options,
uint32_t mhz);
int32_t (*spifi_program) (SPIFIobj *obj, char *source, SPIFIopers *opers);
int32_t (*spifi_erase) (SPIFIobj *obj, SPIFIopers *opers);
/* mode switching */
void (*cancel_mem_mode)(SPIFIobj *obj);
void (*set_mem_mode) (SPIFIobj *obj);
/* mid level functions */
int32_t (*checkAd) (SPIFIobj *obj, SPIFIopers *opers);
int32_t (*setProt) (SPIFIobj *obj, SPIFIopers *opers, char *change,
char *saveProt);
int32_t (*check_block) (SPIFIobj *obj, char *source, SPIFIopers *opers,
uint32_t check_program);
int32_t (*send_erase_cmd) (SPIFIobj *obj, uint8_t op, uint32_t addr);
uint32_t (*ck_erase) (SPIFIobj *obj, uint32_t *addr, uint32_t length);
int32_t (*prog_block) (SPIFIobj *obj, char *source, SPIFIopers *opers,
uint32_t *left_in_page);
uint32_t (*ck_prog) (SPIFIobj *obj, char *source, char *dest, uint32_t length);
/* low level functions */
void(*setSize) (SPIFIobj *obj, int32_t value);
int32_t (*setDev) (SPIFIobj *obj, uint32_t opts, uint32_t mem_cmd,
uint32_t prog_cmd);
uint32_t (*cmd) (uc op, uc addrLen, uc intLen, uint16_t len);
uint32_t (*readAd) (SPIFIobj *obj, uint32_t cmd, uint32_t addr);
void (*send04) (SPIFIobj *obj, uc op, uc len, uint32_t value);
void (*wren_sendAd) (SPIFIobj *obj, uint32_t cmd, uint32_t addr, uint32_t value);
int32_t (*write_stat) (SPIFIobj *obj, uc len, uint16_t value);
int32_t (*wait_busy) (SPIFIobj *obj, uc prog_or_erase);
} SPIFI_RTNS;
#define SPIFI_ROM_PTR 0x10400118
#define define_spifi_romPtr(name) const SPIFI_RTNS *name=*((SPIFI_RTNS **)SPIFI_ROM_PTR)
#endif /* OMIT_ROM_TABLE */
#ifdef USE_SPIFI_LIB
extern SPIFI_RTNS spifi_table;
#endif /* USE_SPIFI_LIB */
/* example of using this interface:
#include "spifi_rom_api.h"
#define CSHIGH 4
#define SPIFI_MHZ 80
#define source_data_ad (char *)1234
int32_t rc;
SPIFIopers opers;
define_spifi_romPtr(spifi);
SPIFIobj *obj = malloc(sizeof(SPIFIobj));
if (!obj) { can't allocate memory }
rc = spifi->spifi_init (obj, CSHIGH, S_FULLCLK+S_RCVCLK, SPIFI_MHZ);
if (rc) { investigate init error rc }
printf ("the serial flash contains %d bytes\n", obj->devSize);
opers.dest = where_to_program;
opers.length = how_many_bytes;
opers.scratch = NULL; // unprogrammed data is not saved/restored
opers.protect = -1; // save & restore protection
opers.options = S_VERIFY_PROG;
rc = spifi->spifi_program (obj, source_data_ad, &opers);
if (rc) { investigate program error rc }
*/
/* these are for normal users, including boot code */
int32_t spifi_init (SPIFIobj *obj, uint32_t csHigh, uint32_t options, uint32_t mhz);
int32_t spifi_program (SPIFIobj *obj, char *source, SPIFIopers *opers);
int32_t spifi_erase (SPIFIobj *obj, SPIFIopers *opers);
/* these are used by the manufacturer-specific init functions */
void setSize (SPIFIobj *obj, int32_t value);
int32_t setDev (SPIFIobj *obj, uint32_t opts, uint32_t mem_cmd, uint32_t prog_cmd);
uint32_t read04(SPIFIobj *obj, uc op, uc len);
int32_t write_stat (SPIFIobj *obj, uc len, uint16_t value);
void setProtEnts(SPIFIobj *obj, const protEnt *p, uint32_t protTabLen);
/* needs to be defined for each platform */
void pullMISO(int high);
#ifdef TESTING
/* used by testing code */
unsigned short getProtBytes (SPIFIobj *obj, unsigned short *sectors);
/* predeclare a debug routine */
void wait_sample (volatile unsigned *addr, unsigned mask, unsigned value);
#endif
#endif /* SPIFI_ROM_API_H */
/*
* (C) Copyright 2013
*
* Dmitry Konyshev, Emcraft Systems, probables@emcraft.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include "spifilib.h"
int32_t cancel_mem_mode (SPIFIobj *obj);
const spifilib_header_t spilib_hdr __attribute__((section(".rodata.spifilib.header"))) =
{
SPIFILIB_SIG,
(spifilib_header_t *)&spilib_hdr,
SPIFILIB_SIZE,
spifi_init,
spifi_program,
spifi_erase,
cancel_mem_mode
};
void *__aeabi_memcpy4(void *dest, const void *src, int n)
{
int i;
for (i = 0; i < n; i++) {
*((char *)dest + i) = *((char *)src + i);
}
return dest;
}
void _start(void)
{
}
/*
* (C) Copyright 2013
*
* Dmitry Konyshev, Emcraft Systems, probables@emcraft.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef __SPIFILIB_H
#define __SPIFILIB_H
#include "spifi_rom_api.h"
#define SPIFILIB_SIG 0x591F121B
#define SPIFILIB_SIZE 16*1024
typedef int32_t (*spifi_init_t)(SPIFIobj *obj, uint32_t csHigh, uint32_t options, uint32_t mhz);
typedef int32_t (*spifi_program_t)(SPIFIobj *obj, char *source, SPIFIopers *opers);
typedef int32_t (*spifi_erase_t)(