Commit bae61eef authored by TsiChung Liew's avatar TsiChung Liew Committed by John Rigby
Browse files

ColdFire: Add dspi and serial flash support for MCF5445x


Signed-off-by: default avatarTsiChung Liew <Tsi-Chung.Liew@freescale.com>
Acked-by: default avatarJohn Rigby <jrigby@freescale.com>
parent 48ead7a7
......@@ -95,6 +95,11 @@ typedef volatile unsigned char FLASH_PORT_WIDTHV;
#define FLASH_28F256P30T 0x00BD /* Intel 28F256P30T ( 256M = 16M x 16 ) */
#define FLASH_28F256P30B 0x00BE /* Intel 28F256P30B ( 256M = 16M x 16 ) */
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
#define STM_ID_M25P16 0x20152015
#define FLASH_M25P16 0x0055
#endif
#define SYNC __asm__("nop")
/*-----------------------------------------------------------------------
......@@ -111,6 +116,12 @@ void inline spin_wheel(void);
void flash_sync_real_protect(flash_info_t * info);
uchar intel_sector_protected(flash_info_t * info, ushort sector);
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
int write_ser_data(flash_info_t * info, ulong dest, uchar * data, ulong cnt);
int serial_flash_read_status(int chipsel);
static int ser_flash_cs = 0;
#endif
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
ulong flash_init(void)
......@@ -119,6 +130,10 @@ ulong flash_init(void)
ulong size = 0;
ulong fbase = 0;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
dspi_init();
#endif
for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
memset(&flash_info[i], 0, sizeof(flash_info_t));
......@@ -129,6 +144,11 @@ ulong flash_init(void)
case 1:
fbase = (ulong) CFG_FLASH1_BASE;
break;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
case 2:
fbase = (ulong) CFG_FLASH2_BASE;
break;
#endif
}
flash_get_size((FPWV *) fbase, &flash_info[i]);
......@@ -152,7 +172,6 @@ int flash_get_offsets(ulong base, flash_info_t * info)
{
int i, j, k;
int sectors, bs, banks;
ulong start;
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_ATM) {
int sect[] = CFG_ATMEL_SECT;
......@@ -196,6 +215,15 @@ int flash_get_offsets(ulong base, flash_info_t * info)
*addr16 = (FPW) INTEL_RESET; /* restore read mode */
}
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_STM) {
info->start[0] = CFG_FLASH2_BASE;
for (k = 0, i = 0; i < CFG_STM_SECT; i++, k++) {
info->start[k + 1] = info->start[k] + CFG_STM_SECTSZ;
info->protect[k] = 0;
}
}
#endif
return ERR_OK;
}
......@@ -211,6 +239,11 @@ void flash_print_info(flash_info_t * info)
case FLASH_MAN_ATM:
printf("ATMEL ");
break;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
case FLASH_MAN_STM:
printf("ST ");
break;
#endif
default:
printf("Unknown Vendor ");
break;
......@@ -221,8 +254,13 @@ void flash_print_info(flash_info_t * info)
printf("AT49BV040A\n");
break;
case FLASH_28F128J3A:
printf("Intel 28F128J3A\n");
printf("28F128J3A\n");
break;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
case FLASH_M25P16:
printf("M25P16\n");
break;
#endif
default:
printf("Unknown Chip Type\n");
return;
......@@ -267,6 +305,45 @@ ulong flash_get_size(FPWV * addr, flash_info_t * info)
u16 value;
int i;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
if ((ulong) addr == CFG_FLASH2_BASE) {
int manufactId = 0;
int deviceId = 0;
ser_flash_cs = 1;
dspi_tx(ser_flash_cs, 0x80, SER_RDID);
dspi_tx(ser_flash_cs, 0x80, 0);
dspi_tx(ser_flash_cs, 0x80, 0);
dspi_tx(ser_flash_cs, 0x80, 0);
dspi_rx();
manufactId = dspi_rx();
deviceId = dspi_rx() << 8;
deviceId |= dspi_rx();
dspi_tx(ser_flash_cs, 0x00, 0);
dspi_rx();
switch (manufactId) {
case (u8) STM_MANUFACT:
info->flash_id = FLASH_MAN_STM;
break;
}
switch (deviceId) {
case (u16) STM_ID_M25P16:
info->flash_id += FLASH_M25P16;
break;
}
info->sector_count = CFG_STM_SECT;
info->size = CFG_STM_SECT * CFG_STM_SECTSZ;
return (info->size);
}
#endif
addr[FLASH_CYCLE1] = (FPWV) 0x00AA00AA; /* for Atmel, Intel ignores this */
addr[FLASH_CYCLE2] = (FPWV) 0x00550055; /* for Atmel, Intel ignores this */
addr[FLASH_CYCLE1] = (FPWV) 0x00900090; /* selects Intel or Atmel */
......@@ -383,6 +460,21 @@ int flash_cmd_rd(volatile u16 * addr, int index)
return (int)addr[index];
}
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
int serial_flash_read_status(int chipsel)
{
u16 status;
dspi_tx(chipsel, 0x80, SER_RDSR);
dspi_rx();
dspi_tx(chipsel, 0x00, 0);
status = dspi_rx();
return status;
}
#endif
/*
* This function gets the u-boot flash sector protection status
* (flash_info_t.protect[]) in sync with the sector protection
......@@ -462,8 +554,11 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
{
int flag, prot, sect;
ulong type, start, last;
int rcode = 0, intel = 0;
int rcode = 0, flashtype = 0;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
int count;
u16 status;
#endif
if ((s_first < 0) || (s_first > s_last)) {
if (info->flash_id == FLASH_UNKNOWN)
printf("- missing\n");
......@@ -474,19 +569,25 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
type = (info->flash_id & FLASH_VENDMASK);
if (type != (FLASH_MAN_INTEL & FLASH_VENDMASK)) {
if (type != (FLASH_MAN_ATM & FLASH_VENDMASK)) {
type = (info->flash_id & FLASH_VENDMASK);
printf
("Can't erase unknown flash type %08lx - aborted\n",
info->flash_id);
return 1;
}
switch (type) {
case FLASH_MAN_ATM:
flashtype = 1;
break;
case FLASH_MAN_INTEL:
flashtype = 2;
break;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
case FLASH_MAN_STM:
flashtype = 3;
break;
#endif
default:
type = (info->flash_id & FLASH_VENDMASK);
printf("Can't erase unknown flash type %08lx - aborted\n",
info->flash_id);
return 1;
}
if (type == FLASH_MAN_INTEL)
intel = 1;
prot = 0;
for (sect = s_first; sect <= s_last; ++sect) {
if (info->protect[sect]) {
......@@ -503,6 +604,51 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
start = get_timer(0);
last = start;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
/* Perform bulk erase */
if (flashtype == 3) {
if ((s_last - s_first) == (CFG_STM_SECT - 1)) {
if (prot == 0) {
dspi_tx(ser_flash_cs, 0x00, SER_WREN);
dspi_rx();
status = serial_flash_read_status(ser_flash_cs);
if (((status & 0x9C) != 0)
&& ((status & 0x02) != 0x02)) {
printf("Can't erase flash\n");
return 1;
}
dspi_tx(ser_flash_cs, 0x00, SER_BULK_ERASE);
dspi_rx();
count = 0;
start = get_timer(0);
do {
status =
serial_flash_read_status
(ser_flash_cs);
if (count++ > 0x10000) {
spin_wheel();
count = 0;
}
if (get_timer(start) >
CFG_FLASH_ERASE_TOUT) {
printf("Timeout\n");
return 1;
}
} while (status & 0x01);
printf("\b. done\n");
return 0;
} else if (prot == CFG_STM_SECT) {
return 1;
}
}
}
#endif
/* Start erase on unprotected sectors */
for (sect = s_first; sect <= s_last; sect++) {
if (info->protect[sect] == 0) { /* not protected */
......@@ -515,65 +661,116 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
/* arm simple, non interrupt dependent timer */
start = get_timer(0);
if (intel) {
*addr = (FPW) INTEL_READID;
min = addr[INTEL_CFI_TERB] & 0xff;
min = 1 << min; /* ms */
min = (min / info->sector_count) * 1000;
/* start erase block */
*addr = (FPW) INTEL_CLEAR; /* clear status register */
*addr = (FPW) INTEL_ERASE; /* erase setup */
*addr = (FPW) INTEL_CONFIRM; /* erase confirm */
while ((*addr & (FPW) INTEL_FINISHED) !=
(FPW) INTEL_FINISHED) {
if (get_timer(start) >
CFG_FLASH_ERASE_TOUT) {
printf("Timeout\n");
*addr = (FPW) INTEL_SUSERASE; /* suspend erase */
*addr = (FPW) INTEL_RESET; /* reset to read mode */
rcode = 1;
break;
switch (flashtype) {
case 1:
{
FPWV *base; /* first address in bank */
FPWV *atmeladdr;
flag = disable_interrupts();
atmeladdr = (FPWV *) addr; /* concatenate to 8 bit */
base = (FPWV *) (CFG_ATMEL_BASE); /* First sector */
base[FLASH_CYCLE1] = (u8) 0x00AA00AA; /* unlock */
base[FLASH_CYCLE2] = (u8) 0x00550055; /* unlock */
base[FLASH_CYCLE1] = (u8) 0x00800080; /* erase mode */
base[FLASH_CYCLE1] = (u8) 0x00AA00AA; /* unlock */
base[FLASH_CYCLE2] = (u8) 0x00550055; /* unlock */
*atmeladdr = (u8) 0x00300030; /* erase sector */
if (flag)
enable_interrupts();
while ((*atmeladdr & (u8) 0x00800080) !=
(u8) 0x00800080) {
if (get_timer(start) >
CFG_FLASH_ERASE_TOUT) {
printf("Timeout\n");
*atmeladdr = (u8) 0x00F000F0; /* reset to read mode */
rcode = 1;
break;
}
}
}
*addr = (FPW) INTEL_RESET; /* resest to read mode */
} else {
FPWV *base; /* first address in bank */
FPWV *atmeladdr;
flag = disable_interrupts();
atmeladdr = (FPWV *) addr; /* concatenate to 8 bit */
base = (FPWV *) (CFG_ATMEL_BASE); /* First sector */
base[FLASH_CYCLE1] = (u8) 0x00AA00AA; /* unlock */
base[FLASH_CYCLE2] = (u8) 0x00550055; /* unlock */
base[FLASH_CYCLE1] = (u8) 0x00800080; /* erase mode */
base[FLASH_CYCLE1] = (u8) 0x00AA00AA; /* unlock */
base[FLASH_CYCLE2] = (u8) 0x00550055; /* unlock */
*atmeladdr = (u8) 0x00300030; /* erase sector */
*atmeladdr = (u8) 0x00F000F0; /* reset to read mode */
break;
}
if (flag)
enable_interrupts();
case 2:
{
*addr = (FPW) INTEL_READID;
min = addr[INTEL_CFI_TERB] & 0xff;
min = 1 << min; /* ms */
min = (min / info->sector_count) * 1000;
/* start erase block */
*addr = (FPW) INTEL_CLEAR; /* clear status register */
*addr = (FPW) INTEL_ERASE; /* erase setup */
*addr = (FPW) INTEL_CONFIRM; /* erase confirm */
while ((*addr & (FPW) INTEL_FINISHED) !=
(FPW) INTEL_FINISHED) {
if (get_timer(start) >
CFG_FLASH_ERASE_TOUT) {
printf("Timeout\n");
*addr = (FPW) INTEL_SUSERASE; /* suspend erase */
*addr = (FPW) INTEL_RESET; /* reset to read mode */
rcode = 1;
break;
}
}
while ((*atmeladdr & (u8) 0x00800080) !=
(u8) 0x00800080) {
if (get_timer(start) >
CFG_FLASH_ERASE_TOUT) {
printf("Timeout\n");
*atmeladdr = (u8) 0x00F000F0; /* reset to read mode */
*addr = (FPW) INTEL_RESET; /* resest to read mode */
break;
}
rcode = 1;
break;
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
case 3:
{
u8 sec = ((ulong) addr >> 16) & 0xFF;
dspi_tx(ser_flash_cs, 0x00, SER_WREN);
dspi_rx();
status =
serial_flash_read_status
(ser_flash_cs);
if (((status & 0x9C) != 0)
&& ((status & 0x02) != 0x02)) {
printf("Error Programming\n");
return 1;
}
}
*atmeladdr = (u8) 0x00F000F0; /* reset to read mode */
} /* Atmel or Intel */
dspi_tx(ser_flash_cs, 0x80,
SER_SECT_ERASE);
dspi_tx(ser_flash_cs, 0x80, sec);
dspi_tx(ser_flash_cs, 0x80, 0);
dspi_tx(ser_flash_cs, 0x00, 0);
dspi_rx();
dspi_rx();
dspi_rx();
dspi_rx();
do {
status =
serial_flash_read_status
(ser_flash_cs);
if (get_timer(start) >
CFG_FLASH_ERASE_TOUT) {
printf("Timeout\n");
return 1;
}
} while (status & 0x01);
break;
}
#endif
} /* switch (flashtype) */
}
}
printf(" done\n");
......@@ -583,6 +780,8 @@ int flash_erase(flash_info_t * info, int s_first, int s_last)
int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
{
int count;
if (info->flash_id == FLASH_UNKNOWN)
return 4;
......@@ -623,7 +822,7 @@ int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
{
ulong cp, wp;
u16 data;
int count, i, l, rc, port_width;
int i, l, rc, port_width;
/* get lower word aligned address */
wp = addr;
......@@ -724,6 +923,51 @@ int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
} /* case FLASH_MAN_INTEL */
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
case FLASH_MAN_STM:
{
ulong wp;
u8 *data = (u8 *) src;
int left; /* number of bytes left to program */
wp = addr;
/* page align, each page is 256 bytes */
if ((wp % 0x100) != 0) {
left = (0x100 - (wp & 0xFF));
write_ser_data(info, wp, data, left);
cnt -= left;
wp += left;
data += left;
}
/* page program - 256 bytes at a time */
if (cnt > 255) {
count = 0;
while (cnt >= 0x100) {
write_ser_data(info, wp, data, 0x100);
cnt -= 0x100;
wp += 0x100;
data += 0x100;
if (count++ > 0x400) {
spin_wheel();
count = 0;
}
}
}
/* remainint bytes */
if (cnt && (cnt < 256)) {
write_ser_data(info, wp, data, cnt);
wp += cnt;
data += cnt;
cnt -= cnt;
}
printf("\b.");
}
#endif
} /* switch */
return ERR_OK;
......@@ -844,6 +1088,75 @@ int write_data(flash_info_t * info, ulong dest, FPW data)
return (0);
}
#if defined(CONFIG_SERIAL_FLASH) && defined(CONFIG_CF_DSPI)
int write_ser_data(flash_info_t * info, ulong dest, uchar * data, ulong cnt)
{
ulong start;
int status, i;
u8 flashdata;
/* Check if Flash is (sufficiently) erased */
dspi_tx(ser_flash_cs, 0x80, SER_READ);
dspi_tx(ser_flash_cs, 0x80, (dest >> 16) & 0xFF);
dspi_tx(ser_flash_cs, 0x80, (dest >> 8) & 0xFF);
dspi_tx(ser_flash_cs, 0x80, dest & 0xFF);
dspi_rx();
dspi_rx();
dspi_rx();
dspi_rx();
dspi_tx(ser_flash_cs, 0x80, 0);
flashdata = dspi_rx();
dspi_tx(ser_flash_cs, 0x00, 0);
dspi_rx();
if ((flashdata & *data) != *data) {
printf("not erased at %08lx (%lx)\n", (ulong) dest,
(ulong) flashdata);
return (2);
}
dspi_tx(ser_flash_cs, 0x00, SER_WREN);
dspi_rx();
status = serial_flash_read_status(ser_flash_cs);
if (((status & 0x9C) != 0) && ((status & 0x02) != 0x02)) {
printf("Error Programming\n");
return 1;
}
start = get_timer(0);
dspi_tx(ser_flash_cs, 0x80, SER_PAGE_PROG);
dspi_tx(ser_flash_cs, 0x80, ((dest & 0xFF0000) >> 16));
dspi_tx(ser_flash_cs, 0x80, ((dest & 0xFF00) >> 8));
dspi_tx(ser_flash_cs, 0x80, (dest & 0xFF));
dspi_rx();
dspi_rx();
dspi_rx();
dspi_rx();
for (i = 0; i < (cnt - 1); i++) {
dspi_tx(ser_flash_cs, 0x80, *data);
dspi_rx();
data++;
}
dspi_tx(ser_flash_cs, 0x00, *data);
dspi_rx();
do {
status = serial_flash_read_status(ser_flash_cs);
if (get_timer(start) > CFG_FLASH_ERASE_TOUT) {
printf("Timeout\n");
return 1;
}
} while (status & 0x01);
return (0);
}
#endif
/*-----------------------------------------------------------------------
* Write a word to Flash for ATMEL FLASH
* A word is 16 bits, whichever the bus width of the flash bank
......
......@@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk
LIB = lib$(CPU).a
START = start.o
COBJS = cpu.o speed.o cpu_init.o interrupts.o pci.o
COBJS = cpu.o speed.o cpu_init.o interrupts.o pci.o dspi.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
......
/*
*
* (C) Copyright 2000-2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
* TsiChung Liew (Tsi-Chung.Liew@freescale.com)
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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 <spi.h>
#if defined(CONFIG_CF_DSPI)
#include <asm/immap.h>
void dspi_init(void)