diff options
| author | Wolfgang Denk <wd@pollux.denx.de> | 2007-03-06 18:08:43 +0100 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2007-03-06 18:08:43 +0100 | 
| commit | ad5bb451ade552c44bef9119d907929ebc2c126f (patch) | |
| tree | df979d3c6385a161cd6df6b6f903ed7eaad31948 | |
| parent | a5284efd125967675b2e9c6ef7b95832268ad360 (diff) | |
| download | olio-uboot-2014.01-ad5bb451ade552c44bef9119d907929ebc2c126f.tar.xz olio-uboot-2014.01-ad5bb451ade552c44bef9119d907929ebc2c126f.zip | |
Restructure POST directory to support of other CPUs, boards, etc.
45 files changed, 7719 insertions, 45 deletions
| @@ -203,7 +203,13 @@ ifeq ($(CPU),mpc83xx)  LIBS += drivers/qe/qe.a  endif  LIBS += drivers/sk98lin/libsk98lin.a -LIBS += post/libpost.a post/cpu/libcpu.a +LIBS += post/libpost.a post/drivers/libpostdrivers.a +LIBS += $(shell if [ -d post/lib_$(ARCH) ]; then echo \ +	"post/lib_$(ARCH)/libpost$(ARCH).a"; fi) +LIBS += $(shell if [ -d post/cpu/$(CPU) ]; then echo \ +	"post/cpu/$(CPU)/libpost$(CPU).a"; fi) +LIBS += $(shell if [ -d post/board/$(BOARDDIR) ]; then echo \ +	"post/board/$(BOARDDIR)/libpost$(BOARD).a"; fi)  LIBS += common/libcommon.a  LIBS += $(BOARDLIBS) @@ -216,9 +222,8 @@ PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -  # The "tools" are needed early, so put this first  # Don't include stuff already done in $(LIBS)  SUBDIRS	= tools \ -	  examples \ -	  post \ -	  post/cpu +	  examples +  .PHONY : $(SUBDIRS)  ifeq ($(CONFIG_NAND_U_BOOT),y) diff --git a/cpu/ppc4xx/44x_spd_ddr2.c b/cpu/ppc4xx/44x_spd_ddr2.c index 35b23152f..3ab050f9f 100644 --- a/cpu/ppc4xx/44x_spd_ddr2.c +++ b/cpu/ppc4xx/44x_spd_ddr2.c @@ -168,8 +168,8 @@ static void program_codt(unsigned long *dimm_populated,  static void program_mode(unsigned long *dimm_populated,  			 unsigned char *iic0_dimm_addr,  			 unsigned long num_dimm_banks, -                         ddr_cas_id_t *selected_cas, -                         int *write_recovery); +			 ddr_cas_id_t *selected_cas, +			 int *write_recovery);  static void program_tr(unsigned long *dimm_populated,  		       unsigned char *iic0_dimm_addr,  		       unsigned long num_dimm_banks); @@ -185,7 +185,7 @@ static void program_copt1(unsigned long *dimm_populated,  static void program_initplr(unsigned long *dimm_populated,  			    unsigned char *iic0_dimm_addr,  			    unsigned long num_dimm_banks, -                            ddr_cas_id_t selected_cas, +			    ddr_cas_id_t selected_cas,  			    int write_recovery);  static unsigned long is_ecc_enabled(void);  static void program_ecc(unsigned long *dimm_populated, @@ -1149,7 +1149,7 @@ static void program_codt(unsigned long *dimm_populated,  static void program_initplr(unsigned long *dimm_populated,  			    unsigned char *iic0_dimm_addr,  			    unsigned long num_dimm_banks, -                            ddr_cas_id_t selected_cas, +			    ddr_cas_id_t selected_cas,  			    int write_recovery)  {  	u32 cas = 0; diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S index 24b30dfe7..6b2c17033 100644 --- a/cpu/ppc4xx/start.S +++ b/cpu/ppc4xx/start.S @@ -1916,43 +1916,43 @@ pll_wait:  /*----------------------------------------------------------------------------+  | dcbz_area.  +----------------------------------------------------------------------------*/ -        function_prolog(dcbz_area) -        rlwinm. r5,r4,0,27,31 -        rlwinm  r5,r4,27,5,31 -        beq     ..d_ra2 -        addi    r5,r5,0x0001 +	function_prolog(dcbz_area) +	rlwinm. r5,r4,0,27,31 +	rlwinm  r5,r4,27,5,31 +	beq     ..d_ra2 +	addi    r5,r5,0x0001  ..d_ra2:mtctr   r5  ..d_ag2:dcbz    r0,r3 -        addi    r3,r3,32 -        bdnz    ..d_ag2 -        sync -        blr -        function_epilog(dcbz_area) +	addi    r3,r3,32 +	bdnz    ..d_ag2 +	sync +	blr +	function_epilog(dcbz_area)  /*----------------------------------------------------------------------------+  | dflush.  Assume 32K at vector address is cachable.  +----------------------------------------------------------------------------*/ -        function_prolog(dflush) -        mfmsr   r9 -        rlwinm  r8,r9,0,15,13 -        rlwinm  r8,r8,0,17,15 -        mtmsr   r8 -        addi    r3,r0,0x0000 -        mtspr   dvlim,r3 -        mfspr   r3,ivpr -        addi    r4,r0,1024 -        mtctr   r4 +	function_prolog(dflush) +	mfmsr   r9 +	rlwinm  r8,r9,0,15,13 +	rlwinm  r8,r8,0,17,15 +	mtmsr   r8 +	addi    r3,r0,0x0000 +	mtspr   dvlim,r3 +	mfspr   r3,ivpr +	addi    r4,r0,1024 +	mtctr   r4  ..dflush_loop: -        lwz     r6,0x0(r3) -        addi    r3,r3,32 -        bdnz    ..dflush_loop -        addi    r3,r3,-32 -        mtctr   r4 +	lwz     r6,0x0(r3) +	addi    r3,r3,32 +	bdnz    ..dflush_loop +	addi    r3,r3,-32 +	mtctr   r4  ..ag:   dcbf    r0,r3 -        addi    r3,r3,-32 -        bdnz    ..ag -        sync -        mtmsr   r9 -        blr -        function_epilog(dflush) +	addi    r3,r3,-32 +	bdnz    ..ag +	sync +	mtmsr   r9 +	blr +	function_epilog(dflush)  #endif /* CONFIG_440 */ diff --git a/post/Makefile b/post/Makefile index 228bafc6a..f32af9516 100644 --- a/post/Makefile +++ b/post/Makefile @@ -22,14 +22,10 @@  # -SUBDIRS = cpu +SUBDIRS = drivers cpu lib_$(ARCH) board/$(BOARDDIR)  LIB	= libpost.a -AOBJS	= cache_8xx.o -COBJS	= cache.o codec.o cpu.o dsp.o ether.o -COBJS  += i2c.o memory.o post.o rtc.o -COBJS  += spr.o sysmon.o tests.o uart.o -COBJS  += usb.o watchdog.o +COBJS	= post.o tests.o  include $(TOPDIR)/post/rules.mk diff --git a/post/board/lwmon/Makefile b/post/board/lwmon/Makefile new file mode 100644 index 000000000..899b0dc1f --- /dev/null +++ b/post/board/lwmon/Makefile @@ -0,0 +1,29 @@ +# +# (C) Copyright 2002-2006 +# 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 +# + + +LIB	= libpostlwmon.a + +COBJS	= sysmon.o + +include $(TOPDIR)/post/rules.mk diff --git a/post/board/lwmon/sysmon.c b/post/board/lwmon/sysmon.c new file mode 100644 index 000000000..f61d59824 --- /dev/null +++ b/post/board/lwmon/sysmon.c @@ -0,0 +1,331 @@ +/* + * (C) Copyright 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 <post.h> +#include <common.h> + +#ifdef CONFIG_POST + +/* + * SYSMON test + * + * This test performs the system hardware monitoring. + * The test passes when all the following voltages and temperatures + * are within allowed ranges: + * + * Board temperature + * Front temperature + * +3.3V CPU logic + * +5V logic + * +12V PCMCIA + * +12V CCFL + * +5V standby + * + * CCFL is not enabled if temperature values are not within allowed ranges + * + * See the list off all parameters in the sysmon_table below + */ + +#include <post.h> +#include <watchdog.h> +#include <i2c.h> + +#if CONFIG_POST & CFG_POST_SYSMON + +DECLARE_GLOBAL_DATA_PTR; + +static int sysmon_temp_invalid = 0; + +/* #define DEBUG */ + +#define	RELOC(x) if (x != NULL) x = (void *) ((ulong) (x) + gd->reloc_off) + +typedef struct sysmon_s sysmon_t; +typedef struct sysmon_table_s sysmon_table_t; + +static void sysmon_lm87_init (sysmon_t * this); +static void sysmon_pic_init (sysmon_t * this); +static uint sysmon_i2c_read (sysmon_t * this, uint addr); +static uint sysmon_i2c_read_sgn (sysmon_t * this, uint addr); +static void sysmon_ccfl_disable (sysmon_table_t * this); +static void sysmon_ccfl_enable (sysmon_table_t * this); + +struct sysmon_s +{ +	uchar	chip; +	void	(*init)(sysmon_t *); +	uint	(*read)(sysmon_t *, uint); +}; + +static sysmon_t sysmon_lm87 = +	{CFG_I2C_SYSMON_ADDR, sysmon_lm87_init, sysmon_i2c_read}; +static sysmon_t sysmon_lm87_sgn = +	{CFG_I2C_SYSMON_ADDR, sysmon_lm87_init, sysmon_i2c_read_sgn}; +static sysmon_t sysmon_pic = +	{CFG_I2C_PICIO_ADDR, sysmon_pic_init, sysmon_i2c_read}; + +static sysmon_t * sysmon_list[] = +{ +	&sysmon_lm87, +	&sysmon_lm87_sgn, +	&sysmon_pic, +	NULL +}; + +struct sysmon_table_s +{ +	char *		name; +	char *		unit_name; +	sysmon_t *	sysmon; +	void		(*exec_before)(sysmon_table_t *); +	void		(*exec_after)(sysmon_table_t *); + +	int		unit_precision; +	int		unit_div; +	int		unit_min; +	int		unit_max; +	uint		val_mask; +	uint		val_min; +	uint		val_max; +	int		val_valid; +	uint		val_min_alt; +	uint		val_max_alt; +	int		val_valid_alt; +	uint		addr; +}; + +static sysmon_table_t sysmon_table[] = +{ +    {"Board temperature", " C", &sysmon_lm87_sgn, NULL, sysmon_ccfl_disable, +     1, 1, -128, 127, 0xFF, 0x58, 0xD5, 0, 0x6C, 0xC6, 0, 0x27}, + +    {"Front temperature", " C", &sysmon_lm87, NULL, sysmon_ccfl_disable, +     1, 100, -27316, 8984, 0xFF, 0xA4, 0xFC, 0, 0xB2, 0xF1, 0, 0x29}, + +    {"+3.3V CPU logic", "V", &sysmon_lm87, NULL, NULL, +     100, 1000, 0, 4386, 0xFF, 0xB6, 0xC9, 0, 0xB6, 0xC9, 0, 0x22}, + +    {"+ 5 V logic", "V", &sysmon_lm87, NULL, NULL, +     100, 1000, 0, 6630, 0xFF, 0xB6, 0xCA, 0, 0xB6, 0xCA, 0, 0x23}, + +    {"+12 V PCMCIA", "V", &sysmon_lm87, NULL, NULL, +     100, 1000, 0, 15460, 0xFF, 0xBC, 0xD0, 0, 0xBC, 0xD0, 0, 0x21}, + +    {"+12 V CCFL", "V", &sysmon_lm87, NULL, sysmon_ccfl_enable, +     100, 1000, 0, 15900, 0xFF, 0xB6, 0xCA, 0, 0xB6, 0xCA, 0, 0x24}, + +    {"+ 5 V standby", "V", &sysmon_pic, NULL, NULL, +     100, 1000, 0, 6040, 0xFF, 0xC8, 0xDE, 0, 0xC8, 0xDE, 0, 0x7C}, +}; +static int sysmon_table_size = sizeof(sysmon_table) / sizeof(sysmon_table[0]); + +static int conversion_done = 0; + + +int sysmon_init_f (void) +{ +	sysmon_t ** l; +	ulong reg; + +	/* Power on CCFL, PCMCIA */ +	reg = pic_read  (0x60); +	reg |= 0x09; +	pic_write (0x60, reg); + +	for (l = sysmon_list; *l; l++) { +		(*l)->init(*l); +	} + +	return 0; +} + +void sysmon_reloc (void) +{ +	sysmon_t ** l; +	sysmon_table_t * t; + +	for (l = sysmon_list; *l; l++) { +		RELOC(*l); +		RELOC((*l)->init); +		RELOC((*l)->read); +	} + +	for (t = sysmon_table; t < sysmon_table + sysmon_table_size; t ++) { +		RELOC(t->exec_before); +		RELOC(t->exec_after); +		RELOC(t->sysmon); +	} +} + +static char *sysmon_unit_value (sysmon_table_t *s, uint val) +{ +	static char buf[32]; +	int unit_val = +	    s->unit_min + (s->unit_max - s->unit_min) * val / s->val_mask; +	char *p, sign; +	int dec, frac; + +	if (val == -1) { +		return "I/O ERROR"; +	} + +	if (unit_val < 0) { +		sign = '-'; +		unit_val = -unit_val; +	} else { +		sign = '+'; +	} + +	p = buf + sprintf(buf, "%c%2d", sign, unit_val / s->unit_div); + + +	frac = unit_val % s->unit_div; + +	frac /= (s->unit_div / s->unit_precision); + +	dec = s->unit_precision; + +	if (dec != 1) { +		*p++ = '.'; +	} +	for (dec /= 10; dec != 0; dec /= 10) { +		*p++ = '0' + (frac / dec) % 10; +	} +	strcpy(p, s->unit_name); + +	return buf; +} + +static void sysmon_lm87_init (sysmon_t * this) +{ +	uchar val; + +	/* Detect LM87 chip */ +	if (i2c_read(this->chip, 0x40, 1, &val, 1) || (val & 0x80) != 0 || +	    i2c_read(this->chip, 0x3E, 1, &val, 1) || val != 0x02) { +		printf("Error: LM87 not found at 0x%02X\n", this->chip); +		return; +	} + +	/* Configure pins 5,6 as AIN */ +	val = 0x03; +	if (i2c_write(this->chip, 0x16, 1, &val, 1)) { +		printf("Error: can't write LM87 config register\n"); +		return; +	} + +	/* Start monitoring */ +	val = 0x01; +	if (i2c_write(this->chip, 0x40, 1, &val, 1)) { +		printf("Error: can't write LM87 config register\n"); +		return; +	} +} + +static void sysmon_pic_init (sysmon_t * this) +{ +} + +static uint sysmon_i2c_read (sysmon_t * this, uint addr) +{ +	uchar val; +	uint res = i2c_read(this->chip, addr, 1, &val, 1); + +	return res == 0 ? val : -1; +} + +static uint sysmon_i2c_read_sgn (sysmon_t * this, uint addr) +{ +	uchar val; +	return i2c_read(this->chip, addr, 1, &val, 1) == 0 ? +		128 + (signed char)val : -1; +} + +static void sysmon_ccfl_disable (sysmon_table_t * this) +{ +	if (!this->val_valid_alt) { +		sysmon_temp_invalid = 1; +	} +} + +static void sysmon_ccfl_enable (sysmon_table_t * this) +{ +	ulong reg; + +	if (!sysmon_temp_invalid) { +		reg = pic_read  (0x60); +		reg |= 0x06; +		pic_write (0x60, reg); +	} +} + +int sysmon_post_test (int flags) +{ +	int res = 0; +	sysmon_table_t * t; +	uint val; + +	/* +	 * The A/D conversion on the LM87 sensor takes 300 ms. +	 */ +	if (! conversion_done) { +		while (post_time_ms(gd->post_init_f_time) < 300) WATCHDOG_RESET (); +		conversion_done = 1; +	} + +	for (t = sysmon_table; t < sysmon_table + sysmon_table_size; t ++) { +		if (t->exec_before) { +			t->exec_before(t); +		} + +		val = t->sysmon->read(t->sysmon, t->addr); +		if (val != -1) { +			t->val_valid = val >= t->val_min && val <= t->val_max; +			t->val_valid_alt = val >= t->val_min_alt && val <= t->val_max_alt; +		} else { +			t->val_valid = 0; +			t->val_valid_alt = 0; +		} + +		if (t->exec_after) { +			t->exec_after(t); +		} + +		if ((!t->val_valid) || (flags & POST_MANUAL)) { +			printf("%-17s = %-10s ", t->name, sysmon_unit_value(t, val)); +			printf("allowed range"); +			printf(" %-8s ..", sysmon_unit_value(t, t->val_min)); +			printf(" %-8s", sysmon_unit_value(t, t->val_max)); +			printf("     %s\n", t->val_valid ? "OK" : "FAIL"); +		} + +		if (!t->val_valid) { +			res = -1; +		} +	} + +	return res; +} + +#endif /* CONFIG_POST & CFG_POST_SYSMON */ +#endif /* CONFIG_POST */ diff --git a/post/board/netta/Makefile b/post/board/netta/Makefile new file mode 100644 index 000000000..60c7790ac --- /dev/null +++ b/post/board/netta/Makefile @@ -0,0 +1,29 @@ +# +# (C) Copyright 2002-2006 +# 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 +# + + +LIB	= libpostnetta.a + +COBJS	= codec.o dsp.o + +include $(TOPDIR)/post/rules.mk diff --git a/post/board/netta/codec.c b/post/board/netta/codec.c new file mode 100644 index 000000000..e8817520f --- /dev/null +++ b/post/board/netta/codec.c @@ -0,0 +1,48 @@ +/* + * (C) Copyright 2004 + * Pantelis Antoniou, Intracom S.A. , panto@intracom.gr + * + * 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> + +/* + * CODEC test + * + * This test verifies the connection and performs a memory test + * on any connected codec(s). The meat of the work is done + * in the board specific function. + */ + +#ifdef CONFIG_POST + +#include <post.h> + +#if CONFIG_POST & CFG_POST_CODEC + +extern int board_post_codec(int flags); + +int codec_post_test (int flags) +{ +	return board_post_codec(flags); +} + +#endif /* CONFIG_POST & CFG_POST_CODEC */ +#endif /* CONFIG_POST */ diff --git a/post/board/netta/dsp.c b/post/board/netta/dsp.c new file mode 100644 index 000000000..63531a2a4 --- /dev/null +++ b/post/board/netta/dsp.c @@ -0,0 +1,48 @@ +/* + * (C) Copyright 2004 + * Pantelis Antoniou, Intracom S.A. , panto@intracom.gr + * + * 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> + +/* + * DSP test + * + * This test verifies the connection and performs a memory test + * on any connected DSP(s). The meat of the work is done + * in the board specific function. + */ + +#ifdef CONFIG_POST + +#include <post.h> + +#if CONFIG_POST & CFG_POST_DSP + +extern int board_post_dsp(int flags); + +int dsp_post_test (int flags) +{ +	return board_post_dsp(flags); +} + +#endif /* CONFIG_POST & CFG_POST_DSP */ +#endif /* CONFIG_POST */ diff --git a/post/cpu/mpc8xx/Makefile b/post/cpu/mpc8xx/Makefile new file mode 100644 index 000000000..9dd3f0fce --- /dev/null +++ b/post/cpu/mpc8xx/Makefile @@ -0,0 +1,29 @@ +# +# (C) Copyright 2002-2007 +# 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 +# + +LIB	= libpostmpc8xx.a + +AOBJS	= cache_8xx.o +COBJS	= ether.o spr.o uart.o usb.o watchdog.o + +include $(TOPDIR)/post/rules.mk diff --git a/post/cpu/mpc8xx/cache_8xx.S b/post/cpu/mpc8xx/cache_8xx.S new file mode 100644 index 000000000..2d41b5566 --- /dev/null +++ b/post/cpu/mpc8xx/cache_8xx.S @@ -0,0 +1,495 @@ +/* + *  Copyright (C) 2002 Wolfgang Denk <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 <config.h> + +#ifdef CONFIG_POST +#if defined(CONFIG_MPC823) || \ +    defined(CONFIG_MPC850) || \ +    defined(CONFIG_MPC855) || \ +    defined(CONFIG_MPC860) || \ +    defined(CONFIG_MPC862) + +#include <post.h> +#include <ppc_asm.tmpl> +#include <ppc_defs.h> +#include <asm/cache.h> + +#if CONFIG_POST & CFG_POST_CACHE + +	.text + +cache_post_dinvalidate: +	lis	r10, IDC_INVALL@h +	mtspr	DC_CST, r10 +	blr + +cache_post_iinvalidate: +	lis	r10, IDC_INVALL@h +	mtspr	IC_CST, r10 +	isync +	blr + +cache_post_ddisable: +	lis	r10, IDC_DISABLE@h +	mtspr	DC_CST, r10 +	blr + +cache_post_dwb: +	lis	r10, IDC_ENABLE@h +	mtspr	DC_CST, r10 +	lis	r10, DC_CFWT@h +	mtspr	DC_CST, r10 +	blr + +cache_post_dwt: +	lis	r10, IDC_ENABLE@h +	mtspr	DC_CST, r10 +	lis	r10, DC_SFWT@h +	mtspr	DC_CST, r10 +	blr + +cache_post_idisable: +	lis	r10, IDC_DISABLE@h +	mtspr	IC_CST, r10 +	isync +	blr + +cache_post_ienable: +	lis	r10, IDC_ENABLE@h +	mtspr	IC_CST, r10 +	isync +	blr + +cache_post_iunlock: +	lis	r10, IDC_UNALL@h +	mtspr	IC_CST, r10 +	isync +	blr + +cache_post_ilock: +	mtspr	IC_ADR, r3 +	lis	r10, IDC_LDLCK@h +	mtspr	IC_CST, r10 +	isync +	blr + +/* + * turn on the data cache + * switch the data cache to write-back or write-through mode + * invalidate the data cache + * write the negative pattern to a cached area + * read the area + * + * The negative pattern must be read at the last step + */ +	.global cache_post_test1 +cache_post_test1: +	mflr	r0 +	stw	r0, 4(r1) + +	stwu	r3, -4(r1) +	stwu	r4, -4(r1) + +	bl	cache_post_dwb +	bl	cache_post_dinvalidate + +	/* Write the negative pattern to the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	li	r0, 0xff +	lwz	r3, 4(r1) +	subi	r3, r3, 1 +1: +	stbu	r0, 1(r3) +	bdnz	1b + +	/* Read the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	lwz	r4, 4(r1) +	subi	r4, r4, 1 +	li	r3, 0 +1: +	lbzu	r0, 1(r4) +	cmpli	cr0, r0, 0xff +	beq	2f +	li	r3, -1 +	b	3f +2: +	bdnz	1b +3: + +	bl	cache_post_ddisable +	bl	cache_post_dinvalidate + +	addi	r1, r1, 8 + +	lwz	r0, 4(r1) +	mtlr	r0 +	blr + +/* + * turn on the data cache + * switch the data cache to write-back or write-through mode + * invalidate the data cache + * write the zero pattern to a cached area + * turn off the data cache + * write the negative pattern to the area + * turn on the data cache + * read the area + * + * The negative pattern must be read at the last step + */ +	.global cache_post_test2 +cache_post_test2: +	mflr	r0 +	stw	r0, 4(r1) + +	stwu	r3, -4(r1) +	stwu	r4, -4(r1) + +	bl	cache_post_dwb +	bl	cache_post_dinvalidate + +	/* Write the zero pattern to the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	li	r0, 0 +	lwz	r3, 4(r1) +	subi	r3, r3, 1 +1: +	stbu	r0, 1(r3) +	bdnz	1b + +	bl	cache_post_ddisable + +	/* Write the negative pattern to the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	li	r0, 0xff +	lwz	r3, 4(r1) +	subi	r3, r3, 1 +1: +	stbu	r0, 1(r3) +	bdnz	1b + +	bl	cache_post_dwb + +	/* Read the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	lwz	r4, 4(r1) +	subi	r4, r4, 1 +	li	r3, 0 +1: +	lbzu	r0, 1(r4) +	cmpli	cr0, r0, 0xff +	beq	2f +	li	r3, -1 +	b	3f +2: +	bdnz	1b +3: + +	bl	cache_post_ddisable +	bl	cache_post_dinvalidate + +	addi	r1, r1, 8 + +	lwz	r0, 4(r1) +	mtlr	r0 +	blr + +/* + * turn on the data cache + * switch the data cache to write-through mode + * invalidate the data cache + * write the zero pattern to a cached area + * flush the data cache + * write the negative pattern to the area + * turn off the data cache + * read the area + * + * The negative pattern must be read at the last step + */ +	.global cache_post_test3 +cache_post_test3: +	mflr	r0 +	stw	r0, 4(r1) + +	stwu	r3, -4(r1) +	stwu	r4, -4(r1) + +	bl	cache_post_ddisable +	bl	cache_post_dinvalidate + +	/* Write the zero pattern to the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	li	r0, 0 +	lwz	r3, 4(r1) +	subi	r3, r3, 1 +1: +	stbu	r0, 1(r3) +	bdnz	1b + +	bl	cache_post_dwt +	bl	cache_post_dinvalidate + +	/* Write the negative pattern to the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	li	r0, 0xff +	lwz	r3, 4(r1) +	subi	r3, r3, 1 +1: +	stbu	r0, 1(r3) +	bdnz	1b + +	bl	cache_post_ddisable +	bl	cache_post_dinvalidate + +	/* Read the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	lwz	r4, 4(r1) +	subi	r4, r4, 1 +	li	r3, 0 +1: +	lbzu	r0, 1(r4) +	cmpli	cr0, r0, 0xff +	beq	2f +	li	r3, -1 +	b	3f +2: +	bdnz	1b +3: + +	addi	r1, r1, 8 + +	lwz	r0, 4(r1) +	mtlr	r0 +	blr + +/* + * turn on the data cache + * switch the data cache to write-back mode + * invalidate the data cache + * write the negative pattern to a cached area + * flush the data cache + * write the zero pattern to the area + * invalidate the data cache + * read the area + * + * The negative pattern must be read at the last step + */ +	.global cache_post_test4 +cache_post_test4: +	mflr	r0 +	stw	r0, 4(r1) + +	stwu	r3, -4(r1) +	stwu	r4, -4(r1) + +	bl	cache_post_ddisable +	bl	cache_post_dinvalidate + +	/* Write the negative pattern to the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	li	r0, 0xff +	lwz	r3, 4(r1) +	subi	r3, r3, 1 +1: +	stbu	r0, 1(r3) +	bdnz	1b + +	bl	cache_post_dwb +	bl	cache_post_dinvalidate + +	/* Write the zero pattern to the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	li	r0, 0 +	lwz	r3, 4(r1) +	subi	r3, r3, 1 +1: +	stbu	r0, 1(r3) +	bdnz	1b + +	bl	cache_post_ddisable +	bl	cache_post_dinvalidate + +	/* Read the test area */ +	lwz	r0, 0(r1) +	mtctr	r0 +	lwz	r4, 4(r1) +	subi	r4, r4, 1 +	li	r3, 0 +1: +	lbzu	r0, 1(r4) +	cmpli	cr0, r0, 0xff +	beq	2f +	li	r3, -1 +	b	3f +2: +	bdnz	1b +3: + +	addi	r1, r1, 8 + +	lwz	r0, 4(r1) +	mtlr	r0 +	blr + +cache_post_test5_1: +	li	r3, 0 +cache_post_test5_2: +	li	r3, -1 + +/* + * turn on the instruction cache + * unlock the entire instruction cache + * invalidate the instruction cache + * lock a branch instruction in the instruction cache + * replace the branch instruction with "nop" + * jump to the branch instruction + * check that the branch instruction was executed +*/ +	.global cache_post_test5 +cache_post_test5: +	mflr	r0 +	stw	r0, 4(r1) + +	bl	cache_post_ienable +	bl	cache_post_iunlock +	bl	cache_post_iinvalidate + +	/* Compute r9 = cache_post_test5_reloc */ +	bl	cache_post_test5_reloc +cache_post_test5_reloc: +	mflr	r9 + +	/* Copy the test instruction to cache_post_test5_data */ +	lis	r3, (cache_post_test5_1 - cache_post_test5_reloc)@h +	ori	r3, r3, (cache_post_test5_1 - cache_post_test5_reloc)@l +	add	r3, r3, r9 +	lis	r4, (cache_post_test5_data - cache_post_test5_reloc)@h +	ori	r4, r4, (cache_post_test5_data - cache_post_test5_reloc)@l +	add	r4, r4, r9 +	lwz	r0, 0(r3) +	stw	r0, 0(r4) + +	bl	cache_post_iinvalidate + +	/* Lock the branch instruction */ +	lis	r3, (cache_post_test5_data - cache_post_test5_reloc)@h +	ori	r3, r3, (cache_post_test5_data - cache_post_test5_reloc)@l +	add	r3, r3, r9 +	bl	cache_post_ilock + +	/* Replace the test instruction */ +	lis	r3, (cache_post_test5_2 - cache_post_test5_reloc)@h +	ori	r3, r3, (cache_post_test5_2 - cache_post_test5_reloc)@l +	add	r3, r3, r9 +	lis	r4, (cache_post_test5_data - cache_post_test5_reloc)@h +	ori	r4, r4, (cache_post_test5_data - cache_post_test5_reloc)@l +	add	r4, r4, r9 +	lwz	r0, 0(r3) +	stw	r0, 0(r4) + +	bl	cache_post_iinvalidate + +	/* Execute to the test instruction */ +cache_post_test5_data: +	nop + +	bl	cache_post_iunlock + +	lwz	r0, 4(r1) +	mtlr	r0 +	blr + +cache_post_test6_1: +	li	r3, -1 +cache_post_test6_2: +	li	r3, 0 + +/* + * turn on the instruction cache + * unlock the entire instruction cache + * invalidate the instruction cache + * lock a branch instruction in the instruction cache + * replace the branch instruction with "nop" + * jump to the branch instruction + * check that the branch instruction was executed + */ +	.global cache_post_test6 +cache_post_test6: +	mflr	r0 +	stw	r0, 4(r1) + +	bl	cache_post_ienable +	bl	cache_post_iunlock +	bl	cache_post_iinvalidate + +	/* Compute r9 = cache_post_test6_reloc */ +	bl	cache_post_test6_reloc +cache_post_test6_reloc: +	mflr	r9 + +	/* Copy the test instruction to cache_post_test6_data */ +	lis	r3, (cache_post_test6_1 - cache_post_test6_reloc)@h +	ori	r3, r3, (cache_post_test6_1 - cache_post_test6_reloc)@l +	add	r3, r3, r9 +	lis	r4, (cache_post_test6_data - cache_post_test6_reloc)@h +	ori	r4, r4, (cache_post_test6_data - cache_post_test6_reloc)@l +	add	r4, r4, r9 +	lwz	r0, 0(r3) +	stw	r0, 0(r4) + +	bl	cache_post_iinvalidate + +	/* Replace the test instruction */ +	lis	r3, (cache_post_test6_2 - cache_post_test6_reloc)@h +	ori	r3, r3, (cache_post_test6_2 - cache_post_test6_reloc)@l +	add	r3, r3, r9 +	lis	r4, (cache_post_test6_data - cache_post_test6_reloc)@h +	ori	r4, r4, (cache_post_test6_data - cache_post_test6_reloc)@l +	add	r4, r4, r9 +	lwz	r0, 0(r3) +	stw	r0, 0(r4) + +	bl	cache_post_iinvalidate + +	/* Execute to the test instruction */ +cache_post_test6_data: +	nop + +	lwz	r0, 4(r1) +	mtlr	r0 +	blr + +#endif /* CONFIG_MPC823 || MPC850 || MPC855 || MPC860 */ +#endif /* CONFIG_POST & CFG_POST_CACHE */ +#endif /* CONFIG_POST */ diff --git a/post/cpu/mpc8xx/ether.c b/post/cpu/mpc8xx/ether.c new file mode 100644 index 000000000..8c87b5927 --- /dev/null +++ b/post/cpu/mpc8xx/ether.c @@ -0,0 +1,631 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * Ethernet test + * + * The Serial Communication Controllers (SCC) listed in ctlr_list array below + * are tested in the loopback ethernet mode. + * The controllers are configured accordingly and several packets + * are transmitted. The configurable test parameters are: + *   MIN_PACKET_LENGTH - minimum size of packet to transmit + *   MAX_PACKET_LENGTH - maximum size of packet to transmit + *   TEST_NUM - number of tests + */ + +#ifdef CONFIG_POST + +#include <post.h> +#if CONFIG_POST & CFG_POST_ETHER +#if defined(CONFIG_8xx) +#include <commproc.h> +#elif defined(CONFIG_MPC8260) +#include <asm/cpm_8260.h> +#else +#error "Apparently a bad configuration, please fix." +#endif + +#include <command.h> +#include <net.h> +#include <serial.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define MIN_PACKET_LENGTH	64 +#define MAX_PACKET_LENGTH	256 +#define TEST_NUM		1 + +#define CTLR_SCC 0 + +extern void spi_init_f (void); +extern void spi_init_r (void); + +/* The list of controllers to test */ +#if defined(CONFIG_MPC823) +static int ctlr_list[][2] = { {CTLR_SCC, 1} }; +#else +static int ctlr_list[][2] = { }; +#endif + +#define CTRL_LIST_SIZE (sizeof(ctlr_list) / sizeof(ctlr_list[0])) + +static struct { +	void (*init) (int index); +	void (*halt) (int index); +	int (*send) (int index, volatile void *packet, int length); +	int (*recv) (int index, void *packet, int length); +} ctlr_proc[1]; + +static char *ctlr_name[1] = { "SCC" }; + +/* Ethernet Transmit and Receive Buffers */ +#define DBUF_LENGTH  1520 + +#define TX_BUF_CNT 2 + +#define TOUT_LOOP 100 + +static char txbuf[DBUF_LENGTH]; + +static uint rxIdx;		/* index of the current RX buffer */ +static uint txIdx;		/* index of the current TX buffer */ + +/* +  * SCC Ethernet Tx and Rx buffer descriptors allocated at the +  *  immr->udata_bd address on Dual-Port RAM +  * Provide for Double Buffering +  */ + +typedef volatile struct CommonBufferDescriptor { +	cbd_t rxbd[PKTBUFSRX];		/* Rx BD */ +	cbd_t txbd[TX_BUF_CNT];		/* Tx BD */ +} RTXBD; + +static RTXBD *rtx; + +  /* +   * SCC callbacks +   */ + +static void scc_init (int scc_index) +{ +	bd_t *bd = gd->bd; + +	static int proff[] = +			{ PROFF_SCC1, PROFF_SCC2, PROFF_SCC3, PROFF_SCC4 }; +	static unsigned int cpm_cr[] = +			{ CPM_CR_CH_SCC1, CPM_CR_CH_SCC2, CPM_CR_CH_SCC3, +CPM_CR_CH_SCC4 }; + +	int i; +	scc_enet_t *pram_ptr; + +	volatile immap_t *immr = (immap_t *) CFG_IMMR; + +	immr->im_cpm.cp_scc[scc_index].scc_gsmrl &= +			~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + +#if defined(CONFIG_FADS) +#if defined(CONFIG_MPC860T) || defined(CONFIG_MPC86xADS) +	/* The FADS860T and MPC86xADS don't use the MODEM_EN or DATA_VOICE signals. */ +	*((uint *) BCSR4) &= ~BCSR4_ETHLOOP; +	*((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL; +	*((uint *) BCSR1) &= ~BCSR1_ETHEN; +#else +	*((uint *) BCSR4) &= ~(BCSR4_ETHLOOP | BCSR4_MODEM_EN); +	*((uint *) BCSR4) |= BCSR4_TFPLDL | BCSR4_TPSQEL | BCSR4_DATA_VOICE; +	*((uint *) BCSR1) &= ~BCSR1_ETHEN; +#endif +#endif + +	pram_ptr = (scc_enet_t *) & (immr->im_cpm.cp_dparam[proff[scc_index]]); + +	rxIdx = 0; +	txIdx = 0; + +#ifdef CFG_ALLOC_DPRAM +	rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + +					 dpram_alloc_align (sizeof (RTXBD), 8)); +#else +	rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_SCC_BASE); +#endif + +#if 0 + +#if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD)) +	/* Configure port A pins for Txd and Rxd. +	 */ +	immr->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD); +	immr->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD); +	immr->im_ioport.iop_paodr &= ~PA_ENET_TXD; +#elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD)) +	/* Configure port B pins for Txd and Rxd. +	 */ +	immr->im_cpm.cp_pbpar |= (PB_ENET_RXD | PB_ENET_TXD); +	immr->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD); +	immr->im_cpm.cp_pbodr &= ~PB_ENET_TXD; +#else +#error Configuration Error: exactly ONE of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined +#endif + +#if defined(PC_ENET_LBK) +	/* Configure port C pins to disable External Loopback +	 */ +	immr->im_ioport.iop_pcpar &= ~PC_ENET_LBK; +	immr->im_ioport.iop_pcdir |= PC_ENET_LBK; +	immr->im_ioport.iop_pcso &= ~PC_ENET_LBK; +	immr->im_ioport.iop_pcdat &= ~PC_ENET_LBK;	/* Disable Loopback */ +#endif /* PC_ENET_LBK */ + +	/* Configure port C pins to enable CLSN and RENA. +	 */ +	immr->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA); +	immr->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA); +	immr->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); + +	/* Configure port A for TCLK and RCLK. +	 */ +	immr->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); +	immr->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); + +	/* +	 * Configure Serial Interface clock routing -- see section 16.7.5.3 +	 * First, clear all SCC bits to zero, then set the ones we want. +	 */ + +	immr->im_cpm.cp_sicr &= ~SICR_ENET_MASK; +	immr->im_cpm.cp_sicr |= SICR_ENET_CLKRT; +#else +	/* +	 * SCC2 receive clock is BRG2 +	 * SCC2 transmit clock is BRG3 +	 */ +	immr->im_cpm.cp_brgc2 = 0x0001000C; +	immr->im_cpm.cp_brgc3 = 0x0001000C; + +	immr->im_cpm.cp_sicr &= ~0x00003F00; +	immr->im_cpm.cp_sicr |=  0x00000a00; +#endif /* 0 */ + + +	/* +	 * Initialize SDCR -- see section 16.9.23.7 +	 * SDMA configuration register +	 */ +	immr->im_siu_conf.sc_sdcr = 0x01; + + +	/* +	 * Setup SCC Ethernet Parameter RAM +	 */ + +	pram_ptr->sen_genscc.scc_rfcr = 0x18;	/* Normal Operation and Mot byte ordering */ +	pram_ptr->sen_genscc.scc_tfcr = 0x18;	/* Mot byte ordering, Normal access */ + +	pram_ptr->sen_genscc.scc_mrblr = DBUF_LENGTH;	/* max. ET package len 1520 */ + +	pram_ptr->sen_genscc.scc_rbase = (unsigned int) (&rtx->rxbd[0]);	/* Set RXBD tbl start at Dual Port */ +	pram_ptr->sen_genscc.scc_tbase = (unsigned int) (&rtx->txbd[0]);	/* Set TXBD tbl start at Dual Port */ + +	/* +	 * Setup Receiver Buffer Descriptors (13.14.24.18) +	 * Settings: +	 *     Empty, Wrap +	 */ + +	for (i = 0; i < PKTBUFSRX; i++) { +		rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; +		rtx->rxbd[i].cbd_datlen = 0;	/* Reset */ +		rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i]; +	} + +	rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; + +	/* +	 * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19) +	 * Settings: +	 *    Add PADs to Short FRAMES, Wrap, Last, Tx CRC +	 */ + +	for (i = 0; i < TX_BUF_CNT; i++) { +		rtx->txbd[i].cbd_sc = +				(BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC); +		rtx->txbd[i].cbd_datlen = 0;	/* Reset */ +		rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]); +	} + +	rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; + +	/* +	 * Enter Command:  Initialize Rx Params for SCC +	 */ + +	do {				/* Spin until ready to issue command    */ +		__asm__ ("eieio"); +	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG); +	/* Issue command */ +	immr->im_cpm.cp_cpcr = +			((CPM_CR_INIT_RX << 8) | (cpm_cr[scc_index] << 4) | +			 CPM_CR_FLG); +	do {				/* Spin until command processed     */ +		__asm__ ("eieio"); +	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG); + +	/* +	 * Ethernet Specific Parameter RAM +	 *     see table 13-16, pg. 660, +	 *     pg. 681 (example with suggested settings) +	 */ + +	pram_ptr->sen_cpres = ~(0x0);	/* Preset CRC */ +	pram_ptr->sen_cmask = 0xdebb20e3;	/* Constant Mask for CRC */ +	pram_ptr->sen_crcec = 0x0;	/* Error Counter CRC (unused) */ +	pram_ptr->sen_alec = 0x0;	/* Alignment Error Counter (unused) */ +	pram_ptr->sen_disfc = 0x0;	/* Discard Frame Counter (unused) */ +	pram_ptr->sen_pads = 0x8888;	/* Short Frame PAD Characters */ + +	pram_ptr->sen_retlim = 15;	/* Retry Limit Threshold */ +	pram_ptr->sen_maxflr = 1518;	/* MAX Frame Length Register */ +	pram_ptr->sen_minflr = 64;	/* MIN Frame Length Register */ + +	pram_ptr->sen_maxd1 = DBUF_LENGTH;	/* MAX DMA1 Length Register */ +	pram_ptr->sen_maxd2 = DBUF_LENGTH;	/* MAX DMA2 Length Register */ + +	pram_ptr->sen_gaddr1 = 0x0;	/* Group Address Filter 1 (unused) */ +	pram_ptr->sen_gaddr2 = 0x0;	/* Group Address Filter 2 (unused) */ +	pram_ptr->sen_gaddr3 = 0x0;	/* Group Address Filter 3 (unused) */ +	pram_ptr->sen_gaddr4 = 0x0;	/* Group Address Filter 4 (unused) */ + +#define ea bd->bi_enetaddr +	pram_ptr->sen_paddrh = (ea[5] << 8) + ea[4]; +	pram_ptr->sen_paddrm = (ea[3] << 8) + ea[2]; +	pram_ptr->sen_paddrl = (ea[1] << 8) + ea[0]; +#undef ea + +	pram_ptr->sen_pper = 0x0;	/* Persistence (unused) */ +	pram_ptr->sen_iaddr1 = 0x0;	/* Individual Address Filter 1 (unused) */ +	pram_ptr->sen_iaddr2 = 0x0;	/* Individual Address Filter 2 (unused) */ +	pram_ptr->sen_iaddr3 = 0x0;	/* Individual Address Filter 3 (unused) */ +	pram_ptr->sen_iaddr4 = 0x0;	/* Individual Address Filter 4 (unused) */ +	pram_ptr->sen_taddrh = 0x0;	/* Tmp Address (MSB) (unused) */ +	pram_ptr->sen_taddrm = 0x0;	/* Tmp Address (unused) */ +	pram_ptr->sen_taddrl = 0x0;	/* Tmp Address (LSB) (unused) */ + +	/* +	 * Enter Command:  Initialize Tx Params for SCC +	 */ + +	do {				/* Spin until ready to issue command    */ +		__asm__ ("eieio"); +	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG); +	/* Issue command */ +	immr->im_cpm.cp_cpcr = +			((CPM_CR_INIT_TX << 8) | (cpm_cr[scc_index] << 4) | +			 CPM_CR_FLG); +	do {				/* Spin until command processed     */ +		__asm__ ("eieio"); +	} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG); + +	/* +	 * Mask all Events in SCCM - we use polling mode +	 */ +	immr->im_cpm.cp_scc[scc_index].scc_sccm = 0; + +	/* +	 * Clear Events in SCCE -- Clear bits by writing 1's +	 */ + +	immr->im_cpm.cp_scc[scc_index].scc_scce = ~(0x0); + + +	/* +	 * Initialize GSMR High 32-Bits +	 * Settings:  Normal Mode +	 */ + +	immr->im_cpm.cp_scc[scc_index].scc_gsmrh = 0; + +	/* +	 * Initialize GSMR Low 32-Bits, but do not Enable Transmit/Receive +	 * Settings: +	 *     TCI = Invert +	 *     TPL =  48 bits +	 *     TPP = Repeating 10's +	 *     LOOP = Loopback +	 *     MODE = Ethernet +	 */ + +	immr->im_cpm.cp_scc[scc_index].scc_gsmrl = (SCC_GSMRL_TCI | +						    SCC_GSMRL_TPL_48 | +						    SCC_GSMRL_TPP_10 | +						    SCC_GSMRL_DIAG_LOOP | +						    SCC_GSMRL_MODE_ENET); + +	/* +	 * Initialize the DSR -- see section 13.14.4 (pg. 513) v0.4 +	 */ + +	immr->im_cpm.cp_scc[scc_index].scc_dsr = 0xd555; + +	/* +	 * Initialize the PSMR +	 * Settings: +	 *  CRC = 32-Bit CCITT +	 *  NIB = Begin searching for SFD 22 bits after RENA +	 *  LPB = Loopback Enable (Needed when FDE is set) +	 */ +	immr->im_cpm.cp_scc[scc_index].scc_psmr = SCC_PSMR_ENCRC | +			SCC_PSMR_NIB22 | SCC_PSMR_LPB; + +#if 0 +	/* +	 * Configure Ethernet TENA Signal +	 */ + +#if (defined(PC_ENET_TENA) && !defined(PB_ENET_TENA)) +	immr->im_ioport.iop_pcpar |= PC_ENET_TENA; +	immr->im_ioport.iop_pcdir &= ~PC_ENET_TENA; +#elif (defined(PB_ENET_TENA) && !defined(PC_ENET_TENA)) +	immr->im_cpm.cp_pbpar |= PB_ENET_TENA; +	immr->im_cpm.cp_pbdir |= PB_ENET_TENA; +#else +#error Configuration Error: exactly ONE of PB_ENET_TENA, PC_ENET_TENA must be defined +#endif + +#if defined(CONFIG_ADS) && defined(CONFIG_MPC860) +	/* +	 * Port C is used to control the PHY,MC68160. +	 */ +	immr->im_ioport.iop_pcdir |= +			(PC_ENET_ETHLOOP | PC_ENET_TPFLDL | PC_ENET_TPSQEL); + +	immr->im_ioport.iop_pcdat |= PC_ENET_TPFLDL; +	immr->im_ioport.iop_pcdat &= ~(PC_ENET_ETHLOOP | PC_ENET_TPSQEL); +	*((uint *) BCSR1) &= ~BCSR1_ETHEN; +#endif /* MPC860ADS */ + +#if defined(CONFIG_AMX860) +	/* +	 * Port B is used to control the PHY,MC68160. +	 */ +	immr->im_cpm.cp_pbdir |= +			(PB_ENET_ETHLOOP | PB_ENET_TPFLDL | PB_ENET_TPSQEL); + +	immr->im_cpm.cp_pbdat |= PB_ENET_TPFLDL; +	immr->im_cpm.cp_pbdat &= ~(PB_ENET_ETHLOOP | PB_ENET_TPSQEL); + +	immr->im_ioport.iop_pddir |= PD_ENET_ETH_EN; +	immr->im_ioport.iop_pddat &= ~PD_ENET_ETH_EN; +#endif /* AMX860 */ + +#endif /* 0 */ + +#ifdef CONFIG_RPXCLASSIC +	*((uchar *) BCSR0) &= ~BCSR0_ETHLPBK; +	*((uchar *) BCSR0) |= (BCSR0_ETHEN | BCSR0_COLTEST | BCSR0_FULLDPLX); +#endif + +#ifdef CONFIG_RPXLITE +	*((uchar *) BCSR0) |= BCSR0_ETHEN; +#endif + +#ifdef CONFIG_MBX +	board_ether_init (); +#endif + +	/* +	 * Set the ENT/ENR bits in the GSMR Low -- Enable Transmit/Receive +	 */ + +	immr->im_cpm.cp_scc[scc_index].scc_gsmrl |= +			(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + +	/* +	 * Work around transmit problem with first eth packet +	 */ +#if defined (CONFIG_FADS) +	udelay (10000);				/* wait 10 ms */ +#elif defined (CONFIG_AMX860) || defined(CONFIG_RPXCLASSIC) +	udelay (100000);			/* wait 100 ms */ +#endif +} + +static void scc_halt (int scc_index) +{ +	volatile immap_t *immr = (immap_t *) CFG_IMMR; + +	immr->im_cpm.cp_scc[scc_index].scc_gsmrl &= +			~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); +	immr->im_ioport.iop_pcso  &=  ~(PC_ENET_CLSN | PC_ENET_RENA); +} + +static int scc_send (int index, volatile void *packet, int length) +{ +	int i, j = 0; + +	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j < TOUT_LOOP)) { +		udelay (1);		/* will also trigger Wd if needed */ +		j++; +	} +	if (j >= TOUT_LOOP) +		printf ("TX not ready\n"); +	rtx->txbd[txIdx].cbd_bufaddr = (uint) packet; +	rtx->txbd[txIdx].cbd_datlen = length; +	rtx->txbd[txIdx].cbd_sc |= +			(BD_ENET_TX_READY | BD_ENET_TX_LAST | BD_ENET_TX_WRAP); +	while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j < TOUT_LOOP)) { +		udelay (1);		/* will also trigger Wd if needed */ +		j++; +	} +	if (j >= TOUT_LOOP) +		printf ("TX timeout\n"); +	i = (rtx->txbd[txIdx]. +		 cbd_sc & BD_ENET_TX_STATS) /* return only status bits */ ; +	return i; +} + +static int scc_recv (int index, void *packet, int max_length) +{ +	int length = -1; + +	if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { +		goto Done;		/* nothing received */ +	} + +	if (!(rtx->rxbd[rxIdx].cbd_sc & 0x003f)) { +		length = rtx->rxbd[rxIdx].cbd_datlen - 4; +		memcpy (packet, +				(void *) (NetRxPackets[rxIdx]), +				length < max_length ? length : max_length); +	} + +	/* Give the buffer back to the SCC. */ +	rtx->rxbd[rxIdx].cbd_datlen = 0; + +	/* wrap around buffer index when necessary */ +	if ((rxIdx + 1) >= PKTBUFSRX) { +		rtx->rxbd[PKTBUFSRX - 1].cbd_sc = +				(BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); +		rxIdx = 0; +	} else { +		rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; +		rxIdx++; +	} + +Done: +	return length; +} + +  /* +   * Test routines +   */ + +static void packet_fill (char *packet, int length) +{ +	char c = (char) length; +	int i; + +	packet[0] = 0xFF; +	packet[1] = 0xFF; +	packet[2] = 0xFF; +	packet[3] = 0xFF; +	packet[4] = 0xFF; +	packet[5] = 0xFF; + +	for (i = 6; i < length; i++) { +		packet[i] = c++; +	} +} + +static int packet_check (char *packet, int length) +{ +	char c = (char) length; +	int i; + +	for (i = 6; i < length; i++) { +		if (packet[i] != c++) +			return -1; +	} + +	return 0; +} + +static int test_ctlr (int ctlr, int index) +{ +	int res = -1; +	char packet_send[MAX_PACKET_LENGTH]; +	char packet_recv[MAX_PACKET_LENGTH]; +	int length; +	int i; +	int l; + +	ctlr_proc[ctlr].init (index); + +	for (i = 0; i < TEST_NUM; i++) { +		for (l = MIN_PACKET_LENGTH; l <= MAX_PACKET_LENGTH; l++) { +			packet_fill (packet_send, l); + +			ctlr_proc[ctlr].send (index, packet_send, l); + +			length = ctlr_proc[ctlr].recv (index, packet_recv, +							MAX_PACKET_LENGTH); + +			if (length != l || packet_check (packet_recv, length) < 0) { +				goto Done; +			} +		} +	} + +	res = 0; + +Done: + +	ctlr_proc[ctlr].halt (index); + +	/* +	 * SCC2 Ethernet parameter RAM space overlaps +	 * the SPI parameter RAM space. So we need to restore +	 * the SPI configuration after SCC2 ethernet test. +	 */ +#if defined(CONFIG_SPI) +	if (ctlr == CTLR_SCC && index == 1) { +		spi_init_f (); +		spi_init_r (); +	} +#endif + +	if (res != 0) { +		post_log ("ethernet %s%d test failed\n", ctlr_name[ctlr], +				  index + 1); +	} + +	return res; +} + +int ether_post_test (int flags) +{ +	int res = 0; +	int i; + +	ctlr_proc[CTLR_SCC].init = scc_init; +	ctlr_proc[CTLR_SCC].halt = scc_halt; +	ctlr_proc[CTLR_SCC].send = scc_send; +	ctlr_proc[CTLR_SCC].recv = scc_recv; + +	for (i = 0; i < CTRL_LIST_SIZE; i++) { +		if (test_ctlr (ctlr_list[i][0], ctlr_list[i][1]) != 0) { +			res = -1; +		} +	} + +#if !defined(CONFIG_8xx_CONS_NONE) +	serial_reinit_all (); +#endif +	return res; +} + +#endif /* CONFIG_POST & CFG_POST_ETHER */ + +#endif /* CONFIG_POST */ diff --git a/post/cpu/mpc8xx/spr.c b/post/cpu/mpc8xx/spr.c new file mode 100644 index 000000000..330b977f1 --- /dev/null +++ b/post/cpu/mpc8xx/spr.c @@ -0,0 +1,152 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * SPR test + * + * The test checks the contents of Special Purpose Registers (SPR) listed + * in the spr_test_list array below. + * Each SPR value is read using mfspr instruction, some bits are masked + * according to the table and the resulting value is compared to the + * corresponding table value. + */ + +#ifdef CONFIG_POST + +#include <post.h> + +#if CONFIG_POST & CFG_POST_SPR + +static struct +{ +    int number; +    char * name; +    unsigned long mask; +    unsigned long value; +} spr_test_list [] = { +	/* Standard Special-Purpose Registers */ + +	{1,	"XER",		0x00000000,	0x00000000}, +	{8,	"LR",		0x00000000,	0x00000000}, +	{9,	"CTR",		0x00000000,	0x00000000}, +	{18,	"DSISR",	0x00000000,	0x00000000}, +	{19,	"DAR",		0x00000000,	0x00000000}, +	{22,	"DEC",		0x00000000,	0x00000000}, +	{26,	"SRR0",		0x00000000,	0x00000000}, +	{27,	"SRR1",		0x00000000,	0x00000000}, +	{272,	"SPRG0",	0x00000000,	0x00000000}, +	{273,	"SPRG1",	0x00000000,	0x00000000}, +	{274,	"SPRG2",	0x00000000,	0x00000000}, +	{275,	"SPRG3",	0x00000000,	0x00000000}, +	{287,	"PVR",		0xFFFF0000,	0x00500000}, + +	/* Additional Special-Purpose Registers */ + +	{144,	"CMPA",		0x00000000,	0x00000000}, +	{145,	"CMPB",		0x00000000,	0x00000000}, +	{146,	"CMPC",		0x00000000,	0x00000000}, +	{147,	"CMPD",		0x00000000,	0x00000000}, +	{148,	"ICR",		0xFFFFFFFF,	0x00000000}, +	{149,	"DER",		0x00000000,	0x00000000}, +	{150,	"COUNTA",	0xFFFFFFFF,	0x00000000}, +	{151,	"COUNTB",	0xFFFFFFFF,	0x00000000}, +	{152,	"CMPE",		0x00000000,	0x00000000}, +	{153,	"CMPF",		0x00000000,	0x00000000}, +	{154,	"CMPG",		0x00000000,	0x00000000}, +	{155,	"CMPH",		0x00000000,	0x00000000}, +	{156,	"LCTRL1",	0xFFFFFFFF,	0x00000000}, +	{157,	"LCTRL2",	0xFFFFFFFF,	0x00000000}, +	{158,	"ICTRL",	0xFFFFFFFF,	0x00000007}, +	{159,	"BAR",		0x00000000,	0x00000000}, +	{630,	"DPDR",		0x00000000,	0x00000000}, +	{631,	"DPIR",		0x00000000,	0x00000000}, +	{638,	"IMMR",		0xFFFF0000,	CFG_IMMR  }, +	{560,	"IC_CST",	0x8E380000,	0x00000000}, +	{561,	"IC_ADR",	0x00000000,	0x00000000}, +	{562,	"IC_DAT",	0x00000000,	0x00000000}, +	{568,	"DC_CST",	0xEF380000,	0x00000000}, +	{569,	"DC_ADR",	0x00000000,	0x00000000}, +	{570,	"DC_DAT",	0x00000000,	0x00000000}, +	{784,	"MI_CTR",	0xFFFFFFFF,	0x00000000}, +	{786,	"MI_AP",	0x00000000,	0x00000000}, +	{787,	"MI_EPN",	0x00000000,	0x00000000}, +	{789,	"MI_TWC",	0xFFFFFE02,	0x00000000}, +	{790,	"MI_RPN",	0x00000000,	0x00000000}, +	{816,	"MI_DBCAM",	0x00000000,	0x00000000}, +	{817,	"MI_DBRAM0",	0x00000000,	0x00000000}, +	{818,	"MI_DBRAM1",	0x00000000,	0x00000000}, +	{792,	"MD_CTR",	0xFFFFFFFF,	0x04000000}, +	{793,	"M_CASID",	0xFFFFFFF0,	0x00000000}, +	{794,	"MD_AP",	0x00000000,	0x00000000}, +	{795,	"MD_EPN",	0x00000000,	0x00000000}, +	{796,	"M_TWB",	0x00000003,	0x00000000}, +	{797,	"MD_TWC",	0x00000003,	0x00000000}, +	{798,	"MD_RPN",	0x00000000,	0x00000000}, +	{799,	"M_TW",		0x00000000,	0x00000000}, +	{824,	"MD_DBCAM",	0x00000000,	0x00000000}, +	{825,	"MD_DBRAM0",	0x00000000,	0x00000000}, +	{826,	"MD_DBRAM1",	0x00000000,	0x00000000}, +}; + +static int spr_test_list_size = +		sizeof (spr_test_list) / sizeof (spr_test_list[0]); + +int spr_post_test (int flags) +{ +	int ret = 0; +	int ic = icache_status (); +	int i; + +	unsigned long code[] = { +		0x7c6002a6,				/* mfspr r3,SPR */ +		0x4e800020				/* blr          */ +	}; +	unsigned long (*get_spr) (void) = (void *) code; + +	if (ic) +		icache_disable (); + +	for (i = 0; i < spr_test_list_size; i++) { +		int num = spr_test_list[i].number; + +		/* mfspr r3,num */ +		code[0] = 0x7c6002a6 | ((num & 0x1F) << 16) | ((num & 0x3E0) << 6); + +		if ((get_spr () & spr_test_list[i].mask) != +			(spr_test_list[i].value & spr_test_list[i].mask)) { +			post_log ("The value of %s special register " +				  "is incorrect: 0x%08X\n", +					spr_test_list[i].name, get_spr ()); +			ret = -1; +		} +	} + +	if (ic) +		icache_enable (); + +	return ret; +} +#endif /* CONFIG_POST & CFG_POST_SPR */ +#endif /* CONFIG_POST */ diff --git a/post/cpu/mpc8xx/uart.c b/post/cpu/mpc8xx/uart.c new file mode 100644 index 000000000..fd97e3899 --- /dev/null +++ b/post/cpu/mpc8xx/uart.c @@ -0,0 +1,560 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * UART test + * + * The Serial Management Controllers (SMC) and the Serial Communication + * Controllers (SCC) listed in ctlr_list array below are tested in + * the loopback UART mode. + * The controllers are configured accordingly and several characters + * are transmitted. The configurable test parameters are: + *   MIN_PACKET_LENGTH - minimum size of packet to transmit + *   MAX_PACKET_LENGTH - maximum size of packet to transmit + *   TEST_NUM - number of tests + */ + +#ifdef CONFIG_POST + +#include <post.h> +#if CONFIG_POST & CFG_POST_UART +#if defined(CONFIG_8xx) +#include <commproc.h> +#elif defined(CONFIG_MPC8260) +#include <asm/cpm_8260.h> +#else +#error "Apparently a bad configuration, please fix." +#endif +#include <command.h> +#include <serial.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define CTLR_SMC 0 +#define CTLR_SCC 1 + +/* The list of controllers to test */ +#if defined(CONFIG_MPC823) +static int ctlr_list[][2] = +		{ {CTLR_SMC, 0}, {CTLR_SMC, 1}, {CTLR_SCC, 1} }; +#else +static int ctlr_list[][2] = { }; +#endif + +#define CTRL_LIST_SIZE (sizeof(ctlr_list) / sizeof(ctlr_list[0])) + +static struct { +	void (*init) (int index); +	void (*halt) (int index); +	void (*putc) (int index, const char c); +	int (*getc) (int index); +} ctlr_proc[2]; + +static char *ctlr_name[2] = { "SMC", "SCC" }; + +static int proff_smc[] = { PROFF_SMC1, PROFF_SMC2 }; +static int proff_scc[] = +		{ PROFF_SCC1, PROFF_SCC2, PROFF_SCC3, PROFF_SCC4 }; + +/* + * SMC callbacks + */ + +static void smc_init (int smc_index) +{ +	static int cpm_cr_ch[] = { CPM_CR_CH_SMC1, CPM_CR_CH_SMC2 }; + +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile smc_t *sp; +	volatile smc_uart_t *up; +	volatile cbd_t *tbdf, *rbdf; +	volatile cpm8xx_t *cp = &(im->im_cpm); +	uint dpaddr; + +	/* initialize pointers to SMC */ + +	sp = (smc_t *) & (cp->cp_smc[smc_index]); +	up = (smc_uart_t *) & cp->cp_dparam[proff_smc[smc_index]]; + +	/* Disable transmitter/receiver. +	 */ +	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + +	/* Enable SDMA. +	 */ +	im->im_siu_conf.sc_sdcr = 1; + +	/* clear error conditions */ +#ifdef	CFG_SDSR +	im->im_sdma.sdma_sdsr = CFG_SDSR; +#else +	im->im_sdma.sdma_sdsr = 0x83; +#endif + +	/* clear SDMA interrupt mask */ +#ifdef	CFG_SDMR +	im->im_sdma.sdma_sdmr = CFG_SDMR; +#else +	im->im_sdma.sdma_sdmr = 0x00; +#endif + +#if defined(CONFIG_FADS) +	/* Enable RS232 */ +	*((uint *) BCSR1) &= +			~(smc_index == 1 ? BCSR1_RS232EN_1 : BCSR1_RS232EN_2); +#endif + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) +	/* Enable Monitor Port Transceiver */ +	*((uchar *) BCSR0) |= BCSR0_ENMONXCVR; +#endif + +	/* Set the physical address of the host memory buffers in +	 * the buffer descriptors. +	 */ + +#ifdef CFG_ALLOC_DPRAM +	dpaddr = dpram_alloc_align (sizeof (cbd_t) * 2 + 2, 8); +#else +	dpaddr = CPM_POST_BASE; +#endif + +	/* Allocate space for two buffer descriptors in the DP ram. +	 * For now, this address seems OK, but it may have to +	 * change with newer versions of the firmware. +	 * damm: allocating space after the two buffers for rx/tx data +	 */ + +	rbdf = (cbd_t *) & cp->cp_dpmem[dpaddr]; +	rbdf->cbd_bufaddr = (uint) (rbdf + 2); +	rbdf->cbd_sc = 0; +	tbdf = rbdf + 1; +	tbdf->cbd_bufaddr = ((uint) (rbdf + 2)) + 1; +	tbdf->cbd_sc = 0; + +	/* Set up the uart parameters in the parameter ram. +	 */ +	up->smc_rbase = dpaddr; +	up->smc_tbase = dpaddr + sizeof (cbd_t); +	up->smc_rfcr = SMC_EB; +	up->smc_tfcr = SMC_EB; + +#if defined(CONFIG_MBX) +	board_serial_init (); +#endif + +	/* Set UART mode, 8 bit, no parity, one stop. +	 * Enable receive and transmit. +	 * Set local loopback mode. +	 */ +	sp->smc_smcmr = smcr_mk_clen (9) | SMCMR_SM_UART | (ushort) 0x0004; + +	/* Mask all interrupts and remove anything pending. +	 */ +	sp->smc_smcm = 0; +	sp->smc_smce = 0xff; + +	/* Set up the baud rate generator. +	 */ +	cp->cp_simode = 0x00000000; + +	cp->cp_brgc1 = +			(((gd->cpu_clk / 16 / gd->baudrate) - +			  1) << 1) | CPM_BRG_EN; + +	/* Make the first buffer the only buffer. +	 */ +	tbdf->cbd_sc |= BD_SC_WRAP; +	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + +	/* Single character receive. +	 */ +	up->smc_mrblr = 1; +	up->smc_maxidl = 0; + +	/* Initialize Tx/Rx parameters. +	 */ + +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; + +	cp->cp_cpcr = +			mk_cr_cmd (cpm_cr_ch[smc_index], CPM_CR_INIT_TRX) | CPM_CR_FLG; + +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; + +	/* Enable transmitter/receiver. +	 */ +	sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +} + +static void smc_halt(int smc_index) +{ +} + +static void smc_putc (int smc_index, const char c) +{ +	volatile cbd_t *tbdf; +	volatile char *buf; +	volatile smc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); + +	up = (smc_uart_t *) & cpmp->cp_dparam[proff_smc[smc_index]]; + +	tbdf = (cbd_t *) & cpmp->cp_dpmem[up->smc_tbase]; + +	/* Wait for last character to go. +	 */ + +	buf = (char *) tbdf->cbd_bufaddr; +#if 0 +	__asm__ ("eieio"); +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif + +	*buf = c; +	tbdf->cbd_datlen = 1; +	tbdf->cbd_sc |= BD_SC_READY; +	__asm__ ("eieio"); +#if 1 +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif +} + +static int smc_getc (int smc_index) +{ +	volatile cbd_t *rbdf; +	volatile unsigned char *buf; +	volatile smc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); +	unsigned char c; +	int i; + +	up = (smc_uart_t *) & cpmp->cp_dparam[proff_smc[smc_index]]; + +	rbdf = (cbd_t *) & cpmp->cp_dpmem[up->smc_rbase]; + +	/* Wait for character to show up. +	 */ +	buf = (unsigned char *) rbdf->cbd_bufaddr; +#if 0 +	while (rbdf->cbd_sc & BD_SC_EMPTY); +#else +	for (i = 100; i > 0; i--) { +		if (!(rbdf->cbd_sc & BD_SC_EMPTY)) +			break; +		udelay (1000); +	} + +	if (i == 0) +		return -1; +#endif +	c = *buf; +	rbdf->cbd_sc |= BD_SC_EMPTY; + +	return (c); +} + +  /* +   * SCC callbacks +   */ + +static void scc_init (int scc_index) +{ +	static int cpm_cr_ch[] = { +		CPM_CR_CH_SCC1, +		CPM_CR_CH_SCC2, +		CPM_CR_CH_SCC3, +		CPM_CR_CH_SCC4, +	}; + +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile scc_t *sp; +	volatile scc_uart_t *up; +	volatile cbd_t *tbdf, *rbdf; +	volatile cpm8xx_t *cp = &(im->im_cpm); +	uint dpaddr; + +	/* initialize pointers to SCC */ + +	sp = (scc_t *) & (cp->cp_scc[scc_index]); +	up = (scc_uart_t *) & cp->cp_dparam[proff_scc[scc_index]]; + +	/* Disable transmitter/receiver. +	 */ +	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + +	/* Allocate space for two buffer descriptors in the DP ram. +	 */ + +#ifdef CFG_ALLOC_DPRAM +	dpaddr = dpram_alloc_align (sizeof (cbd_t) * 2 + 2, 8); +#else +	dpaddr = CPM_POST_BASE; +#endif + +	/* Enable SDMA. +	 */ +	im->im_siu_conf.sc_sdcr = 0x0001; + +	/* Set the physical address of the host memory buffers in +	 * the buffer descriptors. +	 */ + +	rbdf = (cbd_t *) & cp->cp_dpmem[dpaddr]; +	rbdf->cbd_bufaddr = (uint) (rbdf + 2); +	rbdf->cbd_sc = 0; +	tbdf = rbdf + 1; +	tbdf->cbd_bufaddr = ((uint) (rbdf + 2)) + 1; +	tbdf->cbd_sc = 0; + +	/* Set up the baud rate generator. +	 */ +	cp->cp_sicr &= ~(0x000000FF << (8 * scc_index)); +	/* no |= needed, since BRG1 is 000 */ + +	cp->cp_brgc1 = +			(((gd->cpu_clk / 16 / gd->baudrate) - +			  1) << 1) | CPM_BRG_EN; + +	/* Set up the uart parameters in the parameter ram. +	 */ +	up->scc_genscc.scc_rbase = dpaddr; +	up->scc_genscc.scc_tbase = dpaddr + sizeof (cbd_t); + +	/* Initialize Tx/Rx parameters. +	 */ +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; +	cp->cp_cpcr = +			mk_cr_cmd (cpm_cr_ch[scc_index], CPM_CR_INIT_TRX) | CPM_CR_FLG; + +	while (cp->cp_cpcr & CPM_CR_FLG)	/* wait if cp is busy */ +		; + +	up->scc_genscc.scc_rfcr = SCC_EB | 0x05; +	up->scc_genscc.scc_tfcr = SCC_EB | 0x05; + +	up->scc_genscc.scc_mrblr = 1;	/* Single character receive */ +	up->scc_maxidl = 0;		/* disable max idle */ +	up->scc_brkcr = 1;		/* send one break character on stop TX */ +	up->scc_parec = 0; +	up->scc_frmec = 0; +	up->scc_nosec = 0; +	up->scc_brkec = 0; +	up->scc_uaddr1 = 0; +	up->scc_uaddr2 = 0; +	up->scc_toseq = 0; +	up->scc_char1 = 0x8000; +	up->scc_char2 = 0x8000; +	up->scc_char3 = 0x8000; +	up->scc_char4 = 0x8000; +	up->scc_char5 = 0x8000; +	up->scc_char6 = 0x8000; +	up->scc_char7 = 0x8000; +	up->scc_char8 = 0x8000; +	up->scc_rccm = 0xc0ff; + +	/* Set low latency / small fifo. +	 */ +	sp->scc_gsmrh = SCC_GSMRH_RFW; + +	/* Set UART mode +	 */ +	sp->scc_gsmrl &= ~0xF; +	sp->scc_gsmrl |= SCC_GSMRL_MODE_UART; + +	/* Set local loopback mode. +	 */ +	sp->scc_gsmrl &= ~SCC_GSMRL_DIAG_LE; +	sp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP; + +	/* Set clock divider 16 on Tx and Rx +	 */ +	sp->scc_gsmrl |= (SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + +	sp->scc_psmr |= SCU_PSMR_CL; + +	/* Mask all interrupts and remove anything pending. +	 */ +	sp->scc_sccm = 0; +	sp->scc_scce = 0xffff; +	sp->scc_dsr = 0x7e7e; +	sp->scc_psmr = 0x3000; + +	/* Make the first buffer the only buffer. +	 */ +	tbdf->cbd_sc |= BD_SC_WRAP; +	rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + +	/* Enable transmitter/receiver. +	 */ +	sp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); +} + +static void scc_halt(int scc_index) +{ +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cp = &(im->im_cpm); +	volatile scc_t *sp = (scc_t *) & (cp->cp_scc[scc_index]); + +	sp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT | SCC_GSMRL_DIAG_LE); +} + +static void scc_putc (int scc_index, const char c) +{ +	volatile cbd_t *tbdf; +	volatile char *buf; +	volatile scc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); + +	up = (scc_uart_t *) & cpmp->cp_dparam[proff_scc[scc_index]]; + +	tbdf = (cbd_t *) & cpmp->cp_dpmem[up->scc_genscc.scc_tbase]; + +	/* Wait for last character to go. +	 */ + +	buf = (char *) tbdf->cbd_bufaddr; +#if 0 +	__asm__ ("eieio"); +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif + +	*buf = c; +	tbdf->cbd_datlen = 1; +	tbdf->cbd_sc |= BD_SC_READY; +	__asm__ ("eieio"); +#if 1 +	while (tbdf->cbd_sc & BD_SC_READY) +		__asm__ ("eieio"); +#endif +} + +static int scc_getc (int scc_index) +{ +	volatile cbd_t *rbdf; +	volatile unsigned char *buf; +	volatile scc_uart_t *up; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cpmp = &(im->im_cpm); +	unsigned char c; +	int i; + +	up = (scc_uart_t *) & cpmp->cp_dparam[proff_scc[scc_index]]; + +	rbdf = (cbd_t *) & cpmp->cp_dpmem[up->scc_genscc.scc_rbase]; + +	/* Wait for character to show up. +	 */ +	buf = (unsigned char *) rbdf->cbd_bufaddr; +#if 0 +	while (rbdf->cbd_sc & BD_SC_EMPTY); +#else +	for (i = 100; i > 0; i--) { +		if (!(rbdf->cbd_sc & BD_SC_EMPTY)) +			break; +		udelay (1000); +	} + +	if (i == 0) +		return -1; +#endif +	c = *buf; +	rbdf->cbd_sc |= BD_SC_EMPTY; + +	return (c); +} + +  /* +   * Test routines +   */ + +static int test_ctlr (int ctlr, int index) +{ +	int res = -1; +	char test_str[] = "*** UART Test String ***\r\n"; +	int i; + +	ctlr_proc[ctlr].init (index); + +	for (i = 0; i < sizeof (test_str) - 1; i++) { +		ctlr_proc[ctlr].putc (index, test_str[i]); +		if (ctlr_proc[ctlr].getc (index) != test_str[i]) +			goto Done; +	} + +	res = 0; + +Done: +	ctlr_proc[ctlr].halt (index); + +	if (res != 0) { +		post_log ("uart %s%d test failed\n", +				ctlr_name[ctlr], index + 1); +	} + +	return res; +} + +int uart_post_test (int flags) +{ +	int res = 0; +	int i; + +	ctlr_proc[CTLR_SMC].init = smc_init; +	ctlr_proc[CTLR_SMC].halt = smc_halt; +	ctlr_proc[CTLR_SMC].putc = smc_putc; +	ctlr_proc[CTLR_SMC].getc = smc_getc; + +	ctlr_proc[CTLR_SCC].init = scc_init; +	ctlr_proc[CTLR_SCC].halt = scc_halt; +	ctlr_proc[CTLR_SCC].putc = scc_putc; +	ctlr_proc[CTLR_SCC].getc = scc_getc; + +	for (i = 0; i < CTRL_LIST_SIZE; i++) { +		if (test_ctlr (ctlr_list[i][0], ctlr_list[i][1]) != 0) { +			res = -1; +		} +	} + +#if !defined(CONFIG_8xx_CONS_NONE) +	serial_reinit_all (); +#endif + +	return res; +} + +#endif /* CONFIG_POST & CFG_POST_UART */ + +#endif /* CONFIG_POST */ diff --git a/post/cpu/mpc8xx/usb.c b/post/cpu/mpc8xx/usb.c new file mode 100644 index 000000000..0c74cfa5d --- /dev/null +++ b/post/cpu/mpc8xx/usb.c @@ -0,0 +1,269 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * USB test + * + * The USB controller is tested in the local loopback mode. + * It is configured so that endpoint 0 operates as host and endpoint 1 + * operates as function endpoint. After that an IN token transaction + * is performed. + * Refer to MPC850 User Manual, Section 32.11.1 USB Host Controller + * Initialization Example. + */ + +#ifdef CONFIG_POST + +#include <post.h> + +#if CONFIG_POST & CFG_POST_USB + +#include <commproc.h> +#include <command.h> + +#define TOUT_LOOP 100 + +#define	PROFF_USB		((uint)0x0000) + +#define CPM_USB_EP0_BASE	0x0a00 +#define CPM_USB_EP1_BASE	0x0a20 + +#define CPM_USB_DT0_BASE	0x0a80 +#define CPM_USB_DT1_BASE	0x0a90 +#define CPM_USB_DR0_BASE	0x0aa0 +#define CPM_USB_DR1_BASE	0x0ab0 + +#define CPM_USB_RX0_BASE	0x0b00 +#define CPM_USB_RX1_BASE	0x0b08 +#define CPM_USB_TX0_BASE	0x0b20 +#define CPM_USB_TX1_BASE	0x0b28 + +#define USB_EXPECT(x)		if (!(x)) goto Done; + +typedef struct usb_param { +	ushort ep0ptr; +	ushort ep1ptr; +	ushort ep2ptr; +	ushort ep3ptr; +	uint rstate; +	uint rptr; +	ushort frame_n; +	ushort rbcnt; +	ushort rtemp; +} usb_param_t; + +typedef struct usb_param_block { +	ushort rbase; +	ushort tbase; +	uchar rfcr; +	uchar tfcr; +	ushort mrblr; +	ushort rbptr; +	ushort tbptr; +	uint tstate; +	uint tptr; +	ushort tcrc; +	ushort tbcnt; +	uint res[2]; +} usb_param_block_t; + +typedef struct usb { +	uchar usmod; +	uchar usadr; +	uchar uscom; +	uchar res1; +	ushort usep[4]; +	uchar res2[4]; +	ushort usber; +	uchar res3[2]; +	ushort usbmr; +	uchar res4; +	uchar usbs; +	uchar res5[8]; +} usb_t; + +int usb_post_test (int flags) +{ +	int res = -1; +	volatile immap_t *im = (immap_t *) CFG_IMMR; +	volatile cpm8xx_t *cp = &(im->im_cpm); +	volatile usb_param_t *pram_ptr; +	uint dpram; +	ushort DPRAM; +	volatile cbd_t *tx; +	volatile cbd_t *rx; +	volatile usb_t *usbr; +	volatile usb_param_block_t *ep0; +	volatile usb_param_block_t *ep1; +	int j; + +	pram_ptr = (usb_param_t *) & (im->im_cpm.cp_dparam[PROFF_USB]); +	dpram = (uint) im->im_cpm.cp_dpmem; +	DPRAM = dpram; +	tx = (cbd_t *) (dpram + CPM_USB_TX0_BASE); +	rx = (cbd_t *) (dpram + CPM_USB_RX0_BASE); +	ep0 = (usb_param_block_t *) (dpram + CPM_USB_EP0_BASE); +	ep1 = (usb_param_block_t *) (dpram + CPM_USB_EP1_BASE); +	usbr = (usb_t *) & (im->im_cpm.cp_scc[0]); + +	/* 01 */ +	im->im_ioport.iop_padir &= ~(ushort) 0x0200; +	im->im_ioport.iop_papar |= (ushort) 0x0200; + +	cp->cp_sicr &= ~0x000000FF; +	cp->cp_sicr |= 0x00000018; + +	cp->cp_brgc4 = 0x00010001; + +	/* 02 */ +	im->im_ioport.iop_padir &= ~(ushort) 0x0002; +	im->im_ioport.iop_padir &= ~(ushort) 0x0001; + +	im->im_ioport.iop_papar |= (ushort) 0x0002; +	im->im_ioport.iop_papar |= (ushort) 0x0001; + +	/* 03 */ +	im->im_ioport.iop_pcdir &= ~(ushort) 0x0020; +	im->im_ioport.iop_pcdir &= ~(ushort) 0x0010; + +	im->im_ioport.iop_pcpar &= ~(ushort) 0x0020; +	im->im_ioport.iop_pcpar &= ~(ushort) 0x0010; + +	im->im_ioport.iop_pcso |= (ushort) 0x0020; +	im->im_ioport.iop_pcso |= (ushort) 0x0010; + +	/* 04 */ +	im->im_ioport.iop_pcdir |= (ushort) 0x0200; +	im->im_ioport.iop_pcdir |= (ushort) 0x0100; + +	im->im_ioport.iop_pcpar |= (ushort) 0x0200; +	im->im_ioport.iop_pcpar |= (ushort) 0x0100; + +	/* 05 */ +	pram_ptr->frame_n = 0; + +	/* 06 */ +	pram_ptr->ep0ptr = DPRAM + CPM_USB_EP0_BASE; +	pram_ptr->ep1ptr = DPRAM + CPM_USB_EP1_BASE; + +	/* 07-10 */ +	tx[0].cbd_sc = 0xB800; +	tx[0].cbd_datlen = 3; +	tx[0].cbd_bufaddr = dpram + CPM_USB_DT0_BASE; + +	tx[1].cbd_sc = 0xBC80; +	tx[1].cbd_datlen = 3; +	tx[1].cbd_bufaddr = dpram + CPM_USB_DT1_BASE; + +	rx[0].cbd_sc = 0xA000; +	rx[0].cbd_datlen = 0; +	rx[0].cbd_bufaddr = dpram + CPM_USB_DR0_BASE; + +	rx[1].cbd_sc = 0xA000; +	rx[1].cbd_datlen = 0; +	rx[1].cbd_bufaddr = dpram + CPM_USB_DR1_BASE; + +	/* 11-12 */ +	*(volatile int *) (dpram + CPM_USB_DT0_BASE) = 0x69856000; +	*(volatile int *) (dpram + CPM_USB_DT1_BASE) = 0xABCD1234; + +	*(volatile int *) (dpram + CPM_USB_DR0_BASE) = 0; +	*(volatile int *) (dpram + CPM_USB_DR1_BASE) = 0; + +	/* 13-16 */ +	ep0->rbase = DPRAM + CPM_USB_RX0_BASE; +	ep0->tbase = DPRAM + CPM_USB_TX0_BASE; +	ep0->rfcr = 0x18; +	ep0->tfcr = 0x18; +	ep0->mrblr = 0x100; +	ep0->rbptr = DPRAM + CPM_USB_RX0_BASE; +	ep0->tbptr = DPRAM + CPM_USB_TX0_BASE; +	ep0->tstate = 0; + +	/* 17-20 */ +	ep1->rbase = DPRAM + CPM_USB_RX1_BASE; +	ep1->tbase = DPRAM + CPM_USB_TX1_BASE; +	ep1->rfcr = 0x18; +	ep1->tfcr = 0x18; +	ep1->mrblr = 0x100; +	ep1->rbptr = DPRAM + CPM_USB_RX1_BASE; +	ep1->tbptr = DPRAM + CPM_USB_TX1_BASE; +	ep1->tstate = 0; + +	/* 21-24 */ +	usbr->usep[0] = 0x0000; +	usbr->usep[1] = 0x1100; +	usbr->usep[2] = 0x2200; +	usbr->usep[3] = 0x3300; + +	/* 25 */ +	usbr->usmod = 0x06; + +	/* 26 */ +	usbr->usadr = 0x05; + +	/* 27 */ +	usbr->uscom = 0; + +	/* 28 */ +	usbr->usmod |= 0x01; +	udelay (1); + +	/* 29-30 */ +	usbr->uscom = 0x80; +	usbr->uscom = 0x81; + +	/* Wait for the data packet to be transmitted */ +	for (j = 0; j < TOUT_LOOP; j++) { +		if (tx[1].cbd_sc & (ushort) 0x8000) +			udelay (1); +		else +			break; +	} + +	USB_EXPECT (j < TOUT_LOOP); + +	USB_EXPECT (tx[0].cbd_sc == 0x3800); +	USB_EXPECT (tx[0].cbd_datlen == 3); + +	USB_EXPECT (tx[1].cbd_sc == 0x3C80); +	USB_EXPECT (tx[1].cbd_datlen == 3); + +	USB_EXPECT (rx[0].cbd_sc == 0x2C00); +	USB_EXPECT (rx[0].cbd_datlen == 5); + +	USB_EXPECT (*(volatile int *) (dpram + CPM_USB_DR0_BASE) == +				0xABCD122B); +	USB_EXPECT (*(volatile char *) (dpram + CPM_USB_DR0_BASE + 4) == 0x42); + +	res = 0; +  Done: + +	return res; +} + +#endif /* CONFIG_POST & CFG_POST_USB */ + +#endif /* CONFIG_POST */ diff --git a/post/cpu/mpc8xx/watchdog.c b/post/cpu/mpc8xx/watchdog.c new file mode 100644 index 000000000..48c4282e1 --- /dev/null +++ b/post/cpu/mpc8xx/watchdog.c @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * Watchdog test + * + * The test verifies the watchdog timer operation. + * On the first iteration, the test routine disables interrupts and + * makes a 10-second delay. If the system does not reboot during this delay, + * the watchdog timer is not operational and the test fails. If the system + * reboots, on the second iteration the test routine reports a success. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include <watchdog.h> + +#if CONFIG_POST & CFG_POST_WATCHDOG + +static ulong gettbl (void) +{ +	ulong r; + +  asm ("mftbl %0":"=r" (r)); + +	return r; +} + +int watchdog_post_test (int flags) +{ +	if (flags & POST_REBOOT) { +		/* Test passed */ + +		return 0; +	} else { +		/* 10-second delay */ +		int ints = disable_interrupts (); +		ulong base = gettbl (); +		ulong clk = get_tbclk (); + +		while ((gettbl () - base) / 10 < clk); + +		if (ints) +			enable_interrupts (); + +		/* +		 * If we have reached this point, the watchdog timer +		 * does not work +		 */ +		return -1; +	} +} + +#endif /* CONFIG_POST & CFG_POST_WATCHDOG */ +#endif /* CONFIG_POST */ diff --git a/post/drivers/Makefile b/post/drivers/Makefile new file mode 100644 index 000000000..068fa98b1 --- /dev/null +++ b/post/drivers/Makefile @@ -0,0 +1,31 @@ +# +# (C) Copyright 2002-2006 +# 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 +# + + +SUBDIRS = + +LIB	= libpostdrivers.a + +COBJS	= cache.o i2c.o memory.o rtc.o + +include $(TOPDIR)/post/rules.mk diff --git a/post/drivers/cache.c b/post/drivers/cache.c new file mode 100644 index 000000000..501465c06 --- /dev/null +++ b/post/drivers/cache.c @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* Cache test + * + * This test verifies the CPU data and instruction cache using + * several test scenarios. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include <watchdog.h> + +#if CONFIG_POST & CFG_POST_CACHE + +#define CACHE_POST_SIZE	1024 + +extern int cache_post_test1 (char *, unsigned int); +extern int cache_post_test2 (char *, unsigned int); +extern int cache_post_test3 (char *, unsigned int); +extern int cache_post_test4 (char *, unsigned int); +extern int cache_post_test5 (void); +extern int cache_post_test6 (void); + +int cache_post_test (int flags) +{ +	int ints = disable_interrupts (); +	int res = 0; +	static char ta[CACHE_POST_SIZE + 0xf]; +	char *testarea = (char *) (((unsigned long) ta + 0xf) & ~0xf); + +	WATCHDOG_RESET (); +	if (res == 0) +		res = cache_post_test1 (testarea, CACHE_POST_SIZE); +	WATCHDOG_RESET (); +	if (res == 0) +		res = cache_post_test2 (testarea, CACHE_POST_SIZE); +	WATCHDOG_RESET (); +	if (res == 0) +		res = cache_post_test3 (testarea, CACHE_POST_SIZE); +	WATCHDOG_RESET (); +	if (res == 0) +		res = cache_post_test4 (testarea, CACHE_POST_SIZE); +	WATCHDOG_RESET (); +	if (res == 0) +		res = cache_post_test5 (); +	WATCHDOG_RESET (); +	if (res == 0) +		res = cache_post_test6 (); + +	WATCHDOG_RESET (); +	if (ints) +		enable_interrupts (); +	return res; +} + +#endif /* CONFIG_POST & CFG_POST_CACHE */ +#endif /* CONFIG_POST */ diff --git a/post/drivers/i2c.c b/post/drivers/i2c.c new file mode 100644 index 000000000..1b2e64471 --- /dev/null +++ b/post/drivers/i2c.c @@ -0,0 +1,94 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +#ifdef CONFIG_POST + +/* + * I2C test + * + * For verifying the I2C bus, a full I2C bus scanning is performed. + * + * #ifdef I2C_ADDR_LIST + *   The test is considered as passed if all the devices and + *   only the devices in the list are found. + * #else [ ! I2C_ADDR_LIST ] + *   The test is considered as passed if any I2C device is found. + * #endif + */ + +#include <post.h> +#include <i2c.h> + +#if CONFIG_POST & CFG_POST_I2C + +int i2c_post_test (int flags) +{ +	unsigned int i; +	unsigned int good = 0; +#ifdef I2C_ADDR_LIST +	unsigned int bad  = 0; +	int j; +	unsigned char i2c_addr_list[] = I2C_ADDR_LIST; +	unsigned char i2c_miss_list[] = I2C_ADDR_LIST; +#endif + +	for (i = 0; i < 128; i++) { +		if (i2c_probe (i) == 0) { +#ifndef	I2C_ADDR_LIST +			good++; +#else	/* I2C_ADDR_LIST */ +			for (j=0; j<sizeof(i2c_addr_list); ++j) { +				if (i == i2c_addr_list[j]) { +					good++; +					i2c_miss_list[j] = 0xFF; +					break; +				} +			} +			if (j == sizeof(i2c_addr_list)) { +				bad++; +				post_log ("I2C: addr %02X not expected\n", +						i); +			} +#endif	/* I2C_ADDR_LIST */ +		} +	} + +#ifndef	I2C_ADDR_LIST +	return good > 0 ? 0 : -1; +#else	/* I2C_ADDR_LIST */ +	if (good != sizeof(i2c_addr_list)) { +		for (j=0; j<sizeof(i2c_miss_list); ++j) { +			if (i2c_miss_list[j] != 0xFF) { +				post_log ("I2C: addr %02X did not respond\n", +						i2c_miss_list[j]); +			} +		} +	} +	return ((good == sizeof(i2c_addr_list)) && (bad == 0)) ? 0 : -1; +#endif +} + +#endif /* CONFIG_POST & CFG_POST_I2C */ +#endif /* CONFIG_POST */ diff --git a/post/drivers/memory.c b/post/drivers/memory.c new file mode 100644 index 000000000..a2c088bad --- /dev/null +++ b/post/drivers/memory.c @@ -0,0 +1,483 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* Memory test + * + * General observations: + * o The recommended test sequence is to test the data lines: if they are + *   broken, nothing else will work properly.  Then test the address + *   lines.  Finally, test the cells in the memory now that the test + *   program knows that the address and data lines work properly. + *   This sequence also helps isolate and identify what is faulty. + * + * o For the address line test, it is a good idea to use the base + *   address of the lowest memory location, which causes a '1' bit to + *   walk through a field of zeros on the address lines and the highest + *   memory location, which causes a '0' bit to walk through a field of + *   '1's on the address line. + * + * o Floating buses can fool memory tests if the test routine writes + *   a value and then reads it back immediately.  The problem is, the + *   write will charge the residual capacitance on the data bus so the + *   bus retains its state briefely.  When the test program reads the + *   value back immediately, the capacitance of the bus can allow it + *   to read back what was written, even though the memory circuitry + *   is broken.  To avoid this, the test program should write a test + *   pattern to the target location, write a different pattern elsewhere + *   to charge the residual capacitance in a differnt manner, then read + *   the target location back. + * + * o Always read the target location EXACTLY ONCE and save it in a local + *   variable.  The problem with reading the target location more than + *   once is that the second and subsequent reads may work properly, + *   resulting in a failed test that tells the poor technician that + *   "Memory error at 00000000, wrote aaaaaaaa, read aaaaaaaa" which + *   doesn't help him one bit and causes puzzled phone calls.  Been there, + *   done that. + * + * Data line test: + * --------------- + * This tests data lines for shorts and opens by forcing adjacent data + * to opposite states. Because the data lines could be routed in an + * arbitrary manner the must ensure test patterns ensure that every case + * is tested. By using the following series of binary patterns every + * combination of adjacent bits is test regardless of routing. + * + *     ...101010101010101010101010 + *     ...110011001100110011001100 + *     ...111100001111000011110000 + *     ...111111110000000011111111 + * + * Carrying this out, gives us six hex patterns as follows: + * + *     0xaaaaaaaaaaaaaaaa + *     0xcccccccccccccccc + *     0xf0f0f0f0f0f0f0f0 + *     0xff00ff00ff00ff00 + *     0xffff0000ffff0000 + *     0xffffffff00000000 + * + * To test for short and opens to other signals on our boards, we + * simply test with the 1's complemnt of the paterns as well, resulting + * in twelve patterns total. + * + * After writing a test pattern. a special pattern 0x0123456789ABCDEF is + * written to a different address in case the data lines are floating. + * Thus, if a byte lane fails, you will see part of the special + * pattern in that byte lane when the test runs.  For example, if the + * xx__xxxxxxxxxxxx byte line fails, you will see aa23aaaaaaaaaaaa + * (for the 'a' test pattern). + * + * Address line test: + * ------------------ + *  This function performs a test to verify that all the address lines + *  hooked up to the RAM work properly.  If there is an address line + *  fault, it usually shows up as two different locations in the address + *  map (related by the faulty address line) mapping to one physical + *  memory storage location.  The artifact that shows up is writing to + *  the first location "changes" the second location. + * + * To test all address lines, we start with the given base address and + * xor the address with a '1' bit to flip one address line.  For each + * test, we shift the '1' bit left to test the next address line. + * + * In the actual code, we start with address sizeof(ulong) since our + * test pattern we use is a ulong and thus, if we tried to test lower + * order address bits, it wouldn't work because our pattern would + * overwrite itself. + * + * Example for a 4 bit address space with the base at 0000: + *   0000 <- base + *   0001 <- test 1 + *   0010 <- test 2 + *   0100 <- test 3 + *   1000 <- test 4 + * Example for a 4 bit address space with the base at 0010: + *   0010 <- base + *   0011 <- test 1 + *   0000 <- (below the base address, skipped) + *   0110 <- test 2 + *   1010 <- test 3 + * + * The test locations are successively tested to make sure that they are + * not "mirrored" onto the base address due to a faulty address line. + * Note that the base and each test location are related by one address + * line flipped.  Note that the base address need not be all zeros. + * + * Memory tests 1-4: + * ----------------- + * These tests verify RAM using sequential writes and reads + * to/from RAM. There are several test cases that use different patterns to + * verify RAM. Each test case fills a region of RAM with one pattern and + * then reads the region back and compares its contents with the pattern. + * The following patterns are used: + * + *  1a) zero pattern (0x00000000) + *  1b) negative pattern (0xffffffff) + *  1c) checkerboard pattern (0x55555555) + *  1d) checkerboard pattern (0xaaaaaaaa) + *  2)  bit-flip pattern ((1 << (offset % 32)) + *  3)  address pattern (offset) + *  4)  address pattern (~offset) + * + * Being run in normal mode, the test verifies only small 4Kb + * regions of RAM around each 1Mb boundary. For example, for 64Mb + * RAM the following areas are verified: 0x00000000-0x00000800, + * 0x000ff800-0x00100800, 0x001ff800-0x00200800, ..., 0x03fff800- + * 0x04000000. If the test is run in slow-test mode, it verifies + * the whole RAM. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include <watchdog.h> + +#if CONFIG_POST & CFG_POST_MEMORY + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Define INJECT_*_ERRORS for testing error detection in the presence of + * _good_ hardware. + */ +#undef  INJECT_DATA_ERRORS +#undef  INJECT_ADDRESS_ERRORS + +#ifdef INJECT_DATA_ERRORS +#warning "Injecting data line errors for testing purposes" +#endif + +#ifdef INJECT_ADDRESS_ERRORS +#warning "Injecting address line errors for testing purposes" +#endif + + +/* + * This function performs a double word move from the data at + * the source pointer to the location at the destination pointer. + * This is helpful for testing memory on processors which have a 64 bit + * wide data bus. + * + * On those PowerPC with FPU, use assembly and a floating point move: + * this does a 64 bit move. + * + * For other processors, let the compiler generate the best code it can. + */ +static void move64(unsigned long long *src, unsigned long long *dest) +{ +#if defined(CONFIG_MPC8260) || defined(CONFIG_MPC824X) +	asm ("lfd  0, 0(3)\n\t" /* fpr0	  =  *scr	*/ +	 "stfd 0, 0(4)"		/* *dest  =  fpr0	*/ +	 : : : "fr0" );		/* Clobbers fr0		*/ +    return; +#else +	*dest = *src; +#endif +} + +/* + * This is 64 bit wide test patterns.  Note that they reside in ROM + * (which presumably works) and the tests write them to RAM which may + * not work. + * + * The "otherpattern" is written to drive the data bus to values other + * than the test pattern.  This is for detecting floating bus lines. + * + */ +const static unsigned long long pattern[] = { +	0xaaaaaaaaaaaaaaaaULL, +	0xccccccccccccccccULL, +	0xf0f0f0f0f0f0f0f0ULL, +	0xff00ff00ff00ff00ULL, +	0xffff0000ffff0000ULL, +	0xffffffff00000000ULL, +	0x00000000ffffffffULL, +	0x0000ffff0000ffffULL, +	0x00ff00ff00ff00ffULL, +	0x0f0f0f0f0f0f0f0fULL, +	0x3333333333333333ULL, +	0x5555555555555555ULL +}; +const unsigned long long otherpattern = 0x0123456789abcdefULL; + + +static int memory_post_dataline(unsigned long long * pmem) +{ +	unsigned long long temp64 = 0; +	int num_patterns = sizeof(pattern)/ sizeof(pattern[0]); +	int i; +	unsigned int hi, lo, pathi, patlo; +	int ret = 0; + +	for ( i = 0; i < num_patterns; i++) { +		move64((unsigned long long *)&(pattern[i]), pmem++); +		/* +		 * Put a different pattern on the data lines: otherwise they +		 * may float long enough to read back what we wrote. +		 */ +		move64((unsigned long long *)&otherpattern, pmem--); +		move64(pmem, &temp64); + +#ifdef INJECT_DATA_ERRORS +		temp64 ^= 0x00008000; +#endif + +		if (temp64 != pattern[i]){ +			pathi = (pattern[i]>>32) & 0xffffffff; +			patlo = pattern[i] & 0xffffffff; + +			hi = (temp64>>32) & 0xffffffff; +			lo = temp64 & 0xffffffff; + +			post_log ("Memory (date line) error at %08x, " +				  "wrote %08x%08x, read %08x%08x !\n", +					  pmem, pathi, patlo, hi, lo); +			ret = -1; +		} +	} +	return ret; +} + +static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size) +{ +	ulong *target; +	ulong *end; +	ulong readback; +	ulong xor; +	int   ret = 0; + +	end = (ulong *)((ulong)base + size);	/* pointer arith! */ +	xor = 0; +	for(xor = sizeof(ulong); xor > 0; xor <<= 1) { +		target = (ulong *)((ulong)testaddr ^ xor); +		if((target >= base) && (target < end)) { +			*testaddr = ~*target; +			readback  = *target; + +#ifdef INJECT_ADDRESS_ERRORS +			if(xor == 0x00008000) { +				readback = *testaddr; +			} +#endif +			if(readback == *testaddr) { +				post_log ("Memory (address line) error at %08x<->%08x, " +				  	"XOR value %08x !\n", +					testaddr, target, xor); +				ret = -1; +			} +		} +	} +	return ret; +} + +static int memory_post_test1 (unsigned long start, +			      unsigned long size, +			      unsigned long val) +{ +	unsigned long i; +	ulong *mem = (ulong *) start; +	ulong readback; +	int ret = 0; + +	for (i = 0; i < size / sizeof (ulong); i++) { +		mem[i] = val; +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { +		readback = mem[i]; +		if (readback != val) { +			post_log ("Memory error at %08x, " +				  "wrote %08x, read %08x !\n", +					  mem + i, val, readback); + +			ret = -1; +			break; +		} +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	return ret; +} + +static int memory_post_test2 (unsigned long start, unsigned long size) +{ +	unsigned long i; +	ulong *mem = (ulong *) start; +	ulong readback; +	int ret = 0; + +	for (i = 0; i < size / sizeof (ulong); i++) { +		mem[i] = 1 << (i % 32); +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { +		readback = mem[i]; +		if (readback != (1 << (i % 32))) { +			post_log ("Memory error at %08x, " +				  "wrote %08x, read %08x !\n", +					  mem + i, 1 << (i % 32), readback); + +			ret = -1; +			break; +		} +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	return ret; +} + +static int memory_post_test3 (unsigned long start, unsigned long size) +{ +	unsigned long i; +	ulong *mem = (ulong *) start; +	ulong readback; +	int ret = 0; + +	for (i = 0; i < size / sizeof (ulong); i++) { +		mem[i] = i; +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { +		readback = mem[i]; +		if (readback != i) { +			post_log ("Memory error at %08x, " +				  "wrote %08x, read %08x !\n", +					  mem + i, i, readback); + +			ret = -1; +			break; +		} +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	return ret; +} + +static int memory_post_test4 (unsigned long start, unsigned long size) +{ +	unsigned long i; +	ulong *mem = (ulong *) start; +	ulong readback; +	int ret = 0; + +	for (i = 0; i < size / sizeof (ulong); i++) { +		mem[i] = ~i; +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { +		readback = mem[i]; +		if (readback != ~i) { +			post_log ("Memory error at %08x, " +				  "wrote %08x, read %08x !\n", +					  mem + i, ~i, readback); + +			ret = -1; +			break; +		} +		if (i % 1024 == 0) +			WATCHDOG_RESET (); +	} + +	return ret; +} + +static int memory_post_tests (unsigned long start, unsigned long size) +{ +	int ret = 0; + +	if (ret == 0) +		ret = memory_post_dataline ((unsigned long long *)start); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_addrline ((ulong *)start, (ulong *)start, size); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_addrline ((ulong *)(start + size - 8), +					    (ulong *)start, size); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_test1 (start, size, 0x00000000); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_test1 (start, size, 0xffffffff); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_test1 (start, size, 0x55555555); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_test1 (start, size, 0xaaaaaaaa); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_test2 (start, size); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_test3 (start, size); +	WATCHDOG_RESET (); +	if (ret == 0) +		ret = memory_post_test4 (start, size); +	WATCHDOG_RESET (); + +	return ret; +} + +int memory_post_test (int flags) +{ +	int ret = 0; +	bd_t *bd = gd->bd; +	unsigned long memsize = (bd->bi_memsize >= 256 << 20 ? +				 256 << 20 : bd->bi_memsize) - (1 << 20); + + +	if (flags & POST_SLOWTEST) { +		ret = memory_post_tests (CFG_SDRAM_BASE, memsize); +	} else {			/* POST_NORMAL */ + +		unsigned long i; + +		for (i = 0; i < (memsize >> 20) && ret == 0; i++) { +			if (ret == 0) +				ret = memory_post_tests (i << 20, 0x800); +			if (ret == 0) +				ret = memory_post_tests ((i << 20) + 0xff800, 0x800); +		} +	} + +	return ret; +} + +#endif /* CONFIG_POST & CFG_POST_MEMORY */ +#endif /* CONFIG_POST */ diff --git a/post/drivers/rtc.c b/post/drivers/rtc.c new file mode 100644 index 000000000..7d4f9b88e --- /dev/null +++ b/post/drivers/rtc.c @@ -0,0 +1,183 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * RTC test + * + * The Real Time Clock (RTC) operation is verified by this test. + * The following features are verified: + *   o) Time uniformity + *      This is verified by reading RTC in polling within + *      a short period of time. + *   o) Passing month boundaries + *      This is checked by setting RTC to a second before + *      a month boundary and reading it after its passing the + *      boundary. The test is performed for both leap- and + *      nonleap-years. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include <rtc.h> + +#if CONFIG_POST & CFG_POST_RTC + +static int rtc_post_skip (ulong * diff) +{ +	struct rtc_time tm1; +	struct rtc_time tm2; +	ulong start1; +	ulong start2; + +	rtc_get (&tm1); +	start1 = get_timer (0); + +	while (1) { +		rtc_get (&tm2); +		start2 = get_timer (0); +		if (tm1.tm_sec != tm2.tm_sec) +			break; +		if (start2 - start1 > 1500) +			break; +	} + +	if (tm1.tm_sec != tm2.tm_sec) { +		*diff = start2 - start1; + +		return 0; +	} else { +		return -1; +	} +} + +static void rtc_post_restore (struct rtc_time *tm, unsigned int sec) +{ +	time_t t = mktime (tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, +					   tm->tm_min, tm->tm_sec) + sec; +	struct rtc_time ntm; + +	to_tm (t, &ntm); + +	rtc_set (&ntm); +} + +int rtc_post_test (int flags) +{ +	ulong diff; +	unsigned int i; +	struct rtc_time svtm; +	static unsigned int daysnl[] = +			{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +	static unsigned int daysl[] = +			{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +	unsigned int ynl = 1999; +	unsigned int yl = 2000; +	unsigned int skipped = 0; + +	/* Time uniformity */ +	if (rtc_post_skip (&diff) != 0) { +		post_log ("Timeout while waiting for a new second !\n"); + +		return -1; +	} + +	for (i = 0; i < 5; i++) { +		if (rtc_post_skip (&diff) != 0) { +			post_log ("Timeout while waiting for a new second !\n"); + +			return -1; +		} + +		if (diff < 950 || diff > 1050) { +			post_log ("Invalid second duration !\n"); + +			return -1; +		} +	} + +	/* Passing month boundaries */ + +	if (rtc_post_skip (&diff) != 0) { +		post_log ("Timeout while waiting for a new second !\n"); + +		return -1; +	} +	rtc_get (&svtm); + +	for (i = 0; i < 12; i++) { +		time_t t = mktime (ynl, i + 1, daysnl[i], 23, 59, 59); +		struct rtc_time tm; + +		to_tm (t, &tm); +		rtc_set (&tm); + +		skipped++; +		if (rtc_post_skip (&diff) != 0) { +			rtc_post_restore (&svtm, skipped); +			post_log ("Timeout while waiting for a new second !\n"); + +			return -1; +		} + +		rtc_get (&tm); +		if (tm.tm_mon == i + 1) { +			rtc_post_restore (&svtm, skipped); +			post_log ("Month %d boundary is not passed !\n", i + 1); + +			return -1; +		} +	} + +	for (i = 0; i < 12; i++) { +		time_t t = mktime (yl, i + 1, daysl[i], 23, 59, 59); +		struct rtc_time tm; + +		to_tm (t, &tm); +		rtc_set (&tm); + +		skipped++; +		if (rtc_post_skip (&diff) != 0) { +			rtc_post_restore (&svtm, skipped); +			post_log ("Timeout while waiting for a new second !\n"); + +			return -1; +		} + +		rtc_get (&tm); +		if (tm.tm_mon == i + 1) { +			rtc_post_restore (&svtm, skipped); +			post_log ("Month %d boundary is not passed !\n", i + 1); + +			return -1; +		} +	} +	rtc_post_restore (&svtm, skipped); + +	return 0; +} + +#endif /* CONFIG_POST & CFG_POST_RTC */ +#endif /* CONFIG_POST */ diff --git a/post/lib_ppc/Makefile b/post/lib_ppc/Makefile new file mode 100644 index 000000000..14354a032 --- /dev/null +++ b/post/lib_ppc/Makefile @@ -0,0 +1,32 @@ +# +# (C) Copyright 2002-2006 +# 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 +# + + +LIB	= libpostppc.a + +AOBJS	= asm.o +COBJS	= cpu.o cmp.o cmpi.o two.o twox.o three.o threex.o +COBJS   += threei.o andi.o srawi.o rlwnm.o rlwinm.o rlwimi.o +COBJS	+= store.o load.o cr.o b.o multi.o string.o complex.o + +include $(TOPDIR)/post/rules.mk diff --git a/post/lib_ppc/andi.c b/post/lib_ppc/andi.c new file mode 100644 index 000000000..7ddf2ab2f --- /dev/null +++ b/post/lib_ppc/andi.c @@ -0,0 +1,123 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Logic instructions:		andi., andis. + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_21 (ulong *code, ulong *cr, ulong *res, ulong op); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_andi_s +{ +    ulong cmd; +    ulong op1; +    ushort op2; +    ulong res; +} cpu_post_andi_table[] = +{ +    { +    	OP_ANDI_, +	0x80008000, +	0xffff, +	0x00008000 +    }, +    { +    	OP_ANDIS_, +	0x80008000, +	0xffff, +	0x80000000 +    }, +}; +static unsigned int cpu_post_andi_size = +    sizeof (cpu_post_andi_table) / sizeof (struct cpu_post_andi_s); + +int cpu_post_test_andi (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_andi_size && ret == 0; i++) +    { +	struct cpu_post_andi_s *test = cpu_post_andi_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11IX(test->cmd, reg1, reg0, test->op2), +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    cpu_post_exec_21 (codecr, & cr, & res, test->op1); + +	    ret = res == test->res && +		  (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    if (ret != 0) +	    { +	        post_log ("Error at andi test %d !\n", i); +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/asm.S b/post/lib_ppc/asm.S new file mode 100644 index 000000000..a0815a43a --- /dev/null +++ b/post/lib_ppc/asm.S @@ -0,0 +1,346 @@ +/* + *  Copyright (C) 2002 Wolfgang Denk <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 <config.h> + +#ifdef CONFIG_POST + +#include <post.h> +#include <ppc_asm.tmpl> +#include <ppc_defs.h> +#include <asm/cache.h> + +#if CONFIG_POST & CFG_POST_CPU + +/* void cpu_post_exec_02 (ulong *code, ulong op1, ulong op2); */ +	.global	cpu_post_exec_02 +cpu_post_exec_02: +	mflr	r0 +	stwu	r0, -4(r1) + +	subi	r1, r1, 104 +	stmw	r6, 0(r1) + +	mtlr	r3 +	mr	r3, r4 +	mr	r4, r5 +	blrl + +	lmw	r6, 0(r1) +	addi	r1, r1, 104 + +	lwz	r0, 0(r1) +	addi	r1, r1, 4 +	mtlr	r0 +	blr + +/* void cpu_post_exec_04 (ulong *code, ulong op1, ulong op2, ulong op3, ulong op4); */ +	.global	cpu_post_exec_04 +cpu_post_exec_04: +	mflr	r0 +	stwu	r0, -4(r1) + +	subi	r1, r1, 96 +	stmw	r8, 0(r1) + +	mtlr	r3 +	mr	r3, r4 +	mr	r4, r5 +	mr	r5, r6 +	mtxer	r7 +	blrl + +	lmw	r8, 0(r1) +	addi	r1, r1, 96 + +	lwz	r0, 0(r1) +	addi	r1, r1, 4 +	mtlr	r0 +	blr + +/* void cpu_post_exec_12 (ulong *code, ulong *res, ulong op1, ulong op2); */ +	.global	cpu_post_exec_12 +cpu_post_exec_12: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) + +	mtlr	r3 +	mr	r3, r5 +	mr	r4, r6 +	blrl + +	lwz	r4, 0(r1) +	stw	r3, 0(r4) + +	lwz	r0, 4(r1) +	addi	r1, r1, 8 +	mtlr	r0 +	blr + +/* void cpu_post_exec_11 (ulong *code, ulong *res, ulong op1); */ +	.global	cpu_post_exec_11 +cpu_post_exec_11: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) + +	mtlr	r3 +	mr	r3, r5 +	blrl + +	lwz	r4, 0(r1) +	stw	r3, 0(r4) + +	lwz	r0, 4(r1) +	addi	r1, r1, 8 +	mtlr	r0 +	blr + +/* void cpu_post_exec_21 (ulong *code, ulong *cr, ulong *res, ulong op1); */ +	.global	cpu_post_exec_21 +cpu_post_exec_21: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) +	stwu	r5, -4(r1) + +	li	r0, 0 +	mtxer	r0 +	lwz	r0, 0(r4) +	mtcr	r0 + +	mtlr	r3 +	mr	r3, r6 +	blrl + +	mfcr	r0 +	lwz	r4, 4(r1) +	stw	r0, 0(r4) +	lwz	r4, 0(r1) +	stw	r3, 0(r4) + +	lwz	r0, 8(r1) +	addi	r1, r1, 12 +	mtlr	r0 +	blr + +/* void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1, +    ulong op2); */ +	.global	cpu_post_exec_22 +cpu_post_exec_22: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) +	stwu	r5, -4(r1) + +	li	r0, 0 +	mtxer	r0 +	lwz	r0, 0(r4) +	mtcr	r0 + +	mtlr	r3 +	mr	r3, r6 +	mr	r4, r7 +	blrl + +	mfcr	r0 +	lwz	r4, 4(r1) +	stw	r0, 0(r4) +	lwz	r4, 0(r1) +	stw	r3, 0(r4) + +	lwz	r0, 8(r1) +	addi	r1, r1, 12 +	mtlr	r0 +	blr + +/* void cpu_post_exec_12w (ulong *code, ulong *op1, ulong op2, ulong op3); */ +	.global	cpu_post_exec_12w +cpu_post_exec_12w: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) + +	mtlr	r3 +	lwz	r3, 0(r4) +	mr	r4, r5 +	mr	r5, r6 +	blrl + +	lwz	r4, 0(r1) +	stw	r3, 0(r4) + +	lwz	r0, 4(r1) +	addi	r1, r1, 8 +	mtlr	r0 +	blr + +/* void cpu_post_exec_11w (ulong *code, ulong *op1, ulong op2); */ +	.global	cpu_post_exec_11w +cpu_post_exec_11w: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) + +	mtlr	r3 +	lwz	r3, 0(r4) +	mr	r4, r5 +	blrl + +	lwz	r4, 0(r1) +	stw	r3, 0(r4) + +	lwz	r0, 4(r1) +	addi	r1, r1, 8 +	mtlr	r0 +	blr + +/* void cpu_post_exec_22w (ulong *code, ulong *op1, ulong op2, ulong *op3); */ +	.global	cpu_post_exec_22w +cpu_post_exec_22w: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) +	stwu	r6, -4(r1) + +	mtlr	r3 +	lwz	r3, 0(r4) +	mr	r4, r5 +	blrl + +	lwz	r4, 4(r1) +	stw	r3, 0(r4) +	lwz	r4, 0(r1) +	stw	r5, 0(r4) + +	lwz	r0, 8(r1) +	addi	r1, r1, 12 +	mtlr	r0 +	blr + +/* void cpu_post_exec_21w (ulong *code, ulong *op1, ulong *op2); */ +	.global	cpu_post_exec_21w +cpu_post_exec_21w: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) +	stwu	r5, -4(r1) + +	mtlr	r3 +	lwz	r3, 0(r4) +	blrl + +	lwz	r5, 4(r1) +	stw	r3, 0(r5) +	lwz	r5, 0(r1) +	stw	r4, 0(r5) + +	lwz	r0, 8(r1) +	addi	r1, r1, 12 +	mtlr	r0 +	blr + +/* void cpu_post_exec_21x (ulong *code, ulong *op1, ulong *op2, ulong op3); */ +	.global	cpu_post_exec_21x +cpu_post_exec_21x: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) +	stwu	r5, -4(r1) + +	mtlr	r3 +	mr	r3, r6 +	blrl + +	lwz	r5, 4(r1) +	stw	r3, 0(r5) +	lwz	r5, 0(r1) +	stw	r4, 0(r5) + +	lwz	r0, 8(r1) +	addi	r1, r1, 12 +	mtlr	r0 +	blr + +/* void cpu_post_exec_31 (ulong *code, ulong *ctr, ulong *lr, ulong *jump, +    ulong cr); */ +	.global	cpu_post_exec_31 +cpu_post_exec_31: +	mflr	r0 +	stwu	r0, -4(r1) +	stwu	r4, -4(r1) +	stwu	r5, -4(r1) +	stwu	r6, -4(r1) + +	mtlr	r3 +	lwz	r3, 0(r4) +	lwz	r4, 0(r5) +	mr	r6, r7 +	blrl + +	lwz	r7, 8(r1) +	stw	r3, 0(r7) +	lwz	r7, 4(r1) +	stw	r4, 0(r7) +	lwz	r7, 0(r1) +	stw	r5, 0(r7) + +	lwz	r0, 12(r1) +	addi	r1, r1, 16 +	mtlr	r0 +	blr + +/* int cpu_post_complex_1_asm (int a1, int a2, int a3, int a4, int n); */ +	.global	cpu_post_complex_1_asm +cpu_post_complex_1_asm: +	li	r9,0 +	cmpw	r9,r7 +	bge	cpu_post_complex_1_done +	mtctr	r7 +cpu_post_complex_1_loop: +	mullw	r0,r3,r4 +	subf	r0,r5,r0 +	divw	r0,r0,r6 +	add	r9,r9,r0 +	bdnz	cpu_post_complex_1_loop +cpu_post_complex_1_done: +	mr	r3,r9 +	blr + +/* int cpu_post_complex_2_asm (int x, int n); */ +	.global	cpu_post_complex_2_asm +cpu_post_complex_2_asm: +	mr.	r0,r4 +	mtctr	r0 +	mr	r0,r3 +	li	r3,1 +	li	r4,1 +	blelr +cpu_post_complex_2_loop: +	mullw	r3,r3,r0 +	add	r3,r3,r4 +	bdnz	cpu_post_complex_2_loop +blr + +#endif +#endif diff --git a/post/lib_ppc/b.c b/post/lib_ppc/b.c new file mode 100644 index 000000000..b4b17c8ff --- /dev/null +++ b/post/lib_ppc/b.c @@ -0,0 +1,197 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Branch instructions:		b, bl, bc + * + * The first 2 instructions (b, bl) are verified by jumping + * to a fixed address and checking whether control was transfered + * to that very point. For the bl instruction the value of the + * link register is checked as well (using mfspr). + * To verify the bc instruction various combinations of the BI/BO + * fields, the CTR and the condition register values are + * checked. The list of such combinations is pre-built and + * linked in U-Boot at build time. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_11 (ulong *code, ulong *res, ulong op1); +extern void cpu_post_exec_31 (ulong *code, ulong *ctr, ulong *lr, ulong *jump, +    ulong cr); + +static int cpu_post_test_bc (ulong cmd, ulong bo, ulong bi, +    int pjump, int dec, int link, ulong pctr, ulong cr) +{ +    int ret = 0; +    ulong lr = 0; +    ulong ctr = pctr; +    ulong jump; + +    unsigned long code[] = +    { +	ASM_MTCR(6), +	ASM_MFLR(6), +	ASM_MTCTR(3), +	ASM_MTLR(4), +	ASM_LI(5, 1), +	ASM_3O(cmd, bo, bi, 8), +	ASM_LI(5, 0), +	ASM_MFCTR(3), +	ASM_MFLR(4), +	ASM_MTLR(6), +	ASM_BLR, +    }; + +    cpu_post_exec_31 (code, &ctr, &lr, &jump, cr); + +    if (ret == 0) +	ret = pjump == jump ? 0 : -1; +    if (ret == 0) +    { +	if (dec) +	    ret = pctr == ctr + 1 ? 0 : -1; +	else +	    ret = pctr == ctr ? 0 : -1; +    } +    if (ret == 0) +    { +	if (link) +	    ret = lr == (ulong) code + 24 ? 0 : -1; +	else +	    ret = lr == 0 ? 0 : -1; +    } + +    return ret; +} + +int cpu_post_test_b (void) +{ +    int ret = 0; +    unsigned int i; + +    if (ret == 0) +    { +	ulong code[] = +	{ +	   ASM_MFLR(4), +	   ASM_MTLR(3), +	   ASM_B(4), +	   ASM_MFLR(3), +	   ASM_MTLR(4), +	   ASM_BLR, +	}; +	ulong res; + +	cpu_post_exec_11 (code, &res, 0); + +	ret = res == 0 ? 0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at b1 test !\n"); +	} +    } + +    if (ret == 0) +    { +	ulong code[] = +	{ +	   ASM_MFLR(4), +	   ASM_MTLR(3), +	   ASM_BL(4), +	   ASM_MFLR(3), +	   ASM_MTLR(4), +	   ASM_BLR, +	}; +	ulong res; + +	cpu_post_exec_11 (code, &res, 0); + +	ret = res == (ulong)code + 12 ? 0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at b2 test !\n"); +	} +    } + +    if (ret == 0) +    { +	ulong cc, cd; +	int cond; +	ulong ctr; +	int link; + +	i = 0; + +	for (cc = 0; cc < 4 && ret == 0; cc++) +	{ +	    for (cd = 0; cd < 4 && ret == 0; cd++) +	    { +		for (link = 0; link <= 1 && ret == 0; link++) +		{ +		    for (cond = 0; cond <= 1 && ret == 0; cond++) +		    { +			for (ctr = 1; ctr <= 2 && ret == 0; ctr++) +			{ +			    int dec = cd < 2; +			    int cr = cond ? 0x80000000 : 0x00000000; +			    int jumpc = cc >= 2 || +					(cc == 0 && !cond) || +					(cc == 1 && cond); +			    int jumpd = cd >= 2 || +					(cd == 0 && ctr != 1) || +					(cd == 1 && ctr == 1); +			    int jump = jumpc && jumpd; + +			    ret = cpu_post_test_bc (link ? OP_BCL : OP_BC, +				(cc << 3) + (cd << 1), 0, jump, dec, link, +				ctr, cr); + +			    if (ret != 0) +			    { +				post_log ("Error at b3 test %d !\n", i); +			    } + +			    i++; +			} +		    } +		} +	    } +	} +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/cmp.c b/post/lib_ppc/cmp.c new file mode 100644 index 000000000..789a24cb7 --- /dev/null +++ b/post/lib_ppc/cmp.c @@ -0,0 +1,133 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Integer compare instructions:	cmpw, cmplw + * + * To verify these instructions the test runs them with + * different combinations of operands, reads the condition + * register value and compares it with the expected one. + * The test contains a pre-built table + * containing the description of each test case: the instruction, + * the values of the operands, the condition field to save + * the result in and the expected result. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_12 (ulong *code, ulong *res, ulong op1, ulong op2); + +static struct cpu_post_cmp_s +{ +    ulong cmd; +    ulong op1; +    ulong op2; +    ulong cr; +    ulong res; +} cpu_post_cmp_table[] = +{ +    { +	OP_CMPW, +	123, +	123, +	2, +	0x02 +    }, +    { +	OP_CMPW, +	123, +	133, +	3, +	0x08 +    }, +    { +	OP_CMPW, +	123, +	-133, +	4, +	0x04 +    }, +    { +	OP_CMPLW, +	123, +	123, +	2, +	0x02 +    }, +    { +	OP_CMPLW, +	123, +	-133, +	3, +	0x08 +    }, +    { +	OP_CMPLW, +	123, +	113, +	4, +	0x04 +    }, +}; +static unsigned int cpu_post_cmp_size = +    sizeof (cpu_post_cmp_table) / sizeof (struct cpu_post_cmp_s); + +int cpu_post_test_cmp (void) +{ +    int ret = 0; +    unsigned int i; + +    for (i = 0; i < cpu_post_cmp_size && ret == 0; i++) +    { +	struct cpu_post_cmp_s *test = cpu_post_cmp_table + i; +    	unsigned long code[] = +	{ +	    ASM_2C(test->cmd, test->cr, 3, 4), +	    ASM_MFCR(3), +	    ASM_BLR +	}; +	ulong res; + +	cpu_post_exec_12 (code, & res, test->op1, test->op2); + +	ret = ((res >> (28 - 4 * test->cr)) & 0xe) == test->res ? 0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at cmp test %d !\n", i); +	} +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/cmpi.c b/post/lib_ppc/cmpi.c new file mode 100644 index 000000000..e0c2aaff8 --- /dev/null +++ b/post/lib_ppc/cmpi.c @@ -0,0 +1,133 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Integer compare instructions:	cmpwi, cmplwi + * + * To verify these instructions the test runs them with + * different combinations of operands, reads the condition + * register value and compares it with the expected one. + * The test contains a pre-built table + * containing the description of each test case: the instruction, + * the values of the operands, the condition field to save + * the result in and the expected result. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_11 (ulong *code, ulong *res, ulong op1); + +static struct cpu_post_cmpi_s +{ +    ulong cmd; +    ulong op1; +    ushort op2; +    ulong cr; +    ulong res; +} cpu_post_cmpi_table[] = +{ +    { +	OP_CMPWI, +	123, +	123, +	2, +	0x02 +    }, +    { +	OP_CMPWI, +	123, +	133, +	3, +	0x08 +    }, +    { +	OP_CMPWI, +	123, +	-133, +	4, +	0x04 +    }, +    { +	OP_CMPLWI, +	123, +	123, +	2, +	0x02 +    }, +    { +	OP_CMPLWI, +	123, +	-133, +	3, +	0x08 +    }, +    { +	OP_CMPLWI, +	123, +	113, +	4, +	0x04 +    }, +}; +static unsigned int cpu_post_cmpi_size = +    sizeof (cpu_post_cmpi_table) / sizeof (struct cpu_post_cmpi_s); + +int cpu_post_test_cmpi (void) +{ +    int ret = 0; +    unsigned int i; + +    for (i = 0; i < cpu_post_cmpi_size && ret == 0; i++) +    { +	struct cpu_post_cmpi_s *test = cpu_post_cmpi_table + i; +    	unsigned long code[] = +	{ +	    ASM_1IC(test->cmd, test->cr, 3, test->op2), +	    ASM_MFCR(3), +	    ASM_BLR +	}; +	ulong res; + +	cpu_post_exec_11 (code, & res, test->op1); + +	ret = ((res >> (28 - 4 * test->cr)) & 0xe) == test->res ? 0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at cmpi test %d !\n", i); +	} +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/complex.c b/post/lib_ppc/complex.c new file mode 100644 index 000000000..033584bec --- /dev/null +++ b/post/lib_ppc/complex.c @@ -0,0 +1,126 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Complex calculations + * + * The calculations in this test are just a combination of simpler + * calculations, but probably under different timing conditions, etc. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern int cpu_post_complex_1_asm (int a1, int a2, int a3, int a4, int n); +extern int cpu_post_complex_2_asm (int x, int n); + +  /* +   *     n +   *	SUM (a1 * a2 - a3) / a4 = n * result +   *    i=1 +   */ +static int cpu_post_test_complex_1 (void) +{ +    int a1 = 666; +    int a2 = 667; +    int a3 = 668; +    int a4 = 66; +    int n = 100; +    int result = 6720; /* (a1 * a2 - a3) / a4 */ + +    if (cpu_post_complex_1_asm(a1, a2, a3, a4, n) != n * result) +    { +	return -1; +    } + +    return 0; +} + +  /*	(1 + x + x^2 + ... + x^n) * (1 - x) = 1 - x^(n+1) +   */ +static int cpu_post_test_complex_2 (void) +{ +    int ret = -1; +    int x; +    int n; +    int k; +    int left; +    int right; + +    for (x = -8; x <= 8; x ++) +    { +	n = 9; + +	left = cpu_post_complex_2_asm(x, n); +	left *= 1 - x; + +	right = 1; +	for (k = 0; k <= n; k ++) +	{ +	    right *= x; +	} +	right = 1 - right; + +	if (left != right) +	{ +	    goto Done; +	} +    } + +    ret = 0; +    Done: + +    return ret; +} + +int cpu_post_test_complex (void) +{ +    int ret = 0; + +    if (ret == 0) +    { +	ret = cpu_post_test_complex_1(); +    } + +    if (ret == 0) +    { +	ret = cpu_post_test_complex_2(); +    } + +    if (ret != 0) +    { +	post_log ("Error at complex test !\n"); +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/cpu.c b/post/lib_ppc/cpu.c new file mode 100644 index 000000000..1f2ded2bf --- /dev/null +++ b/post/lib_ppc/cpu.c @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * + * This test checks the arithmetic logic unit (ALU) of CPU. + * It tests independently various groups of instructions using + * run-time modification of the code to reduce the memory footprint. + * For more details refer to post/cpu/ *.c files. + */ + +#ifdef CONFIG_POST + +#include <watchdog.h> +#include <post.h> + +#if CONFIG_POST & CFG_POST_CPU + +extern int cpu_post_test_cmp (void); +extern int cpu_post_test_cmpi (void); +extern int cpu_post_test_two (void); +extern int cpu_post_test_twox (void); +extern int cpu_post_test_three (void); +extern int cpu_post_test_threex (void); +extern int cpu_post_test_threei (void); +extern int cpu_post_test_andi (void); +extern int cpu_post_test_srawi (void); +extern int cpu_post_test_rlwnm (void); +extern int cpu_post_test_rlwinm (void); +extern int cpu_post_test_rlwimi (void); +extern int cpu_post_test_store (void); +extern int cpu_post_test_load (void); +extern int cpu_post_test_cr (void); +extern int cpu_post_test_b (void); +extern int cpu_post_test_multi (void); +extern int cpu_post_test_string (void); +extern int cpu_post_test_complex (void); + +ulong cpu_post_makecr (long v) +{ +	ulong cr = 0; + +	if (v < 0) +		cr |= 0x80000000; +	if (v > 0) +		cr |= 0x40000000; +	if (v == 0) +		cr |= 0x20000000; + +	return cr; +} + +int cpu_post_test (int flags) +{ +	int ic = icache_status (); +	int ret = 0; + +	WATCHDOG_RESET(); +	if (ic) +		icache_disable (); + +	if (ret == 0) +		ret = cpu_post_test_cmp (); +	if (ret == 0) +		ret = cpu_post_test_cmpi (); +	if (ret == 0) +		ret = cpu_post_test_two (); +	if (ret == 0) +		ret = cpu_post_test_twox (); +	WATCHDOG_RESET(); +	if (ret == 0) +		ret = cpu_post_test_three (); +	if (ret == 0) +		ret = cpu_post_test_threex (); +	if (ret == 0) +		ret = cpu_post_test_threei (); +	if (ret == 0) +		ret = cpu_post_test_andi (); +	WATCHDOG_RESET(); +	if (ret == 0) +		ret = cpu_post_test_srawi (); +	if (ret == 0) +		ret = cpu_post_test_rlwnm (); +	if (ret == 0) +		ret = cpu_post_test_rlwinm (); +	if (ret == 0) +		ret = cpu_post_test_rlwimi (); +	WATCHDOG_RESET(); +	if (ret == 0) +		ret = cpu_post_test_store (); +	if (ret == 0) +		ret = cpu_post_test_load (); +	if (ret == 0) +		ret = cpu_post_test_cr (); +	if (ret == 0) +		ret = cpu_post_test_b (); +	WATCHDOG_RESET(); +	if (ret == 0) +		ret = cpu_post_test_multi (); +	WATCHDOG_RESET(); +	if (ret == 0) +		ret = cpu_post_test_string (); +	if (ret == 0) +		ret = cpu_post_test_complex (); +	WATCHDOG_RESET(); + +	if (ic) +		icache_enable (); + +	WATCHDOG_RESET(); + +	return ret; +} + +#endif /* CONFIG_POST & CFG_POST_CPU */ +#endif /* CONFIG_POST */ diff --git a/post/lib_ppc/cpu_asm.h b/post/lib_ppc/cpu_asm.h new file mode 100644 index 000000000..1cbaf4121 --- /dev/null +++ b/post/lib_ppc/cpu_asm.h @@ -0,0 +1,224 @@ +/* + * (C) Copyright 2002 + * 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 + */ +#ifndef _CPU_ASM_H +#define _CPU_ASM_H + +#define BIT_C				0x00000001 + +#define OP_BLR				0x4e800020 +#define OP_EXTSB			0x7c000774 +#define OP_EXTSH			0x7c000734 +#define OP_NEG				0x7c0000d0 +#define OP_CNTLZW			0x7c000034 +#define OP_ADD				0x7c000214 +#define OP_ADDC				0x7c000014 +#define OP_ADDME			0x7c0001d4 +#define OP_ADDZE			0x7c000194 +#define OP_ADDE				0x7c000114 +#define OP_ADDI				0x38000000 +#define OP_SUBF				0x7c000050 +#define OP_SUBFC			0x7c000010 +#define OP_SUBFE			0x7c000110 +#define OP_SUBFME			0x7c0001d0 +#define OP_SUBFZE			0x7c000190 +#define OP_MFCR				0x7c000026 +#define OP_MTCR				0x7c0ff120 +#define OP_MFXER			0x7c0102a6 +#define OP_MTXER			0x7c0103a6 +#define OP_MCRXR			0x7c000400 +#define OP_MCRF				0x4c000000 +#define OP_CRAND			0x4c000202 +#define OP_CRANDC			0x4c000102 +#define OP_CROR				0x4c000382 +#define OP_CRORC			0x4c000342 +#define OP_CRXOR			0x4c000182 +#define OP_CRNAND			0x4c0001c2 +#define OP_CRNOR			0x4c000042 +#define OP_CREQV			0x4c000242 +#define OP_CMPW				0x7c000000 +#define OP_CMPLW			0x7c000040 +#define OP_CMPWI			0x2c000000 +#define OP_CMPLWI			0x28000000 +#define OP_MULLW			0x7c0001d6 +#define OP_MULHW			0x7c000096 +#define OP_MULHWU			0x7c000016 +#define OP_DIVW				0x7c0003d6 +#define OP_DIVWU			0x7c000396 +#define OP_OR				0x7c000378 +#define OP_ORC				0x7c000338 +#define OP_XOR				0x7c000278 +#define OP_NAND				0x7c0003b8 +#define OP_NOR				0x7c0000f8 +#define OP_EQV				0x7c000238 +#define OP_SLW				0x7c000030 +#define OP_SRW				0x7c000430 +#define OP_SRAW				0x7c000630 +#define OP_ORI				0x60000000 +#define OP_ORIS				0x64000000 +#define OP_XORI				0x68000000 +#define OP_XORIS			0x6c000000 +#define OP_ANDI_			0x70000000 +#define OP_ANDIS_			0x74000000 +#define OP_SRAWI			0x7c000670 +#define OP_RLWINM			0x54000000 +#define OP_RLWNM			0x5c000000 +#define OP_RLWIMI			0x50000000 +#define OP_LWZ				0x80000000 +#define OP_LHZ				0xa0000000 +#define OP_LHA				0xa8000000 +#define OP_LBZ				0x88000000 +#define OP_LWZU				0x84000000 +#define OP_LHZU				0xa4000000 +#define OP_LHAU				0xac000000 +#define OP_LBZU				0x8c000000 +#define OP_LWZX				0x7c00002e +#define OP_LHZX				0x7c00022e +#define OP_LHAX				0x7c0002ae +#define OP_LBZX				0x7c0000ae +#define OP_LWZUX			0x7c00006e +#define OP_LHZUX			0x7c00026e +#define OP_LHAUX			0x7c0002ee +#define OP_LBZUX			0x7c0000ee +#define OP_STW				0x90000000 +#define OP_STH				0xb0000000 +#define OP_STB				0x98000000 +#define OP_STWU				0x94000000 +#define OP_STHU				0xb4000000 +#define OP_STBU				0x9c000000 +#define OP_STWX				0x7c00012e +#define OP_STHX				0x7c00032e +#define OP_STBX				0x7c0001ae +#define OP_STWUX			0x7c00016e +#define OP_STHUX			0x7c00036e +#define OP_STBUX			0x7c0001ee +#define OP_B				0x48000000 +#define OP_BL				0x48000001 +#define OP_BC				0x40000000 +#define OP_BCL				0x40000001 +#define OP_MTLR				0x7c0803a6 +#define OP_MFLR				0x7c0802a6 +#define OP_MTCTR			0x7c0903a6 +#define OP_MFCTR			0x7c0902a6 +#define OP_LMW				0xb8000000 +#define OP_STMW				0xbc000000 +#define OP_LSWI				0x7c0004aa +#define OP_LSWX				0x7c00042a +#define OP_STSWI			0x7c0005aa +#define OP_STSWX			0x7c00052a + +#define ASM_0(opcode)			(opcode) +#define ASM_1(opcode, rd)		((opcode) +		\ +	                                 ((rd) << 21)) +#define ASM_1C(opcode, cr)		((opcode) +		\ +	                                 ((cr) << 23)) +#define ASM_11(opcode, rd, rs)		((opcode) +		\ +	                                 ((rd) << 21) +		\ +					 ((rs) << 16)) +#define ASM_11C(opcode, cd, cs)		((opcode) +		\ +	                                 ((cd) << 23) +		\ +					 ((cs) << 18)) +#define ASM_11X(opcode, rd, rs)		((opcode) +		\ +	                                 ((rs) << 21) +		\ +					 ((rd) << 16)) +#define ASM_11I(opcode, rd, rs, simm)	((opcode) +		\ +	                                 ((rd) << 21) +		\ +					 ((rs) << 16) +		\ +					 ((simm) & 0xffff)) +#define ASM_11IF(opcode, rd, rs, simm)	((opcode) +		\ +	                                 ((rd) << 21) +		\ +					 ((rs) << 16) +		\ +					 ((simm) << 11)) +#define ASM_11S(opcode, rd, rs, sh)	((opcode) +		\ +	                                 ((rs) << 21) +		\ +					 ((rd) << 16) +		\ +					 ((sh) << 11)) +#define ASM_11IX(opcode, rd, rs, imm)	((opcode) +		\ +	                                 ((rs) << 21) +		\ +					 ((rd) << 16) +		\ +					 ((imm) & 0xffff)) +#define ASM_12(opcode, rd, rs1, rs2)	((opcode) +		\ +	                                 ((rd) << 21) +		\ +					 ((rs1) << 16) +	\ +					 ((rs2) << 11)) +#define ASM_12F(opcode, fd, fs1, fs2)	((opcode) +		\ +	                                 ((fd) << 21) +		\ +					 ((fs1) << 16) +	\ +					 ((fs2) << 11)) +#define ASM_12X(opcode, rd, rs1, rs2)	((opcode) +		\ +	                                 ((rs1) << 21) +	\ +					 ((rd) << 16) +		\ +					 ((rs2) << 11)) +#define ASM_2C(opcode, cr, rs1, rs2)	((opcode) +		\ +	                                 ((cr) << 23) +		\ +					 ((rs1) << 16) +	\ +					 ((rs2) << 11)) +#define ASM_1IC(opcode, cr, rs, imm)	((opcode) +		\ +	                                 ((cr) << 23) +		\ +					 ((rs) << 16) +		\ +					 ((imm) & 0xffff)) +#define ASM_122(opcode, rd, rs1, rs2, imm1, imm2)		\ +					((opcode) +		\ +	                                 ((rs1) << 21) +	\ +					 ((rd) << 16) +		\ +					 ((rs2) << 11) +	\ +					 ((imm1) << 6) +	\ +					 ((imm2) << 1)) +#define ASM_113(opcode, rd, rs, imm1, imm2, imm3)		\ +					((opcode) +		\ +	                                 ((rs) << 21) +		\ +					 ((rd) << 16) +		\ +					 ((imm1) << 11) +	\ +					 ((imm2) << 6) +	\ +					 ((imm3) << 1)) +#define ASM_1O(opcode, off)		((opcode) + (off)) +#define ASM_3O(opcode, bo, bi, off)	((opcode) + 		\ +					 ((bo) << 21) +		\ +					 ((bi) << 16) +		\ +					 (off)) + +#define ASM_ADDI(rd, rs, simm)		ASM_11I(OP_ADDI, rd, rs, simm) +#define ASM_BLR				ASM_0(OP_BLR) +#define ASM_STW(rd, rs, simm)		ASM_11I(OP_STW, rd, rs, simm) +#define ASM_LWZ(rd, rs, simm)		ASM_11I(OP_LWZ, rd, rs, simm) +#define ASM_MFCR(rd)			ASM_1(OP_MFCR, rd) +#define ASM_MTCR(rd)			ASM_1(OP_MTCR, rd) +#define ASM_MFXER(rd)			ASM_1(OP_MFXER, rd) +#define ASM_MTXER(rd)			ASM_1(OP_MTXER, rd) +#define ASM_MFCTR(rd)			ASM_1(OP_MFCTR, rd) +#define ASM_MTCTR(rd)			ASM_1(OP_MTCTR, rd) +#define ASM_MCRXR(cr)			ASM_1C(OP_MCRXR, cr) +#define ASM_MCRF(cd, cs)		ASM_11C(OP_MCRF, cd, cs) +#define ASM_B(off)			ASM_1O(OP_B, off) +#define ASM_BL(off)			ASM_1O(OP_BL, off) +#define ASM_MFLR(rd)			ASM_1(OP_MFLR, rd) +#define ASM_MTLR(rd)			ASM_1(OP_MTLR, rd) +#define ASM_LI(rd, imm)			ASM_ADDI(rd, 0, imm) +#define ASM_LMW(rd, rs, simm)		ASM_11I(OP_LMW, rd, rs, simm) +#define ASM_STMW(rd, rs, simm)		ASM_11I(OP_STMW, rd, rs, simm) +#define ASM_LSWI(rd, rs, simm)		ASM_11IF(OP_LSWI, rd, rs, simm) +#define ASM_LSWX(rd, rs1, rs2)		ASM_12(OP_LSWX, rd, rs1, rs2) +#define ASM_STSWI(rd, rs, simm)		ASM_11IF(OP_STSWI, rd, rs, simm) +#define ASM_STSWX(rd, rs1, rs2)		ASM_12(OP_STSWX, rd, rs1, rs2) + + +#endif /* _CPU_ASM_H */ diff --git a/post/lib_ppc/cr.c b/post/lib_ppc/cr.c new file mode 100644 index 000000000..da6ef3745 --- /dev/null +++ b/post/lib_ppc/cr.c @@ -0,0 +1,356 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Condition register istructions:	mtcr, mfcr, mcrxr, + *					crand, crandc, cror, crorc, crxor, + *					crnand, crnor, creqv, mcrf + * + * The mtcrf/mfcr instructions is tested by loading different + * values into the condition register (mtcrf), moving its value + * to a general-purpose register (mfcr) and comparing this value + * with the expected one. + * The mcrxr instruction is tested by loading a fixed value + * into the XER register (mtspr), moving XER value to the + * condition register (mcrxr), moving it to a general-purpose + * register (mfcr) and comparing the value of this register with + * the expected one. + * The rest of instructions is tested by loading a fixed + * value into the condition register (mtcrf), executing each + * instruction several times to modify all 4-bit condition + * fields, moving the value of the conditional register to a + * general-purpose register (mfcr) and comparing it with the + * expected one. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_11 (ulong *code, ulong *res, ulong op1); +extern void cpu_post_exec_21x (ulong *code, ulong *op1, ulong *op2, ulong op3); + +static ulong cpu_post_cr_table1[] = +{ +    0xaaaaaaaa, +    0x55555555, +}; +static unsigned int cpu_post_cr_size1 = +    sizeof (cpu_post_cr_table1) / sizeof (ulong); + +static struct cpu_post_cr_s2 { +    ulong xer; +    ulong cr; +} cpu_post_cr_table2[] = +{ +    { +	0xa0000000, +	1 +    }, +    { +	0x40000000, +	5 +    }, +}; +static unsigned int cpu_post_cr_size2 = +    sizeof (cpu_post_cr_table2) / sizeof (struct cpu_post_cr_s2); + +static struct cpu_post_cr_s3 { +    ulong cr; +    ulong cs; +    ulong cd; +    ulong res; +} cpu_post_cr_table3[] = +{ +    { +	0x01234567, +	0, +	4, +	0x01230567 +    }, +    { +	0x01234567, +	7, +	0, +	0x71234567 +    }, +}; +static unsigned int cpu_post_cr_size3 = +    sizeof (cpu_post_cr_table3) / sizeof (struct cpu_post_cr_s3); + +static struct cpu_post_cr_s4 { +    ulong cmd; +    ulong cr; +    ulong op1; +    ulong op2; +    ulong op3; +    ulong res; +} cpu_post_cr_table4[] = +{ +    { +	OP_CRAND, +	0x0000ffff, +	0, +	16, +	0, +	0x0000ffff +    }, +    { +	OP_CRAND, +	0x0000ffff, +	16, +	17, +	0, +	0x8000ffff +    }, +    { +	OP_CRANDC, +	0x0000ffff, +	0, +	16, +	0, +	0x0000ffff +    }, +    { +	OP_CRANDC, +	0x0000ffff, +	16, +	0, +	0, +	0x8000ffff +    }, +    { +	OP_CROR, +	0x0000ffff, +	0, +	16, +	0, +	0x8000ffff +    }, +    { +	OP_CROR, +	0x0000ffff, +	0, +	1, +	0, +	0x0000ffff +    }, +    { +	OP_CRORC, +	0x0000ffff, +	0, +	16, +	0, +	0x0000ffff +    }, +    { +	OP_CRORC, +	0x0000ffff, +	0, +	0, +	0, +	0x8000ffff +    }, +    { +	OP_CRXOR, +	0x0000ffff, +	0, +	0, +	0, +	0x0000ffff +    }, +    { +	OP_CRXOR, +	0x0000ffff, +	0, +	16, +	0, +	0x8000ffff +    }, +    { +	OP_CRNAND, +	0x0000ffff, +	0, +	16, +	0, +	0x8000ffff +    }, +    { +	OP_CRNAND, +	0x0000ffff, +	16, +	17, +	0, +	0x0000ffff +    }, +    { +	OP_CRNOR, +	0x0000ffff, +	0, +	16, +	0, +	0x0000ffff +    }, +    { +	OP_CRNOR, +	0x0000ffff, +	0, +	1, +	0, +	0x8000ffff +    }, +    { +	OP_CREQV, +	0x0000ffff, +	0, +	0, +	0, +	0x8000ffff +    }, +    { +	OP_CREQV, +	0x0000ffff, +	0, +	16, +	0, +	0x0000ffff +    }, +}; +static unsigned int cpu_post_cr_size4 = +    sizeof (cpu_post_cr_table4) / sizeof (struct cpu_post_cr_s4); + +int cpu_post_test_cr (void) +{ +    int ret = 0; +    unsigned int i; +    unsigned long cr_sav; + +    asm ( "mfcr %0" : "=r" (cr_sav) : ); + +    for (i = 0; i < cpu_post_cr_size1 && ret == 0; i++) +    { +	ulong cr = cpu_post_cr_table1[i]; +	ulong res; + +	unsigned long code[] = +	{ +	    ASM_MTCR(3), +	    ASM_MFCR(3), +	    ASM_BLR, +	}; + +	cpu_post_exec_11 (code, &res, cr); + +	ret = res == cr ? 0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at cr1 test %d !\n", i); +	} +    } + +    for (i = 0; i < cpu_post_cr_size2 && ret == 0; i++) +    { +	struct cpu_post_cr_s2 *test = cpu_post_cr_table2 + i; +	ulong res; +	ulong xer; + +	unsigned long code[] = +	{ +	    ASM_MTXER(3), +	    ASM_MCRXR(test->cr), +	    ASM_MFCR(3), +	    ASM_MFXER(4), +	    ASM_BLR, +	}; + +	cpu_post_exec_21x (code, &res, &xer, test->xer); + +	ret = xer == 0 && ((res << (4 * test->cr)) & 0xe0000000) == test->xer ? +	      0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at cr2 test %d !\n", i); +	} +    } + +    for (i = 0; i < cpu_post_cr_size3 && ret == 0; i++) +    { +	struct cpu_post_cr_s3 *test = cpu_post_cr_table3 + i; +	ulong res; + +	unsigned long code[] = +	{ +	    ASM_MTCR(3), +	    ASM_MCRF(test->cd, test->cs), +	    ASM_MFCR(3), +	    ASM_BLR, +	}; + +	cpu_post_exec_11 (code, &res, test->cr); + +	ret = res == test->res ? 0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at cr3 test %d !\n", i); +	} +    } + +    for (i = 0; i < cpu_post_cr_size4 && ret == 0; i++) +    { +	struct cpu_post_cr_s4 *test = cpu_post_cr_table4 + i; +	ulong res; + +	unsigned long code[] = +	{ +	    ASM_MTCR(3), +	    ASM_12F(test->cmd, test->op3, test->op1, test->op2), +	    ASM_MFCR(3), +	    ASM_BLR, +	}; + +	cpu_post_exec_11 (code, &res, test->cr); + +	ret = res == test->res ? 0 : -1; + +	if (ret != 0) +	{ +	    post_log ("Error at cr4 test %d !\n", i); +	} +    } + +    asm ( "mtcr %0" : : "r" (cr_sav)); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/load.c b/post/lib_ppc/load.c new file mode 100644 index 000000000..393c56830 --- /dev/null +++ b/post/lib_ppc/load.c @@ -0,0 +1,255 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Load instructions:		lbz(x)(u), lhz(x)(u), lha(x)(u), lwz(x)(u) + * + * All operations are performed on a 16-byte array. The array + * is 4-byte aligned. The base register points to offset 8. + * The immediate offset (index register) ranges in [-8 ... +7]. + * The test cases are composed so that they do not + * cause alignment exceptions. + * The test contains a pre-built table describing all test cases. + * The table entry contains: + * the instruction opcode, the array contents, the value of the index + * register and the expected value of the destination register. + * After executing the instruction, the test verifies the + * value of the destination register and the value of the base + * register (it must change for "load with update" instructions). + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_22w (ulong *code, ulong *op1, ulong op2, ulong *op3); +extern void cpu_post_exec_21w (ulong *code, ulong *op1, ulong *op2); + +static struct cpu_post_load_s +{ +    ulong cmd; +    uint width; +    int update; +    int index; +    ulong offset; +} cpu_post_load_table[] = +{ +    { +	OP_LWZ, +	4, +	0, +	0, +	4 +    }, +    { +	OP_LHA, +	3, +	0, +	0, +	2 +    }, +    { +	OP_LHZ, +	2, +	0, +	0, +	2 +    }, +    { +	OP_LBZ, +	1, +	0, +	0, +	1 +    }, +    { +	OP_LWZU, +	4, +	1, +	0, +	4 +    }, +    { +	OP_LHAU, +	3, +	1, +	0, +	2 +    }, +    { +	OP_LHZU, +	2, +	1, +	0, +	2 +    }, +    { +	OP_LBZU, +	1, +	1, +	0, +	1 +    }, +    { +	OP_LWZX, +	4, +	0, +	1, +	4 +    }, +    { +	OP_LHAX, +	3, +	0, +	1, +	2 +    }, +    { +	OP_LHZX, +	2, +	0, +	1, +	2 +    }, +    { +	OP_LBZX, +	1, +	0, +	1, +	1 +    }, +    { +	OP_LWZUX, +	4, +	1, +	1, +	4 +    }, +    { +	OP_LHAUX, +	3, +	1, +	1, +	2 +    }, +    { +	OP_LHZUX, +	2, +	1, +	1, +	2 +    }, +    { +	OP_LBZUX, +	1, +	1, +	1, +	1 +    }, +}; +static unsigned int cpu_post_load_size = +    sizeof (cpu_post_load_table) / sizeof (struct cpu_post_load_s); + +int cpu_post_test_load (void) +{ +    int ret = 0; +    unsigned int i; + +    for (i = 0; i < cpu_post_load_size && ret == 0; i++) +    { +	struct cpu_post_load_s *test = cpu_post_load_table + i; +	uchar data[16] = +	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +	ulong base0 = (ulong) (data + 8); +	ulong base = base0; +	ulong value; + +	if (test->index) +	{ +	    ulong code[] = +	    { +		ASM_12(test->cmd, 5, 3, 4), +		ASM_BLR, +	    }; + +	    cpu_post_exec_22w (code, &base, test->offset, &value); +	} +	else +	{ +	    ulong code[] = +	    { +		ASM_11I(test->cmd, 4, 3, test->offset), +		ASM_BLR, +	    }; + +	    cpu_post_exec_21w (code, &base, &value); +	} + +	if (ret == 0) +	{ +	   if (test->update) +	       ret = base == base0 + test->offset ? 0 : -1; +	   else +	       ret = base == base0 ? 0 : -1; +	} + +	if (ret == 0) +	{ +	    switch (test->width) +	    { +	    case 1: +		ret = *(uchar *)(base0 + test->offset) == value ? +		      0 : -1; +		break; +	    case 2: +		ret = *(ushort *)(base0 + test->offset) == value ? +		      0 : -1; +		break; +	    case 3: +		ret = *(short *)(base0 + test->offset) == value ? +		      0 : -1; +		break; +	    case 4: +		ret = *(ulong *)(base0 + test->offset) == value ? +		      0 : -1; +		break; +	    } +	} + +	if (ret != 0) +	{ +	    post_log ("Error at load test %d !\n", i); +	} +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/multi.c b/post/lib_ppc/multi.c new file mode 100644 index 000000000..872438478 --- /dev/null +++ b/post/lib_ppc/multi.c @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Load/store multiple word instructions:	lmw, stmw + * + * 26 consecutive words are loaded from a source memory buffer + * into GPRs r6 through r31. After that, 26 consecutive words are stored + * from the GPRs r6 through r31 into a target memory buffer. The contents + * of the source and target buffers are then compared. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_02 (ulong *code, ulong op1, ulong op2); + +int cpu_post_test_multi (void) +{ +    int ret = 0; +    unsigned int i; + +    if (ret == 0) +    { +	ulong src [26], dst [26]; + +	ulong code[] = +	{ +	    ASM_LMW(5, 3, 0), +	    ASM_STMW(5, 4, 0), +	    ASM_BLR, +	}; + +	for (i = 0; i < sizeof(src) / sizeof(src[0]); i ++) +	{ +	    src[i] = i; +	    dst[i] = 0; +	} + +	cpu_post_exec_02(code, (ulong)src, (ulong)dst); + +	ret = memcmp(src, dst, sizeof(dst)) == 0 ? 0 : -1; +    } + +    if (ret != 0) +    { +	post_log ("Error at multi test !\n"); +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/rlwimi.c b/post/lib_ppc/rlwimi.c new file mode 100644 index 000000000..f65f79a8e --- /dev/null +++ b/post/lib_ppc/rlwimi.c @@ -0,0 +1,162 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Shift instructions:		rlwimi + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1, +    ulong op2); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_rlwimi_s +{ +    ulong cmd; +    ulong op0; +    ulong op1; +    uchar op2; +    uchar mb; +    uchar me; +    ulong res; +} cpu_post_rlwimi_table[] = +{ +    { +    	OP_RLWIMI, +	0xff00ffff, +	0x0000aa00, +	8, +	8, +	15, +	0xffaaffff +    }, +}; +static unsigned int cpu_post_rlwimi_size = +    sizeof (cpu_post_rlwimi_table) / sizeof (struct cpu_post_rlwimi_s); + +int cpu_post_test_rlwimi (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_rlwimi_size && ret == 0; i++) +    { +	struct cpu_post_rlwimi_s *test = cpu_post_rlwimi_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -20), +		ASM_STW(3, stk, 8), +		ASM_STW(4, stk, 12), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg1, stk, 8), +		ASM_LWZ(reg0, stk, 12), +		ASM_113(test->cmd, reg1, reg0, test->op2, test->mb, test->me), +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 20), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -20), +		ASM_STW(3, stk, 8), +		ASM_STW(4, stk, 12), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg1, stk, 8), +		ASM_LWZ(reg0, stk, 12), +		ASM_113(test->cmd, reg1, reg0, test->op2, test->mb, test->me) | +		    BIT_C, +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 20), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { + 	    	cr = 0; +	    	cpu_post_exec_22 (code, & cr, & res, test->op0, test->op1); + +	    	ret = res == test->res && cr == 0 ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at rlwimi test %d !\n", i); +	    	} +	    } + +	    if (ret == 0) +	    { +	    	cpu_post_exec_22 (codecr, & cr, & res, test->op0, test->op1); + +	    	ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at rlwimi test %d !\n", i); +	        } +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/rlwinm.c b/post/lib_ppc/rlwinm.c new file mode 100644 index 000000000..e240c41b1 --- /dev/null +++ b/post/lib_ppc/rlwinm.c @@ -0,0 +1,155 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Shift instructions:		rlwinm + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_21 (ulong *code, ulong *cr, ulong *res, ulong op1); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_rlwinm_s +{ +    ulong cmd; +    ulong op1; +    uchar op2; +    uchar mb; +    uchar me; +    ulong res; +} cpu_post_rlwinm_table[] = +{ +   { +   	OP_RLWINM, +	0xffff0000, +	24, +	16, +	23, +	0x0000ff00 +   }, +}; +static unsigned int cpu_post_rlwinm_size = +    sizeof (cpu_post_rlwinm_table) / sizeof (struct cpu_post_rlwinm_s); + +int cpu_post_test_rlwinm (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_rlwinm_size && ret == 0; i++) +    { +	struct cpu_post_rlwinm_s *test = cpu_post_rlwinm_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_113(test->cmd, reg1, reg0, test->op2, test->mb, test->me), +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_113(test->cmd, reg1, reg0, test->op2, test->mb, +		    test->me) | BIT_C, +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { + 	    	cr = 0; +	    	cpu_post_exec_21 (code, & cr, & res, test->op1); + +	    	ret = res == test->res && cr == 0 ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at rlwinm test %d !\n", i); +	    	} +	    } + +	    if (ret == 0) +	    { +	    	cpu_post_exec_21 (codecr, & cr, & res, test->op1); + +	    	ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at rlwinm test %d !\n", i); +	        } +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/rlwnm.c b/post/lib_ppc/rlwnm.c new file mode 100644 index 000000000..523cf4da5 --- /dev/null +++ b/post/lib_ppc/rlwnm.c @@ -0,0 +1,165 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Shift instructions:		rlwnm + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1, +    ulong op2); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_rlwnm_s +{ +    ulong cmd; +    ulong op1; +    ulong op2; +    uchar mb; +    uchar me; +    ulong res; +} cpu_post_rlwnm_table[] = +{ +   { +   	OP_RLWNM, +	0xffff0000, +	24, +	16, +	23, +	0x0000ff00 +   }, +}; +static unsigned int cpu_post_rlwnm_size = +    sizeof (cpu_post_rlwnm_table) / sizeof (struct cpu_post_rlwnm_s); + +int cpu_post_test_rlwnm (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_rlwnm_size && ret == 0; i++) +    { +	struct cpu_post_rlwnm_s *test = cpu_post_rlwnm_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int reg2 = (reg + 2) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -24), +		ASM_STW(3, stk, 12), +		ASM_STW(4, stk, 16), +		ASM_STW(reg0, stk, 8), +		ASM_STW(reg1, stk, 4), +		ASM_STW(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 12), +		ASM_LWZ(reg0, stk, 16), +		ASM_122(test->cmd, reg2, reg1, reg0, test->mb, test->me), +		ASM_STW(reg2, stk, 12), +		ASM_LWZ(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 4), +		ASM_LWZ(reg0, stk, 8), +		ASM_LWZ(3, stk, 12), +		ASM_ADDI(1, stk, 24), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -24), +		ASM_STW(3, stk, 12), +		ASM_STW(4, stk, 16), +		ASM_STW(reg0, stk, 8), +		ASM_STW(reg1, stk, 4), +		ASM_STW(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 12), +		ASM_LWZ(reg0, stk, 16), +		ASM_122(test->cmd, reg2, reg1, reg0, test->mb, test->me) | +		    BIT_C, +		ASM_STW(reg2, stk, 12), +		ASM_LWZ(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 4), +		ASM_LWZ(reg0, stk, 8), +		ASM_LWZ(3, stk, 12), +		ASM_ADDI(1, stk, 24), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { + 	    	cr = 0; +	    	cpu_post_exec_22 (code, & cr, & res, test->op1, test->op2); + +	    	ret = res == test->res && cr == 0 ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at rlwnm test %d !\n", i); +	    	} +	    } + +	    if (ret == 0) +	    { +	    	cpu_post_exec_22 (codecr, & cr, & res, test->op1, test->op2); + +	    	ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at rlwnm test %d !\n", i); +	        } +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/srawi.c b/post/lib_ppc/srawi.c new file mode 100644 index 000000000..91c82c915 --- /dev/null +++ b/post/lib_ppc/srawi.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Shift instructions:		srawi + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_21 (ulong *code, ulong *cr, ulong *res, ulong op); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_srawi_s +{ +    ulong cmd; +    ulong op1; +    uchar op2; +    ulong res; +} cpu_post_srawi_table[] = +{ +    { +    	OP_SRAWI, +	0x8000, +	3, +	0x1000 +    }, +    { +    	OP_SRAWI, +	0x80000000, +	3, +	0xf0000000 +    }, +}; +static unsigned int cpu_post_srawi_size = +    sizeof (cpu_post_srawi_table) / sizeof (struct cpu_post_srawi_s); + +int cpu_post_test_srawi (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_srawi_size && ret == 0; i++) +    { +	struct cpu_post_srawi_s *test = cpu_post_srawi_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11S(test->cmd, reg1, reg0, test->op2), +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11S(test->cmd, reg1, reg0, test->op2) | BIT_C, +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { + 	    	cr = 0; +	    	cpu_post_exec_21 (code, & cr, & res, test->op1); + +	    	ret = res == test->res && cr == 0 ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at srawi test %d !\n", i); +	    	} +	    } + +	    if (ret == 0) +	    { +	    	cpu_post_exec_21 (codecr, & cr, & res, test->op1); + +	    	ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at srawi test %d !\n", i); +	        } +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/store.c b/post/lib_ppc/store.c new file mode 100644 index 000000000..f495bf2aa --- /dev/null +++ b/post/lib_ppc/store.c @@ -0,0 +1,235 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Store instructions:		stb(x)(u), sth(x)(u), stw(x)(u) + * + * All operations are performed on a 16-byte array. The array + * is 4-byte aligned. The base register points to offset 8. + * The immediate offset (index register) ranges in [-8 ... +7]. + * The test cases are composed so that they do not + * cause alignment exceptions. + * The test contains a pre-built table describing all test cases. + * The table entry contains: + * the instruction opcode, the value of the index register and + * the value of the source register. After executing the + * instruction, the test verifies the contents of the array + * and the value of the base register (it must change for "store + * with update" instructions). + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_12w (ulong *code, ulong *op1, ulong op2, ulong op3); +extern void cpu_post_exec_11w (ulong *code, ulong *op1, ulong op2); + +static struct cpu_post_store_s +{ +    ulong cmd; +    uint width; +    int update; +    int index; +    ulong offset; +    ulong value; +} cpu_post_store_table[] = +{ +    { +	OP_STW, +	4, +	0, +	0, +	-4, +	0xff00ff00 +    }, +    { +	OP_STH, +	2, +	0, +	0, +	-2, +	0xff00 +    }, +    { +	OP_STB, +	1, +	0, +	0, +	-1, +	0xff +    }, +    { +	OP_STWU, +	4, +	1, +	0, +	-4, +	0xff00ff00 +    }, +    { +	OP_STHU, +	2, +	1, +	0, +	-2, +	0xff00 +    }, +    { +	OP_STBU, +	1, +	1, +	0, +	-1, +	0xff +    }, +    { +	OP_STWX, +	4, +	0, +	1, +	-4, +	0xff00ff00 +    }, +    { +	OP_STHX, +	2, +	0, +	1, +	-2, +	0xff00 +    }, +    { +	OP_STBX, +	1, +	0, +	1, +	-1, +	0xff +    }, +    { +	OP_STWUX, +	4, +	1, +	1, +	-4, +	0xff00ff00 +    }, +    { +	OP_STHUX, +	2, +	1, +	1, +	-2, +	0xff00 +    }, +    { +	OP_STBUX, +	1, +	1, +	1, +	-1, +	0xff +    }, +}; +static unsigned int cpu_post_store_size = +    sizeof (cpu_post_store_table) / sizeof (struct cpu_post_store_s); + +int cpu_post_test_store (void) +{ +    int ret = 0; +    unsigned int i; + +    for (i = 0; i < cpu_post_store_size && ret == 0; i++) +    { +	struct cpu_post_store_s *test = cpu_post_store_table + i; +	uchar data[16] = +	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +	ulong base0 = (ulong) (data + 8); +	ulong base = base0; + +	if (test->index) +	{ +	    ulong code[] = +	    { +		ASM_12(test->cmd, 5, 3, 4), +		ASM_BLR, +	    }; + +	    cpu_post_exec_12w (code, &base, test->offset, test->value); +	} +	else +	{ +	    ulong code[] = +	    { +		ASM_11I(test->cmd, 4, 3, test->offset), +		ASM_BLR, +	    }; + +	    cpu_post_exec_11w (code, &base, test->value); +	} + +	if (ret == 0) +	{ +	   if (test->update) +	       ret = base == base0 + test->offset ? 0 : -1; +	   else +	       ret = base == base0 ? 0 : -1; +	} + +	if (ret == 0) +	{ +	    switch (test->width) +	    { +	    case 1: +		ret = *(uchar *)(base0 + test->offset) == test->value ? +		      0 : -1; +		break; +	    case 2: +		ret = *(ushort *)(base0 + test->offset) == test->value ? +		      0 : -1; +		break; +	    case 4: +		ret = *(ulong *)(base0 + test->offset) == test->value ? +		      0 : -1; +		break; +	    } +	} + +	if (ret != 0) +	{ +	    post_log ("Error at store test %d !\n", i); +	} +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/string.c b/post/lib_ppc/string.c new file mode 100644 index 000000000..bd83bd136 --- /dev/null +++ b/post/lib_ppc/string.c @@ -0,0 +1,106 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Load/store string instructions:	lswi, stswi, lswx, stswx + * + * Several consecutive bytes from a source memory buffer are loaded + * left to right into GPRs. After that, the bytes are stored + * from the GPRs into a target memory buffer. The contents + * of the source and target buffers are then compared. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_02 (ulong *code, ulong op1, ulong op2); +extern void cpu_post_exec_04 (ulong *code, ulong op1, ulong op2, ulong op3, +    ulong op4); + +#include <bedbug/regs.h> +int cpu_post_test_string (void) +{ +    int ret = 0; +    unsigned int i; + +    if (ret == 0) +    { +	char src [31], dst [31]; + +	ulong code[] = +	{ +	    ASM_LSWI(5, 3, 31), +	    ASM_STSWI(5, 4, 31), +	    ASM_BLR, +	}; + +	for (i = 0; i < sizeof(src); i ++) +	{ +	    src[i] = (char) i; +	    dst[i] = 0; +	} + +	cpu_post_exec_02(code, (ulong)src, (ulong)dst); + +	ret = memcmp(src, dst, sizeof(dst)) == 0 ? 0 : -1; +    } + +    if (ret == 0) +    { +	char src [95], dst [95]; + +	ulong code[] = +	{ +	    ASM_LSWX(8, 3, 5), +	    ASM_STSWX(8, 4, 5), +	    ASM_BLR, +	}; + +	for (i = 0; i < sizeof(src); i ++) +	{ +	    src[i] = (char) i; +	    dst[i] = 0; +	} + +	cpu_post_exec_04(code, (ulong)src, (ulong)dst, 0, sizeof(src)); + +	ret = memcmp(src, dst, sizeof(dst)) == 0 ? 0 : -1; +    } + +    if (ret != 0) +    { +	post_log ("Error at string test !\n"); +    } + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/three.c b/post/lib_ppc/three.c new file mode 100644 index 000000000..c2d747604 --- /dev/null +++ b/post/lib_ppc/three.c @@ -0,0 +1,259 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Ternary instructions		instr rD,rA,rB + * + * Arithmetic instructions:	add, addc, adde, subf, subfc, subfe, + *				mullw, mulhw, mulhwu, divw, divwu + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1, +    ulong op2); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_three_s +{ +    ulong cmd; +    ulong op1; +    ulong op2; +    ulong res; +} cpu_post_three_table[] = +{ +    { +    	OP_ADD, +	100, +	200, +	300 +    }, +    { +    	OP_ADD, +	100, +	-200, +	-100 +    }, +    { +    	OP_ADDC, +	100, +	200, +	300 +    }, +    { +    	OP_ADDC, +	100, +	-200, +	-100 +    }, +    { +    	OP_ADDE, +	100, +	200, +	300 +    }, +    { +    	OP_ADDE, +	100, +	-200, +	-100 +    }, +    { +    	OP_SUBF, +	100, +	200, +	100 +    }, +    { +    	OP_SUBF, +	300, +	200, +	-100 +    }, +    { +    	OP_SUBFC, +	100, +	200, +	100 +    }, +    { +    	OP_SUBFC, +	300, +	200, +	-100 +    }, +    { +    	OP_SUBFE, +	100, +	200, +	200 + ~100 +    }, +    { +    	OP_SUBFE, +	300, +	200, +	200 + ~300 +    }, +    { +    	OP_MULLW, +	200, +	300, +	200 * 300 +    }, +    { +    	OP_MULHW, +	0x10000000, +	0x10000000, +	0x1000000 +    }, +    { +    	OP_MULHWU, +	0x80000000, +	0x80000000, +	0x40000000 +    }, +    { +    	OP_DIVW, +	-20, +	5, +	-4 +    }, +    { +    	OP_DIVWU, +	0x8000, +	0x200, +	0x40 +    }, +}; +static unsigned int cpu_post_three_size = +    sizeof (cpu_post_three_table) / sizeof (struct cpu_post_three_s); + +int cpu_post_test_three (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_three_size && ret == 0; i++) +    { +	struct cpu_post_three_s *test = cpu_post_three_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int reg2 = (reg + 2) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -24), +		ASM_STW(3, stk, 12), +		ASM_STW(4, stk, 16), +		ASM_STW(reg0, stk, 8), +		ASM_STW(reg1, stk, 4), +		ASM_STW(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 12), +		ASM_LWZ(reg0, stk, 16), +		ASM_12(test->cmd, reg2, reg1, reg0), +		ASM_STW(reg2, stk, 12), +		ASM_LWZ(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 4), +		ASM_LWZ(reg0, stk, 8), +		ASM_LWZ(3, stk, 12), +		ASM_ADDI(1, stk, 24), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -24), +		ASM_STW(3, stk, 12), +		ASM_STW(4, stk, 16), +		ASM_STW(reg0, stk, 8), +		ASM_STW(reg1, stk, 4), +		ASM_STW(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 12), +		ASM_LWZ(reg0, stk, 16), +		ASM_12(test->cmd, reg2, reg1, reg0) | BIT_C, +		ASM_STW(reg2, stk, 12), +		ASM_LWZ(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 4), +		ASM_LWZ(reg0, stk, 8), +		ASM_LWZ(3, stk, 12), +		ASM_ADDI(1, stk, 24), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { + 	    	cr = 0; +	    	cpu_post_exec_22 (code, & cr, & res, test->op1, test->op2); + +	    	ret = res == test->res && cr == 0 ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at three test %d !\n", i); +	    	} +	    } + +	    if (ret == 0) +	    { +	    	cpu_post_exec_22 (codecr, & cr, & res, test->op1, test->op2); + +	    	ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at three test %d !\n", i); +	        } +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/threei.c b/post/lib_ppc/threei.c new file mode 100644 index 000000000..79f01789c --- /dev/null +++ b/post/lib_ppc/threei.c @@ -0,0 +1,137 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Ternary instructions		instr rA,rS,UIMM + * + * Logic instructions:		ori, oris, xori, xoris + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_21 (ulong *code, ulong *cr, ulong *res, ulong op); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_threei_s +{ +    ulong cmd; +    ulong op1; +    ushort op2; +    ulong res; +} cpu_post_threei_table[] = +{ +    { +    	OP_ORI, +	0x80000000, +	0xffff, +	0x8000ffff +    }, +    { +    	OP_ORIS, +	0x00008000, +	0xffff, +	0xffff8000 +    }, +    { +    	OP_XORI, +	0x8000ffff, +	0xffff, +	0x80000000 +    }, +    { +    	OP_XORIS, +	0x00008000, +	0xffff, +	0xffff8000 +    }, +}; +static unsigned int cpu_post_threei_size = +    sizeof (cpu_post_threei_table) / sizeof (struct cpu_post_threei_s); + +int cpu_post_test_threei (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_threei_size && ret == 0; i++) +    { +	struct cpu_post_threei_s *test = cpu_post_threei_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11IX(test->cmd, reg1, reg0, test->op2), +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + + 	    cr = 0; +	    cpu_post_exec_21 (code, & cr, & res, test->op1); + +	    ret = res == test->res && cr == 0 ? 0 : -1; + +	    if (ret != 0) +	    { +	        post_log ("Error at threei test %d !\n", i); +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/threex.c b/post/lib_ppc/threex.c new file mode 100644 index 000000000..2c7206384 --- /dev/null +++ b/post/lib_ppc/threex.c @@ -0,0 +1,229 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Ternary instructions		instr rA,rS,rB + * + * Logic instructions:		or, orc, xor, nand, nor, eqv + * Shift instructions:		slw, srw, sraw + * + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_22 (ulong *code, ulong *cr, ulong *res, ulong op1, +    ulong op2); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_threex_s +{ +    ulong cmd; +    ulong op1; +    ulong op2; +    ulong res; +} cpu_post_threex_table[] = +{ +    { +    	OP_OR, +	0x1234, +	0x5678, +	0x1234 | 0x5678 +    }, +    { +    	OP_ORC, +	0x1234, +	0x5678, +	0x1234 | ~0x5678 +    }, +    { +    	OP_XOR, +	0x1234, +	0x5678, +	0x1234 ^ 0x5678 +    }, +    { +    	OP_NAND, +	0x1234, +	0x5678, +	~(0x1234 & 0x5678) +    }, +    { +    	OP_NOR, +	0x1234, +	0x5678, +	~(0x1234 | 0x5678) +    }, +    { +    	OP_EQV, +	0x1234, +	0x5678, +	~(0x1234 ^ 0x5678) +    }, +    { +    	OP_SLW, +	0x80, +	16, +	0x800000 +    }, +    { +    	OP_SLW, +	0x80, +	32, +	0 +    }, +    { +    	OP_SRW, +	0x800000, +	16, +	0x80 +    }, +    { +    	OP_SRW, +	0x800000, +	32, +	0 +    }, +    { +    	OP_SRAW, +	0x80000000, +	3, +	0xf0000000 +    }, +    { +    	OP_SRAW, +	0x8000, +	3, +	0x1000 +    }, +}; +static unsigned int cpu_post_threex_size = +    sizeof (cpu_post_threex_table) / sizeof (struct cpu_post_threex_s); + +int cpu_post_test_threex (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_threex_size && ret == 0; i++) +    { +	struct cpu_post_threex_s *test = cpu_post_threex_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int reg2 = (reg + 2) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -24), +		ASM_STW(3, stk, 12), +		ASM_STW(4, stk, 16), +		ASM_STW(reg0, stk, 8), +		ASM_STW(reg1, stk, 4), +		ASM_STW(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 12), +		ASM_LWZ(reg0, stk, 16), +		ASM_12X(test->cmd, reg2, reg1, reg0), +		ASM_STW(reg2, stk, 12), +		ASM_LWZ(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 4), +		ASM_LWZ(reg0, stk, 8), +		ASM_LWZ(3, stk, 12), +		ASM_ADDI(1, stk, 24), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -24), +		ASM_STW(3, stk, 12), +		ASM_STW(4, stk, 16), +		ASM_STW(reg0, stk, 8), +		ASM_STW(reg1, stk, 4), +		ASM_STW(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 12), +		ASM_LWZ(reg0, stk, 16), +		ASM_12X(test->cmd, reg2, reg1, reg0) | BIT_C, +		ASM_STW(reg2, stk, 12), +		ASM_LWZ(reg2, stk, 0), +		ASM_LWZ(reg1, stk, 4), +		ASM_LWZ(reg0, stk, 8), +		ASM_LWZ(3, stk, 12), +		ASM_ADDI(1, stk, 24), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { + 	    	cr = 0; +	    	cpu_post_exec_22 (code, & cr, & res, test->op1, test->op2); + +	    	ret = res == test->res && cr == 0 ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at threex test %d !\n", i); +	    	} +	    } + +	    if (ret == 0) +	    { +	    	cpu_post_exec_22 (codecr, & cr, & res, test->op1, test->op2); + +	    	ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at threex test %d !\n", i); +	        } +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/two.c b/post/lib_ppc/two.c new file mode 100644 index 000000000..cfbac5e62 --- /dev/null +++ b/post/lib_ppc/two.c @@ -0,0 +1,176 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Binary instructions		instr rD,rA + * + * Logic instructions:		neg + * Arithmetic instructions:	addme, addze, subfme, subfze + + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_21 (ulong *code, ulong *cr, ulong *res, ulong op1); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_two_s +{ +    ulong cmd; +    ulong op; +    ulong res; +} cpu_post_two_table[] = +{ +    { +	OP_NEG, +	3, +	-3 +    }, +    { +	OP_NEG, +	5, +	-5 +    }, +    { +	OP_ADDME, +	6, +	5 +    }, +    { +	OP_ADDZE, +	5, +	5 +    }, +    { +	OP_SUBFME, +	6, +	~6 - 1 +    }, +    { +	OP_SUBFZE, +	5, +	~5 +    }, +}; +static unsigned int cpu_post_two_size = +    sizeof (cpu_post_two_table) / sizeof (struct cpu_post_two_s); + +int cpu_post_test_two (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_two_size && ret == 0; i++) +    { +	struct cpu_post_two_s *test = cpu_post_two_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11(test->cmd, reg1, reg0), +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11(test->cmd, reg1, reg0) | BIT_C, +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { +		cr = 0; +		cpu_post_exec_21 (code, & cr, & res, test->op); + +		ret = res == test->res && cr == 0 ? 0 : -1; + +		if (ret != 0) +		{ +		    post_log ("Error at two test %d !\n", i); +		} +	    } + +	    if (ret == 0) +	    { +		cpu_post_exec_21 (codecr, & cr, & res, test->op); + +		ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +		if (ret != 0) +		{ +		    post_log ("Error at two test %d !\n", i); +		} +	    } +	} +    } + +    if (flag) +	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/lib_ppc/twox.c b/post/lib_ppc/twox.c new file mode 100644 index 000000000..48d9954ca --- /dev/null +++ b/post/lib_ppc/twox.c @@ -0,0 +1,176 @@ +/* + * (C) Copyright 2002 + * 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 <common.h> + +/* + * CPU test + * Binary instructions		instr rA,rS + * + * Logic instructions:		cntlzw + * Arithmetic instructions:	extsb, extsh + + * The test contains a pre-built table of instructions, operands and + * expected results. For each table entry, the test will cyclically use + * different sets of operand registers and result registers. + */ + +#ifdef CONFIG_POST + +#include <post.h> +#include "cpu_asm.h" + +#if CONFIG_POST & CFG_POST_CPU + +extern void cpu_post_exec_21 (ulong *code, ulong *cr, ulong *res, ulong op1); +extern ulong cpu_post_makecr (long v); + +static struct cpu_post_twox_s +{ +    ulong cmd; +    ulong op; +    ulong res; +} cpu_post_twox_table[] = +{ +    { +    	OP_EXTSB, +	3, +	3 +    }, +    { +    	OP_EXTSB, +	0xff, +	-1 +    }, +    { +    	OP_EXTSH, +	3, +	3 +    }, +    { +    	OP_EXTSH, +	0xff, +	0xff +    }, +    { +    	OP_EXTSH, +	0xffff, +	-1 +    }, +    { +    	OP_CNTLZW, +	0x000fffff, +	12 +    }, +}; +static unsigned int cpu_post_twox_size = +    sizeof (cpu_post_twox_table) / sizeof (struct cpu_post_twox_s); + +int cpu_post_test_twox (void) +{ +    int ret = 0; +    unsigned int i, reg; +    int flag = disable_interrupts(); + +    for (i = 0; i < cpu_post_twox_size && ret == 0; i++) +    { +	struct cpu_post_twox_s *test = cpu_post_twox_table + i; + +	for (reg = 0; reg < 32 && ret == 0; reg++) +	{ +	    unsigned int reg0 = (reg + 0) % 32; +	    unsigned int reg1 = (reg + 1) % 32; +	    unsigned int stk = reg < 16 ? 31 : 15; +    	    unsigned long code[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11X(test->cmd, reg1, reg0), +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +    	    unsigned long codecr[] = +	    { +		ASM_STW(stk, 1, -4), +		ASM_ADDI(stk, 1, -16), +		ASM_STW(3, stk, 8), +		ASM_STW(reg0, stk, 4), +		ASM_STW(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 8), +		ASM_11X(test->cmd, reg1, reg0) | BIT_C, +		ASM_STW(reg1, stk, 8), +		ASM_LWZ(reg1, stk, 0), +		ASM_LWZ(reg0, stk, 4), +		ASM_LWZ(3, stk, 8), +		ASM_ADDI(1, stk, 16), +		ASM_LWZ(stk, 1, -4), +		ASM_BLR, +	    }; +	    ulong res; +	    ulong cr; + +	    if (ret == 0) +	    { + 	    	cr = 0; +	    	cpu_post_exec_21 (code, & cr, & res, test->op); + +	    	ret = res == test->res && cr == 0 ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at twox test %d !\n", i); +	    	} +	    } + +	    if (ret == 0) +	    { +	    	cpu_post_exec_21 (codecr, & cr, & res, test->op); + +	    	ret = res == test->res && +		      (cr & 0xe0000000) == cpu_post_makecr (res) ? 0 : -1; + +	    	if (ret != 0) +	    	{ +	            post_log ("Error at twox test %d !\n", i); +	        } +	    } +	} +    } + +    if (flag) +    	enable_interrupts(); + +    return ret; +} + +#endif +#endif diff --git a/post/post.c b/post/post.c index e1066da6b..ac4199086 100644 --- a/post/post.c +++ b/post/post.c @@ -430,6 +430,7 @@ unsigned long post_time_ms (unsigned long base)  #ifdef CONFIG_PPC  	return (unsigned long)get_ticks () / (get_tbclk () / CFG_HZ) - base;  #else +#warning "Not implemented yet"  	return 0; /* Not implemented yet */  #endif  } |