From 77878f16cedee17161ff2336990970fffc6cea35 Mon Sep 17 00:00:00 2001 From: TsiChung Liew Date: Mon, 17 Mar 2008 12:09:07 -0500 Subject: ColdFire: Fix second memory Chipselect for M5475EVB Signed-off-by: TsiChung Liew Acked-by: John Rigby --- board/freescale/m547xevb/m547xevb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'board/freescale') diff --git a/board/freescale/m547xevb/m547xevb.c b/board/freescale/m547xevb/m547xevb.c index 0286084a8e..539da78de9 100644 --- a/board/freescale/m547xevb/m547xevb.c +++ b/board/freescale/m547xevb/m547xevb.c @@ -43,6 +43,9 @@ long int initdram(int board_type) volatile siu_t *siu = (siu_t *) (MMAP_SIU); volatile sdram_t *sdram = (volatile sdram_t *)(MMAP_SDRAM); u32 dramsize, i; +#ifdef CFG_DRAMSZ1 + u32 temp; +#endif siu->drv = CFG_SDRAM_DRVSTRENGTH; -- cgit v1.2.1 From 545c8e0a7cd3ca9d3846668f69b0d201250abea8 Mon Sep 17 00:00:00 2001 From: Matthew Fettke <[matthew.fettke@gmail.com]> Date: Thu, 24 Jan 2008 14:02:32 -0600 Subject: ColdFire: Added M5275EVB support. Signed-off-by: Matthew Fettke Signed-off-by: TsiChung Liew Acked-by: John Rigby --- board/freescale/m5275evb/Makefile | 40 +++++ board/freescale/m5275evb/config.mk | 25 +++ board/freescale/m5275evb/m5275evb.c | 112 +++++++++++++ board/freescale/m5275evb/mii.c | 319 ++++++++++++++++++++++++++++++++++++ board/freescale/m5275evb/u-boot.lds | 141 ++++++++++++++++ 5 files changed, 637 insertions(+) create mode 100644 board/freescale/m5275evb/Makefile create mode 100644 board/freescale/m5275evb/config.mk create mode 100644 board/freescale/m5275evb/m5275evb.c create mode 100644 board/freescale/m5275evb/mii.c create mode 100644 board/freescale/m5275evb/u-boot.lds (limited to 'board/freescale') diff --git a/board/freescale/m5275evb/Makefile b/board/freescale/m5275evb/Makefile new file mode 100644 index 0000000000..9a0fa80538 --- /dev/null +++ b/board/freescale/m5275evb/Makefile @@ -0,0 +1,40 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +OBJS = $(BOARD).o mii.o + +$(LIB): .depend $(OBJS) + $(AR) crv $@ $(OBJS) + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/board/freescale/m5275evb/config.mk b/board/freescale/m5275evb/config.mk new file mode 100644 index 0000000000..ccb2cf735d --- /dev/null +++ b/board/freescale/m5275evb/config.mk @@ -0,0 +1,25 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# Coldfire contribution by Bernhard Kuhn +# +# 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 +# + +TEXT_BASE = 0xffe00000 diff --git a/board/freescale/m5275evb/m5275evb.c b/board/freescale/m5275evb/m5275evb.c new file mode 100644 index 0000000000..a1b2902935 --- /dev/null +++ b/board/freescale/m5275evb/m5275evb.c @@ -0,0 +1,112 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2005-2008 Arthur Shipkowski (art@videon-central.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 +#include + +#define PERIOD 13 /* system bus period in ns */ +#define SDRAM_TREFI 7800 /* in ns */ + +int checkboard(void) +{ + puts("Board: "); + puts("Freescale MCF5275 EVB\n"); + return 0; +}; + +long int initdram(int board_type) +{ + volatile sdramctrl_t *sdp = (sdramctrl_t *)(MMAP_SDRAM); + volatile gpio_t *gpio_reg = (gpio_t *)(MMAP_GPIO); + + gpio_reg->par_sdram = 0x3FF; /* Enable SDRAM */ + + /* Set up chip select */ + sdp->sdbar0 = CFG_SDRAM_BASE; + sdp->sdbmr0 = MCF_SDRAMC_SDMRn_BAM_32M | MCF_SDRAMC_SDMRn_V; + + /* Set up timing */ + sdp->sdcfg1 = 0x83711630; + sdp->sdcfg2 = 0x46770000; + + /* Enable clock */ + sdp->sdcr = MCF_SDRAMC_SDCR_MODE_EN | MCF_SDRAMC_SDCR_CKE; + + /* Set precharge */ + sdp->sdcr |= MCF_SDRAMC_SDCR_IPALL; + + /* Dummy write to start SDRAM */ + *((volatile unsigned long *)CFG_SDRAM_BASE) = 0xa5a59696; + + /* Send LEMR */ + sdp->sdmr = MCF_SDRAMC_SDMR_BNKAD_LEMR + | MCF_SDRAMC_SDMR_AD(0x0) + | MCF_SDRAMC_SDMR_CMD; + *((volatile unsigned long *)CFG_SDRAM_BASE) = 0xa5a59696; + + /* Send LMR */ + sdp->sdmr = 0x058d0000; + *((volatile unsigned long *)CFG_SDRAM_BASE) = 0xa5a59696; + + /* Stop sending commands */ + sdp->sdmr &= ~(MCF_SDRAMC_SDMR_CMD); + + /* Set precharge */ + sdp->sdcr |= MCF_SDRAMC_SDCR_IPALL; + *((volatile unsigned long *)CFG_SDRAM_BASE) = 0xa5a59696; + + /* Stop manual precharge, send 2 IREF */ + sdp->sdcr &= ~(MCF_SDRAMC_SDCR_IPALL); + sdp->sdcr |= MCF_SDRAMC_SDCR_IREF; + *((volatile unsigned long *)CFG_SDRAM_BASE) = 0xa5a59696; + *((volatile unsigned long *)CFG_SDRAM_BASE) = 0xa5a59696; + + /* Write mode register, clear reset DLL */ + sdp->sdmr = 0x018d0000; + *((volatile unsigned long *)CFG_SDRAM_BASE) = 0xa5a59696; + + /* Stop sending commands */ + sdp->sdmr &= ~(MCF_SDRAMC_SDMR_CMD); + sdp->sdcr &= ~(MCF_SDRAMC_SDCR_MODE_EN); + + /* Turn on auto refresh, lock SDMR */ + sdp->sdcr = + MCF_SDRAMC_SDCR_CKE + | MCF_SDRAMC_SDCR_REF + | MCF_SDRAMC_SDCR_MUX(1) + /* 1 added to round up */ + | MCF_SDRAMC_SDCR_RCNT((SDRAM_TREFI/(PERIOD*64)) - 1 + 1) + | MCF_SDRAMC_SDCR_DQS_OE(0x3); + + return CFG_SDRAM_SIZE * 1024 * 1024; +}; + +int testdram(void) +{ + /* TODO: XXX XXX XXX */ + printf("DRAM test not implemented!\n"); + + return (0); +} diff --git a/board/freescale/m5275evb/mii.c b/board/freescale/m5275evb/mii.c new file mode 100644 index 0000000000..bbc93f6d48 --- /dev/null +++ b/board/freescale/m5275evb/mii.c @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2004-2007 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 +#include +#include + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) +#undef MII_DEBUG +#undef ET_DEBUG + +int fecpin_setclear(struct eth_device *dev, int setclear) +{ + struct fec_info_s *info = (struct fec_info_s *) dev->priv; + volatile gpio_t *gpio = (gpio_t *)MMAP_GPIO; + + if (setclear) { + /* Enable Ethernet pins */ + if (info->iobase == CFG_FEC0_IOBASE) { + gpio->par_feci2c |= 0x0F00; + gpio->par_fec0hl |= 0xC0; + } else { + gpio->par_feci2c |= 0x00A0; + gpio->par_fec1hl |= 0xC0; + } + } else { + if (info->iobase == CFG_FEC0_IOBASE) { + gpio->par_feci2c &= ~0x0F00; + gpio->par_fec0hl &= ~0xC0; + } else { + gpio->par_feci2c &= ~0x00A0; + gpio->par_fec1hl &= ~0xC0; + } + } + + return 0; +} + +#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_CMD_MII) +#include + +/* Make MII read/write commands for the FEC. */ +#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | (REG & 0x1f) << 18)) + +#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | (REG & 0x1f) << 18) | (VAL & 0xffff)) + +/* PHY identification */ +#define PHY_ID_LXT970 0x78100000 /* LXT970 */ +#define PHY_ID_LXT971 0x001378e0 /* LXT971 and 972 */ +#define PHY_ID_82555 0x02a80150 /* Intel 82555 */ +#define PHY_ID_QS6612 0x01814400 /* QS6612 */ +#define PHY_ID_AMD79C784 0x00225610 /* AMD 79C784 */ +#define PHY_ID_LSI80225 0x0016f870 /* LSI 80225 */ +#define PHY_ID_LSI80225B 0x0016f880 /* LSI 80225/B */ +#define PHY_ID_DP83848VV 0x20005C90 /* National 83848 */ +#define PHY_ID_DP83849 0x20005CA2 /* National 82849 */ +#define PHY_ID_KS8721BL 0x00221619 /* Micrel KS8721BL/SL */ + +#define STR_ID_LXT970 "LXT970" +#define STR_ID_LXT971 "LXT971" +#define STR_ID_82555 "Intel82555" +#define STR_ID_QS6612 "QS6612" +#define STR_ID_AMD79C784 "AMD79C784" +#define STR_ID_LSI80225 "LSI80225" +#define STR_ID_LSI80225B "LSI80225/B" +#define STR_ID_DP83848VV "N83848" +#define STR_ID_DP83849 "N83849" +#define STR_ID_KS8721BL "KS8721BL" + +/**************************************************************************** + * mii_init -- Initialize the MII for MII command without ethernet + * This function is a subset of eth_init + **************************************************************************** + */ +void mii_reset(struct fec_info_s *info) +{ + volatile fec_t *fecp = (fec_t *) (info->miibase); + int i; + + fecp->ecr = FEC_ECR_RESET; + for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) { + udelay(1); + } + if (i == FEC_RESET_DELAY) { + printf("FEC_RESET_DELAY timeout\n"); + } +} + +/* send command to phy using mii, wait for result */ +uint mii_send(uint mii_cmd) +{ + struct fec_info_s *info; + struct eth_device *dev; + volatile fec_t *ep; + uint mii_reply; + int j = 0; + + /* retrieve from register structure */ + dev = eth_get_dev(); + info = dev->priv; + + ep = (fec_t *) info->miibase; + + ep->mmfr = mii_cmd; /* command to phy */ + + /* wait for mii complete */ + while (!(ep->eir & FEC_EIR_MII) && (j < MCFFEC_TOUT_LOOP)) { + udelay(1); + j++; + } + if (j >= MCFFEC_TOUT_LOOP) { + printf("MII not complete\n"); + return -1; + } + + mii_reply = ep->mmfr; /* result from phy */ + ep->eir = FEC_EIR_MII; /* clear MII complete */ +#ifdef ET_DEBUG + printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n", + __FILE__, __LINE__, __FUNCTION__, mii_cmd, mii_reply); +#endif + + return (mii_reply & 0xffff); /* data read from phy */ +} +#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CONFIG_CMD_MII) */ + +#if defined(CFG_DISCOVER_PHY) +int mii_discover_phy(struct eth_device *dev) +{ +#define MAX_PHY_PASSES 11 + struct fec_info_s *info = dev->priv; + int phyaddr, pass; + uint phyno, phytype; + + if (info->phyname_init) + return info->phy_addr; + + phyaddr = -1; /* didn't find a PHY yet */ + for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) { + if (pass > 1) { + /* PHY may need more time to recover from reset. + * The LXT970 needs 50ms typical, no maximum is + * specified, so wait 10ms before try again. + * With 11 passes this gives it 100ms to wake up. + */ + udelay(10000); /* wait 10ms */ + } + + for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) { + + phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR1)); +#ifdef ET_DEBUG + printf("PHY type 0x%x pass %d type\n", phytype, pass); +#endif + if (phytype != 0xffff) { + phyaddr = phyno; + phytype <<= 16; + phytype |= + mii_send(mk_mii_read(phyno, PHY_PHYIDR2)); + + switch (phytype & 0xffffffff) { + case PHY_ID_KS8721BL: + strcpy(info->phy_name, + STR_ID_KS8721BL); + info->phyname_init = 1; + break; + default: + strcpy(info->phy_name, "unknown"); + info->phyname_init = 1; + break; + } + +#ifdef ET_DEBUG + printf("PHY @ 0x%x pass %d type ", phyno, pass); + switch (phytype & 0xffffffff) { + case PHY_ID_KS8721BL: + printf(STR_ID_KS8721BL); + break; + default: + printf("0x%08x\n", phytype); + break; + } +#endif + } + } + } + if (phyaddr < 0) + printf("No PHY device found.\n"); + + return phyaddr; +} +#endif /* CFG_DISCOVER_PHY */ + +void mii_init(void) __attribute__((weak,alias("__mii_init"))); + +void __mii_init(void) +{ + volatile fec_t *fecp; + struct fec_info_s *info; + struct eth_device *dev; + int miispd = 0, i = 0; + u16 autoneg = 0; + + /* retrieve from register structure */ + dev = eth_get_dev(); + info = dev->priv; + + fecp = (fec_t *) info->miibase; + + fecpin_setclear(dev, 1); + + mii_reset(info); + + /* We use strictly polling mode only */ + fecp->eimr = 0; + + /* Clear any pending interrupt */ + fecp->eir = 0xffffffff; + + /* Set MII speed */ + miispd = (gd->bus_clk / 1000000) / 5; + fecp->mscr = miispd << 1; + + info->phy_addr = mii_discover_phy(dev); + +#define AUTONEGLINK (PHY_BMSR_AUTN_COMP | PHY_BMSR_LS) + while (i < MCFFEC_TOUT_LOOP) { + autoneg = 0; + miiphy_read(dev->name, info->phy_addr, PHY_BMSR, &autoneg); + i++; + + if ((autoneg & AUTONEGLINK) == AUTONEGLINK) + break; + + udelay(500); + } + if (i >= MCFFEC_TOUT_LOOP) { + printf("Auto Negotiation not complete\n"); + } + + /* adapt to the half/full speed settings */ + info->dup_spd = miiphy_duplex(dev->name, info->phy_addr) << 16; + info->dup_spd |= miiphy_speed(dev->name, info->phy_addr); +} + +/***************************************************************************** + * Read and write a MII PHY register, routines used by MII Utilities + * + * FIXME: These routines are expected to return 0 on success, but mii_send + * does _not_ return an error code. Maybe 0xFFFF means error, i.e. + * no PHY connected... + * For now always return 0. + * FIXME: These routines only work after calling eth_init() at least once! + * Otherwise they hang in mii_send() !!! Sorry! + *****************************************************************************/ + +int mcffec_miiphy_read(char *devname, unsigned char addr, unsigned char reg, + unsigned short *value) +{ + short rdreg; /* register working value */ + +#ifdef MII_DEBUG + printf("miiphy_read(0x%x) @ 0x%x = ", reg, addr); +#endif + rdreg = mii_send(mk_mii_read(addr, reg)); + + *value = rdreg; + +#ifdef MII_DEBUG + printf("0x%04x\n", *value); +#endif + + return 0; +} + +int mcffec_miiphy_write(char *devname, unsigned char addr, unsigned char reg, + unsigned short value) +{ + short rdreg; /* register working value */ + +#ifdef MII_DEBUG + printf("miiphy_write(0x%x) @ 0x%x = ", reg, addr); +#endif + + rdreg = mii_send(mk_mii_write(addr, reg, value)); + +#ifdef MII_DEBUG + printf("0x%04x\n", value); +#endif + + return 0; +} + +#endif /* CONFIG_CMD_NET, FEC_ENET & NET_MULTI */ diff --git a/board/freescale/m5275evb/u-boot.lds b/board/freescale/m5275evb/u-boot.lds new file mode 100644 index 0000000000..43d65001b3 --- /dev/null +++ b/board/freescale/m5275evb/u-boot.lds @@ -0,0 +1,141 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + */ + +OUTPUT_ARCH(m68k) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + /* WARNING - the following is hand-optimized to fit within */ + /* the sector layout of our flash chips! XXX FIXME XXX */ + + cpu/mcf52x2/start.o (.text) + common/dlmalloc.o (.text) + lib_generic/string.o (.text) + lib_generic/zlib.o (.text) + + . = DEFINED(env_offset) ? env_offset : .; + common/environment.o(.text) + + *(.text) + *(.fixup) + *(.got1) + } + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x00FF) & 0xFFFFFF00; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + __got_start = .; + *(.got) + __got_end = .; + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; + __fixup_entries = (. - _FIXUP_TABLE_)>>2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + + __bss_start = .; + .bss : + { + _sbss = .; + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } + _end = . ; + PROVIDE (end = .); +} -- cgit v1.2.1 From bae61eefe15b4d454060a7140e49ae58322be803 Mon Sep 17 00:00:00 2001 From: TsiChung Liew Date: Tue, 25 Mar 2008 15:41:15 -0500 Subject: ColdFire: Add dspi and serial flash support for MCF5445x Signed-off-by: TsiChung Liew Acked-by: John Rigby --- board/freescale/m54455evb/flash.c | 449 ++++++++++++++++++++++++++++++++------ 1 file changed, 381 insertions(+), 68 deletions(-) (limited to 'board/freescale') diff --git a/board/freescale/m54455evb/flash.c b/board/freescale/m54455evb/flash.c index de2cca863a..6b50e8d829 100644 --- a/board/freescale/m54455evb/flash.c +++ b/board/freescale/m54455evb/flash.c @@ -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 -- cgit v1.2.1