diff options
Diffstat (limited to 'board/tqc')
33 files changed, 10008 insertions, 0 deletions
| diff --git a/board/tqc/tqm5200/Makefile b/board/tqc/tqm5200/Makefile new file mode 100644 index 000000000..a5ce7bd46 --- /dev/null +++ b/board/tqc/tqm5200/Makefile @@ -0,0 +1,53 @@ +# +# (C) Copyright 2003-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 +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(BOARD).a + +COBJS	:= $(BOARD).o cmd_stk52xx.o cmd_tb5200.o cam5200_flash.o + +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) +SOBJS	:= $(addprefix $(obj),$(SOBJS)) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +clean: +	rm -f $(SOBJS) $(OBJS) + +distclean:	clean +	rm -f $(LIB) core *.bak .depend + +cam5200_flash.o:	cam5200_flash.c +	$(CC) $(CFLAGS) -fno-strict-aliasing -c -o $@ $< + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/tqc/tqm5200/cam5200_flash.c b/board/tqc/tqm5200/cam5200_flash.c new file mode 100644 index 000000000..b3f095d80 --- /dev/null +++ b/board/tqc/tqm5200/cam5200_flash.c @@ -0,0 +1,786 @@ +/* + * (C) Copyright 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 + */ + +#include <common.h> +#include <mpc5xxx.h> +#include <asm/processor.h> + +#if defined(CONFIG_CAM5200) && defined(CONFIG_CAM5200_NIOSFLASH) + +#if 0 +#define DEBUGF(x...) printf(x) +#else +#define DEBUGF(x...) +#endif + +#define swap16(x) __swab16(x) + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS];	/* info for FLASH chips */ + +/* + * CAM5200 is a TQM5200B based board. Additionally it also features + * a NIOS cpu. The NIOS CPU peripherals are accessible through MPC5xxx + * Local Bus on CS5. This includes 32 bit wide RAM and SRAM as well as + * 16 bit wide flash device. Big Endian order on a 32 bit CS5 makes + * access to flash chip slightly more complicated as additional byte + * swapping is necessary within each 16 bit wide flash 'word'. + * + * This driver's task is to handle both flash devices: 32 bit TQM5200B + * flash chip and 16 bit NIOS cpu flash chip. In the below + * flash_addr_table table we use least significant address bit to mark + * 16 bit flash bank and two sets of routines *_32 and *_16 to handle + * specifics of both flashes. + */ +static unsigned long flash_addr_table[][CFG_MAX_FLASH_BANKS] = { +	{CFG_BOOTCS_START, CFG_CS5_START | 1} +}; + +/*----------------------------------------------------------------------- + * Functions + */ +static int write_word(flash_info_t * info, ulong dest, ulong data); +#ifdef CFG_FLASH_2ND_16BIT_DEV +static int write_word_32(flash_info_t * info, ulong dest, ulong data); +static int write_word_16(flash_info_t * info, ulong dest, ulong data); +static int flash_erase_32(flash_info_t * info, int s_first, int s_last); +static int flash_erase_16(flash_info_t * info, int s_first, int s_last); +static ulong flash_get_size_32(vu_long * addr, flash_info_t * info); +static ulong flash_get_size_16(vu_long * addr, flash_info_t * info); +#endif + +void flash_print_info(flash_info_t * info) +{ +	int i, k; +	int size, erased; +	volatile unsigned long *flash; + +	if (info->flash_id == FLASH_UNKNOWN) { +		printf("missing or unknown FLASH type\n"); +		return; +	} + +	switch (info->flash_id & FLASH_VENDMASK) { +		case FLASH_MAN_AMD: +			printf("AMD "); +			break; +		case FLASH_MAN_FUJ: +			printf("FUJITSU "); +			break; +		default: +			printf("Unknown Vendor "); +			break; +	} + +	switch (info->flash_id & FLASH_TYPEMASK) { +		case FLASH_S29GL128N: +			printf ("S29GL128N (256 Mbit, uniform sector size)\n"); +			break; +		case FLASH_AM320B: +			printf ("29LV320B (32 Mbit, bottom boot sect)\n"); +			break; +		case FLASH_AM320T: +			printf ("29LV320T (32 Mbit, top boot sect)\n"); +			break; +		default: +			printf("Unknown Chip Type\n"); +			break; +	} + +	printf("  Size: %ld KB in %d Sectors\n", +			info->size >> 10, info->sector_count); + +	printf("  Sector Start Addresses:"); +	for (i = 0; i < info->sector_count; ++i) { +		/* +		 * Check if whole sector is erased +		 */ +		if (i != (info->sector_count - 1)) +			size = info->start[i + 1] - info->start[i]; +		else +			size = info->start[0] + info->size - info->start[i]; + +		erased = 1; +		flash = (volatile unsigned long *)info->start[i]; +		size = size >> 2;	/* divide by 4 for longword access */ + +		for (k = 0; k < size; k++) { +			if (*flash++ != 0xffffffff) { +				erased = 0; +				break; +			} +		} + +		if ((i % 5) == 0) +			printf("\n   "); + +		printf(" %08lX%s%s", info->start[i], +				erased ? " E" : "  ", +				info->protect[i] ? "RO " : "   "); +	} +	printf("\n"); +	return; +} + + +/* + * The following code cannot be run from FLASH! + */ +#ifdef CFG_FLASH_2ND_16BIT_DEV +static ulong flash_get_size(vu_long * addr, flash_info_t * info) +{ + +	DEBUGF("get_size: FLASH ADDR %08lx\n", addr); + +	/* bit 0 used for big flash marking */ +	if ((ulong)addr & 0x1) +		return flash_get_size_16((vu_long *)((ulong)addr & 0xfffffffe), info); +	else +		return flash_get_size_32(addr, info); +} + +static ulong flash_get_size_32(vu_long * addr, flash_info_t * info) +#else +static ulong flash_get_size(vu_long * addr, flash_info_t * info) +#endif +{ +	short i; +	CFG_FLASH_WORD_SIZE value; +	ulong base = (ulong) addr; +	volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) addr; + +	DEBUGF("get_size32: FLASH ADDR: %08x\n", (unsigned)addr); + +	/* Write auto select command: read Manufacturer ID */ +	addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA; +	addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055; +	addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00900090; +	udelay(1000); + +	value = addr2[0]; +	DEBUGF("FLASH MANUFACT: %x\n", value); + +	switch (value) { +		case (CFG_FLASH_WORD_SIZE) AMD_MANUFACT: +			info->flash_id = FLASH_MAN_AMD; +			break; +		default: +			info->flash_id = FLASH_UNKNOWN; +			info->sector_count = 0; +			info->size = 0; +			return (0);	/* no or unknown flash  */ +	} + +	value = addr2[1];	/* device ID            */ +	DEBUGF("\nFLASH DEVICEID: %x\n", value); + +	switch (value) { +		case AMD_ID_MIRROR: +			DEBUGF("Mirror Bit flash: addr[14] = %08lX  addr[15] = %08lX\n", +					addr[14], addr[15]); +			switch(addr[14]) { +				case AMD_ID_GL128N_2: +					if (addr[15] != AMD_ID_GL128N_3) { +						DEBUGF("Chip: S29GL128N -> unknown\n"); +						info->flash_id = FLASH_UNKNOWN; +					} else { +						DEBUGF("Chip: S29GL128N\n"); +						info->flash_id += FLASH_S29GL128N; +						info->sector_count = 128; +						info->size = 0x02000000; +					} +					break; +				default: +					info->flash_id = FLASH_UNKNOWN; +					return(0); +			} +			break; + +		default: +			info->flash_id = FLASH_UNKNOWN; +			return (0);	/* => no or unknown flash */ +	} + +	/* set up sector start address table */ +	for (i = 0; i < info->sector_count; i++) +		info->start[i] = base + (i * 0x00040000); + +	/* check for protected sectors */ +	for (i = 0; i < info->sector_count; i++) { +		/* read sector protection at sector address, (A7 .. A0) = 0x02 */ +		/* D0 = 1 if protected */ +		addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]); + +		info->protect[i] = addr2[2] & 1; +	} + +	/* issue bank reset to return to read mode */ +	addr2[0] = (CFG_FLASH_WORD_SIZE) 0x00F000F0; + +	return (info->size); +} + +static int wait_for_DQ7_32(flash_info_t * info, int sect) +{ +	ulong start, now, last; +	volatile CFG_FLASH_WORD_SIZE *addr = +		(CFG_FLASH_WORD_SIZE *) (info->start[sect]); + +	start = get_timer(0); +	last = start; +	while ((addr[0] & (CFG_FLASH_WORD_SIZE) 0x00800080) != +			(CFG_FLASH_WORD_SIZE) 0x00800080) { +		if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { +			printf("Timeout\n"); +			return -1; +		} +		/* show that we're waiting */ +		if ((now - last) > 1000) {	/* every second */ +			putc('.'); +			last = now; +		} +	} +	return 0; +} + +#ifdef CFG_FLASH_2ND_16BIT_DEV +int flash_erase(flash_info_t * info, int s_first, int s_last) +{ +	if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) { +		return flash_erase_16(info, s_first, s_last); +	} else { +		return flash_erase_32(info, s_first, s_last); +	} +} + +static int flash_erase_32(flash_info_t * info, int s_first, int s_last) +#else +int flash_erase(flash_info_t * info, int s_first, int s_last) +#endif +{ +	volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *) (info->start[0]); +	volatile CFG_FLASH_WORD_SIZE *addr2; +	int flag, prot, sect, l_sect; + +	if ((s_first < 0) || (s_first > s_last)) { +		if (info->flash_id == FLASH_UNKNOWN) +			printf("- missing\n"); +		else +			printf("- no sectors to erase\n"); +		return 1; +	} + +	if (info->flash_id == FLASH_UNKNOWN) { +		printf("Can't erase unknown flash type - aborted\n"); +		return 1; +	} + +	prot = 0; +	for (sect = s_first; sect <= s_last; ++sect) { +		if (info->protect[sect]) +			prot++; +	} + +	if (prot) +		printf("- Warning: %d protected sectors will not be erased!", prot); + +	printf("\n"); + +	l_sect = -1; + +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts(); + +	/* Start erase on unprotected sectors */ +	for (sect = s_first; sect <= s_last; sect++) { +		if (info->protect[sect] == 0) {	/* not protected */ +			addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[sect]); + +			addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA; +			addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055; +			addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00800080; +			addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA; +			addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055; +			addr2[0] = (CFG_FLASH_WORD_SIZE) 0x00300030;	/* sector erase */ + +			l_sect = sect; +			/* +			 * Wait for each sector to complete, it's more +			 * reliable.  According to AMD Spec, you must +			 * issue all erase commands within a specified +			 * timeout.  This has been seen to fail, especially +			 * if printf()s are included (for debug)!! +			 */ +			wait_for_DQ7_32(info, sect); +		} +	} + +	/* re-enable interrupts if necessary */ +	if (flag) +		enable_interrupts(); + +	/* wait at least 80us - let's wait 1 ms */ +	udelay(1000); + +	/* reset to read mode */ +	addr = (CFG_FLASH_WORD_SIZE *) info->start[0]; +	addr[0] = (CFG_FLASH_WORD_SIZE) 0x00F000F0;	/* reset bank */ + +	printf(" done\n"); +	return 0; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ +	ulong cp, wp, data; +	int i, l, rc; + +	wp = (addr & ~3);	/* get lower word aligned address */ + +	/* +	 * handle unaligned start bytes +	 */ +	if ((l = addr - wp) != 0) { +		data = 0; +		for (i = 0, cp = wp; i < l; ++i, ++cp) +			data = (data << 8) | (*(uchar *) cp); + +		for (; i < 4 && cnt > 0; ++i) { +			data = (data << 8) | *src++; +			--cnt; +			++cp; +		} + +		for (; cnt == 0 && i < 4; ++i, ++cp) +			data = (data << 8) | (*(uchar *) cp); + +		if ((rc = write_word(info, wp, data)) != 0) +			return (rc); + +		wp += 4; +	} + +	/* +	 * handle word aligned part +	 */ +	while (cnt >= 4) { +		data = 0; +		for (i = 0; i < 4; ++i) +			data = (data << 8) | *src++; + +		if ((rc = write_word(info, wp, data)) != 0) +			return (rc); + +		wp += 4; +		cnt -= 4; +	} + +	if (cnt == 0) +		return (0); + +	/* +	 * handle unaligned tail bytes +	 */ +	data = 0; +	for (i = 0, cp = wp; i < 4 && cnt > 0; ++i, ++cp) { +		data = (data << 8) | *src++; +		--cnt; +	} +	for (; i < 4; ++i, ++cp) +		data = (data << 8) | (*(uchar *) cp); + +	return (write_word(info, wp, data)); +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +#ifdef CFG_FLASH_2ND_16BIT_DEV +static int write_word(flash_info_t * info, ulong dest, ulong data) +{ +	if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) { +		return write_word_16(info, dest, data); +	} else { +		return write_word_32(info, dest, data); +	} +} + +static int write_word_32(flash_info_t * info, ulong dest, ulong data) +#else +static int write_word(flash_info_t * info, ulong dest, ulong data) +#endif +{ +	volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[0]); +	volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *) dest; +	volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *) & data; +	ulong start; +	int i, flag; + +	/* Check if Flash is (sufficiently) erased */ +	if ((*((vu_long *)dest) & data) != data) +		return (2); + +	for (i = 0; i < 4 / sizeof(CFG_FLASH_WORD_SIZE); i++) { +		/* Disable interrupts which might cause a timeout here */ +		flag = disable_interrupts(); + +		addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA; +		addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055; +		addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00A000A0; + +		dest2[i] = data2[i]; + +		/* re-enable interrupts if necessary */ +		if (flag) +			enable_interrupts(); + +		/* data polling for D7 */ +		start = get_timer(0); +		while ((dest2[i] & (CFG_FLASH_WORD_SIZE) 0x00800080) != +				(data2[i] & (CFG_FLASH_WORD_SIZE) 0x00800080)) { + +			if (get_timer(start) > CFG_FLASH_WRITE_TOUT) +				return (1); +		} +	} + +	return (0); +} + +#ifdef CFG_FLASH_2ND_16BIT_DEV + +#undef  CFG_FLASH_WORD_SIZE +#define CFG_FLASH_WORD_SIZE unsigned short + +/* + * The following code cannot be run from FLASH! + */ +static ulong flash_get_size_16(vu_long * addr, flash_info_t * info) +{ +	short i; +	CFG_FLASH_WORD_SIZE value; +	ulong base = (ulong) addr; +	volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) addr; + +	DEBUGF("get_size16: FLASH ADDR: %08x\n", (unsigned)addr); + +	/* issue bank reset to return to read mode */ +	addr2[0] = (CFG_FLASH_WORD_SIZE) 0xF000F000; + +	/* Write auto select command: read Manufacturer ID */ +	addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAA00AA00; +	addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55005500; +	addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x90009000; +	udelay(1000); + +	value = swap16(addr2[0]); +	DEBUGF("FLASH MANUFACT: %x\n", value); + +	switch (value) { +		case (CFG_FLASH_WORD_SIZE) AMD_MANUFACT: +			info->flash_id = FLASH_MAN_AMD; +			break; +		case (CFG_FLASH_WORD_SIZE) FUJ_MANUFACT: +			info->flash_id = FLASH_MAN_FUJ; +			break; +		default: +			info->flash_id = FLASH_UNKNOWN; +			info->sector_count = 0; +			info->size = 0; +			return (0);	/* no or unknown flash  */ +	} + +	value = swap16(addr2[1]);	/* device ID            */ +	DEBUGF("\nFLASH DEVICEID: %x\n", value); + +	switch (value) { +		case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320B: +			info->flash_id += FLASH_AM320B; +			info->sector_count = 71; +			info->size = 0x00400000; +			break;	/* => 4 MB	*/ +		case (CFG_FLASH_WORD_SIZE)AMD_ID_LV320T: +			info->flash_id += FLASH_AM320T; +			info->sector_count = 71; +			info->size = 0x00400000; +			break;	/* => 4 MB	*/ +		default: +			info->flash_id = FLASH_UNKNOWN; +			return (0);	/* => no or unknown flash */ +	} + +	if (info->flash_id & FLASH_BTYPE) { +		/* set sector offsets for bottom boot block type        */ +		info->start[0] = base + 0x00000000; +		info->start[1] = base + 0x00002000; +		info->start[2] = base + 0x00004000; +		info->start[3] = base + 0x00006000; +		info->start[4] = base + 0x00008000; +		info->start[5] = base + 0x0000a000; +		info->start[6] = base + 0x0000c000; +		info->start[7] = base + 0x0000e000; + +		for (i = 8; i < info->sector_count; i++) +			info->start[i] = base + (i * 0x00010000) - 0x00070000; +	} else { +		/* set sector offsets for top boot block type           */ +		i = info->sector_count - 1; +		info->start[i--] = base + info->size - 0x00002000; +		info->start[i--] = base + info->size - 0x00004000; +		info->start[i--] = base + info->size - 0x00006000; +		info->start[i--] = base + info->size - 0x00008000; +		info->start[i--] = base + info->size - 0x0000a000; +		info->start[i--] = base + info->size - 0x0000c000; +		info->start[i--] = base + info->size - 0x0000e000; + +		for (; i >= 0; i--) +			info->start[i] = base + i * 0x00010000; +	} + +	/* check for protected sectors */ +	for (i = 0; i < info->sector_count; i++) { +		/* read sector protection at sector address, (A7 .. A0) = 0x02 */ +		/* D0 = 1 if protected */ +		addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]); + +		info->protect[i] = addr2[2] & 1; +	} + +	/* issue bank reset to return to read mode */ +	addr2[0] = (CFG_FLASH_WORD_SIZE) 0xF000F000; + +	return (info->size); +} + +static int wait_for_DQ7_16(flash_info_t * info, int sect) +{ +	ulong start, now, last; +	volatile CFG_FLASH_WORD_SIZE *addr = +		(CFG_FLASH_WORD_SIZE *) (info->start[sect]); + +	start = get_timer(0); +	last = start; +	while ((addr[0] & (CFG_FLASH_WORD_SIZE) 0x80008000) != +			(CFG_FLASH_WORD_SIZE) 0x80008000) { +		if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { +			printf("Timeout\n"); +			return -1; +		} +		/* show that we're waiting */ +		if ((now - last) > 1000) {	/* every second */ +			putc('.'); +			last = now; +		} +	} +	return 0; +} + +static int flash_erase_16(flash_info_t * info, int s_first, int s_last) +{ +	volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *) (info->start[0]); +	volatile CFG_FLASH_WORD_SIZE *addr2; +	int flag, prot, sect, l_sect; + +	if ((s_first < 0) || (s_first > s_last)) { +		if (info->flash_id == FLASH_UNKNOWN) +			printf("- missing\n"); +		else +			printf("- no sectors to erase\n"); +		return 1; +	} + +	if (info->flash_id == FLASH_UNKNOWN) { +		printf("Can't erase unknown flash type - aborted\n"); +		return 1; +	} + +	prot = 0; +	for (sect = s_first; sect <= s_last; ++sect) { +		if (info->protect[sect]) +			prot++; +	} + +	if (prot) +		printf("- Warning: %d protected sectors will not be erased!",	prot); + +	printf("\n"); + +	l_sect = -1; + +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts(); + +	/* Start erase on unprotected sectors */ +	for (sect = s_first; sect <= s_last; sect++) { +		if (info->protect[sect] == 0) {	/* not protected */ +			addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[sect]); + +			addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAA00AA00; +			addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55005500; +			addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x80008000; +			addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAA00AA00; +			addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55005500; +			addr2[0] = (CFG_FLASH_WORD_SIZE) 0x30003000;	/* sector erase */ + +			l_sect = sect; +			/* +			 * Wait for each sector to complete, it's more +			 * reliable.  According to AMD Spec, you must +			 * issue all erase commands within a specified +			 * timeout.  This has been seen to fail, especially +			 * if printf()s are included (for debug)!! +			 */ +			wait_for_DQ7_16(info, sect); +		} +	} + +	/* re-enable interrupts if necessary */ +	if (flag) +		enable_interrupts(); + +	/* wait at least 80us - let's wait 1 ms */ +	udelay(1000); + +	/* reset to read mode */ +	addr = (CFG_FLASH_WORD_SIZE *) info->start[0]; +	addr[0] = (CFG_FLASH_WORD_SIZE) 0xF000F000;	/* reset bank */ + +	printf(" done\n"); +	return 0; +} + +static int write_word_16(flash_info_t * info, ulong dest, ulong data) +{ +	volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[0]); +	volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *) dest; +	volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *) & data; +	ulong start; +	int i; + +	/* Check if Flash is (sufficiently) erased */ +	for (i = 0; i < 4 / sizeof(CFG_FLASH_WORD_SIZE); i++) { +		if ((dest2[i] & swap16(data2[i])) != swap16(data2[i])) +			return (2); +	} + +	for (i = 0; i < 4 / sizeof(CFG_FLASH_WORD_SIZE); i++) { +		int flag; + +		/* Disable interrupts which might cause a timeout here */ +		flag = disable_interrupts(); + +		addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAA00AA00; +		addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55005500; +		addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xA000A000; + +		dest2[i] = swap16(data2[i]); + +		/* re-enable interrupts if necessary */ +		if (flag) +			enable_interrupts(); + +		/* data polling for D7 */ +		start = get_timer(0); +		while ((dest2[i] & (CFG_FLASH_WORD_SIZE) 0x80008000) != +				(swap16(data2[i]) & (CFG_FLASH_WORD_SIZE) 0x80008000)) { + +			if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { +				return (1); +			} +		} +	} + +	return (0); +} +#endif /* CFG_FLASH_2ND_16BIT_DEV */ + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size(vu_long * addr, flash_info_t * info); +static int write_word(flash_info_t * info, ulong dest, ulong data); + +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init(void) +{ +	unsigned long total_b = 0; +	unsigned long size_b[CFG_MAX_FLASH_BANKS]; +	unsigned short index = 0; +	int i; + +	DEBUGF("\n"); +	DEBUGF("FLASH: Index: %d\n", index); + +	/* Init: no FLASHes known */ +	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { +		flash_info[i].flash_id = FLASH_UNKNOWN; +		flash_info[i].sector_count = -1; +		flash_info[i].size = 0; + +		/* check whether the address is 0 */ +		if (flash_addr_table[index][i] == 0) +			continue; + +		/* call flash_get_size() to initialize sector address */ +		size_b[i] = flash_get_size((vu_long *) flash_addr_table[index][i], +				&flash_info[i]); + +		flash_info[i].size = size_b[i]; + +		if (flash_info[i].flash_id == FLASH_UNKNOWN) { +			printf("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", +					i+1, size_b[i], size_b[i] << 20); +			flash_info[i].sector_count = -1; +			flash_info[i].size = 0; +		} + +		/* Monitor protection ON by default */ +		(void)flash_protect(FLAG_PROTECT_SET, CFG_MONITOR_BASE, +				    CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, +				    &flash_info[i]); +#if defined(CFG_ENV_IS_IN_FLASH) +		(void)flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR, +				    CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, +				    &flash_info[i]); +#if defined(CFG_ENV_ADDR_REDUND) +		(void)flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR_REDUND, +				    CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1, +				    &flash_info[i]); +#endif +#endif +		total_b += flash_info[i].size; +	} + +	return total_b; +} +#endif /* if defined(CONFIG_CAM5200) && defined(CONFIG_CAM5200_NIOSFLASH) */ diff --git a/board/tqc/tqm5200/cmd_stk52xx.c b/board/tqc/tqm5200/cmd_stk52xx.c new file mode 100644 index 000000000..7472ca9e9 --- /dev/null +++ b/board/tqc/tqm5200/cmd_stk52xx.c @@ -0,0 +1,1247 @@ +/* + * (C) Copyright 2005 + * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.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 + */ + +/* + * STK52XX specific functions + */ +/*#define DEBUG*/ + +#include <common.h> +#include <command.h> + +#if defined(CONFIG_CMD_BSP) + +#if defined(CONFIG_STK52XX) || defined(CONFIG_FO300) +#define DEFAULT_VOL	45 +#define DEFAULT_FREQ	500 +#define DEFAULT_DURATION	200 +#define LEFT		1 +#define RIGHT		2 +#define LEFT_RIGHT	3 +#define BL_OFF		0 +#define BL_ON		1 + +#define SM501_GPIO_CTRL_LOW		0x00000008UL +#define SM501_GPIO_CTRL_HIGH		0x0000000CUL +#define SM501_POWER_MODE0_GATE		0x00000040UL +#define SM501_POWER_MODE1_GATE		0x00000048UL +#define POWER_MODE_GATE_GPIO_PWM_I2C	0x00000040UL +#define SM501_GPIO_DATA_LOW		0x00010000UL +#define SM501_GPIO_DATA_HIGH		0x00010004UL +#define SM501_GPIO_DATA_DIR_LOW		0x00010008UL +#define SM501_GPIO_DATA_DIR_HIGH	0x0001000CUL +#define SM501_PANEL_DISPLAY_CONTROL	0x00080000UL + +static int i2s_squarewave(unsigned long duration, unsigned int freq, +			  unsigned int channel); +static int i2s_sawtooth(unsigned long duration, unsigned int freq, +			unsigned int channel); +static void spi_init(void); +static int spi_transmit(unsigned char data); +static void pcm1772_write_reg(unsigned char addr, unsigned char data); +static void set_attenuation(unsigned char attenuation); + +static void spi_init(void) +{ +	struct mpc5xxx_spi *spi = (struct mpc5xxx_spi*)MPC5XXX_SPI; +	struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio*)MPC5XXX_GPIO; + +	/* PSC3 as SPI and GPIOs */ +	gpio->port_config &= 0xFFFFF0FF; +	gpio->port_config |= 0x00000800; +	/* +	 * Its important to use the correct order when initializing the +	 * registers +	 */ +	spi->ddr = 0x0F; /* set all SPI pins as output */ +	spi->pdr = 0x08; /* set SS high */ +	spi->cr1 = 0x50; /* SPI is master, SS is general purpose output */ +	spi->cr2 = 0x00; /* normal operation */ +	spi->brr = 0xFF; /* baud rate: IPB clock / 2048 */ +} + +static int spi_transmit(unsigned char data) +{ +	int dummy; +	struct mpc5xxx_spi *spi = (struct mpc5xxx_spi*)MPC5XXX_SPI; + +	spi->dr = data; +	/* wait for SPI transmission completed */ +	while(!(spi->sr & 0x80)) +	{ +		if (spi->sr & 0x40)	/* if write collision occured */ +		{ +			/* do dummy read to clear status register */ +			dummy = spi->dr; +			printf ("SPI write collision\n"); +			return -1; +		} +	} +	return (spi->dr); +} + +static void pcm1772_write_reg(unsigned char addr, unsigned char data) +{ +	struct mpc5xxx_spi *spi = (struct mpc5xxx_spi*)MPC5XXX_SPI; + +	spi->pdr = 0x00; /* Set SS low */ +	spi_transmit(addr); +	spi_transmit(data); +	/* wait some time to meet MS# hold time of PCM1772 */ +	udelay (1); +	spi->pdr = 0x08; /* set SS high */ +} + +static void set_attenuation(unsigned char attenuation) +{ +	pcm1772_write_reg(0x01, attenuation); /* left channel */ +	debug ("PCM1772 attenuation left set to %d.\n", attenuation); +	pcm1772_write_reg(0x02, attenuation); /* right channel */ +	debug ("PCM1772 attenuation right set to %d.\n", attenuation); +} + +void amplifier_init(void) +{ +	static int init_done = 0; +	int i; +	struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio*)MPC5XXX_GPIO; + +	/* Do this only once, because of the long time delay */ +	if (!init_done) { +		/* configure PCM1772 audio format as I2S */ +		pcm1772_write_reg(0x03, 0x01); +		/* enable audio amplifier */ +		gpio->sint_gpioe |=  0x02;	/* PSC3_5 as GPIO */ +		gpio->sint_ode &= ~0x02;	/* PSC3_5 is not open Drain */ +		gpio->sint_dvo &= ~0x02;	/* PSC3_5 is LOW */ +		gpio->sint_ddr |=  0x02;	/* PSC3_5 as output */ +		/* +		 * wait some time to allow amplifier to recover from shutdown +		 * mode. +		 */ +		for(i = 0; i < 350; i++) +			udelay(1000); +		/* +		 * The used amplifier (LM4867) has a so called "pop and click" +		 * elmination filter. The input signal of the amplifier must +		 * exceed a certain level once after power up to activate the +		 * generation of the output signal. This is achieved by +		 * sending a low frequent (nearly inaudible) sawtooth with a +		 * sufficient signal level. +		 */ +		set_attenuation(50); +		i2s_sawtooth (200, 5, LEFT_RIGHT); +		init_done = 1; +	} +} + +static void i2s_init(void) +{ +	unsigned long i; +	struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2;; +	struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio*)MPC5XXX_GPIO; + +	gpio->port_config |= 0x00000070; /* PSC2 ports as Codec with MCLK */ +	psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); +	psc->sicr = 0x22E00000;		/* 16 bit data; I2S */ + +	*(vu_long *)(CFG_MBAR + 0x22C) = 0x805d; /* PSC2 CDM MCLK config; MCLK +						  * 5.617 MHz */ +	*(vu_long *)(CFG_MBAR + 0x214) |= 0x00000040; /* CDM clock enable +						       * register */ +	psc->ccr = 0x1F03;	/* 16 bit data width; 5.617MHz MCLK */ +	psc->ctur = 0x0F;	/* 16 bit frame width */ + +	for(i=0;i<128;i++) +	{ +		psc->psc_buffer_32 = 0; /* clear tx fifo */ +	} +} + +static int i2s_play_wave(unsigned long addr, unsigned long len) +{ +	unsigned long i; +	unsigned char *wave_file = (uchar *)addr + 44;	/* quick'n dirty: skip +							 * wav header*/ +	unsigned char swapped[4]; +	struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2; + +	/* +	 * play wave file in memory; bytes/words are be swapped +	 */ +	psc->command = (PSC_RX_ENABLE | PSC_TX_ENABLE); + +	for(i = 0;i < (len / 4); i++) { +		swapped[3]=*wave_file++; +		swapped[2]=*wave_file++; +		swapped[1]=*wave_file++; +		swapped[0]=*wave_file++; +		psc->psc_buffer_32 =  *((unsigned long*)swapped); +		while (psc->tfnum > 400) { +			if(ctrlc()) +				return 0; +		} +	} +	while (psc->tfnum > 0);		/* wait for fifo empty */ +	udelay (100); +	psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); +	return 0; +} + +static int i2s_sawtooth(unsigned long duration, unsigned int freq, +			unsigned int channel) +{ +	long i,j; +	unsigned long data; +	struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2; + +	psc->command = (PSC_RX_ENABLE | PSC_TX_ENABLE); + +	/* +	 * Generate sawtooth. Start with middle level up to highest level. Then +	 * go to lowest level and back to middle level. +	 */ +	for(j = 0; j < ((duration * freq) / 1000); j++)	{ +		for(i = 0; i <= 0x7FFF; i += (0x7FFF/(44100/(freq*4))))	{ +			data = (i & 0xFFFF); +			/* data format: right data left data) */ +			if (channel == LEFT_RIGHT) +				data |= (data<<16); +			if (channel == RIGHT) +				data = (data<<16); +			psc->psc_buffer_32 = data; +			while (psc->tfnum > 400); +		} +		for(i = 0x7FFF; i >= -0x7FFF; i -= (0xFFFF/(44100/(freq*2)))) { +			data = (i & 0xFFFF); +			/* data format: right data left data) */ +			if (channel == LEFT_RIGHT) +				data |= (data<<16); +			if (channel == RIGHT) +				data = (data<<16); +			psc->psc_buffer_32 = data; +			while (psc->tfnum > 400); +		} +		for(i = -0x7FFF; i <= 0; i += (0x7FFF/(44100/(freq*4)))) { +			data = (i & 0xFFFF); +			/* data format: right data left data) */ +			if (channel == LEFT_RIGHT) +				data |= (data<<16); +			if (channel == RIGHT) +				data = (data<<16); +			psc->psc_buffer_32 = data; +			while (psc->tfnum > 400); +		} +	} +	while (psc->tfnum > 0);		/* wait for fifo empty */ +	udelay (100); +	psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); + +	return 0; +} + +static int i2s_squarewave(unsigned long duration, unsigned int freq, +			 unsigned int channel) +{ +	long i,j; +	unsigned long data; +	struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2; + +	psc->command = (PSC_RX_ENABLE | PSC_TX_ENABLE); + +	/* +	 * Generate sqarewave. Start with high level, duty cycle 1:1. +	 */ +	for(j = 0; j < ((duration * freq) / 1000); j++)	{ +		for(i = 0; i < (44100/(freq*2)); i ++) { +			data = 0x7FFF; +			/* data format: right data left data) */ +			if (channel == LEFT_RIGHT) +				data |= (data<<16); +			if (channel == RIGHT) +				data = (data<<16); +			psc->psc_buffer_32 = data; +			while (psc->tfnum > 400); +		} +		for(i = 0; i < (44100/(freq*2)); i ++) { +			data = 0x8000; +			/* data format: right data left data) */ +			if (channel == LEFT_RIGHT) +				data |= (data<<16); +			if (channel == RIGHT) +				data = (data<<16); +			psc->psc_buffer_32 = data; +			while (psc->tfnum > 400); +		} +	} +	while (psc->tfnum > 0);		/* wait for fifo empty */ +	udelay (100); +	psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); + +	return 0; +} + +static int cmd_sound(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	unsigned long reg, val, duration; +	char *tmp; +	unsigned int freq, channel; +	unsigned char volume; +	int rcode = 1; + +#ifdef CONFIG_STK52XX_REV100 +	printf ("Revision 100 of STK52XX not supported!\n"); +	return 1; +#endif +	spi_init(); +	i2s_init(); +	amplifier_init(); + +	if ((tmp = getenv ("volume")) != NULL) { +		volume = simple_strtoul (tmp, NULL, 10); +	} else { +		volume = DEFAULT_VOL; +	} +	set_attenuation(volume); + +	switch (argc) { +	case 0: +	case 1: +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	case 2: +		if (strncmp(argv[1],"saw",3) == 0) { +			printf ("Play sawtooth\n"); +			rcode = i2s_sawtooth (DEFAULT_DURATION, DEFAULT_FREQ, +					      LEFT_RIGHT); +			return rcode; +		} else if (strncmp(argv[1],"squ",3) == 0) { +			printf ("Play squarewave\n"); +			rcode = i2s_squarewave (DEFAULT_DURATION, DEFAULT_FREQ, +						LEFT_RIGHT); +			return rcode; +		} + +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	case 3: +		if (strncmp(argv[1],"saw",3) == 0) { +			duration = simple_strtoul(argv[2], NULL, 10); +			printf ("Play sawtooth\n"); +			rcode = i2s_sawtooth (duration, DEFAULT_FREQ, +					      LEFT_RIGHT); +			return rcode; +		} else if (strncmp(argv[1],"squ",3) == 0) { +			duration = simple_strtoul(argv[2], NULL, 10); +			printf ("Play squarewave\n"); +			rcode = i2s_squarewave (duration, DEFAULT_FREQ, +						LEFT_RIGHT); +			return rcode; +		} +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	case 4: +		if (strncmp(argv[1],"saw",3) == 0) { +			duration = simple_strtoul(argv[2], NULL, 10); +			freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); +			printf ("Play sawtooth\n"); +			rcode = i2s_sawtooth (duration, freq, +					      LEFT_RIGHT); +			return rcode; +		} else if (strncmp(argv[1],"squ",3) == 0) { +			duration = simple_strtoul(argv[2], NULL, 10); +			freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); +			printf ("Play squarewave\n"); +			rcode = i2s_squarewave (duration, freq, +						LEFT_RIGHT); +			return rcode; +		} else if (strcmp(argv[1],"pcm1772") == 0) { +			reg = simple_strtoul(argv[2], NULL, 10); +			val = simple_strtoul(argv[3], NULL, 10); +			printf("Set PCM1772 %lu. %lu\n", reg, val); +			pcm1772_write_reg((uchar)reg, (uchar)val); +			return 0; +		} +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	case 5: +		if (strncmp(argv[1],"saw",3) == 0) { +			duration = simple_strtoul(argv[2], NULL, 10); +			freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); +			if (strncmp(argv[4],"l",1) == 0) +				channel = LEFT; +			else if (strncmp(argv[4],"r",1) == 0) +				channel = RIGHT; +			else +				channel = LEFT_RIGHT; +			printf ("Play squarewave\n"); +			rcode = i2s_sawtooth (duration, freq, +					      channel); +			return rcode; +		} else if (strncmp(argv[1],"squ",3) == 0) { +			duration = simple_strtoul(argv[2], NULL, 10); +			freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); +			if (strncmp(argv[4],"l",1) == 0) +				channel = LEFT; +			else if (strncmp(argv[4],"r",1) == 0) +				channel = RIGHT; +			else +				channel = LEFT_RIGHT; +			printf ("Play squarewave\n"); +			rcode = i2s_squarewave (duration, freq, +						channel); +			return rcode; +		} +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	} +	printf ("Usage:\nsound cmd [arg1] [arg2] ...\n"); +	return 1; +} + +static int cmd_wav(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	unsigned long length, addr; +	unsigned char volume; +	int rcode = 1; +	char *tmp; + +#ifdef CONFIG_STK52XX_REV100 +	printf ("Revision 100 of STK52XX not supported!\n"); +	return 1; +#endif +	spi_init(); +	i2s_init(); +	amplifier_init(); + +	switch (argc) { + +	case 3: +		length = simple_strtoul(argv[2], NULL, 16); +		addr = simple_strtoul(argv[1], NULL, 16); +		break; + +	case 2: +		if ((tmp = getenv ("filesize")) != NULL) { +			length = simple_strtoul (tmp, NULL, 16); +		} else { +			puts ("No filesize provided\n"); +			return 1; +		} +		addr = simple_strtoul(argv[1], NULL, 16); + +	case 1: +		if ((tmp = getenv ("filesize")) != NULL) { +			length = simple_strtoul (tmp, NULL, 16); +		} else { +			puts ("No filesize provided\n"); +			return 1; +		} +		if ((tmp = getenv ("loadaddr")) != NULL) { +			addr = simple_strtoul (tmp, NULL, 16); +		} else { +			puts ("No loadaddr provided\n"); +			return 1; +		} +		break; + +	default: +		printf("Usage:\nwav <addr> <length[s]\n"); +		return 1; +		break; +	} + +	if ((tmp = getenv ("volume")) != NULL) { +		volume = simple_strtoul (tmp, NULL, 10); +	} else { +		volume = DEFAULT_VOL; +	} +	set_attenuation(volume); + +	printf("Play wave file at %#p with length %#x\n", addr, length); +	rcode = i2s_play_wave(addr, length); + +	return rcode; +} + +static int cmd_beep(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	unsigned char volume; +	unsigned int channel; +	int rcode; +	char *tmp; + +#ifdef CONFIG_STK52XX_REV100 +	printf ("Revision 100 of STK52XX not supported!\n"); +	return 1; +#endif +	spi_init(); +	i2s_init(); +	amplifier_init(); + +	switch (argc) { +	case 0: +	case 1: +		channel = LEFT_RIGHT; +		break; +	case 2: +		if (strncmp(argv[1],"l",1) == 0) +			channel = LEFT; +		else if (strncmp(argv[1],"r",1) == 0) +			channel = RIGHT; +		else +			channel = LEFT_RIGHT; +		break; +	default: +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	} + +	if ((tmp = getenv ("volume")) != NULL) { +		volume = simple_strtoul (tmp, NULL, 10); +	} else { +		volume = DEFAULT_VOL; +	} +	set_attenuation(volume); + +	printf("Beep on "); +	if (channel == LEFT) +		printf ("left "); +	else if (channel == RIGHT) +		printf ("right "); +	else +		printf ("left and right "); +	printf ("channel\n"); + +	rcode = i2s_squarewave (DEFAULT_DURATION, DEFAULT_FREQ, channel); + +	return rcode; +} +#endif + +#if defined(CONFIG_STK52XX) +void led_init(void) +{ +	struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO; +	struct mpc5xxx_gpt_0_7 *gpt = (struct mpc5xxx_gpt_0_7 *)MPC5XXX_GPT; + +	/* configure PSC3 for SPI and GPIO */ +	gpio->port_config &= ~(0x00000F00); +	gpio->port_config |=   0x00000800; + +	gpio->simple_gpioe &= ~(0x00000F00); +	gpio->simple_gpioe |=   0x00000F00; + +	gpio->simple_ddr &= ~(0x00000F00); +	gpio->simple_ddr |=   0x00000F00; + +	/* configure timer 4-7 for simple GPIO output */ +	gpt->gpt4.emsr |=  0x00000024; +	gpt->gpt5.emsr |=  0x00000024; +	gpt->gpt6.emsr |=  0x00000024; +	gpt->gpt7.emsr |=  0x00000024; + +#ifndef CONFIG_TQM5200S +	/* enable SM501 GPIO control (in both power modes) */ +	*(vu_long *) (SM501_MMIO_BASE+SM501_POWER_MODE0_GATE) |= +		POWER_MODE_GATE_GPIO_PWM_I2C; +	*(vu_long *) (SM501_MMIO_BASE+SM501_POWER_MODE1_GATE) |= +		POWER_MODE_GATE_GPIO_PWM_I2C; + +	/* configure SM501 gpio pins 24-27 as output */ +	*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_CTRL_LOW) &= ~(0xF << 24); +	*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_DIR_LOW) |= (0xF << 24); + +	/* configure SM501 gpio pins 48-51 as output */ +	*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_DIR_HIGH) |= (0xF << 16); +#endif /* !CONFIG_TQM5200S */ +} + +/* + * return 1 if led number unknown + * return 0 else + */ +int do_led(char *argv[]) +{ +	struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO; +	struct mpc5xxx_gpt_0_7 *gpt = (struct mpc5xxx_gpt_0_7 *)MPC5XXX_GPT; + +	switch	(simple_strtoul(argv[2], NULL, 10)) { + +	case 0: +		if (strcmp (argv[3], "on") == 0) { +			gpio->simple_dvo |=   (1 << 8); +		} else { +			gpio->simple_dvo &= ~(1 << 8); +		} +		break; + +	case 1: +		if (strcmp (argv[3], "on") == 0) { +			gpio->simple_dvo |=   (1 << 9); +		} else { +			gpio->simple_dvo &= ~(1 << 9); +		} +		break; + +	case 2: +		if (strcmp (argv[3], "on") == 0) { +			gpio->simple_dvo |=   (1 << 10); +		} else { +			gpio->simple_dvo &= ~(1 << 10); +		} +		break; + +	case 3: +		if (strcmp (argv[3], "on") == 0) { +			gpio->simple_dvo |=   (1 << 11); +		} else { +			gpio->simple_dvo &= ~(1 << 11); +		} +		break; + +	case 4: +		if (strcmp (argv[3], "on") == 0) { +			gpt->gpt4.emsr |=  (1 << 4); +		} else { +			gpt->gpt4.emsr &=  ~(1 << 4); +		} +		break; + +	case 5: +		if (strcmp (argv[3], "on") == 0) { +			gpt->gpt5.emsr |=  (1 << 4); +		} else { +			gpt->gpt5.emsr &=  ~(1 << 4); +		} +		break; + +	case 6: +		if (strcmp (argv[3], "on") == 0) { +			gpt->gpt6.emsr |=  (1 << 4); +		} else { +			gpt->gpt6.emsr &=  ~(1 << 4); +		} +		break; + +	case 7: +		if (strcmp (argv[3], "on") == 0) { +			gpt->gpt7.emsr |=  (1 << 4); +		} else { +			gpt->gpt7.emsr &=  ~(1 << 4); +		} +		break; +#ifndef CONFIG_TQM5200S +	case 24: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= +				(0x1 << 24); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= +				~(0x1 << 24); +		} +		break; + +	case 25: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= +				(0x1 << 25); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= +				~(0x1 << 25); +		} +		break; + +	case 26: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= +				(0x1 << 26); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= +				~(0x1 << 26); +		} +		break; + +	case 27: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= +				(0x1 << 27); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= +				~(0x1 << 27); +		} +		break; + +	case 48: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= +				(0x1 << 16); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= +				~(0x1 << 16); +		} +		break; + +	case 49: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= +				(0x1 << 17); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= +				~(0x1 << 17); +		} +		break; + +	case 50: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= +				(0x1 << 18); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= +				~(0x1 << 18); +		} +		break; + +	case 51: +		if (strcmp (argv[3], "on") == 0) { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= +				(0x1 << 19); +		} else { +			*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= +				~(0x1 << 19); +		} +		break; +#endif /* !CONFIG_TQM5200S */ +	default: +		printf ("%s: invalid led number %s\n", __FUNCTION__, argv[2]); +		return 1; +	} + +	return 0; +} +#endif + +#if defined(CONFIG_STK52XX) || defined(CONFIG_FO300) +/* + * return 1 on CAN initialization failure + * return 0 if no failure + */ +int can_init(void) +{ +	static int init_done = 0; +	int i; +	struct mpc5xxx_mscan *can1 = +		(struct mpc5xxx_mscan *)(CFG_MBAR + 0x0900); +	struct mpc5xxx_mscan *can2 = +		(struct mpc5xxx_mscan *)(CFG_MBAR + 0x0980); + +	/* GPIO configuration of the CAN pins is done in TQM5200.h */ + +	if (!init_done) { +		/* init CAN 1 */ +		can1->canctl1 |= 0x80;	/* CAN enable */ +		udelay(100); + +		i = 0; +		can1->canctl0 |= 0x02;	/* sleep mode */ +		/* wait until sleep mode reached */ +		while (!(can1->canctl1 & 0x02)) { +			udelay(10); +		i++; +		if (i == 10) { +			printf ("%s: CAN1 initialize error, " +				"can not enter sleep mode!\n", +				__FUNCTION__); +			return 1; +		} +		} +		i = 0; +		can1->canctl0 = 0x01;	/* enter init mode */ +		/* wait until init mode reached */ +		while (!(can1->canctl1 & 0x01)) { +			udelay(10); +			i++; +			if (i == 10) { +				printf ("%s: CAN1 initialize error, " +					"can not enter init mode!\n", +					__FUNCTION__); +				return 1; +			} +		} +		can1->canctl1 = 0x80; +		can1->canctl1 |= 0x40; +		can1->canbtr0 = 0x0F; +		can1->canbtr1 = 0x7F; +		can1->canidac &= ~(0x30); +		can1->canidar1 = 0x00; +		can1->canidar3 = 0x00; +		can1->canidar5 = 0x00; +		can1->canidar7 = 0x00; +		can1->canidmr0 = 0xFF; +		can1->canidmr1 = 0xFF; +		can1->canidmr2 = 0xFF; +		can1->canidmr3 = 0xFF; +		can1->canidmr4 = 0xFF; +		can1->canidmr5 = 0xFF; +		can1->canidmr6 = 0xFF; +		can1->canidmr7 = 0xFF; + +		i = 0; +		can1->canctl0 &= ~(0x01);	/* leave init mode */ +		can1->canctl0 &= ~(0x02); +		/* wait until init and sleep mode left */ +		while ((can1->canctl1 & 0x01) || (can1->canctl1 & 0x02)) { +			udelay(10); +			i++; +			if (i == 10) { +				printf ("%s: CAN1 initialize error, " +					"can not leave init/sleep mode!\n", +					__FUNCTION__); +				return 1; +			} +		} + +		/* init CAN 2 */ +		can2->canctl1 |= 0x80;	/* CAN enable */ +		udelay(100); + +		i = 0; +		can2->canctl0 |= 0x02;	/* sleep mode */ +		/* wait until sleep mode reached */ +		while (!(can2->canctl1 & 0x02))	{ +			udelay(10); +			i++; +			if (i == 10) { +				printf ("%s: CAN2 initialize error, " +					"can not enter sleep mode!\n", +					__FUNCTION__); +				return 1; +			} +		} +		i = 0; +		can2->canctl0 = 0x01;	/* enter init mode */ +		/* wait until init mode reached */ +		while (!(can2->canctl1 & 0x01))	{ +			udelay(10); +			i++; +			if (i == 10) { +				printf ("%s: CAN2 initialize error, " +					"can not enter init mode!\n", +					__FUNCTION__); +				return 1; +			} +		} +		can2->canctl1 = 0x80; +		can2->canctl1 |= 0x40; +		can2->canbtr0 = 0x0F; +		can2->canbtr1 = 0x7F; +		can2->canidac &= ~(0x30); +		can2->canidar1 = 0x00; +		can2->canidar3 = 0x00; +		can2->canidar5 = 0x00; +		can2->canidar7 = 0x00; +		can2->canidmr0 = 0xFF; +		can2->canidmr1 = 0xFF; +		can2->canidmr2 = 0xFF; +		can2->canidmr3 = 0xFF; +		can2->canidmr4 = 0xFF; +		can2->canidmr5 = 0xFF; +		can2->canidmr6 = 0xFF; +		can2->canidmr7 = 0xFF; +		can2->canctl0 &= ~(0x01);	/* leave init mode */ +		can2->canctl0 &= ~(0x02); + +		i = 0; +		/* wait until init mode left */ +		while ((can2->canctl1 & 0x01) || (can2->canctl1 & 0x02)) { +			udelay(10); +			i++; +			if (i == 10) { +				printf ("%s: CAN2 initialize error, " +					"can not leave init/sleep mode!\n", +					__FUNCTION__); +				return 1; +			} +		} +		init_done = 1; +	} +	return 0; +} + +/* + * return 1 on CAN failure + * return 0 if no failure + */ +int do_can(char *argv[]) +{ +	int i; +	struct mpc5xxx_mscan *can1 = +		(struct mpc5xxx_mscan *)(CFG_MBAR + 0x0900); +	struct mpc5xxx_mscan *can2 = +		(struct mpc5xxx_mscan *)(CFG_MBAR + 0x0980); + +	/* send a message on CAN1 */ +	can1->cantbsel = 0x01; +	can1->cantxfg.idr[0] = 0x55; +	can1->cantxfg.idr[1] = 0x00; +	can1->cantxfg.idr[1] &= ~0x8; +	can1->cantxfg.idr[1] &= ~0x10; +	can1->cantxfg.dsr[0] = 0xCC; +	can1->cantxfg.dlr = 1; +	can1->cantxfg.tbpr = 0; +	can1->cantflg = 0x01; + +	i = 0; +	while ((can1->cantflg & 0x01) == 0) { +		i++; +		if (i == 10) { +			printf ("%s: CAN1 send timeout, " +				"can not send message!\n", +				__FUNCTION__); +			return 1; +		} +		udelay(1000); +	} +	udelay(1000); + +	i = 0; +	while (!(can2->canrflg & 0x01))	{ +		i++; +		if (i == 10) { +			printf ("%s: CAN2 receive timeout, " +				"no message received!\n", +				__FUNCTION__); +			return 1; +		} +		udelay(1000); +	} + +	if (can2->canrxfg.dsr[0] != 0xCC) { +		printf ("%s: CAN2 receive error, " +			 "data mismatch!\n", +			__FUNCTION__); +		return 1; +	} + +	/* send a message on CAN2 */ +	can2->cantbsel = 0x01; +	can2->cantxfg.idr[0] = 0x55; +	can2->cantxfg.idr[1] = 0x00; +	can2->cantxfg.idr[1] &= ~0x8; +	can2->cantxfg.idr[1] &= ~0x10; +	can2->cantxfg.dsr[0] = 0xCC; +	can2->cantxfg.dlr = 1; +	can2->cantxfg.tbpr = 0; +	can2->cantflg = 0x01; + +	i = 0; +	while ((can2->cantflg & 0x01) == 0) { +		i++; +		if (i == 10) { +			printf ("%s: CAN2 send error, " +				"can not send message!\n", +				__FUNCTION__); +			return 1; +		} +		udelay(1000); +	} +	udelay(1000); + +	i = 0; +	while (!(can1->canrflg & 0x01))	{ +		i++; +		if (i == 10) { +			printf ("%s: CAN1 receive timeout, " +				"no message received!\n", +				__FUNCTION__); +			return 1; +		} +		udelay(1000); +	} + +	if (can1->canrxfg.dsr[0] != 0xCC) { +		printf ("%s: CAN1 receive error 0x%02x\n", +			__FUNCTION__, (can1->canrxfg.dsr[0])); +		return 1; +	} + +	return 0; +} + +/* + * return 1 if rs232 port unknown + * return 2 on txd/rxd failure (only rs232 2) + * return 3 on rts/cts failure + * return 0 if no failure + */ +int do_rs232(char *argv[]) +{ +	int error_status = 0; +	struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO; +	struct mpc5xxx_psc *psc1 = (struct mpc5xxx_psc *)MPC5XXX_PSC1; + +	switch	(simple_strtoul(argv[2], NULL, 10)) { + +	case 1: +		/* check RTS <-> CTS loop */ +		/* set rts to 0 */ +		psc1->op1 |= 0x01; + +		/* wait some time before requesting status */ +		udelay(10); + +		/* check status at cts */ +		if ((psc1->ip & 0x01) != 0) { +			error_status = 3; +			printf ("%s: failure at rs232_1, cts status is %d " +				"(should be 0)\n", +				__FUNCTION__, (psc1->ip & 0x01)); +		} + +		/* set rts to 1 */ +		psc1->op0 |= 0x01; + +		/* wait some time before requesting status */ +		udelay(10); + +		/* check status at cts */ +		if ((psc1->ip & 0x01) != 1) { +			error_status = 3; +			printf ("%s: failure at rs232_1, cts status is %d " +				"(should be 1)\n", +				__FUNCTION__, (psc1->ip & 0x01)); +		} + +		break; + +	case 2: +		/* set PSC3_0, PSC3_2 as output and PSC3_1, PSC3_3 as input */ +		gpio->simple_ddr &= ~(0x00000F00); +		gpio->simple_ddr |=   0x00000500; + +		/* check TXD <-> RXD loop */ +		/* set TXD to 1 */ +		gpio->simple_dvo |=   (1 << 8); + +		/* wait some time before requesting status */ +		udelay(10); + +		if ((gpio->simple_ival & 0x00000200) != 0x00000200) { +			error_status = 2; +			printf ("%s: failure at rs232_2, rxd status is %d " +				"(should be 1)\n", +				__FUNCTION__, +				(gpio->simple_ival & 0x00000200) >> 9); +		} + +		/* set TXD to 0 */ +		gpio->simple_dvo &= ~(1 << 8); + +		/* wait some time before requesting status */ +		udelay(10); + +		if ((gpio->simple_ival & 0x00000200) != 0x00000000) { +			error_status = 2; +			printf ("%s: failure at rs232_2, rxd status is %d " +				"(should be 0)\n", +				__FUNCTION__, +				(gpio->simple_ival & 0x00000200) >> 9); +		} + +		/* check RTS <-> CTS loop */ +		/* set RTS to 1 */ +		gpio->simple_dvo |=   (1 << 10); + +		/* wait some time before requesting status */ +		udelay(10); + +		if ((gpio->simple_ival & 0x00000800) != 0x00000800) { +			error_status = 3; +			printf ("%s: failure at rs232_2, cts status is %d " +				"(should be 1)\n", +				__FUNCTION__, +				(gpio->simple_ival & 0x00000800) >> 11); +		} + +		/* set RTS to 0 */ +		gpio->simple_dvo &= ~(1 << 10); + +		/* wait some time before requesting status */ +		udelay(10); + +		if ((gpio->simple_ival & 0x00000800) != 0x00000000) { +			error_status = 3; +			printf ("%s: failure at rs232_2, cts status is %d " +				"(should be 0)\n", +				__FUNCTION__, +				(gpio->simple_ival & 0x00000800) >> 11); +		} + +		/* set PSC3_0, PSC3_1, PSC3_2 and PSC3_3 as output */ +		gpio->simple_ddr &= ~(0x00000F00); +		gpio->simple_ddr |=   0x00000F00; +		break; + +	default: +		printf ("%s: invalid rs232 number %s\n", __FUNCTION__, argv[2]); +		error_status = 1; +		break; +	} + +	return error_status; +} + +#if !defined(CONFIG_FO300) && !defined(CONFIG_TQM5200S) +static void sm501_backlight (unsigned int state) +{ +	if (state == BL_ON) { +		*(vu_long *)(SM501_MMIO_BASE+SM501_PANEL_DISPLAY_CONTROL) |= +			(1 << 26) | (1 << 27); +	} else if (state == BL_OFF) +		*(vu_long *)(SM501_MMIO_BASE+SM501_PANEL_DISPLAY_CONTROL) &= +			~((1 << 26) | (1 << 27)); +} +#endif /* !CONFIG_FO300 & !CONFIG_TQM5200S */ + +int cmd_fkt(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	int rcode; + +#ifdef CONFIG_STK52XX_REV100 +	printf ("Revision 100 of STK52XX not supported!\n"); +	return 1; +#endif +#if defined(CONFIG_STK52XX) +	led_init(); +#endif +	can_init(); + +	switch (argc) { + +	case 0: +	case 1: +		break; + +	case 2: +		if (strncmp (argv[1], "can", 3) == 0) { +			rcode = do_can (argv); +			if (rcode == 0) +				printf ("OK\n"); +			else +				printf ("Error\n"); +			return rcode; +		} +		break; + +	case 3: +		if (strncmp (argv[1], "rs232", 3) == 0) { +			rcode = do_rs232 (argv); +			if (rcode == 0) +				printf ("OK\n"); +			else +				printf ("Error\n"); +			return rcode; +#if !defined(CONFIG_FO300) && !defined(CONFIG_TQM5200S) +		} else if (strncmp (argv[1], "backlight", 4) == 0) { +			if (strncmp (argv[2], "on", 2) == 0) { +				sm501_backlight (BL_ON); +				return 0; +			} +			else if (strncmp (argv[2], "off", 3) == 0) { +				sm501_backlight (BL_OFF); +				return 0; +			} +#endif /* !CONFIG_FO300 & !CONFIG_TQM5200S */ +		} +		break; + +#if defined(CONFIG_STK52XX) +	case 4: +		if (strcmp (argv[1], "led") == 0) { +			return (do_led (argv)); +		} +		break; +#endif + +	default: +		break; +	} + +	printf ("Usage:\nfkt cmd [arg1] [arg2] ...\n"); +	return 1; +} + + +U_BOOT_CMD( +	sound ,    5,    1,     cmd_sound, +	"sound   - Sound sub-system\n", +	"saw [duration] [freq] [channel]\n" +	"    - generate sawtooth for 'duration' ms with frequency 'freq'\n" +	"      on left \"l\" or right \"r\" channel\n" +	"sound square [duration] [freq] [channel]\n" +	"    - generate squarewave for 'duration' ms with frequency 'freq'\n" +	"      on left \"l\" or right \"r\" channel\n" +	"pcm1772 reg val\n" +); + +U_BOOT_CMD( +	wav ,    3,    1,     cmd_wav, +	"wav     - play wav file\n", +	"[addr] [bytes]\n" +	"    - play wav file at address 'addr' with length 'bytes'\n" +); + +U_BOOT_CMD( +	beep ,    2,    1,     cmd_beep, +	"beep    - play short beep\n", +	"[channel]\n" +	"    - play short beep on \"l\"eft or \"r\"ight channel\n" +); +#endif /* CONFIG_STK52XX  || CONFIG_FO300 */ + +#if defined(CONFIG_STK52XX) +U_BOOT_CMD( +	fkt ,	4,	1,	cmd_fkt, +	"fkt     - Function test routines\n", +	"led number on/off\n" +	"     - 'number's like printed on STK52XX board\n" +	"fkt can\n" +	"     - loopback plug for X83 required\n" +	"fkt rs232 number\n" +	"     - loopback plug(s) for X2 required\n" +#ifndef CONFIG_TQM5200S +	"fkt backlight on/off\n" +	"     - switch backlight on or off\n" +#endif /* !CONFIG_TQM5200S */ +); +#elif defined(CONFIG_FO300) +U_BOOT_CMD( +	fkt ,	3,	1,	cmd_fkt, +	"fkt     - Function test routines\n", +	"fkt can\n" +	"     - loopback plug for X16/X29 required\n" +	"fkt rs232 number\n" +	"     - loopback plug(s) for X21/X22 required\n" +); +#endif +#endif diff --git a/board/tqc/tqm5200/cmd_tb5200.c b/board/tqc/tqm5200/cmd_tb5200.c new file mode 100644 index 000000000..214dca65e --- /dev/null +++ b/board/tqc/tqm5200/cmd_tb5200.c @@ -0,0 +1,104 @@ +/* + * (C) Copyright 2005 - 2006 + * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.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 + */ + +/* + * TB5200 specific functions + */ +/*#define DEBUG*/ + +#include <common.h> +#include <command.h> + +#if defined(CONFIG_CMD_BSP) +#if defined (CONFIG_TB5200) + +#define SM501_PANEL_DISPLAY_CONTROL	0x00080000UL + +static void led_init(void) +{ +	struct mpc5xxx_gpt_0_7 *gpt = (struct mpc5xxx_gpt_0_7 *)MPC5XXX_GPT; + +	/* configure timer 4 for simple GPIO output */ +	gpt->gpt4.emsr |=  0x00000024; +} + +int cmd_led(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	struct mpc5xxx_gpt_0_7 *gpt = (struct mpc5xxx_gpt_0_7 *)MPC5XXX_GPT; + +	led_init(); + +	if (strcmp (argv[1], "on") == 0) { +		debug ("switch status LED on\n"); +		gpt->gpt4.emsr |=  (1 << 4); +	} else if (strcmp (argv[1], "off") == 0) { +		debug ("switch status LED off\n"); +		gpt->gpt4.emsr &=  ~(1 << 4); +	} else { +		printf ("Usage:\nled on/off\n"); +		return 1; +	} + +	return 0; +} + +static void sm501_backlight (unsigned int state) +{ +	if (state == 1) { +		*(vu_long *)(SM501_MMIO_BASE+SM501_PANEL_DISPLAY_CONTROL) |= +			(1 << 26) | (1 << 27); +	} else if (state == 0) +		*(vu_long *)(SM501_MMIO_BASE+SM501_PANEL_DISPLAY_CONTROL) &= +			~((1 << 26) | (1 << 27)); +} + +int cmd_backlight(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	if (strcmp (argv[1], "on") == 0) { +		debug ("switch backlight on\n"); +		sm501_backlight (1); +	} else if (strcmp (argv[1], "off") == 0) { +		debug ("switch backlight off\n"); +		sm501_backlight (0); +	} else { +		printf ("Usage:\nbacklight on/off\n"); +		return 1; +	} + +	return 0; +} + +U_BOOT_CMD( +	led ,	2,	1,	cmd_led, +	"led     - switch status LED on or off\n", +	"on/off\n" +); + +U_BOOT_CMD( +	backlight ,	2,	1,	cmd_backlight, +	"backlight - switch backlight on or off\n", +	"on/off\n" +	); + +#endif /* CONFIG_STK52XX */ +#endif diff --git a/board/tqc/tqm5200/config.mk b/board/tqc/tqm5200/config.mk new file mode 100644 index 000000000..d72dfe748 --- /dev/null +++ b/board/tqc/tqm5200/config.mk @@ -0,0 +1,46 @@ +# +# (C) Copyright 2004 +# 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 +# + +# +# TQM5200 board: +# +#	Valid values for TEXT_BASE are: +# +#	0xFC000000   boot low (standard configuration with room for max 64 MByte +#		     Flash ROM) +#	0xFFF00000   boot high (for a backup copy of U-Boot) +#	0x00100000   boot from RAM (for testing only) +# + +sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp + +ifndef TEXT_BASE +## Standard: boot low +TEXT_BASE = 0xFC000000 +## For a backup copy of U-Boot at the end of flash: boot high +# TEXT_BASE = 0xFFF00000 +## For testing: boot from RAM +# TEXT_BASE = 0x00100000 +endif + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR)/board diff --git a/board/tqc/tqm5200/mt48lc16m16a2-75.h b/board/tqc/tqm5200/mt48lc16m16a2-75.h new file mode 100644 index 000000000..3f1e1691b --- /dev/null +++ b/board/tqc/tqm5200/mt48lc16m16a2-75.h @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define SDRAM_DDR	0		/* is SDR */ + +#if defined(CONFIG_MPC5200) +/* Settings for XLB = 132 MHz */ +#define SDRAM_MODE	0x00CD0000 +/* #define SDRAM_MODE	0x008D0000 */ /* CAS latency 2 */ +#define SDRAM_CONTROL	0x504F0000 +#define SDRAM_CONFIG1	0xD2322800 +/* #define SDRAM_CONFIG1	0xD2222800 */ /* CAS latency 2 */ +/*#define SDRAM_CONFIG1	0xD7322800 */ /* SDRAM controller bug workaround */ +#define SDRAM_CONFIG2	0x8AD70000 +/*#define SDRAM_CONFIG2	0xDDD70000 */ /* SDRAM controller bug workaround */ + +#elif defined(CONFIG_MGT5100) +/* Settings for XLB = 66 MHz */ +#define SDRAM_MODE	0x008D0000 +#define SDRAM_CONTROL	0x504F0000 +#define SDRAM_CONFIG1	0xC2222600 +#define SDRAM_CONFIG2	0x88B70004 +#define SDRAM_ADDRSEL	0x02000000 + +#else +#error Neither CONFIG_MPC5200 or CONFIG_MGT5100 defined +#endif diff --git a/board/tqc/tqm5200/tqm5200.c b/board/tqc/tqm5200/tqm5200.c new file mode 100644 index 000000000..f9891dbb7 --- /dev/null +++ b/board/tqc/tqm5200/tqm5200.c @@ -0,0 +1,751 @@ +/* + * (C) Copyright 2003-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * (C) Copyright 2004-2006 + * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.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> +#include <mpc5xxx.h> +#include <pci.h> +#include <asm/processor.h> +#include <libfdt.h> + +#ifdef CONFIG_VIDEO_SM501 +#include <sm501.h> +#endif + +#if defined(CONFIG_MPC5200_DDR) +#include "mt46v16m16-75.h" +#else +#include "mt48lc16m16a2-75.h" +#endif + +#ifdef CONFIG_OF_LIBFDT +#include <fdt_support.h> +#endif /* CONFIG_OF_LIBFDT */ + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_PS2MULT +void ps2mult_early_init(void); +#endif + +#ifndef CFG_RAMBOOT +static void sdram_start (int hi_addr) +{ +	long hi_addr_bit = hi_addr ? 0x01000000 : 0; + +	/* unlock mode register */ +	*(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000000 | +		hi_addr_bit; +	__asm__ volatile ("sync"); + +	/* precharge all banks */ +	*(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | +		hi_addr_bit; +	__asm__ volatile ("sync"); + +#if SDRAM_DDR +	/* set mode register: extended mode */ +	*(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_EMODE; +	__asm__ volatile ("sync"); + +	/* set mode register: reset DLL */ +	*(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE | 0x04000000; +	__asm__ volatile ("sync"); +#endif + +	/* precharge all banks */ +	*(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | +		hi_addr_bit; +	__asm__ volatile ("sync"); + +	/* auto refresh */ +	*(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000004 | +		hi_addr_bit; +	__asm__ volatile ("sync"); + +	/* set mode register */ +	*(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE; +	__asm__ volatile ("sync"); + +	/* normal operation */ +	*(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | hi_addr_bit; +	__asm__ volatile ("sync"); +} +#endif + +/* + * ATTENTION: Although partially referenced initdram does NOT make real use + *	      use of CFG_SDRAM_BASE. The code does not work if CFG_SDRAM_BASE + *	      is something else than 0x00000000. + */ + +long int initdram (int board_type) +{ +	ulong dramsize = 0; +	ulong dramsize2 = 0; +	uint svr, pvr; + +#ifndef CFG_RAMBOOT +	ulong test1, test2; + +	/* setup SDRAM chip selects */ +	*(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x0000001c; /* 512MB at 0x0 */ +	*(vu_long *)MPC5XXX_SDRAM_CS1CFG = 0x40000000; /* disabled */ +	__asm__ volatile ("sync"); + +	/* setup config registers */ +	*(vu_long *)MPC5XXX_SDRAM_CONFIG1 = SDRAM_CONFIG1; +	*(vu_long *)MPC5XXX_SDRAM_CONFIG2 = SDRAM_CONFIG2; +	__asm__ volatile ("sync"); + +#if SDRAM_DDR +	/* set tap delay */ +	*(vu_long *)MPC5XXX_CDM_PORCFG = SDRAM_TAPDELAY; +	__asm__ volatile ("sync"); +#endif + +	/* find RAM size using SDRAM CS0 only */ +	sdram_start(0); +	test1 = get_ram_size((long *)CFG_SDRAM_BASE, 0x20000000); +	sdram_start(1); +	test2 = get_ram_size((long *)CFG_SDRAM_BASE, 0x20000000); +	if (test1 > test2) { +		sdram_start(0); +		dramsize = test1; +	} else { +		dramsize = test2; +	} + +	/* memory smaller than 1MB is impossible */ +	if (dramsize < (1 << 20)) { +		dramsize = 0; +	} + +	/* set SDRAM CS0 size according to the amount of RAM found */ +	if (dramsize > 0) { +		*(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x13 + +			__builtin_ffs(dramsize >> 20) - 1; +	} else { +		*(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ +	} + +	/* let SDRAM CS1 start right after CS0 */ +	*(vu_long *)MPC5XXX_SDRAM_CS1CFG = dramsize + 0x0000001c; /* 512MB */ + +	/* find RAM size using SDRAM CS1 only */ +	if (!dramsize) +		sdram_start(0); +	test2 = test1 = get_ram_size((long *)(CFG_SDRAM_BASE + dramsize), 0x20000000); +	if (!dramsize) { +		sdram_start(1); +		test2 = get_ram_size((long *)(CFG_SDRAM_BASE + dramsize), 0x20000000); +	} +	if (test1 > test2) { +		sdram_start(0); +		dramsize2 = test1; +	} else { +		dramsize2 = test2; +	} + +	/* memory smaller than 1MB is impossible */ +	if (dramsize2 < (1 << 20)) { +		dramsize2 = 0; +	} + +	/* set SDRAM CS1 size according to the amount of RAM found */ +	if (dramsize2 > 0) { +		*(vu_long *)MPC5XXX_SDRAM_CS1CFG = dramsize +			| (0x13 + __builtin_ffs(dramsize2 >> 20) - 1); +	} else { +		*(vu_long *)MPC5XXX_SDRAM_CS1CFG = dramsize; /* disabled */ +	} + +#else /* CFG_RAMBOOT */ + +	/* retrieve size of memory connected to SDRAM CS0 */ +	dramsize = *(vu_long *)MPC5XXX_SDRAM_CS0CFG & 0xFF; +	if (dramsize >= 0x13) { +		dramsize = (1 << (dramsize - 0x13)) << 20; +	} else { +		dramsize = 0; +	} + +	/* retrieve size of memory connected to SDRAM CS1 */ +	dramsize2 = *(vu_long *)MPC5XXX_SDRAM_CS1CFG & 0xFF; +	if (dramsize2 >= 0x13) { +		dramsize2 = (1 << (dramsize2 - 0x13)) << 20; +	} else { +		dramsize2 = 0; +	} +#endif /* CFG_RAMBOOT */ + +	/* +	 * On MPC5200B we need to set the special configuration delay in the +	 * DDR controller. Please refer to Freescale's AN3221 "MPC5200B SDRAM +	 * Initialization and Configuration", 3.3.1 SDelay--MBAR + 0x0190: +	 * +	 * "The SDelay should be written to a value of 0x00000004. It is +	 * required to account for changes caused by normal wafer processing +	 * parameters." +	 */ +	svr = get_svr(); +	pvr = get_pvr(); +	if ((SVR_MJREV(svr) >= 2) && +	    (PVR_MAJ(pvr) == 1) && (PVR_MIN(pvr) == 4)) { + +		*(vu_long *)MPC5XXX_SDRAM_SDELAY = 0x04; +		__asm__ volatile ("sync"); +	} + +#if defined(CONFIG_TQM5200_B) +	return dramsize + dramsize2; +#else +	return dramsize; +#endif /* CONFIG_TQM5200_B */ +} + +int checkboard (void) +{ +#if defined(CONFIG_AEVFIFO) +	puts ("Board: AEVFIFO\n"); +	return 0; +#endif + +#if defined(CONFIG_TQM5200S) +# define MODULE_NAME	"TQM5200S" +#else +# define MODULE_NAME	"TQM5200" +#endif + +#if defined(CONFIG_STK52XX) +# define CARRIER_NAME	"STK52xx" +#elif defined(CONFIG_TB5200) +# define CARRIER_NAME	"TB5200" +#elif defined(CONFIG_CAM5200) +# define CARRIER_NAME	"CAM5200" +#elif defined(CONFIG_FO300) +# define CARRIER_NAME	"FO300" +#else +# error "UNKNOWN" +#endif + +	puts (	"Board: " MODULE_NAME " (TQ-Components GmbH)\n" +		"       on a " CARRIER_NAME " carrier board\n"); + +	return 0; +} + +#undef MODULE_NAME +#undef CARRIER_NAME + +void flash_preinit(void) +{ +	/* +	 * Now, when we are in RAM, enable flash write +	 * access for detection process. +	 * Note that CS_BOOT cannot be cleared when +	 * executing in flash. +	 */ +	*(vu_long *)MPC5XXX_BOOTCS_CFG &= ~0x1; /* clear RO */ +} + + +#ifdef	CONFIG_PCI +static struct pci_controller hose; + +extern void pci_mpc5xxx_init(struct pci_controller *); + +void pci_init_board(void) +{ +	pci_mpc5xxx_init(&hose); +} +#endif + +#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_RESET) + +#if defined (CONFIG_MINIFAP) +#define SM501_POWER_MODE0_GATE		0x00000040UL +#define SM501_POWER_MODE1_GATE		0x00000048UL +#define POWER_MODE_GATE_GPIO_PWM_I2C	0x00000040UL +#define SM501_GPIO_DATA_DIR_HIGH	0x0001000CUL +#define SM501_GPIO_DATA_HIGH		0x00010004UL +#define SM501_GPIO_51			0x00080000UL +#endif /* CONFIG MINIFAP */ + +void init_ide_reset (void) +{ +	debug ("init_ide_reset\n"); + +#if defined (CONFIG_MINIFAP) +	/* Configure GPIO_51 of the SM501 grafic controller as ATA reset */ + +	/* enable GPIO control (in both power modes) */ +	*(vu_long *) (SM501_MMIO_BASE+SM501_POWER_MODE0_GATE) |= +		POWER_MODE_GATE_GPIO_PWM_I2C; +	*(vu_long *) (SM501_MMIO_BASE+SM501_POWER_MODE1_GATE) |= +		POWER_MODE_GATE_GPIO_PWM_I2C; +	/* configure GPIO51 as output */ +	*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_DIR_HIGH) |= +		SM501_GPIO_51; +#else +	/* Configure PSC1_4 as GPIO output for ATA reset */ +	*(vu_long *) MPC5XXX_WU_GPIO_ENABLE |= GPIO_PSC1_4; +	*(vu_long *) MPC5XXX_WU_GPIO_DIR    |= GPIO_PSC1_4; + +	/* by default the ATA reset is de-asserted */ +	*(vu_long *) MPC5XXX_WU_GPIO_DATA_O |=  GPIO_PSC1_4; +#endif +} + +void ide_set_reset (int idereset) +{ +	debug ("ide_reset(%d)\n", idereset); + +#if defined (CONFIG_MINIFAP) +	if (idereset) { +		*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= +			~SM501_GPIO_51; +	} else { +		*(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= +			SM501_GPIO_51; +	} +#else +	if (idereset) { +		*(vu_long *) MPC5XXX_WU_GPIO_DATA_O &= ~GPIO_PSC1_4; +	} else { +		*(vu_long *) MPC5XXX_WU_GPIO_DATA_O |=  GPIO_PSC1_4; +	} +#endif +} +#endif + +#ifdef CONFIG_POST +/* + * Reads GPIO pin PSC6_3. A keypress is reported, if PSC6_3 is low. If PSC6_3 + * is left open, no keypress is detected. + */ +int post_hotkeys_pressed(void) +{ +#ifdef CONFIG_STK52XX +	struct mpc5xxx_gpio *gpio; + +	gpio = (struct mpc5xxx_gpio*) MPC5XXX_GPIO; + +	/* +	 * Configure PSC6_1 and PSC6_3 as GPIO. PSC6 then couldn't be used in +	 * CODEC or UART mode. Consumer IrDA should still be possible. +	 */ +	gpio->port_config &= ~(0x07000000); +	gpio->port_config |=   0x03000000; + +	/* Enable GPIO for GPIO_IRDA_1 (IR_USB_CLK pin) = PSC6_3 */ +	gpio->simple_gpioe |= 0x20000000; + +	/* Configure GPIO_IRDA_1 as input */ +	gpio->simple_ddr &= ~(0x20000000); + +	return ((gpio->simple_ival & 0x20000000) ? 0 : 1); +#else +	return 0; +#endif +} +#endif + +#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER) + +void post_word_store (ulong a) +{ +	volatile ulong *save_addr = +		(volatile ulong *)(MPC5XXX_SRAM + MPC5XXX_SRAM_POST_SIZE); + +	*save_addr = a; +} + +ulong post_word_load (void) +{ +	volatile ulong *save_addr = +		(volatile ulong *)(MPC5XXX_SRAM + MPC5XXX_SRAM_POST_SIZE); + +	return *save_addr; +} +#endif	/* CONFIG_POST || CONFIG_LOGBUFFER*/ + +#ifdef CONFIG_BOARD_EARLY_INIT_R +int board_early_init_r (void) +{ + +	extern int usb_cpu_init(void); + +#ifdef CONFIG_PS2MULT +	ps2mult_early_init(); +#endif /* CONFIG_PS2MULT */ + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) +	/* Low level USB init, required for proper kernel operation */ +	usb_cpu_init(); +#endif + +	return (0); +} +#endif + +#ifdef CONFIG_FO300 +int silent_boot (void) +{ +	vu_long timer3_status; + +	/* Configure GPT3 as GPIO input */ +	*(vu_long *)MPC5XXX_GPT3_ENABLE = 0x00000004; + +	/* Read in TIMER_3 pin status */ +	timer3_status = *(vu_long *)MPC5XXX_GPT3_STATUS; + +#ifdef FO300_SILENT_CONSOLE_WHEN_S1_CLOSED +	/* Force silent console mode if S1 switch +	 * is in closed position (TIMER_3 pin status is LOW). */ +	if (MPC5XXX_GPT_GPIO_PIN(timer3_status) == 0) +		return 1; +#else +	/* Force silent console mode if S1 switch +	 * is in open position (TIMER_3 pin status is HIGH). */ +	if (MPC5XXX_GPT_GPIO_PIN(timer3_status) == 1) +		return 1; +#endif + +	return 0; +} + +int board_early_init_f (void) +{ +	if (silent_boot()) +		gd->flags |= GD_FLG_SILENT; + +	return 0; +} +#endif	/* CONFIG_FO300 */ + +int last_stage_init (void) +{ +	/* +	 * auto scan for really existing devices and re-set chip select +	 * configuration. +	 */ +	u16 save, tmp; +	int restore; + +	/* +	 * Check for SRAM and SRAM size +	 */ + +	/* save original SRAM content  */ +	save = *(volatile u16 *)CFG_CS2_START; +	restore = 1; + +	/* write test pattern to SRAM */ +	*(volatile u16 *)CFG_CS2_START = 0xA5A5; +	__asm__ volatile ("sync"); +	/* +	 * Put a different pattern on the data lines: otherwise they may float +	 * long enough to read back what we wrote. +	 */ +	tmp = *(volatile u16 *)CFG_FLASH_BASE; +	if (tmp == 0xA5A5) +		puts ("!! possible error in SRAM detection\n"); + +	if (*(volatile u16 *)CFG_CS2_START != 0xA5A5) { +		/* no SRAM at all, disable cs */ +		*(vu_long *)MPC5XXX_ADDECR &= ~(1 << 18); +		*(vu_long *)MPC5XXX_CS2_START = 0x0000FFFF; +		*(vu_long *)MPC5XXX_CS2_STOP = 0x0000FFFF; +		restore = 0; +		__asm__ volatile ("sync"); +	} else if (*(volatile u16 *)(CFG_CS2_START + (1<<19)) == 0xA5A5) { +		/* make sure that we access a mirrored address */ +		*(volatile u16 *)CFG_CS2_START = 0x1111; +		__asm__ volatile ("sync"); +		if (*(volatile u16 *)(CFG_CS2_START + (1<<19)) == 0x1111) { +			/* SRAM size = 512 kByte */ +			*(vu_long *)MPC5XXX_CS2_STOP = STOP_REG(CFG_CS2_START, +								0x80000); +			__asm__ volatile ("sync"); +			puts ("SRAM:  512 kB\n"); +		} +		else +			puts ("!! possible error in SRAM detection\n"); +	} else { +		puts ("SRAM:  1 MB\n"); +	} +	/* restore origianl SRAM content  */ +	if (restore) { +		*(volatile u16 *)CFG_CS2_START = save; +		__asm__ volatile ("sync"); +	} + +#ifndef CONFIG_TQM5200S	/* The TQM5200S has no SM501 grafic controller */ +	/* +	 * Check for Grafic Controller +	 */ + +	/* save origianl FB content  */ +	save = *(volatile u16 *)CFG_CS1_START; +	restore = 1; + +	/* write test pattern to FB memory */ +	*(volatile u16 *)CFG_CS1_START = 0xA5A5; +	__asm__ volatile ("sync"); +	/* +	 * Put a different pattern on the data lines: otherwise they may float +	 * long enough to read back what we wrote. +	 */ +	tmp = *(volatile u16 *)CFG_FLASH_BASE; +	if (tmp == 0xA5A5) +		puts ("!! possible error in grafic controller detection\n"); + +	if (*(volatile u16 *)CFG_CS1_START != 0xA5A5) { +		/* no grafic controller at all, disable cs */ +		*(vu_long *)MPC5XXX_ADDECR &= ~(1 << 17); +		*(vu_long *)MPC5XXX_CS1_START = 0x0000FFFF; +		*(vu_long *)MPC5XXX_CS1_STOP = 0x0000FFFF; +		restore = 0; +		__asm__ volatile ("sync"); +	} else { +		puts ("VGA:   SMI501 (Voyager) with 8 MB\n"); +	} +	/* restore origianl FB content  */ +	if (restore) { +		*(volatile u16 *)CFG_CS1_START = save; +		__asm__ volatile ("sync"); +	} + +#ifdef CONFIG_FO300 +	if (silent_boot()) { +		setenv("bootdelay", "0"); +		disable_ctrlc(1); +	} +#endif +#endif /* !CONFIG_TQM5200S */ + +	return 0; +} + +#ifdef CONFIG_VIDEO_SM501 + +#ifdef CONFIG_FO300 +#define DISPLAY_WIDTH   800 +#else +#define DISPLAY_WIDTH   640 +#endif +#define DISPLAY_HEIGHT  480 + +#ifdef CONFIG_VIDEO_SM501_8BPP +#error CONFIG_VIDEO_SM501_8BPP not supported. +#endif /* CONFIG_VIDEO_SM501_8BPP */ + +#ifdef CONFIG_VIDEO_SM501_16BPP +#error CONFIG_VIDEO_SM501_16BPP not supported. +#endif /* CONFIG_VIDEO_SM501_16BPP */ +#ifdef CONFIG_VIDEO_SM501_32BPP +static const SMI_REGS init_regs [] = +{ +#if 0 /* CRT only */ +	{0x00004, 0x0}, +	{0x00048, 0x00021807}, +	{0x0004C, 0x10090a01}, +	{0x00054, 0x1}, +	{0x00040, 0x00021807}, +	{0x00044, 0x10090a01}, +	{0x00054, 0x0}, +	{0x80200, 0x00010000}, +	{0x80204, 0x0}, +	{0x80208, 0x0A000A00}, +	{0x8020C, 0x02fa027f}, +	{0x80210, 0x004a028b}, +	{0x80214, 0x020c01df}, +	{0x80218, 0x000201e9}, +	{0x80200, 0x00013306}, +#else  /* panel + CRT */ +#ifdef CONFIG_FO300 +	{0x00004, 0x0}, +	{0x00048, 0x00021807}, +	{0x0004C, 0x301a0a01}, +	{0x00054, 0x1}, +	{0x00040, 0x00021807}, +	{0x00044, 0x091a0a01}, +	{0x00054, 0x0}, +	{0x80000, 0x0f013106}, +	{0x80004, 0xc428bb17}, +	{0x8000C, 0x00000000}, +	{0x80010, 0x0C800C80}, +	{0x80014, 0x03200000}, +	{0x80018, 0x01e00000}, +	{0x8001C, 0x00000000}, +	{0x80020, 0x01e00320}, +	{0x80024, 0x042a031f}, +	{0x80028, 0x0086034a}, +	{0x8002C, 0x020c01df}, +	{0x80030, 0x000201ea}, +	{0x80200, 0x00010000}, +#else +	{0x00004, 0x0}, +	{0x00048, 0x00021807}, +	{0x0004C, 0x091a0a01}, +	{0x00054, 0x1}, +	{0x00040, 0x00021807}, +	{0x00044, 0x091a0a01}, +	{0x00054, 0x0}, +	{0x80000, 0x0f013106}, +	{0x80004, 0xc428bb17}, +	{0x8000C, 0x00000000}, +	{0x80010, 0x0a000a00}, +	{0x80014, 0x02800000}, +	{0x80018, 0x01e00000}, +	{0x8001C, 0x00000000}, +	{0x80020, 0x01e00280}, +	{0x80024, 0x02fa027f}, +	{0x80028, 0x004a028b}, +	{0x8002C, 0x020c01df}, +	{0x80030, 0x000201e9}, +	{0x80200, 0x00010000}, +#endif /* #ifdef CONFIG_FO300 */ +#endif +	{0, 0} +}; +#endif /* CONFIG_VIDEO_SM501_32BPP */ + +#ifdef CONFIG_CONSOLE_EXTRA_INFO +/* + * Return text to be printed besides the logo. + */ +void video_get_info_str (int line_number, char *info) +{ +	if (line_number == 1) { +	strcpy (info, " Board: TQM5200 (TQ-Components GmbH)"); +#if defined (CONFIG_STK52XX) || defined (CONFIG_TB5200) || defined(CONFIG_FO300) +	} else if (line_number == 2) { +#if defined (CONFIG_STK52XX) +		strcpy (info, "        on a STK52xx carrier board"); +#endif +#if defined (CONFIG_TB5200) +		strcpy (info, "        on a TB5200 carrier board"); +#endif +#if defined (CONFIG_FO300) +		strcpy (info, "        on a FO300 carrier board"); +#endif +#endif +	} +	else { +		info [0] = '\0'; +	} +} +#endif + +/* + * Returns SM501 register base address. First thing called in the + * driver. Checks if SM501 is physically present. + */ +unsigned int board_video_init (void) +{ +	u16 save, tmp; +	int restore, ret; + +	/* +	 * Check for Grafic Controller +	 */ + +	/* save origianl FB content  */ +	save = *(volatile u16 *)CFG_CS1_START; +	restore = 1; + +	/* write test pattern to FB memory */ +	*(volatile u16 *)CFG_CS1_START = 0xA5A5; +	__asm__ volatile ("sync"); +	/* +	 * Put a different pattern on the data lines: otherwise they may float +	 * long enough to read back what we wrote. +	 */ +	tmp = *(volatile u16 *)CFG_FLASH_BASE; +	if (tmp == 0xA5A5) +		puts ("!! possible error in grafic controller detection\n"); + +	if (*(volatile u16 *)CFG_CS1_START != 0xA5A5) { +		/* no grafic controller found */ +		restore = 0; +		ret = 0; +	} else { +		ret = SM501_MMIO_BASE; +	} + +	if (restore) { +		*(volatile u16 *)CFG_CS1_START = save; +		__asm__ volatile ("sync"); +	} +	return ret; +} + +/* + * Returns SM501 framebuffer address + */ +unsigned int board_video_get_fb (void) +{ +	return SM501_FB_BASE; +} + +/* + * Called after initializing the SM501 and before clearing the screen. + */ +void board_validate_screen (unsigned int base) +{ +} + +/* + * Return a pointer to the initialization sequence. + */ +const SMI_REGS *board_get_regs (void) +{ +	return init_regs; +} + +int board_get_width (void) +{ +	return DISPLAY_WIDTH; +} + +int board_get_height (void) +{ +	return DISPLAY_HEIGHT; +} + +#endif /* CONFIG_VIDEO_SM501 */ + +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) +void ft_board_setup(void *blob, bd_t *bd) +{ +	ft_cpu_setup(blob, bd); +	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize); +} +#endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */ diff --git a/board/tqc/tqm8260/Makefile b/board/tqc/tqm8260/Makefile new file mode 100644 index 000000000..61221fdca --- /dev/null +++ b/board/tqc/tqm8260/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2001-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 +# + +include $(TOPDIR)/config.mk +ifneq ($(OBJTREE),$(SRCTREE)) +$(shell mkdir -p $(obj)../tqm8xx/) +endif + +LIB	= $(obj)lib$(BOARD).a + +COBJS	= $(BOARD).o flash.o ../tqm8xx/load_sernum_ethaddr.o + +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) +SOBJS	:= $(addprefix $(obj),$(SOBJS)) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/tqc/tqm8260/config.mk b/board/tqc/tqm8260/config.mk new file mode 100644 index 000000000..1fe99524c --- /dev/null +++ b/board/tqc/tqm8260/config.mk @@ -0,0 +1,34 @@ +# +# (C) Copyright 2001 +# 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 +# + +# +# TQM8260 boards +# + +# This should be equal to the CFG_FLASH_BASE define in config_TQM8260.h +# for the "final" configuration, with U-Boot in flash, or the address +# in RAM where U-Boot is loaded at for debugging. +# +TEXT_BASE = 0x40000000 + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR) diff --git a/board/tqc/tqm8260/flash.c b/board/tqc/tqm8260/flash.c new file mode 100644 index 000000000..056fe810b --- /dev/null +++ b/board/tqc/tqm8260/flash.c @@ -0,0 +1,488 @@ +/* + * (C) Copyright 2001, 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Flash Routines for AMD devices on the TQM8260 board + * + *-------------------------------------------------------------------- + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <mpc8xx.h> + +#define V_ULONG(a)	(*(volatile unsigned long *)( a )) +#define V_BYTE(a)	(*(volatile unsigned char *)( a )) + + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + + +/*----------------------------------------------------------------------- + */ +void flash_reset (void) +{ +	if (flash_info[0].flash_id != FLASH_UNKNOWN) { +		V_ULONG (flash_info[0].start[0]) = 0x00F000F0; +		V_ULONG (flash_info[0].start[0] + 4) = 0x00F000F0; +	} +} + +/*----------------------------------------------------------------------- + */ +ulong flash_get_size (ulong baseaddr, flash_info_t * info) +{ +	short i; +	unsigned long flashtest_h, flashtest_l; + +	/* Write auto select command sequence and test FLASH answer */ +	V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055; +	V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090; +	V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055; +	V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090; + +	flashtest_h = V_ULONG (baseaddr);	/* manufacturer ID     */ +	flashtest_l = V_ULONG (baseaddr + 4); + +	switch ((int) flashtest_h) { +	case AMD_MANUFACT: +		info->flash_id = FLASH_MAN_AMD; +		break; +	case FUJ_MANUFACT: +		info->flash_id = FLASH_MAN_FUJ; +		break; +	default: +		info->flash_id = FLASH_UNKNOWN; +		info->sector_count = 0; +		info->size = 0; +		return (0);			/* no or unknown flash     */ +	} + +	flashtest_h = V_ULONG (baseaddr + 8);	/* device ID           */ +	flashtest_l = V_ULONG (baseaddr + 12); +	if (flashtest_h != flashtest_l) { +		info->flash_id = FLASH_UNKNOWN; +	} else { +		switch (flashtest_h) { +		case AMD_ID_LV800T: +			info->flash_id += FLASH_AM800T; +			info->sector_count = 19; +			info->size = 0x00400000; +			break;			/* 4 * 1 MB = 4 MB  */ +		case AMD_ID_LV800B: +			info->flash_id += FLASH_AM800B; +			info->sector_count = 19; +			info->size = 0x00400000; +			break;			/* 4 * 1 MB = 4 MB  */ +		case AMD_ID_LV160T: +			info->flash_id += FLASH_AM160T; +			info->sector_count = 35; +			info->size = 0x00800000; +			break;			/* 4 * 2 MB = 8 MB  */ +		case AMD_ID_LV160B: +			info->flash_id += FLASH_AM160B; +			info->sector_count = 35; +			info->size = 0x00800000; +			break;			/* 4 * 2 MB = 8 MB  */ +		case AMD_ID_DL322T: +			info->flash_id += FLASH_AMDL322T; +			info->sector_count = 71; +			info->size = 0x01000000; +			break;			/* 4 * 4 MB = 16 MB */ +		case AMD_ID_DL322B: +			info->flash_id += FLASH_AMDL322B; +			info->sector_count = 71; +			info->size = 0x01000000; +			break;			/* 4 * 4 MB = 16 MB */ +		case AMD_ID_DL323T: +			info->flash_id += FLASH_AMDL323T; +			info->sector_count = 71; +			info->size = 0x01000000; +			break;			/* 4 * 4 MB = 16 MB */ +		case AMD_ID_DL323B: +			info->flash_id += FLASH_AMDL323B; +			info->sector_count = 71; +			info->size = 0x01000000; +			break;			/* 4 * 4 MB = 16 MB */ +		case AMD_ID_LV640U: +			info->flash_id += FLASH_AM640U; +			info->sector_count = 128; +			info->size = 0x02000000; +			break;			/* 4 * 8 MB = 32 MB */ +		default: +			info->flash_id = FLASH_UNKNOWN; +			return (0);		/* no or unknown flash     */ +		} +	} + +	if (flashtest_h == AMD_ID_LV640U) { + +		/* set up sector start adress table (uniform sector type) */ +		for (i = 0; i < info->sector_count; i++) +			info->start[i] = baseaddr + (i * 0x00040000); + +	} else if (info->flash_id & FLASH_BTYPE) { + +		/* set up sector start adress table (bottom sector type) */ +		info->start[0] = baseaddr + 0x00000000; +		info->start[1] = baseaddr + 0x00010000; +		info->start[2] = baseaddr + 0x00018000; +		info->start[3] = baseaddr + 0x00020000; +		for (i = 4; i < info->sector_count; i++) { +			info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000; +		} + +	} else { + +		/* set up sector start adress table (top sector type) */ +		i = info->sector_count - 1; +		info->start[i--] = baseaddr + info->size - 0x00010000; +		info->start[i--] = baseaddr + info->size - 0x00018000; +		info->start[i--] = baseaddr + info->size - 0x00020000; +		for (; i >= 0; i--) { +			info->start[i] = baseaddr + i * 0x00040000; +		} +	} + +	/* check for protected sectors */ +	for (i = 0; i < info->sector_count; i++) { +		/* read sector protection at sector address, (A7 .. A0) = 0x02 */ +		if ((V_ULONG (info->start[i] + 16) & 0x00010001) || +			(V_ULONG (info->start[i] + 20) & 0x00010001)) { +			info->protect[i] = 1;	/* D0 = 1 if protected */ +		} else { +			info->protect[i] = 0; +		} +	} + +	flash_reset (); +	return (info->size); +} + +/*----------------------------------------------------------------------- + */ +unsigned long flash_init (void) +{ +	unsigned long size_b0 = 0; +	int i; + +	/* Init: no FLASHes known */ +	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { +		flash_info[i].flash_id = FLASH_UNKNOWN; +	} + +	/* Static FLASH Bank configuration here (only one bank) */ + +	size_b0 = flash_get_size (CFG_FLASH0_BASE, &flash_info[0]); +	if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b0 == 0) { +		printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n", +				size_b0, size_b0 >> 20); +	} + +	/* +	 * protect monitor and environment sectors +	 */ + +#if CFG_MONITOR_BASE >= CFG_FLASH0_BASE +	flash_protect (FLAG_PROTECT_SET, +		       CFG_MONITOR_BASE, +		       CFG_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0]); +#endif + +#if (CFG_ENV_IS_IN_FLASH == 1) && defined(CFG_ENV_ADDR) +# ifndef  CFG_ENV_SIZE +#  define CFG_ENV_SIZE	CFG_ENV_SECT_SIZE +# endif +	flash_protect (FLAG_PROTECT_SET, +		       CFG_ENV_ADDR, +		       CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]); +#endif + +	return (size_b0); +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info (flash_info_t * info) +{ +	int i; + +	if (info->flash_id == FLASH_UNKNOWN) { +		printf ("missing or unknown FLASH type\n"); +		return; +	} + +	switch (info->flash_id & FLASH_VENDMASK) { +	case FLASH_MAN_AMD: +		printf ("AMD "); +		break; +	case FLASH_MAN_FUJ: +		printf ("FUJITSU "); +		break; +	default: +		printf ("Unknown Vendor "); +		break; +	} + +	switch (info->flash_id & FLASH_TYPEMASK) { +	case FLASH_AM800T: +		printf ("29LV800T (8 M, top sector)\n"); +		break; +	case FLASH_AM800B: +		printf ("29LV800T (8 M, bottom sector)\n"); +		break; +	case FLASH_AM160T: +		printf ("29LV160T (16 M, top sector)\n"); +		break; +	case FLASH_AM160B: +		printf ("29LV160B (16 M, bottom sector)\n"); +		break; +	case FLASH_AMDL322T: +		printf ("29DL322T (32 M, top sector)\n"); +		break; +	case FLASH_AMDL322B: +		printf ("29DL322B (32 M, bottom sector)\n"); +		break; +	case FLASH_AMDL323T: +		printf ("29DL323T (32 M, top sector)\n"); +		break; +	case FLASH_AMDL323B: +		printf ("29DL323B (32 M, bottom sector)\n"); +		break; +	case FLASH_AM640U: +		printf ("29LV640D (64 M, uniform sector)\n"); +		break; +	default: +		printf ("Unknown Chip Type\n"); +		break; +	} + +	printf ("  Size: %ld MB in %d Sectors\n", +			info->size >> 20, info->sector_count); + +	printf ("  Sector Start Addresses:"); +	for (i = 0; i < info->sector_count; ++i) { +		if ((i % 5) == 0) +			printf ("\n   "); +		printf (" %08lX%s", +			info->start[i], +			info->protect[i] ? " (RO)" : "     " +		); +	} +	printf ("\n"); +	return; +} + +/*----------------------------------------------------------------------- + */ +int flash_erase (flash_info_t * info, int s_first, int s_last) +{ +	int flag, prot, sect, l_sect; +	ulong start, now, last; + +	if ((s_first < 0) || (s_first > s_last)) { +		if (info->flash_id == FLASH_UNKNOWN) { +			printf ("- missing\n"); +		} else { +			printf ("- no sectors to erase\n"); +		} +		return 1; +	} + +	prot = 0; +	for (sect = s_first; sect <= s_last; sect++) { +		if (info->protect[sect]) +			prot++; +	} + +	if (prot) { +		printf ("- Warning: %d protected sectors will not be erased!\n", +			prot); +	} else { +		printf ("\n"); +	} + +	l_sect = -1; + +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts (); + +	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055; +	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00800080; +	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055; +	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055; +	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00800080; +	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055; +	udelay (1000); + +	/* Start erase on unprotected sectors */ +	for (sect = s_first; sect <= s_last; sect++) { +		if (info->protect[sect] == 0) {	/* not protected */ +			V_ULONG (info->start[sect]) = 0x00300030; +			V_ULONG (info->start[sect] + 4) = 0x00300030; +			l_sect = sect; +		} +	} + +	/* re-enable interrupts if necessary */ +	if (flag) +		enable_interrupts (); + +	/* wait at least 80us - let's wait 1 ms */ +	udelay (1000); + +	/* +	 * We wait for the last triggered sector +	 */ +	if (l_sect < 0) +		goto DONE; + +	start = get_timer (0); +	last = start; +	while ((V_ULONG (info->start[l_sect]) & 0x00800080) != 0x00800080 || +	       (V_ULONG (info->start[l_sect] + 4) & 0x00800080) != 0x00800080) +	{ +		if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT) { +			printf ("Timeout\n"); +			return 1; +		} +		/* show that we're waiting */ +		if ((now - last) > 1000) {	/* every second */ +			serial_putc ('.'); +			last = now; +		} +	} + +  DONE: +	/* reset to read mode */ +	flash_reset (); + +	printf (" done\n"); +	return 0; +} + +static int write_dword (flash_info_t *, ulong, unsigned char *); + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ + +int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ +	ulong dp; +	static unsigned char bb[8]; +	int i, l, rc, cc = cnt; + +	dp = (addr & ~7);		/* get lower dword aligned address */ + +	/* +	 * handle unaligned start bytes +	 */ +	if ((l = addr - dp) != 0) { +		for (i = 0; i < 8; i++) +			bb[i] = (i < l || (i - l) >= cc) ? V_BYTE (dp + i) : *src++; +		if ((rc = write_dword (info, dp, bb)) != 0) { +			return (rc); +		} +		dp += 8; +		cc -= 8 - l; +	} + +	/* +	 * handle word aligned part +	 */ +	while (cc >= 8) { +		if ((rc = write_dword (info, dp, src)) != 0) { +			return (rc); +		} +		dp += 8; +		src += 8; +		cc -= 8; +	} + +	if (cc <= 0) { +		return (0); +	} + +	/* +	 * handle unaligned tail bytes +	 */ +	for (i = 0; i < 8; i++) { +		bb[i] = (i < cc) ? *src++ : V_BYTE (dp + i); +	} +	return (write_dword (info, dp, bb)); +} + +/*----------------------------------------------------------------------- + * Write a dword to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_dword (flash_info_t * info, ulong dest, unsigned char *pdata) +{ +	ulong start, cl, ch; +	int flag, i; + +	for (ch = 0, i = 0; i < 4; i++) +		ch = (ch << 8) + *pdata++;	/* high word    */ +	for (cl = 0, i = 0; i < 4; i++) +		cl = (cl << 8) + *pdata++;	/* low word */ + +	/* Check if Flash is (sufficiently) erased */ +	if ((*((vu_long *) dest) & ch) != ch +		|| (*((vu_long *) (dest + 4)) & cl) != cl) { +		return (2); +	} + +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts (); + +	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (info->start[0] + (0x02AA << 3)) = 0x00550055; +	V_ULONG (info->start[0] + (0x0555 << 3)) = 0x00A000A0; +	V_ULONG (dest) = ch; +	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00AA00AA; +	V_ULONG (info->start[0] + 4 + (0x02AA << 3)) = 0x00550055; +	V_ULONG (info->start[0] + 4 + (0x0555 << 3)) = 0x00A000A0; +	V_ULONG (dest + 4) = cl; + +	/* re-enable interrupts if necessary */ +	if (flag) +		enable_interrupts (); + +	/* data polling for D7 */ +	start = get_timer (0); +	while (((V_ULONG (dest) & 0x00800080) != (ch & 0x00800080)) || +		   ((V_ULONG (dest + 4) & 0x00800080) != (cl & 0x00800080))) { +		if (get_timer (start) > CFG_FLASH_WRITE_TOUT) { +			return (1); +		} +	} +	return (0); +} diff --git a/board/tqc/tqm8260/tqm8260.c b/board/tqc/tqm8260/tqm8260.c new file mode 100644 index 000000000..736c410ed --- /dev/null +++ b/board/tqc/tqm8260/tqm8260.c @@ -0,0 +1,368 @@ +/* + * (C) Copyright 2001 + * 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> +#include <ioports.h> +#include <mpc8260.h> + +/* + * I/O Port configuration table + * + * if conf is 1, then that port pin will be configured at boot time + * according to the five values podr/pdir/ppar/psor/pdat for that entry + */ + +const iop_conf_t iop_conf_tab[4][32] = { + +    /* Port A configuration */ +    {	/*	      conf ppar psor pdir podr pdat */ +	/* PA31 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 *ATMTXEN */ +	/* PA30 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTCA   */ +	/* PA29 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTSOC  */ +	/* PA28 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 *ATMRXEN */ +	/* PA27 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRSOC */ +	/* PA26 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRCA */ +	/* PA25 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[0] */ +	/* PA24 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[1] */ +	/* PA23 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[2] */ +	/* PA22 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[3] */ +	/* PA21 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[4] */ +	/* PA20 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[5] */ +	/* PA19 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[6] */ +	/* PA18 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMTXD[7] */ +	/* PA17 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[7] */ +	/* PA16 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[6] */ +	/* PA15 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[5] */ +	/* PA14 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[4] */ +	/* PA13 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[3] */ +	/* PA12 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[2] */ +	/* PA11 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[1] */ +	/* PA10 */ {   0,   0,   0,   1,   0,   0   }, /* FCC1 ATMRXD[0] */ +	/* PA9  */ {   1,   1,   0,   1,   0,   0   }, /* SMC2 TXD */ +	/* PA8  */ {   1,   1,   0,   0,   0,   0   }, /* SMC2 RXD */ +	/* PA7  */ {   0,   0,   0,   1,   0,   0   }, /* PA7 */ +	/* PA6  */ {   0,   0,   0,   1,   0,   0   }, /* PA6 */ +	/* PA5  */ {   0,   0,   0,   1,   0,   0   }, /* PA5 */ +	/* PA4  */ {   0,   0,   0,   1,   0,   0   }, /* PA4 */ +	/* PA3  */ {   0,   0,   0,   1,   0,   0   }, /* PA3 */ +	/* PA2  */ {   0,   0,   0,   1,   0,   0   }, /* PA2 */ +	/* PA1  */ {   0,   0,   0,   1,   0,   0   }, /* PA1 */ +	/* PA0  */ {   0,   0,   0,   1,   0,   0   }  /* PA0 */ +    }, + +    /* Port B configuration */ +    {   /*	      conf ppar psor pdir podr pdat */ +	/* PB31 */ {   1,   1,   0,   1,   0,   0   }, /* FCC2 MII TX_ER */ +	/* PB30 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII RX_DV */ +	/* PB29 */ {   1,   1,   1,   1,   0,   0   }, /* FCC2 MII TX_EN */ +	/* PB28 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII RX_ER */ +	/* PB27 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII COL */ +	/* PB26 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII CRS */ +	/* PB25 */ {   1,   1,   0,   1,   0,   0   }, /* FCC2 MII TxD[3] */ +	/* PB24 */ {   1,   1,   0,   1,   0,   0   }, /* FCC2 MII TxD[2] */ +	/* PB23 */ {   1,   1,   0,   1,   0,   0   }, /* FCC2 MII TxD[1] */ +	/* PB22 */ {   1,   1,   0,   1,   0,   0   }, /* FCC2 MII TxD[0] */ +	/* PB21 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII RxD[0] */ +	/* PB20 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII RxD[1] */ +	/* PB19 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII RxD[2] */ +	/* PB18 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII RxD[3] */ +	/* PB17 */ {   0,   0,   0,   0,   0,   0   }, /* PB17 */ +	/* PB16 */ {   0,   0,   0,   0,   0,   0   }, /* PB16 */ +	/* PB15 */ {   0,   0,   0,   0,   0,   0   }, /* PB15 */ +	/* PB14 */ {   0,   0,   0,   0,   0,   0   }, /* PB14 */ +	/* PB13 */ {   0,   0,   0,   0,   0,   0   }, /* PB13 */ +	/* PB12 */ {   0,   0,   0,   0,   0,   0   }, /* PB12 */ +	/* PB11 */ {   0,   0,   0,   0,   0,   0   }, /* PB11 */ +	/* PB10 */ {   0,   0,   0,   0,   0,   0   }, /* PB10 */ +	/* PB9  */ {   0,   0,   0,   0,   0,   0   }, /* PB9 */ +	/* PB8  */ {   0,   0,   0,   0,   0,   0   }, /* PB8 */ +	/* PB7  */ {   0,   0,   0,   0,   0,   0   }, /* PB7 */ +	/* PB6  */ {   0,   0,   0,   0,   0,   0   }, /* PB6 */ +	/* PB5  */ {   0,   0,   0,   0,   0,   0   }, /* PB5 */ +	/* PB4  */ {   0,   0,   0,   0,   0,   0   }, /* PB4 */ +	/* PB3  */ {   0,   0,   0,   0,   0,   0   }, /* pin doesn't exist */ +	/* PB2  */ {   0,   0,   0,   0,   0,   0   }, /* pin doesn't exist */ +	/* PB1  */ {   0,   0,   0,   0,   0,   0   }, /* pin doesn't exist */ +	/* PB0  */ {   0,   0,   0,   0,   0,   0   }  /* pin doesn't exist */ +    }, + +    /* Port C */ +    {   /*	      conf ppar psor pdir podr pdat */ +	/* PC31 */ {   0,   0,   0,   1,   0,   0   }, /* PC31 */ +	/* PC30 */ {   0,   0,   0,   1,   0,   0   }, /* PC30 */ +	/* PC29 */ {   1,   1,   1,   0,   0,   0   }, /* SCC1 EN *CLSN */ +	/* PC28 */ {   0,   0,   0,   1,   0,   0   }, /* PC28 */ +	/* PC27 */ {   0,   0,   0,   1,   0,   0   }, /* PC27 */ +	/* PC26 */ {   0,   0,   0,   1,   0,   0   }, /* PC26 */ +	/* PC25 */ {   0,   0,   0,   1,   0,   0   }, /* PC25 */ +	/* PC24 */ {   0,   0,   0,   1,   0,   0   }, /* PC24 */ +	/* PC23 */ {   0,   1,   0,   1,   0,   0   }, /* ATMTFCLK */ +	/* PC22 */ {   0,   1,   0,   0,   0,   0   }, /* ATMRFCLK */ +	/* PC21 */ {   1,   1,   0,   0,   0,   0   }, /* SCC1 EN RXCLK */ +	/* PC20 */ {   1,   1,   0,   0,   0,   0   }, /* SCC1 EN TXCLK */ +	/* PC19 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII RX_CLK */ +	/* PC18 */ {   1,   1,   0,   0,   0,   0   }, /* FCC2 MII TX_CLK */ +	/* PC17 */ {   0,   0,   0,   1,   0,   0   }, /* PC17 */ +	/* PC16 */ {   0,   0,   0,   1,   0,   0   }, /* PC16 */ +	/* PC15 */ {   0,   0,   0,   1,   0,   0   }, /* PC15 */ +	/* PC14 */ {   1,   1,   0,   0,   0,   0   }, /* SCC1 EN *CD */ +	/* PC13 */ {   0,   0,   0,   1,   0,   0   }, /* PC13 */ +	/* PC12 */ {   0,   0,   0,   1,   0,   0   }, /* PC12 */ +	/* PC11 */ {   0,   0,   0,   1,   0,   0   }, /* PC11 */ +	/* PC10 */ {   0,   0,   0,   1,   0,   0   }, /* FCC2 MDC */ +	/* PC9  */ {   0,   0,   0,   1,   0,   0   }, /* FCC2 MDIO */ +	/* PC8  */ {   0,   0,   0,   1,   0,   0   }, /* PC8 */ +	/* PC7  */ {   0,   0,   0,   1,   0,   0   }, /* PC7 */ +	/* PC6  */ {   0,   0,   0,   1,   0,   0   }, /* PC6 */ +	/* PC5  */ {   0,   0,   0,   1,   0,   0   }, /* PC5 */ +	/* PC4  */ {   0,   0,   0,   1,   0,   0   }, /* PC4 */ +	/* PC3  */ {   0,   0,   0,   1,   0,   0   }, /* PC3 */ +	/* PC2  */ {   0,   0,   0,   1,   0,   1   }, /* ENET FDE */ +	/* PC1  */ {   0,   0,   0,   1,   0,   0   }, /* ENET DSQE */ +	/* PC0  */ {   0,   0,   0,   1,   0,   0   }, /* ENET LBK */ +    }, + +    /* Port D */ +    {   /*	      conf ppar psor pdir podr pdat */ +	/* PD31 */ {   1,   1,   0,   0,   0,   0   }, /* SCC1 EN RxD */ +	/* PD30 */ {   1,   1,   1,   1,   0,   0   }, /* SCC1 EN TxD */ +	/* PD29 */ {   1,   1,   0,   1,   0,   0   }, /* SCC1 EN TENA */ +	/* PD28 */ {   0,   0,   0,   1,   0,   0   }, /* PD28 */ +	/* PD27 */ {   0,   0,   0,   1,   0,   0   }, /* PD27 */ +	/* PD26 */ {   0,   0,   0,   1,   0,   0   }, /* PD26 */ +	/* PD25 */ {   0,   0,   0,   1,   0,   0   }, /* PD25 */ +	/* PD24 */ {   0,   0,   0,   1,   0,   0   }, /* PD24 */ +	/* PD23 */ {   0,   0,   0,   1,   0,   0   }, /* PD23 */ +	/* PD22 */ {   0,   0,   0,   1,   0,   0   }, /* PD22 */ +	/* PD21 */ {   0,   0,   0,   1,   0,   0   }, /* PD21 */ +	/* PD20 */ {   0,   0,   0,   1,   0,   0   }, /* PD20 */ +	/* PD19 */ {   0,   0,   0,   1,   0,   0   }, /* PD19 */ +	/* PD18 */ {   0,   0,   0,   1,   0,   0   }, /* PD19 */ +	/* PD17 */ {   0,   1,   0,   0,   0,   0   }, /* FCC1 ATMRXPRTY */ +	/* PD16 */ {   0,   1,   0,   1,   0,   0   }, /* FCC1 ATMTXPRTY */ +#if defined(CONFIG_SOFT_I2C) +	/* PD15 */ {   1,   0,   0,   1,   1,   1   }, /* I2C SDA */ +	/* PD14 */ {   1,   0,   0,   1,   1,   1   }, /* I2C SCL */ +#else +#if defined(CONFIG_HARD_I2C) +	/* PD15 */ {   1,   1,   1,   0,   1,   0   }, /* I2C SDA */ +	/* PD14 */ {   1,   1,   1,   0,   1,   0   }, /* I2C SCL */ +#else /* normal I/O port pins */ +	/* PD15 */ {   0,   1,   1,   0,   1,   0   }, /* I2C SDA */ +	/* PD14 */ {   0,   1,   1,   0,   1,   0   }, /* I2C SCL */ +#endif +#endif +	/* PD13 */ {   0,   0,   0,   0,   0,   0   }, /* PD13 */ +	/* PD12 */ {   0,   0,   0,   0,   0,   0   }, /* PD12 */ +	/* PD11 */ {   0,   0,   0,   0,   0,   0   }, /* PD11 */ +	/* PD10 */ {   0,   0,   0,   0,   0,   0   }, /* PD10 */ +	/* PD9  */ {   1,   1,   0,   1,   0,   0   }, /* SMC1 TXD */ +	/* PD8  */ {   1,   1,   0,   0,   0,   0   }, /* SMC1 RXD */ +	/* PD7  */ {   0,   0,   0,   1,   0,   1   }, /* PD7 */ +	/* PD6  */ {   0,   0,   0,   1,   0,   1   }, /* PD6 */ +	/* PD5  */ {   0,   0,   0,   1,   0,   1   }, /* PD5 */ +	/* PD4  */ {   0,   0,   0,   1,   0,   1   }, /* PD4 */ +	/* PD3  */ {   0,   0,   0,   0,   0,   0   }, /* pin doesn't exist */ +	/* PD2  */ {   0,   0,   0,   0,   0,   0   }, /* pin doesn't exist */ +	/* PD1  */ {   0,   0,   0,   0,   0,   0   }, /* pin doesn't exist */ +	/* PD0  */ {   0,   0,   0,   0,   0,   0   }  /* pin doesn't exist */ +    } +}; + +/* ------------------------------------------------------------------------- */ + +/* Check Board Identity: + */ +int checkboard (void) +{ +	char str[64]; +	int i = getenv_r ("serial#", str, sizeof (str)); + +	puts ("Board: "); + +	if (!i || strncmp (str, "TQM82", 5)) { +		puts ("### No HW ID - assuming TQM8260\n"); +		return (0); +	} + +	puts (str); +	putc ('\n'); + +	return 0; +} + +/* ------------------------------------------------------------------------- */ + +/* Try SDRAM initialization with P/LSDMR=sdmr and ORx=orx + * + * This routine performs standard 8260 initialization sequence + * and calculates the available memory size. It may be called + * several times to try different SDRAM configurations on both + * 60x and local buses. + */ +static long int try_init (volatile memctl8260_t * memctl, ulong sdmr, +						  ulong orx, volatile uchar * base) +{ +	volatile uchar c = 0xff; +	volatile uint *sdmr_ptr; +	volatile uint *orx_ptr; +	ulong maxsize, size; +	int i; + +	/* We must be able to test a location outsize the maximum legal size +	 * to find out THAT we are outside; but this address still has to be +	 * mapped by the controller. That means, that the initial mapping has +	 * to be (at least) twice as large as the maximum expected size. +	 */ +	maxsize = (1 + (~orx | 0x7fff)) / 2; + +	/* Since CFG_SDRAM_BASE is always 0 (??), we assume that +	 * we are configuring CS1 if base != 0 +	 */ +	sdmr_ptr = base ? &memctl->memc_lsdmr : &memctl->memc_psdmr; +	orx_ptr = base ? &memctl->memc_or2 : &memctl->memc_or1; + +	*orx_ptr = orx; + +	/* +	 * Quote from 8260 UM (10.4.2 SDRAM Power-On Initialization, 10-35): +	 * +	 * "At system reset, initialization software must set up the +	 *  programmable parameters in the memory controller banks registers +	 *  (ORx, BRx, P/LSDMR). After all memory parameters are configured, +	 *  system software should execute the following initialization sequence +	 *  for each SDRAM device. +	 * +	 *  1. Issue a PRECHARGE-ALL-BANKS command +	 *  2. Issue eight CBR REFRESH commands +	 *  3. Issue a MODE-SET command to initialize the mode register +	 * +	 *  The initial commands are executed by setting P/LSDMR[OP] and +	 *  accessing the SDRAM with a single-byte transaction." +	 * +	 * The appropriate BRx/ORx registers have already been set when we +	 * get here. The SDRAM can be accessed at the address CFG_SDRAM_BASE. +	 */ + +	*sdmr_ptr = sdmr | PSDMR_OP_PREA; +	*base = c; + +	*sdmr_ptr = sdmr | PSDMR_OP_CBRR; +	for (i = 0; i < 8; i++) +		*base = c; + +	*sdmr_ptr = sdmr | PSDMR_OP_MRW; +	*(base + CFG_MRS_OFFS) = c;	/* setting MR on address lines */ + +	*sdmr_ptr = sdmr | PSDMR_OP_NORM | PSDMR_RFEN; +	*base = c; + +	size = get_ram_size((long *)base, maxsize); +	*orx_ptr = orx | ~(size - 1); + +	return (size); +} + +long int initdram (int board_type) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile memctl8260_t *memctl = &immap->im_memctl; + +#ifndef CFG_RAMBOOT +	long size8, size9; +#endif +	long psize, lsize; + +	psize = 16 * 1024 * 1024; +	lsize = 0; + +	memctl->memc_psrt = CFG_PSRT; +	memctl->memc_mptpr = CFG_MPTPR; + +#if 0							/* Just for debugging */ +#define	prt_br_or(brX,orX) do {				\ +    ulong start =  memctl->memc_ ## brX & 0xFFFF8000;	\ +    ulong sizem = ~memctl->memc_ ## orX | 0x00007FFF;	\ +    printf ("\n"					\ +	    #brX " 0x%08x  " #orX " 0x%08x "		\ +	    "==> 0x%08lx ... 0x%08lx = %ld MB\n",	\ +	memctl->memc_ ## brX, memctl->memc_ ## orX,	\ +	start, start+sizem, (sizem+1)>>20);		\ +    } while (0) +	prt_br_or (br0, or0); +	prt_br_or (br1, or1); +	prt_br_or (br2, or2); +	prt_br_or (br3, or3); +#endif + +#ifndef CFG_RAMBOOT +	/* 60x SDRAM setup: +	 */ +	size8 = try_init (memctl, CFG_PSDMR_8COL, CFG_OR1_8COL, +					  (uchar *) CFG_SDRAM_BASE); +	size9 = try_init (memctl, CFG_PSDMR_9COL, CFG_OR1_9COL, +					  (uchar *) CFG_SDRAM_BASE); + +	if (size8 < size9) { +		psize = size9; +		printf ("(60x:9COL - %ld MB, ", psize >> 20); +	} else { +		psize = try_init (memctl, CFG_PSDMR_8COL, CFG_OR1_8COL, +						  (uchar *) CFG_SDRAM_BASE); +		printf ("(60x:8COL - %ld MB, ", psize >> 20); +	} + +	/* Local SDRAM setup: +	 */ +#ifdef CFG_INIT_LOCAL_SDRAM +	memctl->memc_lsrt = CFG_LSRT; +	size8 = try_init (memctl, CFG_LSDMR_8COL, CFG_OR2_8COL, +					  (uchar *) SDRAM_BASE2_PRELIM); +	size9 = try_init (memctl, CFG_LSDMR_9COL, CFG_OR2_9COL, +					  (uchar *) SDRAM_BASE2_PRELIM); + +	if (size8 < size9) { +		lsize = size9; +		printf ("Local:9COL - %ld MB) using ", lsize >> 20); +	} else { +		lsize = try_init (memctl, CFG_LSDMR_8COL, CFG_OR2_8COL, +						  (uchar *) SDRAM_BASE2_PRELIM); +		printf ("Local:8COL - %ld MB) using ", lsize >> 20); +	} + +#if 0 +	/* Set up BR2 so that the local SDRAM goes +	 * right after the 60x SDRAM +	 */ +	memctl->memc_br2 = (CFG_BR2_PRELIM & ~BRx_BA_MSK) | +			(CFG_SDRAM_BASE + psize); +#endif +#endif /* CFG_INIT_LOCAL_SDRAM */ +#endif /* CFG_RAMBOOT */ + +	icache_enable (); + +	return (psize); +} + +/* ------------------------------------------------------------------------- */ diff --git a/board/tqc/tqm8272/Makefile b/board/tqc/tqm8272/Makefile new file mode 100644 index 000000000..673026351 --- /dev/null +++ b/board/tqc/tqm8272/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2001-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk +ifneq ($(OBJTREE),$(SRCTREE)) +$(shell mkdir -p $(obj)../tqm8xx/) +endif + +LIB	= $(obj)lib$(BOARD).a + +COBJS	= $(BOARD).o ../tqm8xx/load_sernum_ethaddr.o + +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) +SOBJS	:= $(addprefix $(obj),$(SOBJS)) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/tqc/tqm8272/config.mk b/board/tqc/tqm8272/config.mk new file mode 100644 index 000000000..af7a81e33 --- /dev/null +++ b/board/tqc/tqm8272/config.mk @@ -0,0 +1,34 @@ +# +# (C) Copyright 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 +# + +# +# TQM8272 boards +# + +# This should be equal to the CFG_FLASH_BASE define in config_TQM8260.h +# for the "final" configuration, with U-Boot in flash, or the address +# in RAM where U-Boot is loaded at for debugging. +# +TEXT_BASE = 0x40000000 + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR) diff --git a/board/tqc/tqm8272/tqm8272.c b/board/tqc/tqm8272/tqm8272.c new file mode 100644 index 000000000..7bd64012c --- /dev/null +++ b/board/tqc/tqm8272/tqm8272.c @@ -0,0 +1,1234 @@ +/* + * (C) Copyright 2006 + * Heiko Schocher, DENX Software Engineering, hs@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> +#include <ioports.h> +#include <mpc8260.h> + +#include <command.h> +#ifdef CONFIG_PCI +#include <pci.h> +#include <asm/m8260_pci.h> +#endif +#if CONFIG_OF_FLAT_TREE +#include <ft_build.h> +#include <image.h> +#endif + +#if 0 +#define deb_printf(fmt,arg...) \ +	printf ("TQM8272 %s %s: " fmt,__FILE__, __FUNCTION__, ##arg) +#else +#define deb_printf(fmt,arg...) \ +	do { } while (0) +#endif + +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) +unsigned long board_get_cpu_clk_f (void); +#endif + +/* + * I/O Port configuration table + * + * if conf is 1, then that port pin will be configured at boot time + * according to the five values podr/pdir/ppar/psor/pdat for that entry + */ + +const iop_conf_t iop_conf_tab[4][32] = { + +    /* Port A configuration */ +    {	/*	      conf ppar psor pdir podr pdat */ +	/* PA31 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 *ATMTXEN */ +	/* PA30 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTCA	*/ +	/* PA29 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTSOC	*/ +	/* PA28 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 *ATMRXEN */ +	/* PA27 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRSOC */ +	/* PA26 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRCA */ +	/* PA25 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[0] */ +	/* PA24 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[1] */ +	/* PA23 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[2] */ +	/* PA22 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[3] */ +	/* PA21 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[4] */ +	/* PA20 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[5] */ +	/* PA19 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[6] */ +	/* PA18 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMTXD[7] */ +	/* PA17 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[7] */ +	/* PA16 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[6] */ +	/* PA15 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[5] */ +	/* PA14 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[4] */ +	/* PA13 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[3] */ +	/* PA12 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[2] */ +	/* PA11 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[1] */ +	/* PA10 */ {   0,   0,	 0,   1,   0,	0   }, /* FCC1 ATMRXD[0] */ +	/* PA9	*/ {   1,   1,	 0,   1,   0,	0   }, /* SMC2 TXD */ +	/* PA8	*/ {   1,   1,	 0,   0,   0,	0   }, /* SMC2 RXD */ +	/* PA7	*/ {   0,   0,	 0,   1,   0,	0   }, /* PA7 */ +	/* PA6	*/ {   0,   0,	 0,   1,   0,	0   }, /* PA6 */ +	/* PA5	*/ {   0,   0,	 0,   1,   0,	0   }, /* PA5 */ +	/* PA4	*/ {   0,   0,	 0,   1,   0,	0   }, /* PA4 */ +	/* PA3	*/ {   0,   0,	 0,   1,   0,	0   }, /* PA3 */ +	/* PA2	*/ {   0,   0,	 0,   1,   0,	0   }, /* PA2 */ +	/* PA1	*/ {   0,   0,	 0,   1,   0,	0   }, /* PA1 */ +	/* PA0	*/ {   0,   0,	 0,   1,   0,	0   }  /* PA0 */ +    }, + +    /* Port B configuration */ +    {	/*	      conf ppar psor pdir podr pdat */ +	/* PB31 */ {   1,   1,	 0,   1,   0,	0   }, /* FCC2 MII TX_ER */ +	/* PB30 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII RX_DV */ +	/* PB29 */ {   1,   1,	 1,   1,   0,	0   }, /* FCC2 MII TX_EN */ +	/* PB28 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII RX_ER */ +	/* PB27 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII COL */ +	/* PB26 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII CRS */ +	/* PB25 */ {   1,   1,	 0,   1,   0,	0   }, /* FCC2 MII TxD[3] */ +	/* PB24 */ {   1,   1,	 0,   1,   0,	0   }, /* FCC2 MII TxD[2] */ +	/* PB23 */ {   1,   1,	 0,   1,   0,	0   }, /* FCC2 MII TxD[1] */ +	/* PB22 */ {   1,   1,	 0,   1,   0,	0   }, /* FCC2 MII TxD[0] */ +	/* PB21 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII RxD[0] */ +	/* PB20 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII RxD[1] */ +	/* PB19 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII RxD[2] */ +	/* PB18 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII RxD[3] */ +	/* PB17 */ {   0,   0,	 0,   0,   0,	0   }, /* PB17 */ +	/* PB16 */ {   0,   0,	 0,   0,   0,	0   }, /* PB16 */ +	/* PB15 */ {   0,   0,	 0,   0,   0,	0   }, /* PB15 */ +	/* PB14 */ {   0,   0,	 0,   0,   0,	0   }, /* PB14 */ +	/* PB13 */ {   0,   0,	 0,   0,   0,	0   }, /* PB13 */ +	/* PB12 */ {   0,   0,	 0,   0,   0,	0   }, /* PB12 */ +	/* PB11 */ {   0,   0,	 0,   0,   0,	0   }, /* PB11 */ +	/* PB10 */ {   0,   0,	 0,   0,   0,	0   }, /* PB10 */ +	/* PB9	*/ {   0,   0,	 0,   0,   0,	0   }, /* PB9 */ +	/* PB8	*/ {   0,   0,	 0,   0,   0,	0   }, /* PB8 */ +	/* PB7	*/ {   0,   0,	 0,   0,   0,	0   }, /* PB7 */ +	/* PB6	*/ {   0,   0,	 0,   0,   0,	0   }, /* PB6 */ +	/* PB5	*/ {   0,   0,	 0,   0,   0,	0   }, /* PB5 */ +	/* PB4	*/ {   0,   0,	 0,   0,   0,	0   }, /* PB4 */ +	/* PB3	*/ {   0,   0,	 0,   0,   0,	0   }, /* pin doesn't exist */ +	/* PB2	*/ {   0,   0,	 0,   0,   0,	0   }, /* pin doesn't exist */ +	/* PB1	*/ {   0,   0,	 0,   0,   0,	0   }, /* pin doesn't exist */ +	/* PB0	*/ {   0,   0,	 0,   0,   0,	0   }  /* pin doesn't exist */ +    }, + +    /* Port C */ +    {	/*	      conf ppar psor pdir podr pdat */ +	/* PC31 */ {   0,   0,	 0,   1,   0,	0   }, /* PC31 */ +	/* PC30 */ {   0,   0,	 0,   0,   0,	0   }, /* PC30 */ +	/* PC29 */ {   1,   1,	 1,   0,   0,	0   }, /* SCC1 EN *CLSN */ +	/* PC28 */ {   0,   0,	 0,   1,   0,	0   }, /* PC28 */ +	/* PC27 */ {   0,   0,	 0,   1,   0,	0   }, /* PC27 */ +	/* PC26 */ {   0,   0,	 0,   1,   0,	0   }, /* PC26 */ +	/* PC25 */ {   0,   0,	 0,   1,   0,	0   }, /* PC25 */ +	/* PC24 */ {   0,   0,	 0,   1,   0,	0   }, /* PC24 */ +	/* PC23 */ {   0,   1,	 0,   1,   0,	0   }, /* ATMTFCLK */ +	/* PC22 */ {   0,   1,	 0,   0,   0,	0   }, /* ATMRFCLK */ +	/* PC21 */ {   1,   1,	 0,   0,   0,	0   }, /* SCC1 EN RXCLK */ +	/* PC20 */ {   1,   1,	 0,   0,   0,	0   }, /* SCC1 EN TXCLK */ +	/* PC19 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII RX_CLK */ +	/* PC18 */ {   1,   1,	 0,   0,   0,	0   }, /* FCC2 MII TX_CLK */ +	/* PC17 */ {   1,   0,	 0,   1,   0,	0   }, /* PC17 MDC */ +	/* PC16 */ {   1,   0,	 0,   0,   0,	0   }, /* PC16 MDIO*/ +	/* PC15 */ {   0,   0,	 0,   1,   0,	0   }, /* PC15 */ +	/* PC14 */ {   1,   1,	 0,   0,   0,	0   }, /* SCC1 EN *CD */ +	/* PC13 */ {   0,   0,	 0,   1,   0,	0   }, /* PC13 */ +	/* PC12 */ {   0,   0,	 0,   1,   0,	0   }, /* PC12 */ +	/* PC11 */ {   0,   0,	 0,   1,   0,	0   }, /* PC11 */ +	/* PC10 */ {   0,   0,	 0,   1,   0,	0   }, /* PC10 */ +	/* PC9	*/ {   0,   0,	 0,   1,   0,	0   }, /* PC9 */ +	/* PC8	*/ {   0,   0,	 0,   1,   0,	0   }, /* PC8 */ +	/* PC7	*/ {   0,   0,	 0,   1,   0,	0   }, /* PC7 */ +	/* PC6	*/ {   0,   0,	 0,   1,   0,	0   }, /* PC6 */ +	/* PC5	*/ {   1,   1,	 0,   1,   0,	0   }, /* PC5 SMC1 TXD */ +	/* PC4	*/ {   1,   1,	 0,   0,   0,	0   }, /* PC4 SMC1 RXD */ +	/* PC3	*/ {   0,   0,	 0,   1,   0,	0   }, /* PC3 */ +	/* PC2	*/ {   0,   0,	 0,   1,   0,	1   }, /* ENET FDE */ +	/* PC1	*/ {   0,   0,	 0,   1,   0,	0   }, /* ENET DSQE */ +	/* PC0	*/ {   0,   0,	 0,   1,   0,	0   }, /* ENET LBK */ +    }, + +    /* Port D */ +    {	/*	      conf ppar psor pdir podr pdat */ +	/* PD31 */ {   1,   1,	 0,   0,   0,	0   }, /* SCC1 EN RxD */ +	/* PD30 */ {   1,   1,	 1,   1,   0,	0   }, /* SCC1 EN TxD */ +	/* PD29 */ {   1,   1,	 0,   1,   0,	0   }, /* SCC1 EN TENA */ +	/* PD28 */ {   0,   0,	 0,   1,   0,	0   }, /* PD28 */ +	/* PD27 */ {   0,   0,	 0,   1,   0,	0   }, /* PD27 */ +	/* PD26 */ {   0,   0,	 0,   1,   0,	0   }, /* PD26 */ +	/* PD25 */ {   0,   0,	 0,   1,   0,	0   }, /* PD25 */ +	/* PD24 */ {   0,   0,	 0,   1,   0,	0   }, /* PD24 */ +	/* PD23 */ {   0,   0,	 0,   1,   0,	0   }, /* PD23 */ +	/* PD22 */ {   0,   0,	 0,   1,   0,	0   }, /* PD22 */ +	/* PD21 */ {   0,   0,	 0,   1,   0,	0   }, /* PD21 */ +	/* PD20 */ {   0,   0,	 0,   1,   0,	0   }, /* PD20 */ +	/* PD19 */ {   0,   0,	 0,   1,   0,	0   }, /* PD19 */ +	/* PD18 */ {   0,   0,	 0,   1,   0,	0   }, /* PD19 */ +	/* PD17 */ {   0,   1,	 0,   0,   0,	0   }, /* FCC1 ATMRXPRTY */ +	/* PD16 */ {   0,   1,	 0,   1,   0,	0   }, /* FCC1 ATMTXPRTY */ +#if defined(CONFIG_SOFT_I2C) +	/* PD15 */ {   1,   0,	 0,   1,   1,	1   }, /* I2C SDA */ +	/* PD14 */ {   1,   0,	 0,   1,   1,	1   }, /* I2C SCL */ +#else +#if defined(CONFIG_HARD_I2C) +	/* PD15 */ {   1,   1,	 1,   0,   1,	0   }, /* I2C SDA */ +	/* PD14 */ {   1,   1,	 1,   0,   1,	0   }, /* I2C SCL */ +#else /* normal I/O port pins */ +	/* PD15 */ {   0,   1,	 1,   0,   1,	0   }, /* I2C SDA */ +	/* PD14 */ {   0,   1,	 1,   0,   1,	0   }, /* I2C SCL */ +#endif +#endif +	/* PD13 */ {   0,   0,	 0,   0,   0,	0   }, /* PD13 */ +	/* PD12 */ {   0,   0,	 0,   0,   0,	0   }, /* PD12 */ +	/* PD11 */ {   0,   0,	 0,   0,   0,	0   }, /* PD11 */ +	/* PD10 */ {   0,   0,	 0,   0,   0,	0   }, /* PD10 */ +	/* PD9	*/ {   1,   1,	 0,   1,   0,	0   }, /* SMC1 TXD */ +	/* PD8	*/ {   1,   1,	 0,   0,   0,	0   }, /* SMC1 RXD */ +	/* PD7	*/ {   0,   0,	 0,   1,   0,	1   }, /* PD7 */ +	/* PD6	*/ {   0,   0,	 0,   1,   0,	1   }, /* PD6 */ +	/* PD5	*/ {   0,   0,	 0,   1,   0,	0   }, /* PD5 */ +	/* PD4	*/ {   0,   0,	 0,   1,   0,	1   }, /* PD4 */ +	/* PD3	*/ {   0,   0,	 0,   0,   0,	0   }, /* pin doesn't exist */ +	/* PD2	*/ {   0,   0,	 0,   0,   0,	0   }, /* pin doesn't exist */ +	/* PD1	*/ {   0,   0,	 0,   0,   0,	0   }, /* pin doesn't exist */ +	/* PD0	*/ {   0,   0,	 0,   0,   0,	0   }  /* pin doesn't exist */ +    } +}; + +#define _NOT_USED_	0xFFFFFFFF + +/* UPM pattern for bus clock = 66.7 MHz */ +static const uint upmTable67[] = +{ +    /* Offset	UPM Read Single RAM array entry -> NAND Read Data */ +    /* 0x00 */	0x0fa3f100, 0x0fa3b000, 0x0fa33100, 0x0fa33000, +    /* 0x04 */	0x0fa33000, 0x0fa33004, 0xfffffc01, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x08 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x0C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x10 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x14 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Write Single RAM array entry -> NAND Write Data, ADDR and CMD */ +    /* 0x18 */	0x00a3fc00, 0x00a3fc00, 0x00a3fc00, 0x00a3fc00, +    /* 0x1C */	0x0fa3fc00, 0x0fa3fc04, 0xfffffc01, 0xfffffc00, + +		/* UPM Write Burst RAM array entry -> unused */ +    /* 0x20 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x24 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x28 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x2C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Refresh Timer RAM array entry -> unused */ +    /* 0x30 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x34 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x38 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Exception RAM array entry -> unsused */ +    /* 0x3C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 100 MHz */ +static const uint upmTable100[] = +{ +    /* Offset	UPM Read Single RAM array entry -> NAND Read Data */ +    /* 0x00 */	0x0fa3f200, 0x0fa3b000, 0x0fa33300, 0x0fa33000, +    /* 0x04 */	0x0fa33000, 0x0fa33004, 0xfffffc01, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x08 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x0C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x10 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x14 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Write Single RAM array entry -> NAND Write Data, ADDR and CMD */ +    /* 0x18 */	0x00a3ff00, 0x00a3fc00, 0x00a3fc00, 0x0fa3fc00, +    /* 0x1C */	0x0fa3fc00, 0x0fa3fc04, 0xfffffc01, 0xfffffc00, + +		/* UPM Write Burst RAM array entry -> unused */ +    /* 0x20 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x24 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x28 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x2C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Refresh Timer RAM array entry -> unused */ +    /* 0x30 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x34 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x38 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Exception RAM array entry -> unsused */ +    /* 0x3C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 133.3 MHz */ +static const uint upmTable133[] = +{ +    /* Offset	UPM Read Single RAM array entry -> NAND Read Data */ +    /* 0x00 */	0x0fa3f300, 0x0fa3b000, 0x0fa33300, 0x0fa33000, +    /* 0x04 */	0x0fa33200, 0x0fa33004, 0xfffffc01, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x08 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x0C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x10 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x14 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Write Single RAM array entry -> NAND Write Data, ADDR and CMD */ +    /* 0x18 */	0x00a3ff00, 0x00a3fc00, 0x00a3fd00, 0x0fa3fc00, +    /* 0x1C */	0x0fa3fd00, 0x0fa3fc04, 0xfffffc01, 0xfffffc00, + +		/* UPM Write Burst RAM array entry -> unused */ +    /* 0x20 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x24 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x28 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x2C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Refresh Timer RAM array entry -> unused */ +    /* 0x30 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x34 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x38 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Exception RAM array entry -> unsused */ +    /* 0x3C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +static int	chipsel = 0; + +/* UPM pattern for slow init */ +static const uint upmTableSlow[] = +{ +    /* Offset	UPM Read Single RAM array entry */ +    /* 0x00 */	0xffffee00, 0x00ffcc80, 0x00ffcf00, 0x00ffdc00, +    /* 0x04 */	0x00ffce80, 0x00ffcc00, 0x00ffee00, 0x3fffcc07, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x08 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x0C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x10 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x14 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Write Single RAM array entry */ +    /* 0x18 */	0xffffee00, 0x00ffec80, 0x00ffef00, 0x00fffc80, +    /* 0x1C */	0x00fffe00, 0x00ffec00, 0x0fffef00, 0x3fffec05, + +		/* UPM Write Burst RAM array entry -> unused */ +    /* 0x20 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x24 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x28 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x2C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Refresh Timer RAM array entry -> unused */ +    /* 0x30 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x34 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x38 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Exception RAM array entry -> unused */ +    /* 0x3C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for fast init */ +static const uint upmTableFast[] = +{ +    /* Offset	UPM Read Single RAM array entry */ +    /* 0x00 */	0xffffee00, 0x00ffcc80, 0x00ffcd80, 0x00ffdc00, +    /* 0x04 */	0x00ffdc00, 0x00ffcf00, 0x00ffec00, 0x3fffcc07, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x08 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x0C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Read Burst RAM array entry -> unused */ +    /* 0x10 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x14 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +		/* UPM Write Single RAM array entry */ +    /* 0x18 */	0xffffee00, 0x00ffec80, 0x00ffee80, 0x00fffc00, +    /* 0x1C */	0x00fffc00, 0x00ffec00, 0x0fffef00, 0x3fffec05, + +		/* UPM Write Burst RAM array entry -> unused */ +    /* 0x20 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x24 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x28 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x2C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Refresh Timer RAM array entry -> unused */ +    /* 0x30 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x34 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +    /* 0x38 */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +		/* UPM Exception RAM array entry -> unused */ +    /* 0x3C */	0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + + +/* ------------------------------------------------------------------------- */ + +/* Check Board Identity: + */ +int checkboard (void) +{ +	char *p = (char *) HWIB_INFO_START_ADDR; + +	puts ("Board: "); +	if (*((unsigned long *)p) == (unsigned long)CFG_HWINFO_MAGIC) { +		puts (p); +	} else { +		puts ("No HWIB assuming TQM8272"); +	} +	putc ('\n'); + +	return 0; +} + +/* ------------------------------------------------------------------------- */ +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) +static int get_cas_latency (void) +{ +	/* get it from the option -ts in CIB */ +	/* default is 3 */ +	int	ret = 3; +	int	pos = 0; +	char	*p = (char *) CIB_INFO_START_ADDR; + +	while ((*p != '\0') && (pos < CIB_INFO_LEN)) { +		if (*p < ' ' || *p > '~') { /* ASCII strings! */ +			return ret; +		} +		if (*p == '-') { +			if ((p[1] == 't') && (p[2] == 's')) { +				return (p[4] - '0'); +			} +		} +		p++; +		pos++; +	} +	return ret; +} +#endif + +static ulong set_sdram_timing (volatile uint *sdmr_ptr, ulong sdmr, int col) +{ +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) +	int	clk = board_get_cpu_clk_f (); +	volatile immap_t *immr = (immap_t *)CFG_IMMR; +	int	busmode = (immr->im_siu_conf.sc_bcr & BCR_EBM ? 1 : 0); +	int	cas; + +	sdmr = sdmr & ~(PSDMR_RFRC_MSK | PSDMR_PRETOACT_MSK | PSDMR_WRC_MSK | \ +			 PSDMR_BUFCMD); +	if (busmode) { +		switch (clk) { +			case 66666666: +				sdmr |= (PSDMR_RFRC_66MHZ_60X | \ +					PSDMR_PRETOACT_66MHZ_60X | \ +					PSDMR_WRC_66MHZ_60X | \ +					PSDMR_BUFCMD_66MHZ_60X); +				break; +			case 100000000: +				sdmr |= (PSDMR_RFRC_100MHZ_60X | \ +					PSDMR_PRETOACT_100MHZ_60X | \ +					PSDMR_WRC_100MHZ_60X | \ +					PSDMR_BUFCMD_100MHZ_60X); +				break; + +		} +	} else { +		switch (clk) { +			case 66666666: +				sdmr |= (PSDMR_RFRC_66MHZ_SINGLE | \ +					PSDMR_PRETOACT_66MHZ_SINGLE | \ +					PSDMR_WRC_66MHZ_SINGLE | \ +					PSDMR_BUFCMD_66MHZ_SINGLE); +				break; +			case 100000000: +				sdmr |= (PSDMR_RFRC_100MHZ_SINGLE | \ +					PSDMR_PRETOACT_100MHZ_SINGLE | \ +					PSDMR_WRC_100MHZ_SINGLE | \ +					PSDMR_BUFCMD_100MHZ_SINGLE); +				break; +			case 133333333: +				sdmr |= (PSDMR_RFRC_133MHZ_SINGLE | \ +					PSDMR_PRETOACT_133MHZ_SINGLE | \ +					PSDMR_WRC_133MHZ_SINGLE | \ +					PSDMR_BUFCMD_133MHZ_SINGLE); +				break; +		} +	} +	cas = get_cas_latency(); +	sdmr &=~ (PSDMR_CL_MSK | PSDMR_LDOTOPRE_MSK); +	sdmr |= cas; +	sdmr |= ((cas - 1) << 6); +	return sdmr; +#else +	return sdmr; +#endif +} + +/* Try SDRAM initialization with P/LSDMR=sdmr and ORx=orx + * + * This routine performs standard 8260 initialization sequence + * and calculates the available memory size. It may be called + * several times to try different SDRAM configurations on both + * 60x and local buses. + */ +static long int try_init (volatile memctl8260_t * memctl, ulong sdmr, +						  ulong orx, volatile uchar * base, int col) +{ +	volatile uchar c = 0xff; +	volatile uint *sdmr_ptr; +	volatile uint *orx_ptr; +	ulong maxsize, size; +	int i; + +	/* We must be able to test a location outsize the maximum legal size +	 * to find out THAT we are outside; but this address still has to be +	 * mapped by the controller. That means, that the initial mapping has +	 * to be (at least) twice as large as the maximum expected size. +	 */ +	maxsize = (1 + (~orx | 0x7fff)) / 2; + +	/* Since CFG_SDRAM_BASE is always 0 (??), we assume that +	 * we are configuring CS1 if base != 0 +	 */ +	sdmr_ptr = base ? &memctl->memc_lsdmr : &memctl->memc_psdmr; +	orx_ptr = base ? &memctl->memc_or2 : &memctl->memc_or1; + +	*orx_ptr = orx; +	sdmr = set_sdram_timing (sdmr_ptr, sdmr, col); +	/* +	 * Quote from 8260 UM (10.4.2 SDRAM Power-On Initialization, 10-35): +	 * +	 * "At system reset, initialization software must set up the +	 *  programmable parameters in the memory controller banks registers +	 *  (ORx, BRx, P/LSDMR). After all memory parameters are configured, +	 *  system software should execute the following initialization sequence +	 *  for each SDRAM device. +	 * +	 *  1. Issue a PRECHARGE-ALL-BANKS command +	 *  2. Issue eight CBR REFRESH commands +	 *  3. Issue a MODE-SET command to initialize the mode register +	 * +	 *  The initial commands are executed by setting P/LSDMR[OP] and +	 *  accessing the SDRAM with a single-byte transaction." +	 * +	 * The appropriate BRx/ORx registers have already been set when we +	 * get here. The SDRAM can be accessed at the address CFG_SDRAM_BASE. +	 */ + +	*sdmr_ptr = sdmr | PSDMR_OP_PREA; +	*base = c; + +	*sdmr_ptr = sdmr | PSDMR_OP_CBRR; +	for (i = 0; i < 8; i++) +		*base = c; + +	*sdmr_ptr = sdmr | PSDMR_OP_MRW; +	*(base + CFG_MRS_OFFS) = c;	/* setting MR on address lines */ + +	*sdmr_ptr = sdmr | PSDMR_OP_NORM | PSDMR_RFEN; +	*base = c; + +	size = get_ram_size((long *)base, maxsize); +	*orx_ptr = orx | ~(size - 1); + +	return (size); +} + +long int initdram (int board_type) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile memctl8260_t *memctl = &immap->im_memctl; + +#ifndef CFG_RAMBOOT +	long size8, size9; +#endif +	long psize, lsize; + +	psize = 16 * 1024 * 1024; +	lsize = 0; + +	memctl->memc_psrt = CFG_PSRT; +	memctl->memc_mptpr = CFG_MPTPR; + +#ifndef CFG_RAMBOOT +	/* 60x SDRAM setup: +	 */ +	size8 = try_init (memctl, CFG_PSDMR_8COL, CFG_OR1_8COL, +					  (uchar *) CFG_SDRAM_BASE, 8); +	size9 = try_init (memctl, CFG_PSDMR_9COL, CFG_OR1_9COL, +					  (uchar *) CFG_SDRAM_BASE, 9); + +	if (size8 < size9) { +		psize = size9; +		printf ("(60x:9COL - %ld MB, ", psize >> 20); +	} else { +		psize = try_init (memctl, CFG_PSDMR_8COL, CFG_OR1_8COL, +						  (uchar *) CFG_SDRAM_BASE, 8); +		printf ("(60x:8COL - %ld MB, ", psize >> 20); +	} + +#endif /* CFG_RAMBOOT */ + +	icache_enable (); + +	return (psize); +} + + +static inline int scanChar (char *p, int len, unsigned long *number) +{ +	int	akt = 0; + +	*number = 0; +	while (akt < len) { +		if ((*p >= '0') && (*p <= '9')) { +			*number *= 10; +			*number += *p - '0'; +			p += 1; +		} else { +			if (*p == '-')	return akt; +			return -1; +		} +		akt ++; +	} +	return akt; +} + +typedef struct{ +	int	Bus; +	int	flash; +	int	flash_nr; +	int	ram; +	int	ram_cs; +	int	nand; +	int	nand_cs; +	int	eeprom; +	int	can; +	unsigned long	cpunr; +	unsigned long	option; +	int	SecEng; +	int	cpucl; +	int	cpmcl; +	int	buscl; +	int	busclk_real_ok; +	int	busclk_real; +	unsigned char	OK; +	unsigned char  ethaddr[20]; +} HWIB_INFO; + +HWIB_INFO	hwinf = {0, 0, 1, 0, 1, 0, 0, 0, 0, 8272, 0 ,0, +			 0, 0, 0, 0, 0, 0}; + +static int dump_hwib(void) +{ +	HWIB_INFO	*hw = &hwinf; +	volatile immap_t *immr = (immap_t *)CFG_IMMR; +	char *s = getenv("serial#"); + +	if (hw->OK) { +		printf ("HWIB on %x\n", HWIB_INFO_START_ADDR); +		printf ("serial : %s\n", s); +		printf ("ethaddr: %s\n", hw->ethaddr); +		printf ("FLASH	: %x nr:%d\n", hw->flash, hw->flash_nr); +		printf ("RAM	: %x cs:%d\n", hw->ram, hw->ram_cs); +		printf ("CPU	: %d\n", hw->cpunr); +		printf ("CAN	: %d\n", hw->can); +		if (hw->eeprom) printf ("EEprom : %x\n", hw->eeprom); +		else printf ("No EEprom\n"); +		if (hw->nand) { +			printf ("NAND	: %x\n", hw->nand); +			printf ("NAND CS: %d\n", hw->nand_cs); +		} else { printf ("No NAND\n");} +		printf ("Bus %s mode.\n", (hw->Bus ? "60x" : "Single PQII")); +		printf ("  real : %s\n", (immr->im_siu_conf.sc_bcr & BCR_EBM ? \ +				 "60x" : "Single PQII")); +		printf ("Option : %x\n", hw->option); +		printf ("%s Security Engine\n", (hw->SecEng ? "with" : "no")); +		printf ("CPM Clk: %d\n", hw->cpmcl); +		printf ("CPU Clk: %d\n", hw->cpucl); +		printf ("Bus Clk: %d\n", hw->buscl); +		if (hw->busclk_real_ok) { +			printf ("  real Clk: %d\n", hw->busclk_real); +		} +		printf ("CAS	: %d\n", get_cas_latency()); +	} else { +		printf("HWIB @%x not OK\n", HWIB_INFO_START_ADDR); +	} +	return 0; +} + +static inline int search_real_busclk (int *clk) +{ +	int	part = 0, pos = 0; +	char *p = (char *) CIB_INFO_START_ADDR; +	int	ok = 0; + +	while ((*p != '\0') && (pos < CIB_INFO_LEN)) { +		if (*p < ' ' || *p > '~') { /* ASCII strings! */ +			return 0; +		} +		switch (part) { +		default: +			if (*p == '-') { +				++part; +			} +			break; +		case 3: +			if (*p == '-') { +				++part; +				break; +			} +			if (*p == 'b') { +				ok = 1; +				p++; +				break; +			} +			if (ok) { +				switch (*p) { +				case '6': +					*clk = 66666666; +					return 1; +					break; +				case '1': +					if (p[1] == '3') { +						*clk = 133333333; +					} else { +						*clk = 100000000; +					} +					return 1; +					break; +				} +			} +			break; +		} +		p++; +	} +	return 0; +} + +int analyse_hwib (void) +{ +	char	*p = (char *) HWIB_INFO_START_ADDR; +	int	anz; +	int	part = 1, i = 0, pos = 0; +	HWIB_INFO	*hw = &hwinf; + +	deb_printf(" %s pointer: %p\n", __FUNCTION__, p); +	/* Head = TQM */ +	if (*((unsigned long *)p) != (unsigned long)CFG_HWINFO_MAGIC) { +		deb_printf("No HWIB\n"); +		return -1; +	} +	p += 3; +	if (scanChar (p, 4, &hw->cpunr) < 0) { +		deb_printf("No CPU\n"); +		return -2; +	} +	p +=4; + +	hw->flash = 0x200000 << (*p - 'A'); +	p++; +	hw->flash_nr = *p - '0'; +	p++; + +	hw->ram = 0x2000000 << (*p - 'A'); +	p++; +	if (*p == '2') { +		hw->ram_cs = 2; +		p++; +	} + +	if (*p == 'A') hw->can = 1; +	if (*p == 'B') hw->can = 2; +	p +=1; +	p +=1;	/* connector */ +	if (*p != '0') { +		hw->eeprom = 0x1000 << (*p - 'A'); +	} +	p++; + +	if ((*p < '0') || (*p > '9')) { +		/* NAND before z-option */ +		hw->nand = 0x8000000 << (*p - 'A'); +		p++; +		hw->nand_cs = *p - '0'; +		p += 2; +	} +	/* z-option */ +	anz = scanChar (p, 4, &hw->option); +	if (anz < 0) { +		deb_printf("No option\n"); +		return -3; +	} +	if (hw->option & 0x8) hw->Bus = 1; +	p += anz; +	if (*p != '-') { +		deb_printf("No -\n"); +		return -4; +	} +	p++; +	/* C option */ +	if (*p == 'E') { +		hw->SecEng = 1; +		p++; +	} +	switch (*p) { +		case 'M': hw->cpucl = 266666666; +			break; +		case 'P': hw->cpucl = 300000000; +			break; +		case 'T': hw->cpucl = 400000000; +			break; +		default: +			deb_printf("No CPU Clk: %c\n", *p); +			return -5; +			break; +	} +	p++; +	switch (*p) { +		case 'I': hw->cpmcl = 200000000; +			break; +		case 'M': hw->cpmcl = 300000000; +			break; +		default: +			deb_printf("No CPM Clk\n"); +			return -6; +			break; +	} +	p++; +	switch (*p) { +		case 'B': hw->buscl = 66666666; +			break; +		case 'E': hw->buscl = 100000000; +			break; +		case 'F': hw->buscl = 133333333; +			break; +		default: +			deb_printf("No BUS Clk\n"); +			return -7; +			break; +	} +	p++; + +	hw->OK = 1; +	/* search MAC Address */ +	while ((*p != '\0') && (pos < CFG_HWINFO_SIZE)) { +		if (*p < ' ' || *p > '~') { /* ASCII strings! */ +			return 0; +		} +		switch (part) { +		default: +			if (*p == ' ') { +				++part; +				i = 0; +			} +			break; +		case 3:			/* Copy MAC address */ +			if (*p == ' ') { +				++part; +				i = 0; +				break; +			} +			hw->ethaddr[i++] = *p; +			if ((i % 3) == 2) +				hw->ethaddr[i++] = ':'; +			break; + +		} +		p++; +	} + +	hw->busclk_real_ok = search_real_busclk (&hw->busclk_real); +	return 0; +} + +#if defined(CONFIG_GET_CPU_STR_F) +/* !! This routine runs from Flash */ +char get_cpu_str_f (char *buf) +{ +	char *p = (char *) HWIB_INFO_START_ADDR; +	int	i = 0; + +	buf[i++] = 'M'; +	buf[i++] = 'P'; +	buf[i++] = 'C'; +	if (*((unsigned long *)p) == (unsigned long)CFG_HWINFO_MAGIC) { +		buf[i++] = *&p[3]; +		buf[i++] = *&p[4]; +		buf[i++] = *&p[5]; +		buf[i++] = *&p[6]; +	} else { +		buf[i++] = '8'; +		buf[i++] = '2'; +		buf[i++] = '7'; +		buf[i++] = 'x'; +	} +	buf[i++] = 0; +	return 0; +} +#endif + +#if defined(CONFIG_BOARD_GET_CPU_CLK_F) +/* !! This routine runs from Flash */ +unsigned long board_get_cpu_clk_f (void) +{ +	char *p = (char *) HWIB_INFO_START_ADDR; +	int i = 0; + +	if (*((unsigned long *)p) == (unsigned long)CFG_HWINFO_MAGIC) { +		if (search_real_busclk (&i)) +			return i; +	} +	return CONFIG_8260_CLKIN; +} +#endif + +#if CONFIG_BOARD_EARLY_INIT_R + +static int can_test (unsigned long off) +{ +	volatile unsigned char	*base	= (unsigned char *) (CFG_CAN_BASE + off); + +	*(base + 0x17) = 'T'; +	*(base + 0x18) = 'Q'; +	*(base + 0x19) = 'M'; +	if ((*(base + 0x17) != 'T') || +	    (*(base + 0x18) != 'Q') || +	    (*(base + 0x19) != 'M')) { +		return 0; +	} +	return 1; +} + +static int can_config_one (unsigned long off) +{ +	volatile unsigned char	*ctrl	= (unsigned char *) (CFG_CAN_BASE + off); +	volatile unsigned char	*cpu_if = (unsigned char *) (CFG_CAN_BASE + off + 0x02); +	volatile unsigned char	*clkout = (unsigned char *) (CFG_CAN_BASE + off + 0x1f); +	unsigned char temp; + +	*cpu_if = 0x45; +	temp = *ctrl; +	temp |= 0x40; +	*ctrl	= temp; +	*clkout = 0x20; +	temp = *ctrl; +	temp &= ~0x40; +	*ctrl	= temp; +	return 0; +} + +static int can_config (void) +{ +	int	ret = 0; +	can_config_one (0); +	if (hwinf.can == 2) { +		can_config_one (0x100); +	} +	/* make Test if they really there */ +	ret += can_test (0); +	ret += can_test (0x100); +	return ret; +} + +static int init_can (void) +{ +	volatile immap_t * immr = (immap_t *)CFG_IMMR; +	volatile memctl8260_t *memctl = &immr->im_memctl; +	int	count = 0; + +	if ((hwinf.OK) && (hwinf.can)) { +		memctl->memc_or4 = CFG_CAN_OR; +		memctl->memc_br4 = CFG_CAN_BR; +		/* upm Init */ +		upmconfig (UPMC, (uint *) upmTableFast, +			   sizeof (upmTableFast) / sizeof (uint)); +		memctl->memc_mcmr =	(MxMR_DSx_3_CYCL | +					MxMR_GPL_x4DIS | +					MxMR_RLFx_2X | +					MxMR_WLFx_2X | +					MxMR_OP_NORM); +		/* can configure */ +		count = can_config (); +		printf ("CAN:	%d @ %x\n", count, CFG_CAN_BASE); +		if (hwinf.can != count) printf("!!! difference to HWIB\n"); +	} else { +		printf ("CAN:	No\n"); +	} +	return 0; +} + +int board_early_init_r(void) +{ +	analyse_hwib (); +	init_can (); +	return 0; +} +#endif + +int do_hwib_dump (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ +	dump_hwib (); +	return 0; +} + +U_BOOT_CMD( +	  hwib, 1,	1,	do_hwib_dump, +	  "hwib	   - dump HWIB'\n", +	  "\n" +); + +#ifdef CFG_UPDATE_FLASH_SIZE +static int get_flash_timing (void) +{ +	/* get it from the option -tf in CIB */ +	/* default is 0x00000c84 */ +	int	ret = 0x00000c84; +	int	pos = 0; +	int	nr = 0; +	char	*p = (char *) CIB_INFO_START_ADDR; + +	while ((*p != '\0') && (pos < CIB_INFO_LEN)) { +		if (*p < ' ' || *p > '~') { /* ASCII strings! */ +			return ret; +		} +		if (*p == '-') { +			if ((p[1] == 't') && (p[2] == 'f')) { +				p += 6; +				ret = 0; +				while (nr < 8) { +				if ((*p >= '0') && (*p <= '9')) { +					ret *= 0x10; +					ret += *p - '0'; +					p += 1; +					nr ++; +				} else if ((*p >= 'A') && (*p <= 'F')) { +					ret *= 10; +					ret += *p - '7'; +					p += 1; +					nr ++; +				} else { +					if (nr < 8) return 0x00000c84; +					return ret; +				} +				} +			} +		} +		p++; +		pos++; +	} +	return ret; +} + +/* Update the Flash_Size and the Flash Timing */ +int update_flash_size (int flash_size) +{ +	volatile immap_t * immr = (immap_t *)CFG_IMMR; +	volatile memctl8260_t *memctl = &immr->im_memctl; +	unsigned long reg; +	unsigned long tim; + +	/* I must use reg, otherwise the board hang */ +	reg = memctl->memc_or0; +	reg &= ~ORxU_AM_MSK; +	reg |= MEG_TO_AM(flash_size >> 20); +	tim = get_flash_timing (); +	reg &= ~0xfff; +	reg |= (tim & 0xfff); +	memctl->memc_or0 = reg; +	return 0; +} +#endif + +#if defined(CONFIG_CMD_NAND) + +#include <nand.h> +#include <linux/mtd/mtd.h> + +static u8 hwctl = 0; + +static void upmnand_hwcontrol(struct mtd_info *mtdinfo, int cmd) +{ +	switch (cmd) { +	case NAND_CTL_SETCLE: +		hwctl |= 0x1; +		break; +	case NAND_CTL_CLRCLE: +		hwctl &= ~0x1; +		break; + +	case NAND_CTL_SETALE: +		hwctl |= 0x2; +		break; + +	case NAND_CTL_CLRALE: +		hwctl &= ~0x2; +		break; +	} +} + +static void upmnand_write_byte(struct mtd_info *mtdinfo, u_char byte) +{ +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) (this->IO_ADDR_W + chipsel * CFG_NAND_CS_DIST); + +	if (hwctl & 0x1) { +		WRITE_NAND_UPM(byte, base, CFG_NAND_UPM_WRITE_CMD_OFS); +	} else if (hwctl & 0x2) { +		WRITE_NAND_UPM(byte, base, CFG_NAND_UPM_WRITE_ADDR_OFS); +	} else { +		WRITE_NAND(byte, base); +	} +} + +static u_char upmnand_read_byte(struct mtd_info *mtdinfo) +{ +	struct nand_chip *this = mtdinfo->priv; +	ulong base = (ulong) (this->IO_ADDR_W + chipsel * CFG_NAND_CS_DIST); + +	return READ_NAND(base); +} + +static int tqm8272_dev_ready(struct mtd_info *mtdinfo) +{ +	/* constant delay (see also tR in the datasheet) */ +	udelay(12); \ +	return 1; +} + +#ifndef CONFIG_NAND_SPL +static void tqm8272_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len) +{ +	struct nand_chip *this = mtdinfo->priv; +	unsigned char *base = (unsigned char *) (this->IO_ADDR_W + chipsel * CFG_NAND_CS_DIST); +	int	i; + +	for (i = 0; i< len; i++) +		buf[i] = *base; +} + +static void tqm8272_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) +{ +	struct nand_chip *this = mtdinfo->priv; +	unsigned char *base = (unsigned char *) (this->IO_ADDR_W + chipsel * CFG_NAND_CS_DIST); +	int	i; + +	for (i = 0; i< len; i++) +		*base = buf[i]; +} + +static int tqm8272_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) +{ +	struct nand_chip *this = mtdinfo->priv; +	unsigned char *base = (unsigned char *) (this->IO_ADDR_W + chipsel * CFG_NAND_CS_DIST); +	int	i; + +	for (i = 0; i < len; i++) +		if (buf[i] != *base) +			return -1; +	return 0; +} +#endif /* #ifndef CONFIG_NAND_SPL */ + +void board_nand_select_device(struct nand_chip *nand, int chip) +{ +	chipsel = chip; +} + +int board_nand_init(struct nand_chip *nand) +{ +	static	int	UpmInit = 0; +	volatile immap_t * immr = (immap_t *)CFG_IMMR; +	volatile memctl8260_t *memctl = &immr->im_memctl; + +	if (hwinf.nand == 0) return -1; + +	/* Setup the UPM */ +	if (UpmInit == 0) { +		switch (hwinf.busclk_real) { +		case 100000000: +			upmconfig (UPMB, (uint *) upmTable100, +			   sizeof (upmTable100) / sizeof (uint)); +			break; +		case 133333333: +			upmconfig (UPMB, (uint *) upmTable133, +			   sizeof (upmTable133) / sizeof (uint)); +			break; +		default: +			upmconfig (UPMB, (uint *) upmTable67, +			   sizeof (upmTable67) / sizeof (uint)); +			break; +		} +		UpmInit = 1; +	} + +	/* Setup the memctrl */ +	memctl->memc_or3 = CFG_NAND_OR; +	memctl->memc_br3 = CFG_NAND_BR; +	memctl->memc_mbmr = (MxMR_OP_NORM); + +	nand->eccmode = NAND_ECC_SOFT; + +	nand->hwcontrol	 = upmnand_hwcontrol; +	nand->read_byte	 = upmnand_read_byte; +	nand->write_byte = upmnand_write_byte; +	nand->dev_ready	 = tqm8272_dev_ready; + +#ifndef CONFIG_NAND_SPL +	nand->write_buf	 = tqm8272_write_buf; +	nand->read_buf	 = tqm8272_read_buf; +	nand->verify_buf = tqm8272_verify_buf; +#endif + +	/* +	 * Select required NAND chip +	 */ +	board_nand_select_device(nand, 0); +	return 0; +} + +#endif + +#ifdef CONFIG_PCI +struct pci_controller hose; + +int board_early_init_f (void) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; + +	immap->im_clkrst.car_sccr |= M826X_SCCR_PCI_MODE_EN; +	return 0; +} + +extern void pci_mpc8250_init(struct pci_controller *); + +void pci_init_board(void) +{ +	pci_mpc8250_init(&hose); +} +#endif diff --git a/board/tqc/tqm834x/Makefile b/board/tqc/tqm834x/Makefile new file mode 100644 index 000000000..4c0d20417 --- /dev/null +++ b/board/tqc/tqm834x/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright 2004 Freescale Semiconductor, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(BOARD).a + +COBJS	= $(BOARD).o pci.o + +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) +SOBJS	:= $(addprefix $(obj),$(SOBJS)) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +clean: +	rm -f $(SOBJS) $(OBJS) + +distclean:	clean +	rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/tqc/tqm834x/config.mk b/board/tqc/tqm834x/config.mk new file mode 100644 index 000000000..f172c4ede --- /dev/null +++ b/board/tqc/tqm834x/config.mk @@ -0,0 +1,23 @@ +# +# Copyright 2004 Freescale Semiconductor, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +TEXT_BASE   =   0x80000000 diff --git a/board/tqc/tqm834x/pci.c b/board/tqc/tqm834x/pci.c new file mode 100644 index 000000000..e3d0309d9 --- /dev/null +++ b/board/tqc/tqm834x/pci.c @@ -0,0 +1,220 @@ +/* + * (C) Copyright 2005 + * 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 <asm/mmu.h> +#include <common.h> +#include <pci.h> + +#ifdef CONFIG_PCI + +/* System RAM mapped to PCI space */ +#define CONFIG_PCI_SYS_MEM_BUS	CFG_SDRAM_BASE +#define CONFIG_PCI_SYS_MEM_PHYS	CFG_SDRAM_BASE +#define CONFIG_PCI_SYS_MEM_SIZE	(1024 * 1024 * 1024) + +#ifndef CONFIG_PCI_PNP +static struct pci_config_table pci_tqm834x_config_table[] = { +	{PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, +	 PCI_IDSEL_NUMBER, PCI_ANY_ID, +	 pci_cfgfunc_config_device, {PCI_ENET0_IOADDR, +				     PCI_ENET0_MEMADDR, +				     PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER +		} +	}, +	{} +}; +#endif + +static struct pci_controller pci1_hose = { +#ifndef CONFIG_PCI_PNP +	config_table:pci_tqm834x_config_table, +#endif +}; + + +/************************************************************************** + * pci_init_board() + * + * NOTICE: MPC8349 internally has two PCI controllers (PCI1 and PCI2) but since + * per TQM834x design physical connections to external devices (PCI sockets) + * are routed only to the PCI1 we do not account for the second one - this code + * supports PCI1 module only. Should support for the PCI2 be required in the + * future it needs a separate pci_controller structure (above) and handling - + * please refer to other boards' implementation for dual PCI host controllers, + * for example board/Marvell/db64360/pci.c, pci_init_board() + * + */ +void +pci_init_board(void) +{ +	volatile immap_t *	immr; +	volatile clk83xx_t *	clk; +	volatile law83xx_t *	pci_law; +	volatile pot83xx_t *	pci_pot; +	volatile pcictrl83xx_t *	pci_ctrl; +	volatile pciconf83xx_t *	pci_conf; +	u16 reg16; +	u32 reg32; +	struct	pci_controller * hose; + +	immr = (immap_t *)CFG_IMMR; +	clk = (clk83xx_t *)&immr->clk; +	pci_law = immr->sysconf.pcilaw; +	pci_pot = immr->ios.pot; +	pci_ctrl = immr->pci_ctrl; +	pci_conf = immr->pci_conf; + +	hose = &pci1_hose; + +	/* +	 * Configure PCI controller and PCI_CLK_OUTPUT +	 */ + +	/* +	 * WARNING! only PCI_CLK_OUTPUT1 is enabled here as this is the one +	 * line actually used for clocking all external PCI devices in TQM83xx. +	 * Enabling other PCI_CLK_OUTPUT lines may lead to board's hang for +	 * unknown reasons - particularly PCI_CLK_OUTPUT6 and PCI_CLK_OUTPUT7 +	 * are known to hang the board; this issue is under investigation +	 * (13 oct 05) +	 */ +	reg32 = OCCR_PCICOE1; +#if 0 +	/* enabling all PCI_CLK_OUTPUT lines HANGS the board... */ +	reg32 = 0xff000000; +#endif +	if (clk->spmr & SPMR_CKID) { +		/* PCI Clock is half CONFIG_83XX_CLKIN so need to set up OCCR +		 * fields accordingly */ +		reg32 |= (OCCR_PCI1CR | OCCR_PCI2CR); + +		reg32 |= (OCCR_PCICD0 | OCCR_PCICD1 | OCCR_PCICD2 \ +			  | OCCR_PCICD3 | OCCR_PCICD4 | OCCR_PCICD5 \ +			  | OCCR_PCICD6 | OCCR_PCICD7); +	} + +	clk->occr = reg32; +	udelay(2000); + +	/* +	 * Release PCI RST Output signal +	 */ +	pci_ctrl[0].gcr = 0; +	udelay(2000); +	pci_ctrl[0].gcr = 1; +	udelay(2000); + +	/* +	 * Configure PCI Local Access Windows +	 */ +	pci_law[0].bar = CFG_PCI1_MEM_PHYS & LAWBAR_BAR; +	pci_law[0].ar = LAWAR_EN | LAWAR_SIZE_512M; + +	pci_law[1].bar = CFG_PCI1_IO_PHYS & LAWBAR_BAR; +	pci_law[1].ar = LAWAR_EN | LAWAR_SIZE_16M; + +	/* +	 * Configure PCI Outbound Translation Windows +	 */ + +	/* PCI1 mem space */ +	pci_pot[0].potar = (CFG_PCI1_MEM_BASE >> 12) & POTAR_TA_MASK; +	pci_pot[0].pobar = (CFG_PCI1_MEM_PHYS >> 12) & POBAR_BA_MASK; +	pci_pot[0].pocmr = POCMR_EN | (POCMR_CM_512M & POCMR_CM_MASK); + +	/* PCI1 IO space */ +	pci_pot[1].potar = (CFG_PCI1_IO_BASE >> 12) & POTAR_TA_MASK; +	pci_pot[1].pobar = (CFG_PCI1_IO_PHYS >> 12) & POBAR_BA_MASK; +	pci_pot[1].pocmr = POCMR_EN | POCMR_IO | (POCMR_CM_16M & POCMR_CM_MASK); + +	/* +	 * Configure PCI Inbound Translation Windows +	 */ + +	/* we need RAM mapped to PCI space for the devices to +	 * access main memory */ +	pci_ctrl[0].pitar1 = 0x0; +	pci_ctrl[0].pibar1 = 0x0; +	pci_ctrl[0].piebar1 = 0x0; +	pci_ctrl[0].piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_256M; + +	hose->first_busno = 0; +	hose->last_busno = 0xff; + +	/* PCI memory space */ +	pci_set_region(hose->regions + 0, +		       CFG_PCI1_MEM_BASE, +		       CFG_PCI1_MEM_PHYS, +		       CFG_PCI1_MEM_SIZE, +		       PCI_REGION_MEM); + +	/* PCI IO space */ +	pci_set_region(hose->regions + 1, +		       CFG_PCI1_IO_BASE, +		       CFG_PCI1_IO_PHYS, +		       CFG_PCI1_IO_SIZE, +		       PCI_REGION_IO); + +	/* System memory space */ +	pci_set_region(hose->regions + 2, +		       CONFIG_PCI_SYS_MEM_BUS, +		       CONFIG_PCI_SYS_MEM_PHYS, +		       CONFIG_PCI_SYS_MEM_SIZE, +		       PCI_REGION_MEM | PCI_REGION_MEMORY); + +	hose->region_count = 3; + +	pci_setup_indirect(hose, +			   (CFG_IMMR+0x8300), +			   (CFG_IMMR+0x8304)); + +	pci_register_hose(hose); + +	/* +	 * Write to Command register +	 */ +	reg16 = 0xff; +	pci_hose_read_config_word (hose, PCI_BDF(0,0,0), PCI_COMMAND, +					®16); +	reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; +	pci_hose_write_config_word(hose, PCI_BDF(0,0,0), PCI_COMMAND, +					reg16); + +	/* +	 * Clear non-reserved bits in status register. +	 */ +	pci_hose_write_config_word(hose, PCI_BDF(0,0,0), PCI_STATUS, +					0xffff); +	pci_hose_write_config_byte(hose, PCI_BDF(0,0,0), PCI_LATENCY_TIMER, +					0x80); + +#ifdef CONFIG_PCI_SCAN_SHOW +	printf("PCI:   Bus Dev VenId DevId Class Int\n"); +#endif +	/* +	 * Hose scan. +	 */ +	hose->last_busno = pci_hose_scan(hose); +} +#endif /* CONFIG_PCI */ diff --git a/board/tqc/tqm834x/tqm834x.c b/board/tqc/tqm834x/tqm834x.c new file mode 100644 index 000000000..aea985ccc --- /dev/null +++ b/board/tqc/tqm834x/tqm834x.c @@ -0,0 +1,433 @@ +/* + * (C) Copyright 2005 + * 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> +#include <ioports.h> +#include <mpc83xx.h> +#include <asm/mpc8349_pci.h> +#include <i2c.h> +#include <miiphy.h> +#include <asm-ppc/mmu.h> +#include <pci.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define IOSYNC			asm("eieio") +#define ISYNC			asm("isync") +#define SYNC			asm("sync") +#define FPW			FLASH_PORT_WIDTH +#define FPWV			FLASH_PORT_WIDTHV + +#define DDR_MAX_SIZE_PER_CS	0x20000000 + +#if defined(DDR_CASLAT_20) +#define TIMING_CASLAT		TIMING_CFG1_CASLAT_20 +#define MODE_CASLAT		DDR_MODE_CASLAT_20 +#else +#define TIMING_CASLAT		TIMING_CFG1_CASLAT_25 +#define MODE_CASLAT		DDR_MODE_CASLAT_25 +#endif + +#define INITIAL_CS_CONFIG	(CSCONFIG_EN | CSCONFIG_ROW_BIT_12 | \ +				CSCONFIG_COL_BIT_9) + +/* Global variable used to store detected number of banks */ +int tqm834x_num_flash_banks; + +/* External definitions */ +ulong flash_get_size (ulong base, int banknum); +extern flash_info_t flash_info[]; + +/* Local functions */ +static int detect_num_flash_banks(void); +static long int get_ddr_bank_size(short cs, volatile long *base); +static void set_cs_bounds(short cs, long base, long size); +static void set_cs_config(short cs, long config); +static void set_ddr_config(void); + +/* Local variable */ +static volatile immap_t *im = (immap_t *)CFG_IMMR; + +/************************************************************************** + * Board initialzation after relocation to RAM. Used to detect the number + * of Flash banks on TQM834x. + */ +int board_early_init_r (void) { +	/* sanity check, IMMARBAR should be mirrored at offset zero of IMMR */ +	if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32)im) +		return 0; + +	/* detect the number of Flash banks */ +	return detect_num_flash_banks(); +} + +/************************************************************************** + * DRAM initalization and size detection + */ +long int initdram (int board_type) +{ +	long bank_size; +	long size; +	int cs; + +	/* during size detection, set up the max DDRLAW size */ +	im->sysconf.ddrlaw[0].bar = CFG_DDR_BASE; +	im->sysconf.ddrlaw[0].ar = (LAWAR_EN | LAWAR_SIZE_2G); + +	/* set CS bounds to maximum size */ +	for(cs = 0; cs < 4; ++cs) { +		set_cs_bounds(cs, +			CFG_DDR_BASE + (cs * DDR_MAX_SIZE_PER_CS), +			DDR_MAX_SIZE_PER_CS); + +		set_cs_config(cs, INITIAL_CS_CONFIG); +	} + +	/* configure ddr controller */ +	set_ddr_config(); + +	udelay(200); + +	/* enable DDR controller */ +	im->ddr.sdram_cfg = (SDRAM_CFG_MEM_EN | +		SDRAM_CFG_SREN | +		SDRAM_CFG_SDRAM_TYPE_DDR1); +	SYNC; + +	/* size detection */ +	debug("\n"); +	size = 0; +	for(cs = 0; cs < 4; ++cs) { +		debug("\nDetecting Bank%d\n", cs); + +		bank_size = get_ddr_bank_size(cs, +			(volatile long*)(CFG_DDR_BASE + size)); +		size += bank_size; + +		debug("DDR Bank%d size: %d MiB\n\n", cs, bank_size >> 20); + +		/* exit if less than one bank */ +		if(size < DDR_MAX_SIZE_PER_CS) break; +	} + +	return size; +} + +/************************************************************************** + * checkboard() + */ +int checkboard (void) +{ +	puts("Board: TQM834x\n"); + +#ifdef CONFIG_PCI +	volatile immap_t * immr; +	u32 w, f; + +	immr = (immap_t *)CFG_IMMR; +	if (!(immr->reset.rcwh & HRCWH_PCI_HOST)) { +		printf("PCI:   NOT in host mode..?!\n"); +		return 0; +	} + +	/* get bus width */ +	w = 32; +	if (immr->reset.rcwh & HRCWH_64_BIT_PCI) +		w = 64; + +	/* get clock */ +	f = gd->pci_clk; + +	printf("PCI1:  %d bit, %d MHz\n", w, f / 1000000); +#else +	printf("PCI:   disabled\n"); +#endif +	return 0; +} + + +/************************************************************************** + * + * Local functions + * + *************************************************************************/ + +/************************************************************************** + * Detect the number of flash banks (1 or 2). Store it in + * a global variable tqm834x_num_flash_banks. + * Bank detection code based on the Monitor code. + */ +static int detect_num_flash_banks(void) +{ +	typedef unsigned long FLASH_PORT_WIDTH; +	typedef volatile unsigned long FLASH_PORT_WIDTHV; +	FPWV *bank1_base; +	FPWV *bank2_base; +	FPW bank1_read; +	FPW bank2_read; +	ulong bank1_size; +	ulong bank2_size; +	ulong total_size; + +	tqm834x_num_flash_banks = 2;	/* assume two banks */ + +	/* Get bank 1 and 2 information */ +	bank1_size = flash_get_size(CFG_FLASH_BASE, 0); +	debug("Bank1 size: %lu\n", bank1_size); +	bank2_size = flash_get_size(CFG_FLASH_BASE + bank1_size, 1); +	debug("Bank2 size: %lu\n", bank2_size); +	total_size = bank1_size + bank2_size; + +	if (bank2_size > 0) { +		/* Seems like we've got bank 2, but maybe it's mirrored 1 */ + +		/* Set the base addresses */ +		bank1_base = (FPWV *) (CFG_FLASH_BASE); +		bank2_base = (FPWV *) (CFG_FLASH_BASE + bank1_size); + +		/* Put bank 2 into CFI command mode and read */ +		bank2_base[0x55] = 0x00980098; +		IOSYNC; +		ISYNC; +		bank2_read = bank2_base[0x10]; + +		/* Read from bank 1 (it's in read mode) */ +		bank1_read = bank1_base[0x10]; + +		/* Reset Flash */ +		bank1_base[0] = 0x00F000F0; +		bank2_base[0] = 0x00F000F0; + +		if (bank2_read == bank1_read) { +			/* +			 * Looks like just one bank, but not sure yet. Let's +			 * read from bank 2 in autosoelect mode. +			 */ +			bank2_base[0x0555] = 0x00AA00AA; +			bank2_base[0x02AA] = 0x00550055; +			bank2_base[0x0555] = 0x00900090; +			IOSYNC; +			ISYNC; +			bank2_read = bank2_base[0x10]; + +			/* Read from bank 1 (it's in read mode) */ +			bank1_read = bank1_base[0x10]; + +			/* Reset Flash */ +			bank1_base[0] = 0x00F000F0; +			bank2_base[0] = 0x00F000F0; + +			if (bank2_read == bank1_read) { +				/* +				 * In both CFI command and autoselect modes, +				 * we got the some data reading from Flash. +				 * There is only one mirrored bank. +				 */ +				tqm834x_num_flash_banks = 1; +				total_size = bank1_size; +			} +		} +	} + +	debug("Number of flash banks detected: %d\n", tqm834x_num_flash_banks); + +	/* set OR0 and BR0 */ +	im->lbus.bank[0].or = CFG_OR_TIMING_FLASH | +		(-(total_size) & OR_GPCM_AM); +	im->lbus.bank[0].br = (CFG_FLASH_BASE & BR_BA) | +		(BR_MS_GPCM | BR_PS_32 | BR_V); + +	return (0); +} + +/************************************************************************* + * Detect the size of a ddr bank. Sets CS bounds and CS config accordingly. + */ +static long int get_ddr_bank_size(short cs, volatile long *base) +{ +	/* This array lists all valid DDR SDRAM configurations, with +	 * Bank sizes in bytes. (Refer to Table 9-27 in the MPC8349E RM). +	 * The last entry has to to have size equal 0 and is igonred during +	 * autodection. Bank sizes must be in increasing order of size +	 */ +	struct { +		long row; +		long col; +		long size; +	} conf[] = { +		{CSCONFIG_ROW_BIT_12,	CSCONFIG_COL_BIT_8,	32 << 20}, +		{CSCONFIG_ROW_BIT_12,	CSCONFIG_COL_BIT_9,	64 << 20}, +		{CSCONFIG_ROW_BIT_12,	CSCONFIG_COL_BIT_10,	128 << 20}, +		{CSCONFIG_ROW_BIT_13,	CSCONFIG_COL_BIT_9,	128 << 20}, +		{CSCONFIG_ROW_BIT_13,	CSCONFIG_COL_BIT_10,	256 << 20}, +		{CSCONFIG_ROW_BIT_13,	CSCONFIG_COL_BIT_11,	512 << 20}, +		{CSCONFIG_ROW_BIT_14,	CSCONFIG_COL_BIT_10,	512 << 20}, +		{CSCONFIG_ROW_BIT_14,	CSCONFIG_COL_BIT_11,	1024 << 20}, +		{0,			0,			0} +	}; + +	int i; +	int detected; +	long size; + +	detected = -1; +	for(i = 0; conf[i].size != 0; ++i) { + +		/* set sdram bank configuration */ +		set_cs_config(cs, CSCONFIG_EN | conf[i].col | conf[i].row); + +		debug("Getting RAM size...\n"); +		size = get_ram_size(base, DDR_MAX_SIZE_PER_CS); + +		if((size == conf[i].size) && (i == detected + 1)) +			detected = i; + +		debug("Trying %ld x %ld (%ld MiB) at addr %p, detected: %ld MiB\n", +			conf[i].row, +			conf[i].col, +			conf[i].size >> 20, +			base, +			size >> 20); +	} + +	if(detected == -1){ +		/* disable empty cs */ +		debug("\nNo valid configurations for CS%d, disabling...\n", cs); +		set_cs_config(cs, 0); +		return 0; +	} + +	debug("\nDetected configuration %ld x %ld (%ld MiB) at addr %p\n", +			conf[detected].row, conf[detected].col, conf[detected].size >> 20, base); + +	/* configure cs ro detected params */ +	set_cs_config(cs, CSCONFIG_EN | conf[detected].row | +			conf[detected].col); + +	set_cs_bounds(cs, (long)base, conf[detected].size); + +	return(conf[detected].size); +} + +/************************************************************************** + * Sets DDR bank CS bounds. + */ +static void set_cs_bounds(short cs, long base, long size) +{ +	debug("Setting bounds %08x, %08x for cs %d\n", base, size, cs); +	if(size == 0){ +		im->ddr.csbnds[cs].csbnds = 0x00000000; +	} else { +		im->ddr.csbnds[cs].csbnds = +			((base >> CSBNDS_SA_SHIFT) & CSBNDS_SA) | +			(((base + size - 1) >> CSBNDS_EA_SHIFT) & +				CSBNDS_EA); +	} +	SYNC; +} + +/************************************************************************** + * Sets DDR banks CS configuration. + * config == 0x00000000 disables the CS. + */ +static void set_cs_config(short cs, long config) +{ +	debug("Setting config %08x for cs %d\n", config, cs); +	im->ddr.cs_config[cs] = config; +	SYNC; +} + +/************************************************************************** + * Sets DDR clocks, timings and configuration. + */ +static void set_ddr_config(void) { +	/* clock control */ +	im->ddr.sdram_clk_cntl = DDR_SDRAM_CLK_CNTL_SS_EN | +		DDR_SDRAM_CLK_CNTL_CLK_ADJUST_05; +	SYNC; + +	/* timing configuration */ +	im->ddr.timing_cfg_1 = +		(4 << TIMING_CFG1_PRETOACT_SHIFT) | +		(7 << TIMING_CFG1_ACTTOPRE_SHIFT) | +		(4 << TIMING_CFG1_ACTTORW_SHIFT)  | +		(5 << TIMING_CFG1_REFREC_SHIFT)   | +		(3 << TIMING_CFG1_WRREC_SHIFT)    | +		(3 << TIMING_CFG1_ACTTOACT_SHIFT) | +		(1 << TIMING_CFG1_WRTORD_SHIFT)   | +		(TIMING_CFG1_CASLAT & TIMING_CASLAT); + +	im->ddr.timing_cfg_2 = +		TIMING_CFG2_CPO_DEF | +		(2 << TIMING_CFG2_WR_DATA_DELAY_SHIFT); +	SYNC; + +	/* don't enable DDR controller yet */ +	im->ddr.sdram_cfg = +		SDRAM_CFG_SREN | +		SDRAM_CFG_SDRAM_TYPE_DDR1; +	SYNC; + +	/* Set SDRAM mode */ +	im->ddr.sdram_mode = +		((DDR_MODE_EXT_MODEREG | DDR_MODE_WEAK) << +			SDRAM_MODE_ESD_SHIFT) | +		((DDR_MODE_MODEREG | DDR_MODE_BLEN_4) << +			SDRAM_MODE_SD_SHIFT) | +		((DDR_MODE_CASLAT << SDRAM_MODE_SD_SHIFT) & +			MODE_CASLAT); +	SYNC; + +	/* Set fast SDRAM refresh rate */ +	im->ddr.sdram_interval = +		(DDR_REFINT_166MHZ_7US << SDRAM_INTERVAL_REFINT_SHIFT) | +		(DDR_BSTOPRE << SDRAM_INTERVAL_BSTOPRE_SHIFT); +	SYNC; + +	/* Workaround for DDR6 Erratum +	 * see MPC8349E Device Errata Rev.8, 2/2006 +	 * This workaround influences the MPC internal "input enables" +	 * dependent on CAS latency and MPC revision. According to errata +	 * sheet the internal reserved registers for this workaround are +	 * not available from revision 2.0 and up. +	 */ + +	/* Get REVID from register SPRIDR. Skip workaround if rev >= 2.0 +	 * (0x200) +	 */ +	if ((im->sysconf.spridr & SPRIDR_REVID) < 0x200) { + +		/* There is a internal reserved register at IMMRBAR+0x2F00 +		 * which has to be written with a certain value defined by +		 * errata sheet. +		 */ +		u32 *reserved_p = (u32 *)((u8 *)im + 0x2f00); + +#if defined(DDR_CASLAT_20) +		*reserved_p = 0x201c0000; +#else +		*reserved_p = 0x202c0000; +#endif +	} +} diff --git a/board/tqc/tqm85xx/Makefile b/board/tqc/tqm85xx/Makefile new file mode 100644 index 000000000..8ea07f246 --- /dev/null +++ b/board/tqc/tqm85xx/Makefile @@ -0,0 +1,56 @@ +# +# (C) Copyright 2001-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 +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(BOARD).a + +COBJS-y	+= $(BOARD).o +COBJS-y	+= sdram.o +COBJS-y	+= law.o +COBJS-y	+= tlb.o + +COBJS-$(CONFIG_NAND) += nand.o + +COBJS	:= $(COBJS-y) +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) +SOBJS	:= $(addprefix $(obj),$(SOBJS)) + +$(LIB):	$(obj).depend $(OBJS) $(SOBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +clean: +	rm -f $(OBJS) $(SOBJS) + +distclean:	clean +	rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/tqc/tqm85xx/config.mk b/board/tqc/tqm85xx/config.mk new file mode 100644 index 000000000..52e84ad77 --- /dev/null +++ b/board/tqc/tqm85xx/config.mk @@ -0,0 +1,29 @@ +# Copyright 2004 Freescale Semiconductor. +# Modified by Xianghua Xiao, X.Xiao@motorola.com +# (C) Copyright 2002,Motorola Inc. +# +# 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 +# + +# +# tqm85xx board +# default CCARBAR is at 0xff700000 +# assume U-Boot is less than 256k +# +TEXT_BASE = 0xfffc0000 diff --git a/board/tqc/tqm85xx/law.c b/board/tqc/tqm85xx/law.c new file mode 100644 index 000000000..de3ea00e3 --- /dev/null +++ b/board/tqc/tqm85xx/law.c @@ -0,0 +1,86 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * 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> +#include <asm/fsl_law.h> +#include <asm/mmu.h> + +/* + * LAW(Local Access Window) configuration: + * + * Standard mapping: + * + * 0x0000_0000	   0x7fff_ffff	   DDR			   2G + * 0x8000_0000	   0x9fff_ffff	   PCI1 MEM		   512M + * 0xc000_0000	   0xdfff_ffff	   RapidIO or PCI express  512M + * 0xe000_0000	   0xe000_ffff	   CCSR			   1M + * 0xe200_0000	   0xe2ff_ffff	   PCI1 IO		   16M + * 0xe300_0000	   0xe3ff_ffff	   CAN and NAND Flash	   16M + * 0xef00_0000	   0xefff_ffff     PCI express IO          16M + * 0xfc00_0000	   0xffff_ffff	   FLASH (boot bank)	   128M + * + * Big FLASH mapping: + * + * 0x0000_0000	   0x7fff_ffff	   DDR			   2G + * 0x8000_0000	   0x9fff_ffff	   PCI1 MEM		   512M + * 0xa000_0000	   0xa000_ffff	   CCSR			   1M + * 0xa200_0000	   0xa2ff_ffff	   PCI1 IO		   16M + * 0xa300_0000	   0xa3ff_ffff	   CAN and NAND Flash	   16M + * 0xaf00_0000	   0xafff_ffff     PCI express IO          16M + * 0xb000_0000	   0xbfff_ffff	   RapidIO or PCI express  256M + * 0xc000_0000	   0xffff_ffff	   FLASH (boot bank)	   1G + * + * Notes: + *    CCSRBAR and L2-as-SRAM don't need a configured Local Access Window. + *    If flash is 8M at default position (last 8M), no LAW needed. + */ + +#ifdef CONFIG_TQM_BIGFLASH +#define LAW_3_SIZE LAW_SIZE_1G +#define LAW_5_SIZE LAW_SIZE_256M +#else +#define LAW_3_SIZE LAW_SIZE_128M +#define LAW_5_SIZE LAW_SIZE_512M +#endif + +struct law_entry law_table[] = { +	SET_LAW(CFG_DDR_SDRAM_BASE, LAW_SIZE_512M, LAW_TRGT_IF_DDR), +	SET_LAW(CFG_PCI1_MEM_PHYS, LAW_SIZE_512M, LAW_TRGT_IF_PCI), +	SET_LAW(CFG_LBC_FLASH_BASE, LAW_3_SIZE, LAW_TRGT_IF_LBC), +	SET_LAW(CFG_PCI1_IO_PHYS, LAW_SIZE_16M, LAW_TRGT_IF_PCI), +#ifdef CONFIG_PCIE1 +	SET_LAW(CFG_PCIE1_MEM_BASE, LAW_5_SIZE, LAW_TRGT_IF_PCIE_1), +#else /* !CONFIG_PCIE1 */ +	SET_LAW(CFG_RIO_MEM_BASE, LAW_5_SIZE, LAW_TRGT_IF_RIO), +#endif /* CONFIG_PCIE1 */ +#if defined(CONFIG_CAN_DRIVER) || defined(CONFIG_NAND) +	SET_LAW(CFG_CAN_BASE, LAW_SIZE_16M, LAW_TRGT_IF_LBC), +#endif /* CONFIG_CAN_DRIVER || CONFIG_NAND */ +#ifdef CONFIG_PCIE1 +	SET_LAW(CFG_PCIE1_IO_BASE, LAW_SIZE_16M, LAW_TRGT_IF_PCIE_1), +#endif /* CONFIG_PCIE */ +}; + +int num_law_entries = ARRAY_SIZE (law_table); diff --git a/board/tqc/tqm85xx/nand.c b/board/tqc/tqm85xx/nand.c new file mode 100644 index 000000000..fe3b31f04 --- /dev/null +++ b/board/tqc/tqm85xx/nand.c @@ -0,0 +1,469 @@ +/* + * (C) Copyright 2008 Wolfgang Grandegger <wg@denx.de> + * + * (C) Copyright 2006 + * Thomas Waehner, TQ-System GmbH, thomas.waehner@tqs.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> +#include <asm/processor.h> +#include <asm/immap_85xx.h> +#include <asm/processor.h> +#include <asm/mmu.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/fsl_upm.h> +#include <ioports.h> + +#include <nand.h> + +DECLARE_GLOBAL_DATA_PTR; + +extern uint get_lbc_clock (void); + +/* index of UPM RAM array run pattern for NAND command cycle */ +#define	CFG_NAN_UPM_WRITE_CMD_OFS	0x08 + +/* index of UPM RAM array run pattern for NAND address cycle */ +#define	CFG_NAND_UPM_WRITE_ADDR_OFS	0x10 + +/* Structure for table with supported UPM timings */ +struct upm_freq { +	ulong freq; +	const u32 *upm_patt; +	uchar gpl4_disable; +	uchar ehtr; +	uchar ead; +}; + +/* NAND-FLASH UPM tables for TQM85XX according to TQM8548.pq.timing.101.doc */ + +/* UPM pattern for bus clock = 25 MHz */ +static const u32 upm_patt_25[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff32000, 0x0fa32000, 0x3fb32005, 0xfffffc00, +	/* 0x04 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff2c30, 0x00ff2c30, 0x0fff2c35, 0xfffffc00, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3ec30, 0x00f3ec30, 0x0ff3ec35, 0xfffffc00, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f32c00, 0x00f32c00, 0x0ff32c05, 0xfffffc00, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 33.3 MHz */ +static const u32 upm_patt_33[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff32000, 0x0fa32100, 0x3fb32005, 0xfffffc00, +	/* 0x04 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff2c30, 0x00ff2c30, 0x0fff2c35, 0xfffffc00, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3ec30, 0x00f3ec30, 0x0ff3ec35, 0xfffffc00, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f32c00, 0x00f32c00, 0x0ff32c05, 0xfffffc00, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 41.7 MHz */ +static const u32 upm_patt_42[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff32000, 0x0fa32100, 0x3fb32005, 0xfffffc00, +	/* 0x04 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff2c30, 0x00ff2c30, 0x0fff2c35, 0xfffffc00, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3ec30, 0x00f3ec30, 0x0ff3ec35, 0xfffffc00, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f32c00, 0x00f32c00, 0x0ff32c05, 0xfffffc00, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 50 MHz */ +static const u32 upm_patt_50[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff33000, 0x0fa33100, 0x0fa33005, 0xfffffc00, +	/* 0x04 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff3d30, 0x00ff3c30, 0x0fff3c35, 0xfffffc00, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3fd30, 0x00f3fc30, 0x0ff3fc35, 0xfffffc00, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f33d00, 0x00f33c00, 0x0ff33c05, 0xfffffc00, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 66.7 MHz */ +static const u32 upm_patt_67[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff33000, 0x0fe33000, 0x0fa33100, 0x0fa33000, +	/* 0x04 */ 0x0fa33005, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff3d30, 0x00ff3c30, 0x0fff3c30, 0x0fff3c35, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3fd30, 0x00f3fc30, 0x0ff3fc30, 0x0ff3fc35, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f33d00, 0x00f33c00, 0x0ff33c00, 0x0ff33c05, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 83.3 MHz */ +static const u32 upm_patt_83[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff33000, 0x0fe33000, 0x0fa33100, 0x0fa33000, +	/* 0x04 */ 0x0fa33005, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff3e30, 0x00ff3c30, 0x0fff3c30, 0x0fff3c35, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3fe30, 0x00f3fc30, 0x0ff3fc30, 0x0ff3fc35, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f33e00, 0x00f33c00, 0x0ff33c00, 0x0ff33c05, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 100 MHz */ +static const u32 upm_patt_100[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff33100, 0x0fe33000, 0x0fa33200, 0x0fa33000, +	/* 0x04 */ 0x0fa33005, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff3f30, 0x00ff3c30, 0x0fff3c30, 0x0fff3c35, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3ff30, 0x00f3fc30, 0x0ff3fc30, 0x0ff3fc35, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f33f00, 0x00f33c00, 0x0ff33c00, 0x0ff33c05, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 133.3 MHz */ +static const u32 upm_patt_133[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff33100, 0x0fe33000, 0x0fa33300, 0x0fa33000, +	/* 0x04 */ 0x0fa33000, 0x0fa33005, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff3f30, 0x00ff3d30, 0x0fff3d30, 0x0fff3c35, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3ff30, 0x00f3fd30, 0x0ff3fd30, 0x0ff3fc35, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f33f00, 0x00f33d00, 0x0ff33d00, 0x0ff33c05, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* UPM pattern for bus clock = 166.7 MHz */ +static const u32 upm_patt_167[] = { +	/* Offset *//* UPM Read Single RAM array entry -> NAND Read Data */ +	/* 0x00 */ 0x0ff33200, 0x0fe33000, 0x0fa33300, 0x0fa33300, +	/* 0x04 */ 0x0fa33005, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write CMD */ +	/* 0x08 */ 0x00ff3f30, 0x00ff3f30, 0x0fff3e30, 0xffff3c35, +	/* 0x0C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Read Burst RAM array entry -> NAND Write ADDR */ +	/* 0x10 */ 0x00f3ff30, 0x00f3ff30, 0x0ff3fe30, 0x0ff3fc35, +	/* 0x14 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Single RAM array entry -> NAND Write Data */ +	/* 0x18 */ 0x00f33f00, 0x00f33f00, 0x0ff33e00, 0x0ff33c05, +	/* 0x1C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, + +	/* UPM Write Burst RAM array entry -> unused */ +	/* 0x20 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x24 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x28 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x2C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Refresh Timer RAM array entry -> unused */ +	/* 0x30 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x34 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc00, +	/* 0x38 */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, + +	/* UPM Exception RAM array entry -> unsused */ +	/* 0x3C */ 0xfffffc00, 0xfffffc00, 0xfffffc00, 0xfffffc01, +}; + +/* Supported UPM timings */ +struct upm_freq upm_freq_table[] = { +	/* nominal freq. | ptr to table | GPL4 dis. | EHTR  | EAD */ +	{25000000, upm_patt_25, 1, 0, 0}, +	{33333333, upm_patt_33, 1, 0, 0}, +	{41666666, upm_patt_42, 1, 0, 0}, +	{50000000, upm_patt_50, 0, 0, 0}, +	{66666666, upm_patt_67, 0, 0, 0}, +	{83333333, upm_patt_83, 0, 0, 0}, +	{100000000, upm_patt_100, 0, 1, 1}, +	{133333333, upm_patt_133, 0, 1, 1}, +	{166666666, upm_patt_167, 0, 1, 1}, +}; + +#define UPM_FREQS (sizeof(upm_freq_table) / sizeof(struct upm_freq)) + +volatile const u32 *nand_upm_patt; + +/* + * write into UPMB ram + */ +static void upmb_write (u_char addr, ulong val) +{ +	volatile ccsr_lbc_t *lbc = (void *)(CFG_MPC85xx_LBC_ADDR); + +	out_be32 (&lbc->mdr, val); + +	clrsetbits_be32(&lbc->mbmr, MxMR_MAD_MSK, +			MxMR_OP_WARR | (addr & MxMR_MAD_MSK)); + +	/* dummy access to perform write */ +	out_8 ((void __iomem *)CFG_NAND0_BASE, 0); + +	clrbits_be32(&lbc->mbmr, MxMR_OP_WARR); +} + +/* + * Initialize UPM for NAND flash access. + */ +static void nand_upm_setup (volatile ccsr_lbc_t *lbc) +{ +	uint i; +	uint or3 = CFG_OR3_PRELIM; +	uint clock = get_lbc_clock (); + +	out_be32 (&lbc->br3, 0);	/* disable bank and reset all bits */ +	out_be32 (&lbc->br3, CFG_BR3_PRELIM); + +	/* +	 * Search appropriate UPM table for bus clock. +	 * If the bus clock exceeds a tolerated value, take the UPM timing for +	 * the next higher supported frequency to ensure that access works +	 * (even the access may be slower then). +	 */ +	for (i = 0; (i < UPM_FREQS) && (clock > upm_freq_table[i].freq); i++) +		; + +	if (i >= UPM_FREQS) +	/* no valid entry found */ +		/* take last entry with configuration for max. bus clock */ +		i--; + +	if (upm_freq_table[i].ehtr) { +		/* EHTR must be set due to TQM8548 timing specification */ +		or3 |= OR_UPM_EHTR; +	} +	if (upm_freq_table[i].ead) +		/* EAD must be set due to TQM8548 timing specification */ +		or3 |= OR_UPM_EAD; + +	out_be32 (&lbc->or3, or3); + +	/* Assign address of table */ +	nand_upm_patt = upm_freq_table[i].upm_patt; + +	for (i = 0; i < 64; i++) { +		upmb_write (i, *nand_upm_patt); +		nand_upm_patt++; +	} + +	/* Put UPM back to normal operation mode */ +	if (upm_freq_table[i].gpl4_disable) +		/* GPL4 must be disabled according to timing specification */ +		out_be32 (&lbc->mbmr, MxMR_OP_NORM | MxMR_GPL_x4DIS); + +	return; +} + +static struct fsl_upm_nand fun = { +	.width = 8, +	.upm_cmd_offset = 0x08, +	.upm_addr_offset = 0x10, +	.chip_delay = NAND_BIG_DELAY_US, +}; + +void board_nand_select_device (struct nand_chip *nand, int chip) +{ +} + +int board_nand_init (struct nand_chip *nand) +{ +	volatile ccsr_lbc_t *lbc = (void *)(CFG_MPC85xx_LBC_ADDR); + +	if (!nand_upm_patt) +		nand_upm_setup (lbc); + +	fun.upm.io_addr = nand->IO_ADDR_R; +	fun.upm.mxmr = (void __iomem *)&lbc->mbmr; +	fun.upm.mdr = (void __iomem *)&lbc->mdr; +	fun.upm.mar = (void __iomem *)&lbc->mar; + +	return fsl_upm_nand_init (nand, &fun); +} diff --git a/board/tqc/tqm85xx/sdram.c b/board/tqc/tqm85xx/sdram.c new file mode 100644 index 000000000..442ff667c --- /dev/null +++ b/board/tqc/tqm85xx/sdram.c @@ -0,0 +1,371 @@ +/* + * (C) Copyright 2005 + * Stefan Roese, DENX Software Engineering, sr@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> +#include <asm/processor.h> +#include <asm/immap_85xx.h> +#include <asm/processor.h> +#include <asm/mmu.h> + +struct sdram_conf_s { +	unsigned long size; +	unsigned long reg; +#ifdef CONFIG_TQM8548 +	unsigned long refresh; +#endif /* CONFIG_TQM8548 */ +}; + +typedef struct sdram_conf_s sdram_conf_t; + +#ifdef CONFIG_TQM8548 +sdram_conf_t ddr_cs_conf[] = { +	{(512 << 20), 0x80044102, 0x0001A000},	/* 512MB, 13x10(4)	*/ +	{(256 << 20), 0x80040102, 0x00014000},	/* 256MB, 13x10(4)	*/ +	{(128 << 20), 0x80040101, 0x0000C000},	/* 128MB, 13x9(4)	*/ +}; +#else /* !CONFIG_TQM8548 */ +sdram_conf_t ddr_cs_conf[] = { +	{(512 << 20), 0x80000202},	/* 512MB, 14x10(4)	*/ +	{(256 << 20), 0x80000102},	/* 256MB, 13x10(4)	*/ +	{(128 << 20), 0x80000101},	/* 128MB, 13x9(4)	*/ +	{( 64 << 20), 0x80000001},	/*  64MB, 12x9(4)	*/ +}; +#endif /* CONFIG_TQM8548 */ + +#define	N_DDR_CS_CONF (sizeof(ddr_cs_conf) / sizeof(ddr_cs_conf[0])) + +int cas_latency (void); + +/* + * Autodetect onboard DDR SDRAM on 85xx platforms + * + * NOTE: Some of the hardcoded values are hardware dependant, + *       so this should be extended for other future boards + *       using this routine! + */ +long int sdram_setup (int casl) +{ +	int i; +	volatile ccsr_ddr_t *ddr = (void *)(CFG_MPC85xx_DDR_ADDR); +#ifdef CONFIG_TQM8548 +	volatile ccsr_gur_t *gur = (void *)(CFG_MPC85xx_GUTS_ADDR); +#else /* !CONFIG_TQM8548 */ +	unsigned long cfg_ddr_timing1; +	unsigned long cfg_ddr_mode; +#endif /* CONFIG_TQM8548 */ + +	/* +	 * Disable memory controller. +	 */ +	ddr->cs0_config = 0; +	ddr->sdram_cfg = 0; + +#ifdef CONFIG_TQM8548 +	ddr->cs0_bnds = (ddr_cs_conf[0].size - 1) >> 24; +	ddr->cs0_config = ddr_cs_conf[0].reg; +	ddr->timing_cfg_3 = 0x00010000; + +	/* TIMING CFG 1, 533MHz +	 * PRETOACT: 4 Clocks +	 * ACTTOPRE: 12 Clocks +	 * ACTTORW:  4 Clocks +	 * CASLAT:   4 Clocks +	 * REFREC:   34 Clocks +	 * WRREC:    4 Clocks +	 * ACTTOACT: 3 Clocks +	 * WRTORD:   2 Clocks +	 */ +	ddr->timing_cfg_1 = 0x4C47A432; + +	/* TIMING CFG 2, 533MHz +	 * ADD_LAT:       3 Clocks +	 * CPO:           READLAT + 1 +	 * WR_LAT:        3 Clocks +	 * RD_TO_PRE:     2 Clocks +	 * WR_DATA_DELAY: 1/2 Clock +	 * CKE_PLS:       1 Clock +	 * FOUR_ACT:      13 Clocks +	 */ +	ddr->timing_cfg_2 = 0x3318484D; + +	/* DDR SDRAM Mode, 533MHz +	 * MRS:          Extended Mode Register +	 * OUT:          Outputs enabled +	 * RDQS:         no +	 * DQS:          enabled +	 * OCD:          default state +	 * RTT:          75 Ohms +	 * Posted CAS:   3 Clocks +	 * ODS:          reduced strength +	 * DLL:          enabled +	 * MR:           Mode Register +	 * PD:           fast exit +	 * WR:           4 Clocks +	 * DLL:          no DLL reset +	 * TM:           normal +	 * CAS latency:  4 Clocks +	 * BT:           sequential +	 * Burst length: 4 +	 */ +	ddr->sdram_mode = 0x439E0642; + +	/* DDR SDRAM Interval, 533MHz +	 * REFINT:  1040 Clocks +	 * BSTOPRE: 256 +	 */ +	ddr->sdram_interval = (1040 << 16) | 0x100; + +	/* +	 * workaround for erratum DD10 of MPC8458 family below rev. 2.0: +	 * DDR IO receiver must be set to an acceptable bias point by modifying +	 * a hidden register. +	 */ +	if (SVR_REV (get_svr ()) < 0x20) { +		gur->ddrioovcr = 0x90000000;	/* enable, VSEL 1.8V */ +	} + +	/* DDR SDRAM CFG 2 +	 * FRC_SR:      normal mode +	 * SR_IE:       no self-refresh interrupt +	 * DLL_RST_DIS: don't care, leave at reset value +	 * DQS_CFG:     differential DQS signals +	 * ODT_CFG:     assert ODT to internal IOs only during reads to DRAM +	 * LVWx_CFG:    don't care, leave at reset value +	 * NUM_PR:      1 refresh will be issued at a time +	 * DM_CFG:      don't care, leave at reset value +	 * D_INIT:      no data initialization +	 */ +	ddr->sdram_cfg_2 = 0x04401000; + +	/* DDR SDRAM MODE 2 +	 * MRS: Extended Mode Register 2 +	 */ +	ddr->sdram_mode_2 = 0x8000C000; + +	/* DDR SDRAM CLK CNTL +	 * CLK_ADJUST: 1/2 Clock 0x02000000 +	 * CLK_ADJUST: 5/8 Clock 0x02800000 +	 */ +	ddr->sdram_clk_cntl = 0x02800000; + +	/* wait for clock stabilization */ +	asm ("sync;isync;msync"); +	udelay(1000); + +	/* DDR SDRAM CLK CNTL +	 * MEM_EN:       enabled +	 * SREN:         don't care, leave at reset value +	 * ECC_EN:       no error report +	 * RD_EN:        no register DIMMs +	 * SDRAM_TYPE:   DDR2 +	 * DYN_PWR:      no power management +	 * 32_BE:        don't care, leave at reset value +	 * 8_BE:         4 beat burst +	 * NCAP:         don't care, leave at reset value +	 * 2T_EN:        1T Timing +	 * BA_INTLV_CTL: no interleaving +	 * x32_EN:       x16 organization +	 * PCHB8:        MA[10] for auto-precharge +	 * HSE:          half strength for single and 2-layer stacks +	 * (full strength for 3- and 4-layer stacks no yet considered) +	 * MEM_HALT:     no halt +	 * BI:           automatic initialization +	 */ +	ddr->sdram_cfg = 0x83000008; +	asm ("sync; isync; msync"); +	udelay(1000); + +#else /* !CONFIG_TQM8548 */ +	switch (casl) { +	case 20: +		cfg_ddr_timing1 = 0x47405331 | (3 << 16); +		cfg_ddr_mode = 0x40020002 | (2 << 4); +		break; + +	case 25: +		cfg_ddr_timing1 = 0x47405331 | (4 << 16); +		cfg_ddr_mode = 0x40020002 | (6 << 4); +		break; + +	case 30: +	default: +		cfg_ddr_timing1 = 0x47405331 | (5 << 16); +		cfg_ddr_mode = 0x40020002 | (3 << 4); +		break; +	} + +	ddr->cs0_bnds = (ddr_cs_conf[0].size - 1) >> 24; +	ddr->cs0_config = ddr_cs_conf[0].reg; +	ddr->timing_cfg_1 = cfg_ddr_timing1; +	ddr->timing_cfg_2 = 0x00000800;		/* P9-45,may need tuning */ +	ddr->sdram_mode = cfg_ddr_mode; +	ddr->sdram_interval = 0x05160100;	/* autocharge,no open page */ +	ddr->err_disable = 0x0000000D; + +	asm ("sync; isync; msync"); +	udelay (1000); + +	ddr->sdram_cfg = 0xc2000000;		/* unbuffered,no DYN_PWR */ +	asm ("sync; isync; msync"); +	udelay (1000); +#endif /* CONFIG_TQM8548 */ + +	for (i = 0; i < N_DDR_CS_CONF; i++) { +		ddr->cs0_config = ddr_cs_conf[i].reg; + +		if (get_ram_size (0, ddr_cs_conf[i].size) == +		    ddr_cs_conf[i].size) { +			/* +			 * size detected -> set Chip Select Bounds Register +			 */ +			ddr->cs0_bnds = (ddr_cs_conf[i].size - 1) >> 24; + +			break; +		} +	} + +#ifdef CONFIG_TQM8548 +	if (i < N_DDR_CS_CONF) { +		/* Adjust refresh rate for DDR2 */ + +		ddr->timing_cfg_3 = ddr_cs_conf[i].refresh & 0x00070000; + +		ddr->timing_cfg_1 = (ddr->timing_cfg_1 & 0xFFFF0FFF) | +		    (ddr_cs_conf[i].refresh & 0x0000F000); + +		return ddr_cs_conf[i].size; +	} +#endif /* CONFIG_TQM8548 */ + +	/* return size if detected, else return 0 */ +	return (i < N_DDR_CS_CONF) ? ddr_cs_conf[i].size : 0; +} + +void board_add_ram_info (int use_default) +{ +	int casl; + +	if (use_default) +		casl = CONFIG_DDR_DEFAULT_CL; +	else +		casl = cas_latency (); + +	puts (" (CL="); +	switch (casl) { +	case 20: +		puts ("2)"); +		break; + +	case 25: +		puts ("2.5)"); +		break; + +	case 30: +		puts ("3)"); +		break; +	} +} + +long int initdram (int board_type) +{ +	long dram_size = 0; +	int casl; + +#if defined(CONFIG_DDR_DLL) +	/* +	 * This DLL-Override only used on TQM8540 and TQM8560 +	 */ +	{ +		volatile ccsr_gur_t *gur = (void *)(CFG_MPC85xx_GUTS_ADDR); +		int i, x; + +		x = 10; + +		/* +		 * Work around to stabilize DDR DLL +		 */ +		gur->ddrdllcr = 0x81000000; +		asm ("sync; isync; msync"); +		udelay (200); +		while (gur->ddrdllcr != 0x81000100) { +			gur->devdisr = gur->devdisr | 0x00010000; +			asm ("sync; isync; msync"); +			for (i = 0; i < x; i++) +				; +			gur->devdisr = gur->devdisr & 0xfff7ffff; +			asm ("sync; isync; msync"); +			x++; +		} +	} +#endif + +	casl = cas_latency (); +	dram_size = sdram_setup (casl); +	if ((dram_size == 0) && (casl != CONFIG_DDR_DEFAULT_CL)) { +		/* +		 * Try again with default CAS latency +		 */ +		puts ("Problem with CAS lantency"); +		board_add_ram_info (1); +		puts (", using default CL!\n"); +		casl = CONFIG_DDR_DEFAULT_CL; +		dram_size = sdram_setup (casl); +		puts ("       "); +	} + +	return dram_size; +} + +#if defined(CFG_DRAM_TEST) +int testdram (void) +{ +	uint *pstart = (uint *) CFG_MEMTEST_START; +	uint *pend = (uint *) CFG_MEMTEST_END; +	uint *p; + +	printf ("SDRAM test phase 1:\n"); +	for (p = pstart; p < pend; p++) +		*p = 0xaaaaaaaa; + +	for (p = pstart; p < pend; p++) { +		if (*p != 0xaaaaaaaa) { +			printf ("SDRAM test fails at: %08x\n", (uint) p); +			return 1; +		} +	} + +	printf ("SDRAM test phase 2:\n"); +	for (p = pstart; p < pend; p++) +		*p = 0x55555555; + +	for (p = pstart; p < pend; p++) { +		if (*p != 0x55555555) { +			printf ("SDRAM test fails at: %08x\n", (uint) p); +			return 1; +		} +	} + +	printf ("SDRAM test passed.\n"); +	return 0; +} +#endif diff --git a/board/tqc/tqm85xx/tlb.c b/board/tqc/tqm85xx/tlb.c new file mode 100644 index 000000000..380448a4f --- /dev/null +++ b/board/tqc/tqm85xx/tlb.c @@ -0,0 +1,248 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * (C) Copyright 2000 + * 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> +#include <asm/mmu.h> + +struct fsl_e_tlb_entry tlb_table[] = { +	/* TLB 0 - for temp stack in cache */ +	SET_TLB_ENTRY (0, CFG_INIT_RAM_ADDR, CFG_INIT_RAM_ADDR, +		       MAS3_SX | MAS3_SW | MAS3_SR, 0, +		       0, 0, BOOKE_PAGESZ_4K, 0), +	SET_TLB_ENTRY (0, CFG_INIT_RAM_ADDR + 4 * 1024, +		       CFG_INIT_RAM_ADDR + 4 * 1024, +		       MAS3_SX | MAS3_SW | MAS3_SR, 0, +		       0, 0, BOOKE_PAGESZ_4K, 0), +	SET_TLB_ENTRY (0, CFG_INIT_RAM_ADDR + 8 * 1024, +		       CFG_INIT_RAM_ADDR + 8 * 1024, +		       MAS3_SX | MAS3_SW | MAS3_SR, 0, +		       0, 0, BOOKE_PAGESZ_4K, 0), +	SET_TLB_ENTRY (0, CFG_INIT_RAM_ADDR + 12 * 1024, +		       CFG_INIT_RAM_ADDR + 12 * 1024, +		       MAS3_SX | MAS3_SW | MAS3_SR, 0, +		       0, 0, BOOKE_PAGESZ_4K, 0), + +#ifndef CONFIG_TQM_BIGFLASH +	/* +	 * TLB 0, 1:	128M	Non-cacheable, guarded +	 * 0xf8000000	128M	FLASH +	 * Out of reset this entry is only 4K. +	 */ +	SET_TLB_ENTRY (1, CFG_FLASH_BASE, CFG_FLASH_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 1, BOOKE_PAGESZ_64M, 1), +	SET_TLB_ENTRY (1, CFG_FLASH_BASE + 0x4000000, +		       CFG_FLASH_BASE + 0x4000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 0, BOOKE_PAGESZ_64M, 1), + +	/* +	 * TLB 2:	256M	Non-cacheable, guarded +	 * 0x80000000	256M	PCI1 MEM First half +	 */ +	SET_TLB_ENTRY (1, CFG_PCI1_MEM_PHYS, CFG_PCI1_MEM_PHYS, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 2, BOOKE_PAGESZ_256M, 1), + +	/* +	 * TLB 3:	256M	Non-cacheable, guarded +	 * 0x90000000	256M	PCI1 MEM Second half +	 */ +	SET_TLB_ENTRY (1, CFG_PCI1_MEM_PHYS + 0x10000000, +		       CFG_PCI1_MEM_PHYS + 0x10000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 3, BOOKE_PAGESZ_256M, 1), + +#ifdef CONFIG_PCIE1 +	/* +	 * TLB 4:	256M	Non-cacheable, guarded +	 * 0xc0000000	256M	PCI express MEM First half +	 */ +	SET_TLB_ENTRY (1, CFG_PCIE1_MEM_BASE, CFG_PCIE1_MEM_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 4, BOOKE_PAGESZ_256M, 1), + +	/* +	 * TLB 5:	256M	Non-cacheable, guarded +	 * 0xd0000000	256M	PCI express MEM Second half +	 */ +	SET_TLB_ENTRY (1, CFG_PCIE1_MEM_BASE + 0x10000000, +		       CFG_PCIE1_MEM_BASE + 0x10000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 5, BOOKE_PAGESZ_256M, 1), +#else /* !CONFIG_PCIE */ +	/* +	 * TLB 4:	256M	Non-cacheable, guarded +	 * 0xc0000000	256M	Rapid IO MEM First half +	 */ +	SET_TLB_ENTRY (1, CFG_RIO_MEM_BASE, CFG_RIO_MEM_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 4, BOOKE_PAGESZ_256M, 1), + +	/* +	 * TLB 5:	256M	Non-cacheable, guarded +	 * 0xd0000000	256M	Rapid IO MEM Second half +	 */ +	SET_TLB_ENTRY (1, CFG_RIO_MEM_BASE + 0x10000000, +		       CFG_RIO_MEM_BASE + 0x10000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 5, BOOKE_PAGESZ_256M, 1), +#endif /* CONFIG_PCIE */ + +	/* +	 * TLB 6:	 64M	Non-cacheable, guarded +	 * 0xe0000000	  1M	CCSRBAR +	 * 0xe2000000	 16M	PCI1 IO +	 * 0xe3000000	 16M	CAN and NAND Flash +	 */ +	SET_TLB_ENTRY (1, CFG_CCSRBAR, CFG_CCSRBAR_PHYS, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 6, BOOKE_PAGESZ_64M, 1), + +	/* +	 * TLB 7+8:	512M	 DDR, cache disabled (needed for memory test) +	 * 0x00000000	512M	 DDR System memory +	 * Without SPD EEPROM configured DDR, this must be setup manually. +	 * Make sure the TLB count at the top of this table is correct. +	 * Likely it needs to be increased by two for these entries. +	 */ +	SET_TLB_ENTRY (1, CFG_DDR_SDRAM_BASE, CFG_DDR_SDRAM_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 7, BOOKE_PAGESZ_256M, 1), + +	SET_TLB_ENTRY (1, CFG_DDR_SDRAM_BASE + 0x10000000, +		       CFG_DDR_SDRAM_BASE + 0x10000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 8, BOOKE_PAGESZ_256M, 1), + +#ifdef CONFIG_PCIE1 +	/* +	 * TLB 9:	 16M	Non-cacheable, guarded +	 * 0xef000000	 16M	PCI express IO +	 */ +	SET_TLB_ENTRY (1, CFG_PCIE1_IO_BASE, CFG_PCIE1_IO_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 9, BOOKE_PAGESZ_16M, 1), +#endif /* CONFIG_PCIE */ + +#else /* CONFIG_TQM_BIGFLASH */ + +	/* +	 * TLB 0,1,2,3:	  1G	Non-cacheable, guarded +	 * 0xc0000000	  1G	FLASH +	 * Out of reset this entry is only 4K. +	 */ +	SET_TLB_ENTRY (1, CFG_FLASH_BASE, CFG_FLASH_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 3, BOOKE_PAGESZ_256M, 1), +	SET_TLB_ENTRY (1, CFG_FLASH_BASE + 0x10000000, +		       CFG_FLASH_BASE + 0x10000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 2, BOOKE_PAGESZ_256M, 1), +	SET_TLB_ENTRY (1, CFG_FLASH_BASE + 0x20000000, +		       CFG_FLASH_BASE + 0x20000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 1, BOOKE_PAGESZ_256M, 1), +	SET_TLB_ENTRY (1, CFG_FLASH_BASE + 0x30000000, +		       CFG_FLASH_BASE + 0x30000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 0, BOOKE_PAGESZ_256M, 1), + +	/* +	 * TLB 4:	256M	Non-cacheable, guarded +	 * 0x80000000	256M	PCI1 MEM First half +	 */ +	SET_TLB_ENTRY (1, CFG_PCI1_MEM_PHYS, CFG_PCI1_MEM_PHYS, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 4, BOOKE_PAGESZ_256M, 1), + +	/* +	 * TLB 5:	256M	Non-cacheable, guarded +	 * 0x90000000	256M	PCI1 MEM Second half +	 */ +	SET_TLB_ENTRY (1, CFG_PCI1_MEM_PHYS + 0x10000000, +		       CFG_PCI1_MEM_PHYS + 0x10000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 5, BOOKE_PAGESZ_256M, 1), + +#ifdef CONFIG_PCIE1 +	/* +	 * TLB 6:	256M	Non-cacheable, guarded +	 * 0xc0000000	256M	PCI express MEM First half +	 */ +	SET_TLB_ENTRY (1, CFG_PCIE1_MEM_BASE, CFG_PCIE1_MEM_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 6, BOOKE_PAGESZ_256M, 1), +#else /* !CONFIG_PCIE */ +	/* +	 * TLB 6:	256M	Non-cacheable, guarded +	 * 0xb0000000	256M	Rapid IO MEM First half +	 */ +	SET_TLB_ENTRY (1, CFG_RIO_MEM_BASE, CFG_RIO_MEM_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 6, BOOKE_PAGESZ_256M, 1), + +#endif /* CONFIG_PCIE */ + +	/* +	 * TLB 7:	 64M	Non-cacheable, guarded +	 * 0xa0000000	  1M	CCSRBAR +	 * 0xa2000000	 16M	PCI1 IO +	 * 0xa3000000	 16M	CAN and NAND Flash +	 */ +	SET_TLB_ENTRY (1, CFG_CCSRBAR, CFG_CCSRBAR_PHYS, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 7, BOOKE_PAGESZ_64M, 1), + +	/* +	 * TLB 8+9:	512M	 DDR, cache disabled (needed for memory test) +	 * 0x00000000	512M	 DDR System memory +	 * Without SPD EEPROM configured DDR, this must be setup manually. +	 * Make sure the TLB count at the top of this table is correct. +	 * Likely it needs to be increased by two for these entries. +	 */ +	SET_TLB_ENTRY (1, CFG_DDR_SDRAM_BASE, CFG_DDR_SDRAM_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 8, BOOKE_PAGESZ_256M, 1), + +	SET_TLB_ENTRY (1, CFG_DDR_SDRAM_BASE + 0x10000000, +		       CFG_DDR_SDRAM_BASE + 0x10000000, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 9, BOOKE_PAGESZ_256M, 1), + +#ifdef CONFIG_PCIE1 +	/* +	 * TLB 10:	 16M	Non-cacheable, guarded +	 * 0xaf000000	 16M	PCI express IO +	 */ +	SET_TLB_ENTRY (1, CFG_PCIE1_IO_BASE, CFG_PCIE1_IO_BASE, +		       MAS3_SX | MAS3_SW | MAS3_SR, MAS2_I | MAS2_G, +		       0, 10, BOOKE_PAGESZ_16M, 1), +#endif /* CONFIG_PCIE */ + +#endif /* CONFIG_TQM_BIGFLASH */ +}; + +int num_tlb_entries = ARRAY_SIZE (tlb_table); diff --git a/board/tqc/tqm85xx/tqm85xx.c b/board/tqc/tqm85xx/tqm85xx.c new file mode 100644 index 000000000..f1c2e58ed --- /dev/null +++ b/board/tqc/tqm85xx/tqm85xx.c @@ -0,0 +1,744 @@ +/* + * (C) Copyright 2008 Wolfgang Grandegger <wg@denx.de> + * + * (C) Copyright 2006 + * Thomas Waehner, TQ-Systems GmbH, thomas.waehner@tqs.de. + * + * (C) Copyright 2005 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * Copyright 2004 Freescale Semiconductor. + * (C) Copyright 2002,2003, Motorola Inc. + * Xianghua Xiao, (X.Xiao@motorola.com) + * + * (C) Copyright 2002 Scott McNutt <smcnutt@artesyncp.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/immap_85xx.h> +#include <asm/immap_fsl_pci.h> +#include <asm/io.h> +#include <ioports.h> +#include <flash.h> +#include <libfdt.h> +#include <fdt_support.h> + +DECLARE_GLOBAL_DATA_PTR; + +extern flash_info_t flash_info[];	/* FLASH chips info */ + +void local_bus_init (void); +ulong flash_get_size (ulong base, int banknum); + +#ifdef CONFIG_PS2MULT +void ps2mult_early_init (void); +#endif + +#ifdef CONFIG_CPM2 +/* + * I/O Port configuration table + * + * if conf is 1, then that port pin will be configured at boot time + * according to the five values podr/pdir/ppar/psor/pdat for that entry + */ + +const iop_conf_t iop_conf_tab[4][32] = { + +	/* Port A: conf, ppar, psor, pdir, podr, pdat */ +	{ +	 {1, 1, 1, 0, 0, 0},	/* PA31: FCC1 MII COL */ +	 {1, 1, 1, 0, 0, 0},	/* PA30: FCC1 MII CRS */ +	 {1, 1, 1, 1, 0, 0},	/* PA29: FCC1 MII TX_ER */ +	 {1, 1, 1, 1, 0, 0},	/* PA28: FCC1 MII TX_EN */ +	 {1, 1, 1, 0, 0, 0},	/* PA27: FCC1 MII RX_DV */ +	 {1, 1, 1, 0, 0, 0},	/* PA26: FCC1 MII RX_ER */ +	 {0, 1, 0, 1, 0, 0},	/* PA25: FCC1 ATMTXD[0] */ +	 {0, 1, 0, 1, 0, 0},	/* PA24: FCC1 ATMTXD[1] */ +	 {0, 1, 0, 1, 0, 0},	/* PA23: FCC1 ATMTXD[2] */ +	 {0, 1, 0, 1, 0, 0},	/* PA22: FCC1 ATMTXD[3] */ +	 {1, 1, 0, 1, 0, 0},	/* PA21: FCC1 MII TxD[3] */ +	 {1, 1, 0, 1, 0, 0},	/* PA20: FCC1 MII TxD[2] */ +	 {1, 1, 0, 1, 0, 0},	/* PA19: FCC1 MII TxD[1] */ +	 {1, 1, 0, 1, 0, 0},	/* PA18: FCC1 MII TxD[0] */ +	 {1, 1, 0, 0, 0, 0},	/* PA17: FCC1 MII RxD[0] */ +	 {1, 1, 0, 0, 0, 0},	/* PA16: FCC1 MII RxD[1] */ +	 {1, 1, 0, 0, 0, 0},	/* PA15: FCC1 MII RxD[2] */ +	 {1, 1, 0, 0, 0, 0},	/* PA14: FCC1 MII RxD[3] */ +	 {0, 1, 0, 0, 0, 0},	/* PA13: FCC1 ATMRXD[3] */ +	 {0, 1, 0, 0, 0, 0},	/* PA12: FCC1 ATMRXD[2] */ +	 {0, 1, 0, 0, 0, 0},	/* PA11: FCC1 ATMRXD[1] */ +	 {0, 1, 0, 0, 0, 0},	/* PA10: FCC1 ATMRXD[0] */ +	 {0, 1, 1, 1, 0, 0},	/* PA9 : FCC1 L1TXD */ +	 {0, 1, 1, 0, 0, 0},	/* PA8 : FCC1 L1RXD */ +	 {0, 0, 0, 1, 0, 0},	/* PA7 : PA7 */ +	 {0, 1, 1, 1, 0, 0},	/* PA6 : TDM A1 L1RSYNC */ +	 {0, 0, 0, 1, 0, 0},	/* PA5 : PA5 */ +	 {0, 0, 0, 1, 0, 0},	/* PA4 : PA4 */ +	 {0, 0, 0, 1, 0, 0},	/* PA3 : PA3 */ +	 {0, 0, 0, 1, 0, 0},	/* PA2 : PA2 */ +	 {0, 0, 0, 0, 0, 0},	/* PA1 : FREERUN */ +	 {0, 0, 0, 1, 0, 0}	/* PA0 : PA0 */ +	 }, + +	/* Port B: conf, ppar, psor, pdir, podr, pdat */ +	{ +	 {1, 1, 0, 1, 0, 0},	/* PB31: FCC2 MII TX_ER */ +	 {1, 1, 0, 0, 0, 0},	/* PB30: FCC2 MII RX_DV */ +	 {1, 1, 1, 1, 0, 0},	/* PB29: FCC2 MII TX_EN */ +	 {1, 1, 0, 0, 0, 0},	/* PB28: FCC2 MII RX_ER */ +	 {1, 1, 0, 0, 0, 0},	/* PB27: FCC2 MII COL */ +	 {1, 1, 0, 0, 0, 0},	/* PB26: FCC2 MII CRS */ +	 {1, 1, 0, 1, 0, 0},	/* PB25: FCC2 MII TxD[3] */ +	 {1, 1, 0, 1, 0, 0},	/* PB24: FCC2 MII TxD[2] */ +	 {1, 1, 0, 1, 0, 0},	/* PB23: FCC2 MII TxD[1] */ +	 {1, 1, 0, 1, 0, 0},	/* PB22: FCC2 MII TxD[0] */ +	 {1, 1, 0, 0, 0, 0},	/* PB21: FCC2 MII RxD[0] */ +	 {1, 1, 0, 0, 0, 0},	/* PB20: FCC2 MII RxD[1] */ +	 {1, 1, 0, 0, 0, 0},	/* PB19: FCC2 MII RxD[2] */ +	 {1, 1, 0, 0, 0, 0},	/* PB18: FCC2 MII RxD[3] */ +	 {1, 1, 0, 0, 0, 0},	/* PB17: FCC3:RX_DIV */ +	 {1, 1, 0, 0, 0, 0},	/* PB16: FCC3:RX_ERR */ +	 {1, 1, 0, 1, 0, 0},	/* PB15: FCC3:TX_ERR */ +	 {1, 1, 0, 1, 0, 0},	/* PB14: FCC3:TX_EN */ +	 {1, 1, 0, 0, 0, 0},	/* PB13: FCC3:COL */ +	 {1, 1, 0, 0, 0, 0},	/* PB12: FCC3:CRS */ +	 {1, 1, 0, 0, 0, 0},	/* PB11: FCC3:RXD */ +	 {1, 1, 0, 0, 0, 0},	/* PB10: FCC3:RXD */ +	 {1, 1, 0, 0, 0, 0},	/* PB9 : FCC3:RXD */ +	 {1, 1, 0, 0, 0, 0},	/* PB8 : FCC3:RXD */ +	 {1, 1, 0, 1, 0, 0},	/* PB7 : FCC3:TXD */ +	 {1, 1, 0, 1, 0, 0},	/* PB6 : FCC3:TXD */ +	 {1, 1, 0, 1, 0, 0},	/* PB5 : FCC3:TXD */ +	 {1, 1, 0, 1, 0, 0},	/* PB4 : FCC3:TXD */ +	 {0, 0, 0, 0, 0, 0},	/* PB3 : pin doesn't exist */ +	 {0, 0, 0, 0, 0, 0},	/* PB2 : pin doesn't exist */ +	 {0, 0, 0, 0, 0, 0},	/* PB1 : pin doesn't exist */ +	 {0, 0, 0, 0, 0, 0}	/* PB0 : pin doesn't exist */ +	 }, + +	/* Port C: conf, ppar, psor, pdir, podr, pdat */ +	{ +	 {0, 0, 0, 1, 0, 0},	/* PC31: PC31 */ +	 {0, 0, 0, 1, 0, 0},	/* PC30: PC30 */ +	 {0, 1, 1, 0, 0, 0},	/* PC29: SCC1 EN *CLSN */ +	 {0, 0, 0, 1, 0, 0},	/* PC28: PC28 */ +	 {0, 0, 0, 1, 0, 0},	/* PC27: UART Clock in */ +	 {0, 0, 0, 1, 0, 0},	/* PC26: PC26 */ +	 {0, 0, 0, 1, 0, 0},	/* PC25: PC25 */ +	 {0, 0, 0, 1, 0, 0},	/* PC24: PC24 */ +	 {0, 1, 0, 1, 0, 0},	/* PC23: ATMTFCLK */ +	 {0, 1, 0, 0, 0, 0},	/* PC22: ATMRFCLK */ +	 {1, 1, 0, 0, 0, 0},	/* PC21: SCC1 EN RXCLK */ +	 {1, 1, 0, 0, 0, 0},	/* PC20: SCC1 EN TXCLK */ +	 {1, 1, 0, 0, 0, 0},	/* PC19: FCC2 MII RX_CLK CLK13 */ +	 {1, 1, 0, 0, 0, 0},	/* PC18: FCC Tx Clock (CLK14) */ +	 {1, 1, 0, 0, 0, 0},	/* PC17: PC17 */ +	 {1, 1, 0, 0, 0, 0},	/* PC16: FCC Tx Clock (CLK16) */ +	 {0, 1, 0, 0, 0, 0},	/* PC15: PC15 */ +	 {0, 1, 0, 0, 0, 0},	/* PC14: SCC1 EN *CD */ +	 {0, 1, 0, 0, 0, 0},	/* PC13: PC13 */ +	 {0, 1, 0, 1, 0, 0},	/* PC12: PC12 */ +	 {0, 0, 0, 1, 0, 0},	/* PC11: LXT971 transmit control */ +	 {0, 0, 0, 1, 0, 0},	/* PC10: FETHMDC */ +	 {0, 0, 0, 0, 0, 0},	/* PC9 : FETHMDIO */ +	 {0, 0, 0, 1, 0, 0},	/* PC8 : PC8 */ +	 {0, 0, 0, 1, 0, 0},	/* PC7 : PC7 */ +	 {0, 0, 0, 1, 0, 0},	/* PC6 : PC6 */ +	 {0, 0, 0, 1, 0, 0},	/* PC5 : PC5 */ +	 {0, 0, 0, 1, 0, 0},	/* PC4 : PC4 */ +	 {0, 0, 0, 1, 0, 0},	/* PC3 : PC3 */ +	 {0, 0, 0, 1, 0, 1},	/* PC2 : ENET FDE */ +	 {0, 0, 0, 1, 0, 0},	/* PC1 : ENET DSQE */ +	 {0, 0, 0, 1, 0, 0},	/* PC0 : ENET LBK */ +	 }, + +	/* Port D: conf, ppar, psor, pdir, podr, pdat */ +	{ +#ifdef CONFIG_TQM8560 +	 {1, 1, 0, 0, 0, 0},	/* PD31: SCC1 EN RxD */ +	 {1, 1, 1, 1, 0, 0},	/* PD30: SCC1 EN TxD */ +	 {1, 1, 0, 1, 0, 0},	/* PD29: SCC1 EN TENA */ +#else /* !CONFIG_TQM8560 */ +	 {0, 0, 0, 0, 0, 0},	/* PD31: PD31 */ +	 {0, 0, 0, 0, 0, 0},	/* PD30: PD30 */ +	 {0, 0, 0, 0, 0, 0},	/* PD29: PD29 */ +#endif /* CONFIG_TQM8560 */ +	 {1, 1, 0, 0, 0, 0},	/* PD28: PD28 */ +	 {1, 1, 0, 1, 0, 0},	/* PD27: PD27 */ +	 {1, 1, 0, 1, 0, 0},	/* PD26: PD26 */ +	 {0, 0, 0, 1, 0, 0},	/* PD25: PD25 */ +	 {0, 0, 0, 1, 0, 0},	/* PD24: PD24 */ +	 {0, 0, 0, 1, 0, 0},	/* PD23: PD23 */ +	 {0, 0, 0, 1, 0, 0},	/* PD22: PD22 */ +	 {0, 0, 0, 1, 0, 0},	/* PD21: PD21 */ +	 {0, 0, 0, 1, 0, 0},	/* PD20: PD20 */ +	 {0, 0, 0, 1, 0, 0},	/* PD19: PD19 */ +	 {0, 0, 0, 1, 0, 0},	/* PD18: PD18 */ +	 {0, 1, 0, 0, 0, 0},	/* PD17: FCC1 ATMRXPRTY */ +	 {0, 1, 0, 1, 0, 0},	/* PD16: FCC1 ATMTXPRTY */ +	 {0, 1, 1, 0, 1, 0},	/* PD15: I2C SDA */ +	 {0, 0, 0, 1, 0, 0},	/* PD14: LED */ +	 {0, 0, 0, 0, 0, 0},	/* PD13: PD13 */ +	 {0, 0, 0, 0, 0, 0},	/* PD12: PD12 */ +	 {0, 0, 0, 0, 0, 0},	/* PD11: PD11 */ +	 {0, 0, 0, 0, 0, 0},	/* PD10: PD10 */ +	 {0, 1, 0, 1, 0, 0},	/* PD9 : SMC1 TXD */ +	 {0, 1, 0, 0, 0, 0},	/* PD8 : SMC1 RXD */ +	 {0, 0, 0, 1, 0, 1},	/* PD7 : PD7 */ +	 {0, 0, 0, 1, 0, 1},	/* PD6 : PD6 */ +	 {0, 0, 0, 1, 0, 1},	/* PD5 : PD5 */ +	 {0, 0, 0, 1, 0, 1},	/* PD4 : PD4 */ +	 {0, 0, 0, 0, 0, 0},	/* PD3 : pin doesn't exist */ +	 {0, 0, 0, 0, 0, 0},	/* PD2 : pin doesn't exist */ +	 {0, 0, 0, 0, 0, 0},	/* PD1 : pin doesn't exist */ +	 {0, 0, 0, 0, 0, 0}	/* PD0 : pin doesn't exist */ +	 } +}; +#endif /*  CONFIG_CPM2 */ + +#define CASL_STRING1	"casl=xx" +#define CASL_STRING2	"casl=" + +static const int casl_table[] = { 20, 25, 30 }; +#define	N_CASL (sizeof(casl_table) / sizeof(casl_table[0])) + +int cas_latency (void) +{ +	char *s = getenv ("serial#"); +	int casl; +	int val; +	int i; + +	casl = CONFIG_DDR_DEFAULT_CL; + +	if (s != NULL) { +		if (strncmp(s + strlen (s) - strlen (CASL_STRING1), +			    CASL_STRING2, strlen (CASL_STRING2)) == 0) { +			val = simple_strtoul (s + strlen (s) - 2, NULL, 10); + +			for (i = 0; i < N_CASL; ++i) { +				if (val == casl_table[i]) { +					return val; +				} +			} +		} +	} + +	return casl; +} + +int checkboard (void) +{ +	char *s = getenv ("serial#"); + +	printf ("Board: %s", CONFIG_BOARDNAME); +	if (s != NULL) { +		puts (", serial# "); +		puts (s); +	} +	putc ('\n'); + +	/* +	 * Initialize local bus. +	 */ +	local_bus_init (); + +	return 0; +} + +int misc_init_r (void) +{ +	volatile ccsr_lbc_t *memctl = (void *)(CFG_MPC85xx_LBC_ADDR); + +	/* +	 * Adjust flash start and offset to detected values +	 */ +	gd->bd->bi_flashstart = 0 - gd->bd->bi_flashsize; +	gd->bd->bi_flashoffset = 0; + +	/* +	 * Recalculate CS configuration if second FLASH bank is available +	 */ +	if (flash_info[0].size > 0) { +		memctl->or1 = ((-flash_info[0].size) & 0xffff8000) | +			(CFG_OR1_PRELIM & 0x00007fff); +		memctl->br1 = gd->bd->bi_flashstart | +			(CFG_BR1_PRELIM & 0x00007fff); +		/* +		 * Re-check to get correct base address for bank 1 +		 */ +		flash_get_size (gd->bd->bi_flashstart, 0); +	} else { +		memctl->or1 = 0; +		memctl->br1 = 0; +	} + +	/* +	 *  If bank 1 is equipped, bank 0 is mapped after bank 1 +	 */ +	memctl->or0 = ((-flash_info[1].size) & 0xffff8000) | +		(CFG_OR0_PRELIM & 0x00007fff); +	memctl->br0 = (gd->bd->bi_flashstart + flash_info[0].size) | +		(CFG_BR0_PRELIM & 0x00007fff); +	/* +	 * Re-check to get correct base address for bank 0 +	 */ +	flash_get_size (gd->bd->bi_flashstart + flash_info[0].size, 1); + +	/* +	 * Re-do flash protection upon new addresses +	 */ +	flash_protect (FLAG_PROTECT_CLEAR, +		       gd->bd->bi_flashstart, 0xffffffff, +		       &flash_info[CFG_MAX_FLASH_BANKS - 1]); + +	/* Monitor protection ON by default */ +	flash_protect (FLAG_PROTECT_SET, +		       CFG_MONITOR_BASE, +		       CFG_MONITOR_BASE + monitor_flash_len - 1, +		       &flash_info[CFG_MAX_FLASH_BANKS - 1]); + +	/* Environment protection ON by default */ +	flash_protect (FLAG_PROTECT_SET, +		       CFG_ENV_ADDR, +		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, +		       &flash_info[CFG_MAX_FLASH_BANKS - 1]); + +#ifdef CFG_ENV_ADDR_REDUND +	/* Redundant environment protection ON by default */ +	flash_protect (FLAG_PROTECT_SET, +		       CFG_ENV_ADDR_REDUND, +		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, +		       &flash_info[CFG_MAX_FLASH_BANKS - 1]); +#endif + +	return 0; +} + +#ifdef CONFIG_CAN_DRIVER +/* + * Initialize UPMC RAM + */ +static void upmc_write (u_char addr, uint val) +{ +	volatile ccsr_lbc_t *lbc = (void *)(CFG_MPC85xx_LBC_ADDR); + +	out_be32 (&lbc->mdr, val); + +	clrsetbits_be32(&lbc->mcmr, MxMR_MAD_MSK, +			MxMR_OP_WARR | (addr & MxMR_MAD_MSK)); + +	/* dummy access to perform write */ +	out_8 ((void __iomem *)CFG_CAN_BASE, 0); + +	/* normal operation */ +	clrbits_be32(&lbc->mcmr, MxMR_OP_WARR); +} +#endif /* CONFIG_CAN_DRIVER */ + +uint get_lbc_clock (void) +{ +	volatile ccsr_lbc_t *lbc = (void *)(CFG_MPC85xx_LBC_ADDR); +	sys_info_t sys_info; +	ulong clkdiv = lbc->lcrr & 0x0f; + +	get_sys_info (&sys_info); + +	if (clkdiv == 2 || clkdiv == 4 || clkdiv == 8) { +#ifdef CONFIG_MPC8548 +		/* +		 * Yes, the entire PQ38 family use the same +		 * bit-representation for twice the clock divider value. +		 */ +		clkdiv *= 2; +#endif +		return sys_info.freqSystemBus / clkdiv; +	} + +	puts("Invalid clock divider value in CFG_LBC_LCRR\n"); + +	return 0; +} + +/* + * Initialize Local Bus + */ +void local_bus_init (void) +{ +	volatile ccsr_gur_t *gur = (void *)(CFG_MPC85xx_GUTS_ADDR); +	volatile ccsr_lbc_t *lbc = (void *)(CFG_MPC85xx_LBC_ADDR); +	uint lbc_mhz = get_lbc_clock ()  / 1000000; + +#ifdef CONFIG_MPC8548 +	uint svr = get_svr (); +	uint lcrr; + +	/* +	 * MPC revision < 2.0 +	 * According to MPC8548E_Device_Errata Rev. L, Erratum LBIU1: +	 * Modify engineering use only register at address 0xE_0F20. +	 * "1. Read register at offset 0xE_0F20 +	 * 2. And value with 0x0000_FFFF +	 * 3. OR result with 0x0000_0004 +	 * 4. Write result back to offset 0xE_0F20." +	 * +	 * According to MPC8548E_Device_Errata Rev. L, Erratum LBIU2: +	 * Modify engineering use only register at address 0xE_0F20. +	 * "1. Read register at offset 0xE_0F20 +	 * 2. And value with 0xFFFF_FFDF +	 * 3. Write result back to offset 0xE_0F20." +	 * +	 * Since it is the same register, we do the modification in one step. +	 */ +	if (SVR_MAJ (svr) < 2) { +		uint dummy = gur->lbiuiplldcr1; +		dummy &= 0x0000FFDF; +		dummy |= 0x00000004; +		gur->lbiuiplldcr1 = dummy; +	} + +	lcrr = CFG_LBC_LCRR; + +	/* +	 * Local Bus Clock > 83.3 MHz. According to timing +	 * specifications set LCRR[EADC] to 2 delay cycles. +	 */ +	if (lbc_mhz > 83) { +		lcrr &= ~LCRR_EADC; +		lcrr |= LCRR_EADC_2; +	} + +	/* +	 * According to MPC8548ERMAD Rev. 1.3, 13.3.1.16, 13-30 +	 * disable PLL bypass for Local Bus Clock > 83 MHz. +	 */ +	if (lbc_mhz >= 66) +		lcrr &= (~LCRR_DBYP);	/* DLL Enabled */ + +	else +		lcrr |= LCRR_DBYP;	/* DLL Bypass */ + +	lbc->lcrr = lcrr; +	asm ("sync;isync;msync"); + +	/* +	 * According to MPC8548ERMAD Rev.1.3 read back LCRR +	 * and terminate with isync +	 */ +	lcrr = lbc->lcrr; +	asm ("isync;"); + +	/* let DLL stabilize */ +	udelay (500); + +#else /* !CONFIG_MPC8548 */ + +	/* +	 * Errata LBC11. +	 * Fix Local Bus clock glitch when DLL is enabled. +	 * +	 * If localbus freq is < 66Mhz, DLL bypass mode must be used. +	 * If localbus freq is > 133Mhz, DLL can be safely enabled. +	 * Between 66 and 133, the DLL is enabled with an override workaround. +	 */ + +	if (lbc_mhz < 66) { +		lbc->lcrr = CFG_LBC_LCRR | LCRR_DBYP;	/* DLL Bypass */ +		lbc->ltedr = 0xa4c80000;	/* DK: !!! */ + +	} else if (lbc_mhz >= 133) { +		lbc->lcrr = CFG_LBC_LCRR & (~LCRR_DBYP);	/* DLL Enabled */ + +	} else { +		/* +		 * On REV1 boards, need to change CLKDIV before enable DLL. +		 * Default CLKDIV is 8, change it to 4 temporarily. +		 */ +		uint pvr = get_pvr (); +		uint temp_lbcdll = 0; + +		if (pvr == PVR_85xx_REV1) { +			/* FIXME: Justify the high bit here. */ +			lbc->lcrr = 0x10000004; +		} + +		lbc->lcrr = CFG_LBC_LCRR & (~LCRR_DBYP);	/* DLL Enabled */ +		udelay (200); + +		/* +		 * Sample LBC DLL ctrl reg, upshift it to set the +		 * override bits. +		 */ +		temp_lbcdll = gur->lbcdllcr; +		gur->lbcdllcr = (((temp_lbcdll & 0xff) << 16) | 0x80000000); +		asm ("sync;isync;msync"); +	} +#endif /* !CONFIG_MPC8548 */ + +#ifdef	CONFIG_CAN_DRIVER +	/* +	 * According to timing specifications EAD must be +	 * set if Local Bus Clock is > 83 MHz. +	 */ +	if (lbc_mhz > 83) +		out_be32 (&lbc->or2, CFG_OR2_CAN | OR_UPM_EAD); +	else +		out_be32 (&lbc->or2, CFG_OR2_CAN); +	out_be32 (&lbc->br2, CFG_BR2_CAN); + +	/* LGPL4 is UPWAIT */ +	out_be32(&lbc->mcmr, MxMR_DSx_3_CYCL | MxMR_GPL_x4DIS | MxMR_WLFx_3X); + +	/* Initialize UPMC for CAN: single read */ +	upmc_write (0x00, 0xFFFFED00); +	upmc_write (0x01, 0xCCFFCC00); +	upmc_write (0x02, 0x00FFCF00); +	upmc_write (0x03, 0x00FFCF00); +	upmc_write (0x04, 0x00FFDC00); +	upmc_write (0x05, 0x00FFCF00); +	upmc_write (0x06, 0x00FFED00); +	upmc_write (0x07, 0x3FFFCC07); + +	/* Initialize UPMC for CAN: single write */ +	upmc_write (0x18, 0xFFFFED00); +	upmc_write (0x19, 0xCCFFEC00); +	upmc_write (0x1A, 0x00FFED80); +	upmc_write (0x1B, 0x00FFED80); +	upmc_write (0x1C, 0x00FFFC00); +	upmc_write (0x1D, 0x0FFFEC00); +	upmc_write (0x1E, 0x0FFFEF00); +	upmc_write (0x1F, 0x3FFFEC05); +#endif /* CONFIG_CAN_DRIVER */ +} + +/* + * Initialize PCI Devices, report devices found. + */ +static int first_free_busno; + +#if defined(CONFIG_PCI) || defined(CONFIG_PCI1) +static struct pci_controller pci1_hose; +#endif /* CONFIG_PCI || CONFIG_PCI1 */ + +#ifdef CONFIG_PCIE1 +static struct pci_controller pcie1_hose; +#endif /* CONFIG_PCIE1 */ + +static inline void init_pci1(void) +{ +	volatile ccsr_gur_t *gur = (void *)(CFG_MPC85xx_GUTS_ADDR); +#if defined(CONFIG_PCI) || defined(CONFIG_PCI1) +	uint host_agent = (gur->porbmsr & MPC85xx_PORBMSR_HA) >> 16; +	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)CFG_PCI1_ADDR; +	extern void fsl_pci_init(struct pci_controller *hose); +	struct pci_controller *hose = &pci1_hose; + +	/* PORDEVSR[15] */ +	uint pci_32 = gur->pordevsr & MPC85xx_PORDEVSR_PCI1_PCI32; +	/* PORDEVSR[14] */ +	uint pci_arb = gur->pordevsr & MPC85xx_PORDEVSR_PCI1_ARB; +	/* PORPLLSR[16] */ +	uint pci_clk_sel = gur->porpllsr & MPC85xx_PORDEVSR_PCI1_SPD; + +	uint pci_agent = (host_agent == 3) || (host_agent == 4 ) || +		(host_agent == 6); + +	uint pci_speed = CONFIG_SYS_CLK_FREQ;	/* PCI PSPEED in [4:5] */ + +	if (!(gur->devdisr & MPC85xx_DEVDISR_PCI1)) { +		printf ("PCI1:  %d bit, %s MHz, %s, %s, %s\n", +			(pci_32) ? 32 : 64, +			(pci_speed == 33333333) ? "33" : +			(pci_speed == 66666666) ? "66" : "unknown", +			pci_clk_sel ? "sync" : "async", +			pci_agent ? "agent" : "host", +			pci_arb ? "arbiter" : "external-arbiter"); + + +		/* inbound */ +		pci_set_region (hose->regions + 0, +				CFG_PCI_MEMORY_BUS, +				CFG_PCI_MEMORY_PHYS, +				CFG_PCI_MEMORY_SIZE, +				PCI_REGION_MEM | PCI_REGION_MEMORY); + + +		/* outbound memory */ +		pci_set_region (hose->regions + 1, +				CFG_PCI1_MEM_BASE, +				CFG_PCI1_MEM_PHYS, +				CFG_PCI1_MEM_SIZE, +				PCI_REGION_MEM); + +		/* outbound io */ +		pci_set_region (hose->regions + 2, +				CFG_PCI1_IO_BASE, +				CFG_PCI1_IO_PHYS, +				CFG_PCI1_IO_SIZE, +				PCI_REGION_IO); + +		hose->region_count = 3; + +		hose->first_busno = first_free_busno; +		pci_setup_indirect (hose, (int)&pci->cfg_addr, +				    (int)&pci->cfg_data); + +		fsl_pci_init (hose); + +		printf ("       PCI on bus %02x..%02x\n", +			hose->first_busno, hose->last_busno); + +		first_free_busno = hose->last_busno + 1; +#ifdef CONFIG_PCIX_CHECK +		if (!(gur->pordevsr & PORDEVSR_PCI)) { +			ushort reg16 = +				PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ | +				PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E; +			uint dev = PCI_BDF(hose->first_busno, 0, 0); + +			/* PCI-X init */ +			if (CONFIG_SYS_CLK_FREQ < 66000000) +				puts ("PCI-X will only work at 66 MHz\n"); + +			pci_hose_write_config_word (hose, dev, PCIX_COMMAND, +						    reg16); +		} +#endif +	} else { +		puts ("PCI1:  disabled\n"); +	} +#else /* !(CONFIG_PCI || CONFIG_PCI1) */ +	gur->devdisr |= MPC85xx_DEVDISR_PCI1; /* disable */ +#endif /* CONFIG_PCI || CONFIG_PCI1) */ +} + +static inline void init_pcie1(void) +{ +	volatile ccsr_gur_t *gur = (void *)(CFG_MPC85xx_GUTS_ADDR); +#ifdef CONFIG_PCIE1 +	uint io_sel = (gur->pordevsr & MPC85xx_PORDEVSR_IO_SEL) >> 19; +	uint host_agent = (gur->porbmsr & MPC85xx_PORBMSR_HA) >> 16; +	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)CFG_PCIE1_ADDR; +	extern void fsl_pci_init(struct pci_controller *hose); +	struct pci_controller *hose = &pcie1_hose; +	int pcie_ep =  (host_agent == 0) || (host_agent == 2 ) || +		(host_agent == 3); + +	int pcie_configured  = io_sel >= 1; + +	if (pcie_configured && !(gur->devdisr & MPC85xx_DEVDISR_PCIE)){ +		printf ("PCIe:  %s, base address %x", +			pcie_ep ? "End point" : "Root complex", (uint)pci); + +		if (pci->pme_msg_det) { +			pci->pme_msg_det = 0xffffffff; +			debug (", with errors. Clearing. Now 0x%08x", +			       pci->pme_msg_det); +		} +		puts ("\n"); + +		/* inbound */ +		pci_set_region (hose->regions + 0, +				CFG_PCI_MEMORY_BUS, +				CFG_PCI_MEMORY_PHYS, +				CFG_PCI_MEMORY_SIZE, +				PCI_REGION_MEM | PCI_REGION_MEMORY); + +		/* outbound memory */ +		pci_set_region (hose->regions + 1, +				CFG_PCIE1_MEM_BASE, +				CFG_PCIE1_MEM_PHYS, +				CFG_PCIE1_MEM_SIZE, +				PCI_REGION_MEM); + +		/* outbound io */ +		pci_set_region (hose->regions + 2, +				CFG_PCIE1_IO_BASE, +				CFG_PCIE1_IO_PHYS, +				CFG_PCIE1_IO_SIZE, +				PCI_REGION_IO); + +		hose->region_count = 3; + +		hose->first_busno = first_free_busno; +		pci_setup_indirect(hose, (int)&pci->cfg_addr, +				   (int)&pci->cfg_data); + +		fsl_pci_init (hose); +		printf ("       PCIe on bus %02x..%02x\n", +			hose->first_busno, hose->last_busno); + +		first_free_busno = hose->last_busno + 1; + +	} else { +		printf ("PCIe:  disabled\n"); +	} +#else /* !CONFIG_PCIE1 */ +	gur->devdisr |= MPC85xx_DEVDISR_PCIE; /* disable */ +#endif /* CONFIG_PCIE1 */ +} + +void pci_init_board (void) +{ +	init_pci1(); +	init_pcie1(); +} + +#ifdef CONFIG_OF_BOARD_SETUP +void ft_board_setup (void *blob, bd_t *bd) +{ +	int node, tmp[2]; +	const char *path; + +	ft_cpu_setup (blob, bd); + +	node = fdt_path_offset (blob, "/aliases"); +	tmp[0] = 0; +	if (node >= 0) { +#if defined(CONFIG_PCI) || defined(CONFIG_PCI1) +		path = fdt_getprop (blob, node, "pci0", NULL); +		if (path) { +			tmp[1] = pci1_hose.last_busno - pci1_hose.first_busno; +			do_fixup_by_path (blob, path, "bus-range", &tmp, 8, 1); +		} +#endif /* CONFIG_PCI || CONFIG_PCI1 */ +#ifdef CONFIG_PCIE1 +		path = fdt_getprop (blob, node, "pci1", NULL); +		if (path) { +			tmp[1] = pcie1_hose.last_busno - pcie1_hose.first_busno; +			do_fixup_by_path (blob, path, "bus-range", &tmp, 8, 1); +		} +#endif /* CONFIG_PCIE1 */ +	} +} +#endif /* CONFIG_OF_BOARD_SETUP */ + +#ifdef CONFIG_BOARD_EARLY_INIT_R +int board_early_init_r (void) +{ +#ifdef CONFIG_PS2MULT +	ps2mult_early_init (); +#endif /* CONFIG_PS2MULT */ +	return (0); +} +#endif /* CONFIG_BOARD_EARLY_INIT_R */ diff --git a/board/tqc/tqm85xx/u-boot.lds b/board/tqc/tqm85xx/u-boot.lds new file mode 100644 index 000000000..8cb551ae4 --- /dev/null +++ b/board/tqc/tqm85xx/u-boot.lds @@ -0,0 +1,147 @@ +/* + * (C) Copyright 2002,2003, Motorola,Inc. + * Xianghua Xiao, X.Xiao@motorola.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +/* Do we need any of these for elf? +   __DYNAMIC = 0;    */ +SECTIONS +{ +  .resetvec 0xFFFFFFFC : +  { +    *(.resetvec) +  } = 0xffff + +  .bootpg 0xFFFFF000 : +  { +    cpu/mpc85xx/start.o (.bootpg) +  } = 0xffff + +  /* Read-only sections, merged into text segment: */ +  . = + SIZEOF_HEADERS; +  .interp : { *(.interp) } +  .hash		 : { *(.hash)		} +  .dynsym	 : { *(.dynsym)		} +  .dynstr	 : { *(.dynstr)		} +  .rel.text	 : { *(.rel.text)		} +  .rela.text	 : { *(.rela.text)	} +  .rel.data	 : { *(.rel.data)		} +  .rela.data	 : { *(.rela.data)	} +  .rel.rodata	 : { *(.rel.rodata)	} +  .rela.rodata	 : { *(.rela.rodata)	} +  .rel.got	 : { *(.rel.got)		} +  .rela.got	 : { *(.rela.got)		} +  .rel.ctors	 : { *(.rel.ctors)	} +  .rela.ctors	 : { *(.rela.ctors)	} +  .rel.dtors	 : { *(.rel.dtors)	} +  .rela.dtors	 : { *(.rela.dtors)	} +  .rel.bss	 : { *(.rel.bss)		} +  .rela.bss	 : { *(.rela.bss)		} +  .rel.plt	 : { *(.rel.plt)		} +  .rela.plt	 : { *(.rela.plt)		} +  .init		 : { *(.init)	} +  .plt : { *(.plt) } +  .text	     : +  { +    cpu/mpc85xx/start.o (.text) +    cpu/mpc85xx/traps.o (.text) +    cpu/mpc85xx/interrupts.o (.text) +    cpu/mpc85xx/cpu_init.o (.text) +    cpu/mpc85xx/cpu.o (.text) +    cpu/mpc85xx/speed.o (.text) +    cpu/mpc85xx/pci.o (.text) +    common/dlmalloc.o (.text) +    lib_generic/crc32.o (.text) +    lib_ppc/extable.o (.text) +    lib_generic/zlib.o (.text) +    *(.text) +    *(.fixup) +    *(.got1) +   } +    _etext = .; +    PROVIDE (etext = .); +    .rodata    : +   { +    *(.rodata) +    *(.rodata1) +    *(.rodata.str1.4) +    *(.eh_frame) +  } +  .fini	     : { *(.fini)    } =0 +  .ctors     : { *(.ctors)   } +  .dtors     : { *(.dtors)   } + +  /* Read-write section, merged into data segment: */ +  . = (. + 0x00FF) & 0xFFFFFF00; +  _erotext = .; +  PROVIDE (erotext = .); +  .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; +  __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + +  .data	   : +  { +    *(.data) +    *(.data1) +    *(.sdata) +    *(.sdata2) +    *(.dynamic) +    CONSTRUCTORS +  } +  _edata  =  .; +  PROVIDE (edata = .); + +  . = .; +  __u_boot_cmd_start = .; +  .u_boot_cmd : { *(.u_boot_cmd) } +  __u_boot_cmd_end = .; + +  . = .; +  __start___ex_table = .; +  __ex_table : { *(__ex_table) } +  __stop___ex_table = .; + +  . = ALIGN(256); +  __init_begin = .; +  .text.init : { *(.text.init) } +  .data.init : { *(.data.init) } +  . = ALIGN(256); +  __init_end = .; + +  __bss_start = .; +  .bss (NOLOAD)	     : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +  } +  _end = . ; +  PROVIDE (end = .); +} diff --git a/board/tqc/tqm8xx/Makefile b/board/tqc/tqm8xx/Makefile new file mode 100644 index 000000000..b48934b42 --- /dev/null +++ b/board/tqc/tqm8xx/Makefile @@ -0,0 +1,44 @@ +# +# (C) Copyright 2000-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 +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(BOARD).a + +COBJS	= $(BOARD).o flash.o load_sernum_ethaddr.o + +SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS	:= $(addprefix $(obj),$(COBJS)) +SOBJS	:= $(addprefix $(obj),$(SOBJS)) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/tqc/tqm8xx/config.mk b/board/tqc/tqm8xx/config.mk new file mode 100644 index 000000000..9d6080b84 --- /dev/null +++ b/board/tqc/tqm8xx/config.mk @@ -0,0 +1,28 @@ +# +# (C) Copyright 2000 +# 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 +# + +# +# TQM8xxL boards +# + +TEXT_BASE = 0x40000000 diff --git a/board/tqc/tqm8xx/flash.c b/board/tqc/tqm8xx/flash.c new file mode 100644 index 000000000..4342ebc84 --- /dev/null +++ b/board/tqc/tqm8xx/flash.c @@ -0,0 +1,834 @@ +/* + * (C) Copyright 2000-2004 + * 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 + */ + +#if 0 +#define DEBUG +#endif + +#include <common.h> +#include <mpc8xx.h> +#include <environment.h> + +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if !defined(CFG_FLASH_CFI_DRIVER) /* do not use if CFI driver is configured */ + +#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \ +    && !defined(CONFIG_TQM885D) +# ifndef CFG_OR_TIMING_FLASH_AT_50MHZ +#  define CFG_OR_TIMING_FLASH_AT_50MHZ	(OR_ACS_DIV1  | OR_TRLX | OR_CSNT_SAM | \ +					 OR_SCY_2_CLK | OR_EHTR | OR_BI) +# endif +#endif /* CONFIG_TQM8xxL/M, !TQM866M, !TQM885D */ + +#ifndef	CFG_ENV_ADDR +#define CFG_ENV_ADDR	(CFG_FLASH_BASE + CFG_ENV_OFFSET) +#endif + +flash_info_t	flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips	*/ + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size (vu_long *addr, flash_info_t *info); +static int write_word (flash_info_t *info, ulong dest, ulong data); + +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init (void) +{ +	volatile immap_t     *immap  = (immap_t *)CFG_IMMR; +	volatile memctl8xx_t *memctl = &immap->im_memctl; +	unsigned long size_b0, size_b1; +	int i; + +#ifdef	CFG_OR_TIMING_FLASH_AT_50MHZ +	int scy, trlx, flash_or_timing, clk_diff; + +	scy = (CFG_OR_TIMING_FLASH_AT_50MHZ & OR_SCY_MSK) >> 4; +	if (CFG_OR_TIMING_FLASH_AT_50MHZ & OR_TRLX) { +		trlx = OR_TRLX; +		scy *= 2; +	} else +		trlx = 0; + +		/* We assume that each 10MHz of bus clock require 1-clk SCY +		 * adjustment. +		 */ +	clk_diff = (gd->bus_clk / 1000000) - 50; + +		/* We need proper rounding here. This is what the "+5" and "-5" +		 * are here for. +		 */ +	if (clk_diff >= 0) +		scy += (clk_diff + 5) / 10; +	else +		scy += (clk_diff - 5) / 10; + +		/* For bus frequencies above 50MHz, we want to use relaxed timing +		 * (OR_TRLX). +		 */ +	if (gd->bus_clk >= 50000000) +		trlx = OR_TRLX; +	else +		trlx = 0; + +	if (trlx) +		scy /= 2; + +	if (scy > 0xf) +		scy = 0xf; +	if (scy < 1) +		scy = 1; + +	flash_or_timing = (scy << 4) | trlx | +	                  (CFG_OR_TIMING_FLASH_AT_50MHZ & ~(OR_TRLX | OR_SCY_MSK)); +#endif +	/* Init: no FLASHes known */ +	for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) { +		flash_info[i].flash_id = FLASH_UNKNOWN; +	} + +	/* Static FLASH Bank configuration here - FIXME XXX */ + +	debug ("\n## Get flash bank 1 size @ 0x%08x\n",FLASH_BASE0_PRELIM); + +	size_b0 = flash_get_size((vu_long *)FLASH_BASE0_PRELIM, &flash_info[0]); + +	debug ("## Get flash bank 2 size @ 0x%08x\n",FLASH_BASE1_PRELIM); + +	if (flash_info[0].flash_id == FLASH_UNKNOWN) { +		printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n", +			size_b0, size_b0<<20); +	} + +	size_b1 = flash_get_size((vu_long *)FLASH_BASE1_PRELIM, &flash_info[1]); + +	debug ("## Prelim. Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1); + +	if (size_b1 > size_b0) { +		printf ("## ERROR: " +			"Bank 1 (0x%08lx = %ld MB) > Bank 0 (0x%08lx = %ld MB)\n", +			size_b1, size_b1<<20, +			size_b0, size_b0<<20 +		); +		flash_info[0].flash_id	= FLASH_UNKNOWN; +		flash_info[1].flash_id	= FLASH_UNKNOWN; +		flash_info[0].sector_count	= -1; +		flash_info[1].sector_count	= -1; +		flash_info[0].size		= 0; +		flash_info[1].size		= 0; +		return (0); +	} + +	debug  ("## Before remap: " +		"BR0: 0x%08x    OR0: 0x%08x    " +		"BR1: 0x%08x    OR1: 0x%08x\n", +		memctl->memc_br0, memctl->memc_or0, +		memctl->memc_br1, memctl->memc_or1); + +	/* Remap FLASH according to real size */ +#ifndef	CFG_OR_TIMING_FLASH_AT_50MHZ +	memctl->memc_or0 = CFG_OR_TIMING_FLASH | (-size_b0 & OR_AM_MSK); +#else +	memctl->memc_or0 = flash_or_timing | (-size_b0 & OR_AM_MSK); +#endif +	memctl->memc_br0 = (CFG_FLASH_BASE & BR_BA_MSK) | BR_MS_GPCM | BR_V; + +	debug ("## BR0: 0x%08x    OR0: 0x%08x\n", +		memctl->memc_br0, memctl->memc_or0); + +	/* Re-do sizing to get full correct info */ +	size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]); + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE +	/* monitor protection ON by default */ +	debug ("Protect monitor: %08lx ... %08lx\n", +		(ulong)CFG_MONITOR_BASE, +		(ulong)CFG_MONITOR_BASE + monitor_flash_len - 1); + +	flash_protect(FLAG_PROTECT_SET, +		      CFG_MONITOR_BASE, +		      CFG_MONITOR_BASE + monitor_flash_len - 1, +		      &flash_info[0]); +#endif + +#ifdef	CFG_ENV_IS_IN_FLASH +	/* ENV protection ON by default */ +# ifdef CFG_ENV_ADDR_REDUND +	debug ("Protect primary   environment: %08lx ... %08lx\n", +		(ulong)CFG_ENV_ADDR, +		(ulong)CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1); +# else +	debug ("Protect environment: %08lx ... %08lx\n", +		(ulong)CFG_ENV_ADDR, +		(ulong)CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1); +# endif + +	flash_protect(FLAG_PROTECT_SET, +		      CFG_ENV_ADDR, +		      CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, +		      &flash_info[0]); +#endif + +#ifdef CFG_ENV_ADDR_REDUND +	debug ("Protect redundand environment: %08lx ... %08lx\n", +		(ulong)CFG_ENV_ADDR_REDUND, +		(ulong)CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1); + +	flash_protect(FLAG_PROTECT_SET, +		      CFG_ENV_ADDR_REDUND, +		      CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1, +		      &flash_info[0]); +#endif + +	if (size_b1) { +#ifndef	CFG_OR_TIMING_FLASH_AT_50MHZ +		memctl->memc_or1 = CFG_OR_TIMING_FLASH | (-size_b1 & 0xFFFF8000); +#else +		memctl->memc_or1 = flash_or_timing | (-size_b1 & 0xFFFF8000); +#endif +		memctl->memc_br1 = ((CFG_FLASH_BASE + size_b0) & BR_BA_MSK) | +				    BR_MS_GPCM | BR_V; + +		debug ("## BR1: 0x%08x    OR1: 0x%08x\n", +			memctl->memc_br1, memctl->memc_or1); + +		/* Re-do sizing to get full correct info */ +		size_b1 = flash_get_size((vu_long *)(CFG_FLASH_BASE + size_b0), +					  &flash_info[1]); + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE +		/* monitor protection ON by default */ +		flash_protect(FLAG_PROTECT_SET, +			      CFG_MONITOR_BASE, +			      CFG_MONITOR_BASE+monitor_flash_len-1, +			      &flash_info[1]); +#endif + +#ifdef	CFG_ENV_IS_IN_FLASH +		/* ENV protection ON by default */ +		flash_protect(FLAG_PROTECT_SET, +			      CFG_ENV_ADDR, +			      CFG_ENV_ADDR+CFG_ENV_SIZE-1, +			      &flash_info[1]); +#endif +	} else { +		memctl->memc_br1 = 0;		/* invalidate bank */ + +		flash_info[1].flash_id = FLASH_UNKNOWN; +		flash_info[1].sector_count = -1; +		flash_info[1].size = 0; + +		debug ("## DISABLE BR1: 0x%08x    OR1: 0x%08x\n", +			memctl->memc_br1, memctl->memc_or1); +	} + +	debug ("## Final Flash bank sizes: %08lx + 0x%08lx\n",size_b0,size_b1); + +	flash_info[0].size = size_b0; +	flash_info[1].size = size_b1; + +	return (size_b0 + size_b1); +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info  (flash_info_t *info) +{ +	int i; + +	if (info->flash_id == FLASH_UNKNOWN) { +		printf ("missing or unknown FLASH type\n"); +		return; +	} + +	switch (info->flash_id & FLASH_VENDMASK) { +	case FLASH_MAN_AMD:	printf ("AMD ");		break; +	case FLASH_MAN_FUJ:	printf ("FUJITSU ");		break; +	default:		printf ("Unknown Vendor ");	break; +	} + +	switch (info->flash_id & FLASH_TYPEMASK) { +#ifdef CONFIG_TQM8xxM	/* mirror bit flash */ +	case FLASH_AMLV128U:	printf ("AM29LV128ML (128Mbit, uniform sector size)\n"); +				break; +	case FLASH_AMLV320U:	printf ("AM29LV320ML (32Mbit, uniform sector size)\n"); +				break; +	case FLASH_AMLV640U:	printf ("AM29LV640ML (64Mbit, uniform sector size)\n"); +				break; +	case FLASH_AMLV320B:	printf ("AM29LV320MB (32Mbit, bottom boot sect)\n"); +				break; +# else	/* ! TQM8xxM */ +	case FLASH_AM400B:	printf ("AM29LV400B (4 Mbit, bottom boot sect)\n"); +				break; +	case FLASH_AM400T:	printf ("AM29LV400T (4 Mbit, top boot sector)\n"); +				break; +	case FLASH_AM800B:	printf ("AM29LV800B (8 Mbit, bottom boot sect)\n"); +				break; +	case FLASH_AM800T:	printf ("AM29LV800T (8 Mbit, top boot sector)\n"); +				break; +	case FLASH_AM320B:	printf ("AM29LV320B (32 Mbit, bottom boot sect)\n"); +				break; +	case FLASH_AM320T:	printf ("AM29LV320T (32 Mbit, top boot sector)\n"); +				break; +#endif	/* TQM8xxM */ +	case FLASH_AM160B:	printf ("AM29LV160B (16 Mbit, bottom boot sect)\n"); +				break; +	case FLASH_AM160T:	printf ("AM29LV160T (16 Mbit, top boot sector)\n"); +				break; +	case FLASH_AMDL163B:	printf ("AM29DL163B (16 Mbit, bottom boot sect)\n"); +				break; +	default:		printf ("Unknown Chip Type\n"); +				break; +	} + +	printf ("  Size: %ld MB in %d Sectors\n", +		info->size >> 20, info->sector_count); + +	printf ("  Sector Start Addresses:"); +	for (i=0; i<info->sector_count; ++i) { +		if ((i % 5) == 0) +			printf ("\n   "); +		printf (" %08lX%s", +			info->start[i], +			info->protect[i] ? " (RO)" : "     " +		); +	} +	printf ("\n"); +	return; +} + +/*----------------------------------------------------------------------- + */ + + +/*----------------------------------------------------------------------- + */ + +/* + * The following code cannot be run from FLASH! + */ + +static ulong flash_get_size (vu_long *addr, flash_info_t *info) +{ +	short i; +	ulong value; +	ulong base = (ulong)addr; + +	/* Write auto select command: read Manufacturer ID */ +	addr[0x0555] = 0x00AA00AA; +	addr[0x02AA] = 0x00550055; +	addr[0x0555] = 0x00900090; + +	value = addr[0]; + +	debug ("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value); + +	switch (value) { +	case AMD_MANUFACT: +		debug ("Manufacturer: AMD\n"); +		info->flash_id = FLASH_MAN_AMD; +		break; +	case FUJ_MANUFACT: +		debug ("Manufacturer: FUJITSU\n"); +		info->flash_id = FLASH_MAN_FUJ; +		break; +	default: +		debug ("Manufacturer: *** unknown ***\n"); +		info->flash_id = FLASH_UNKNOWN; +		info->sector_count = 0; +		info->size = 0; +		return (0);			/* no or unknown flash	*/ +	} + +	value = addr[1];			/* device ID		*/ + +	debug ("Device ID @ 0x%08lx: 0x%08lx\n", (ulong)(&addr[1]), value); + +	switch (value) { +#ifdef CONFIG_TQM8xxM	/* mirror bit flash */ +	case AMD_ID_MIRROR: +		debug ("Mirror Bit flash: addr[14] = %08lX  addr[15] = %08lX\n", +			addr[14], addr[15]); +		/* Special case for AMLV320MH/L */ +		if ((addr[14] & 0x00ff00ff) == 0x001d001d && +		    (addr[15] & 0x00ff00ff) == 0x00000000) { +			debug ("Chip: AMLV320MH/L\n"); +			info->flash_id += FLASH_AMLV320U; +			info->sector_count = 64; +			info->size = 0x00800000;	/* => 8 MB */ +			break; +		} +		switch(addr[14]) { +		case AMD_ID_LV128U_2: +			if (addr[15] != AMD_ID_LV128U_3) { +				debug ("Chip: AMLV128U -> unknown\n"); +				info->flash_id = FLASH_UNKNOWN; +			} else { +				debug ("Chip: AMLV128U\n"); +				info->flash_id += FLASH_AMLV128U; +				info->sector_count = 256; +				info->size = 0x02000000; +			} +			break;				/* => 32 MB	*/ +		case AMD_ID_LV640U_2: +			if (addr[15] != AMD_ID_LV640U_3) { +				debug ("Chip: AMLV640U -> unknown\n"); +				info->flash_id = FLASH_UNKNOWN; +			} else { +				debug ("Chip: AMLV640U\n"); +				info->flash_id += FLASH_AMLV640U; +				info->sector_count = 128; +				info->size = 0x01000000; +			} +			break;				/* => 16 MB	*/ +		case AMD_ID_LV320B_2: +			if (addr[15] != AMD_ID_LV320B_3) { +				debug ("Chip: AMLV320B -> unknown\n"); +				info->flash_id = FLASH_UNKNOWN; +			} else { +				debug ("Chip: AMLV320B\n"); +				info->flash_id += FLASH_AMLV320B; +				info->sector_count = 71; +				info->size = 0x00800000; +			} +			break;				/* =>  8 MB	*/ +		default: +			debug ("Chip: *** unknown ***\n"); +			info->flash_id = FLASH_UNKNOWN; +			break; +		} +		break; +# else	/* ! TQM8xxM */ +	case AMD_ID_LV400T: +		info->flash_id += FLASH_AM400T; +		info->sector_count = 11; +		info->size = 0x00100000; +		break;					/* => 1 MB		*/ + +	case AMD_ID_LV400B: +		info->flash_id += FLASH_AM400B; +		info->sector_count = 11; +		info->size = 0x00100000; +		break;					/* => 1 MB		*/ + +	case AMD_ID_LV800T: +		info->flash_id += FLASH_AM800T; +		info->sector_count = 19; +		info->size = 0x00200000; +		break;					/* => 2 MB	*/ + +	case AMD_ID_LV800B: +		info->flash_id += FLASH_AM800B; +		info->sector_count = 19; +		info->size = 0x00200000; +		break;					/* => 2 MB	*/ + +	case AMD_ID_LV320T: +		info->flash_id += FLASH_AM320T; +		info->sector_count = 71; +		info->size = 0x00800000; +		break;					/* => 8 MB	*/ + +	case AMD_ID_LV320B: +		info->flash_id += FLASH_AM320B; +		info->sector_count = 71; +		info->size = 0x00800000; +		break;					/* => 8 MB	*/ +#endif	/* TQM8xxM */ + +	case AMD_ID_LV160T: +		info->flash_id += FLASH_AM160T; +		info->sector_count = 35; +		info->size = 0x00400000; +		break;					/* => 4 MB	*/ + +	case AMD_ID_LV160B: +		info->flash_id += FLASH_AM160B; +		info->sector_count = 35; +		info->size = 0x00400000; +		break;					/* => 4 MB	*/ + +	case AMD_ID_DL163B: +		info->flash_id += FLASH_AMDL163B; +		info->sector_count = 39; +		info->size = 0x00400000; +		break;					/* => 4 MB	*/ + +	default: +		info->flash_id = FLASH_UNKNOWN; +		return (0);			/* => no or unknown flash */ +	} + +	/* set up sector start address table */ +	switch (value) { +#ifdef CONFIG_TQM8xxM	/* mirror bit flash */ +	case AMD_ID_MIRROR: +		switch (info->flash_id & FLASH_TYPEMASK) { +			/* only known types here - no default */ +		case FLASH_AMLV128U: +		case FLASH_AMLV640U: +		case FLASH_AMLV320U: +			for (i = 0; i < info->sector_count; i++) { +				info->start[i] = base; +				base += 0x20000; +			} +			break; +		case FLASH_AMLV320B: +			for (i = 0; i < info->sector_count; i++) { +				info->start[i] = base; +				/* +				 * The first 8 sectors are 8 kB, +				 * all the other ones  are 64 kB +				 */ +				base += (i < 8) +					?  2 * ( 8 << 10) +					:  2 * (64 << 10); +			} +			break; +		} +		break; +# else	/* ! TQM8xxM */ +	case AMD_ID_LV400B: +	case AMD_ID_LV800B: +		/* set sector offsets for bottom boot block type	*/ +		info->start[0] = base + 0x00000000; +		info->start[1] = base + 0x00008000; +		info->start[2] = base + 0x0000C000; +		info->start[3] = base + 0x00010000; +		for (i = 4; i < info->sector_count; i++) { +			info->start[i] = base + (i * 0x00020000) - 0x00060000; +		} +		break; +	case AMD_ID_LV400T: +	case AMD_ID_LV800T: +		/* set sector offsets for top boot block type		*/ +		i = info->sector_count - 1; +		info->start[i--] = base + info->size - 0x00008000; +		info->start[i--] = base + info->size - 0x0000C000; +		info->start[i--] = base + info->size - 0x00010000; +		for (; i >= 0; i--) { +			info->start[i] = base + i * 0x00020000; +		} +		break; +	case AMD_ID_LV320B: +		for (i = 0; i < info->sector_count; i++) { +			info->start[i] = base; +			/* +			 * The first 8 sectors are 8 kB, +			 * all the other ones  are 64 kB +			 */ +			base += (i < 8) +				?  2 * ( 8 << 10) +				:  2 * (64 << 10); +		} +		break; +	case AMD_ID_LV320T: +		for (i = 0; i < info->sector_count; i++) { +			info->start[i] = base; +			/* +			 * The last 8 sectors are 8 kB, +			 * all the other ones  are 64 kB +			 */ +			base += (i < (info->sector_count - 8)) +				?  2 * (64 << 10) +				:  2 * ( 8 << 10); +		} +		break; +#endif	/* TQM8xxM */ +	case AMD_ID_LV160B: +		/* set sector offsets for bottom boot block type	*/ +		info->start[0] = base + 0x00000000; +		info->start[1] = base + 0x00008000; +		info->start[2] = base + 0x0000C000; +		info->start[3] = base + 0x00010000; +		for (i = 4; i < info->sector_count; i++) { +			info->start[i] = base + (i * 0x00020000) - 0x00060000; +		} +		break; +	case AMD_ID_LV160T: +		/* set sector offsets for top boot block type		*/ +		i = info->sector_count - 1; +		info->start[i--] = base + info->size - 0x00008000; +		info->start[i--] = base + info->size - 0x0000C000; +		info->start[i--] = base + info->size - 0x00010000; +		for (; i >= 0; i--) { +			info->start[i] = base + i * 0x00020000; +		} +		break; +	case AMD_ID_DL163B: +		for (i = 0; i < info->sector_count; i++) { +			info->start[i] = base; +			/* +			 * The first 8 sectors are 8 kB, +			 * all the other ones  are 64 kB +			 */ +			base += (i < 8) +				?  2 * ( 8 << 10) +				:  2 * (64 << 10); +		} +		break; +	default: +		return (0); +		break; +	} + +#if 0 +	/* check for protected sectors */ +	for (i = 0; i < info->sector_count; i++) { +		/* read sector protection at sector address, (A7 .. A0) = 0x02 */ +		/* D0 = 1 if protected */ +		addr = (volatile unsigned long *)(info->start[i]); +		info->protect[i] = addr[2] & 1; +	} +#endif + +	/* +	 * Prevent writes to uninitialized FLASH. +	 */ +	if (info->flash_id != FLASH_UNKNOWN) { +		addr = (volatile unsigned long *)info->start[0]; + +		*addr = 0x00F000F0;	/* reset bank */ +	} + +	return (info->size); +} + + +/*----------------------------------------------------------------------- + */ + +int	flash_erase (flash_info_t *info, int s_first, int s_last) +{ +	vu_long *addr = (vu_long*)(info->start[0]); +	int flag, prot, sect, l_sect; +	ulong start, now, last; + +	debug ("flash_erase: first: %d last: %d\n", s_first, s_last); + +	if ((s_first < 0) || (s_first > s_last)) { +		if (info->flash_id == FLASH_UNKNOWN) { +			printf ("- missing\n"); +		} else { +			printf ("- no sectors to erase\n"); +		} +		return 1; +	} + +	if ((info->flash_id == FLASH_UNKNOWN) || +	    (info->flash_id > FLASH_AMD_COMP)) { +		printf ("Can't erase unknown flash type %08lx - aborted\n", +			info->flash_id); +		return 1; +	} + +	prot = 0; +	for (sect=s_first; sect<=s_last; ++sect) { +		if (info->protect[sect]) { +			prot++; +		} +	} + +	if (prot) { +		printf ("- Warning: %d protected sectors will not be erased!\n", +			prot); +	} else { +		printf ("\n"); +	} + +	l_sect = -1; + +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts(); + +	addr[0x0555] = 0x00AA00AA; +	addr[0x02AA] = 0x00550055; +	addr[0x0555] = 0x00800080; +	addr[0x0555] = 0x00AA00AA; +	addr[0x02AA] = 0x00550055; + +	/* Start erase on unprotected sectors */ +	for (sect = s_first; sect<=s_last; sect++) { +		if (info->protect[sect] == 0) {	/* not protected */ +			addr = (vu_long*)(info->start[sect]); +			addr[0] = 0x00300030; +			l_sect = sect; +		} +	} + +	/* re-enable interrupts if necessary */ +	if (flag) +		enable_interrupts(); + +	/* wait at least 80us - let's wait 1 ms */ +	udelay (1000); + +	/* +	 * We wait for the last triggered sector +	 */ +	if (l_sect < 0) +		goto DONE; + +	start = get_timer (0); +	last  = start; +	addr = (vu_long*)(info->start[l_sect]); +	while ((addr[0] & 0x00800080) != 0x00800080) { +		if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { +			printf ("Timeout\n"); +			return 1; +		} +		/* show that we're waiting */ +		if ((now - last) > 1000) {	/* every second */ +			putc ('.'); +			last = now; +		} +	} + +DONE: +	/* reset to read mode */ +	addr = (volatile unsigned long *)info->start[0]; +	addr[0] = 0x00F000F0;	/* reset bank */ + +	printf (" done\n"); +	return 0; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ + +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ +	ulong cp, wp, data; +	int i, l, rc; + +	wp = (addr & ~3);	/* get lower word aligned address */ + +	/* +	 * handle unaligned start bytes +	 */ +	if ((l = addr - wp) != 0) { +		data = 0; +		for (i=0, cp=wp; i<l; ++i, ++cp) { +			data = (data << 8) | (*(uchar *)cp); +		} +		for (; i<4 && cnt>0; ++i) { +			data = (data << 8) | *src++; +			--cnt; +			++cp; +		} +		for (; cnt==0 && i<4; ++i, ++cp) { +			data = (data << 8) | (*(uchar *)cp); +		} + +		if ((rc = write_word(info, wp, data)) != 0) { +			return (rc); +		} +		wp += 4; +	} + +	/* +	 * handle word aligned part +	 */ +	while (cnt >= 4) { +		data = 0; +		for (i=0; i<4; ++i) { +			data = (data << 8) | *src++; +		} +		if ((rc = write_word(info, wp, data)) != 0) { +			return (rc); +		} +		wp  += 4; +		cnt -= 4; +	} + +	if (cnt == 0) { +		return (0); +	} + +	/* +	 * handle unaligned tail bytes +	 */ +	data = 0; +	for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { +		data = (data << 8) | *src++; +		--cnt; +	} +	for (; i<4; ++i, ++cp) { +		data = (data << 8) | (*(uchar *)cp); +	} + +	return (write_word(info, wp, data)); +} + +/*----------------------------------------------------------------------- + * Write a word to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_word (flash_info_t *info, ulong dest, ulong data) +{ +	vu_long *addr = (vu_long*)(info->start[0]); +	ulong start; +	int flag; + +	/* Check if Flash is (sufficiently) erased */ +	if ((*((vu_long *)dest) & data) != data) { +		return (2); +	} +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts(); + +	addr[0x0555] = 0x00AA00AA; +	addr[0x02AA] = 0x00550055; +	addr[0x0555] = 0x00A000A0; + +	*((vu_long *)dest) = data; + +	/* re-enable interrupts if necessary */ +	if (flag) +		enable_interrupts(); + +	/* data polling for D7 */ +	start = get_timer (0); +	while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) { +		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { +			return (1); +		} +	} +	return (0); +} + +/*----------------------------------------------------------------------- + */ + +#endif /* !defined(CFG_FLASH_CFI_DRIVER) */ diff --git a/board/tqc/tqm8xx/load_sernum_ethaddr.c b/board/tqc/tqm8xx/load_sernum_ethaddr.c new file mode 100644 index 000000000..143f36801 --- /dev/null +++ b/board/tqc/tqm8xx/load_sernum_ethaddr.c @@ -0,0 +1,105 @@ +/* + * (C) Copyright 2000, 2001, 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> +#include <mpc8xx.h> + +/*----------------------------------------------------------------------- + * Process Hardware Information Block: + * + * If we boot on a system fresh from factory, check if the Hardware + * Information Block exists and save the information it contains. + * + * The TQM8xxL / TQM82xx Hardware Information Block is defined as + * follows: + * - located in first flash bank + * - starts at offset 0x0003FFC0 + * - size 0x00000040 + * + * Internal structure: + * - sequence of ASCII character strings + * - fields separated by a single space character (0x20) + * - last field terminated by NUL character (0x00) + * - remaining space filled with NUL characters (0x00) + * + * Fields in Hardware Information Block: + * 1) Module Type + * 2) Serial Number + * 3) First MAC Address + * 4) Number of additional MAC addresses + */ + +void load_sernum_ethaddr (void) +{ +	unsigned char *hwi; +	unsigned char  serial [CFG_HWINFO_SIZE]; +	unsigned char  ethaddr[CFG_HWINFO_SIZE]; +	unsigned short ih, is, ie, part; + +	hwi = (unsigned char *)(CFG_FLASH_BASE + CFG_HWINFO_OFFSET); +	ih = is = ie = 0; + +	if (*((unsigned long *)hwi) != (unsigned long)CFG_HWINFO_MAGIC) { +		return; +	} + +	part = 1; + +	/* copy serial # / MAC address */ +	while ((hwi[ih] != '\0') && (ih < CFG_HWINFO_SIZE)) { +		if (hwi[ih] < ' ' || hwi[ih] > '~') { /* ASCII strings! */ +			return; +		} +		switch (part) { +		default:		/* Copy serial # */ +			if (hwi[ih] == ' ') { +				++part; +			} +			serial[is++] = hwi[ih]; +			break; +		case 3:			/* Copy MAC address */ +			if (hwi[ih] == ' ') { +				++part; +				break; +			} +			ethaddr[ie++] = hwi[ih]; +			if ((ie % 3) == 2) +				ethaddr[ie++] = ':'; +			break; +		} +		++ih; +	} +	serial[is]  = '\0'; +	if (ie && ethaddr[ie-1] == ':') +		--ie; +	ethaddr[ie] = '\0'; + +	/* set serial# and ethaddr if not yet defined */ +	if (getenv("serial#") == NULL) { +		setenv ((char *)"serial#", (char *)serial); +	} + +	if (getenv("ethaddr") == NULL) { +		setenv ((char *)"ethaddr", (char *)ethaddr); +	} +} diff --git a/board/tqc/tqm8xx/tqm8xx.c b/board/tqc/tqm8xx/tqm8xx.c new file mode 100644 index 000000000..18bf2a830 --- /dev/null +++ b/board/tqc/tqm8xx/tqm8xx.c @@ -0,0 +1,554 @@ +/* + * (C) Copyright 2000-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 + */ + +#if 0 +#define DEBUG +#endif + +#include <common.h> +#include <mpc8xx.h> +#ifdef CONFIG_PS2MULT +#include <ps2mult.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +static long int dram_size (long int, long int *, long int); + +#define	_NOT_USED_	0xFFFFFFFF + +/* UPM initialization table for SDRAM: 40, 50, 66 MHz CLKOUT @ CAS latency 2, tWR=2 */ +const uint sdram_table[] = +{ +	/* +	 * Single Read. (Offset 0 in UPMA RAM) +	 */ +	0x1F0DFC04, 0xEEAFBC04, 0x11AF7C04, 0xEFBAFC00, +	0x1FF5FC47, /* last */ +	/* +	 * SDRAM Initialization (offset 5 in UPMA RAM) +	 * +	 * This is no UPM entry point. The following definition uses +	 * the remaining space to establish an initialization +	 * sequence, which is executed by a RUN command. +	 * +	 */ +		    0x1FF5FC34, 0xEFEABC34, 0x1FB57C35, /* last */ +	/* +	 * Burst Read. (Offset 8 in UPMA RAM) +	 */ +	0x1F0DFC04, 0xEEAFBC04, 0x10AF7C04, 0xF0AFFC00, +	0xF0AFFC00, 0xF1AFFC00, 0xEFBAFC00, 0x1FF5FC47, /* last */ +	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, +	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, +	/* +	 * Single Write. (Offset 18 in UPMA RAM) +	 */ +	0x1F0DFC04, 0xEEABBC00, 0x11B77C04, 0xEFFAFC44, +	0x1FF5FC47, /* last */ +		    _NOT_USED_, _NOT_USED_, _NOT_USED_, +	/* +	 * Burst Write. (Offset 20 in UPMA RAM) +	 */ +	0x1F0DFC04, 0xEEABBC00, 0x10A77C00, 0xF0AFFC00, +	0xF0AFFC00, 0xF0AFFC04, 0xE1BAFC44, 0x1FF5FC47, /* last */ +	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, +	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, +	/* +	 * Refresh  (Offset 30 in UPMA RAM) +	 */ +	0x1FFD7C84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, +	0xFFFFFC84, 0xFFFFFC07, /* last */ +				_NOT_USED_, _NOT_USED_, +	_NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, +	/* +	 * Exception. (Offset 3c in UPMA RAM) +	 */ +	0xFFFFFC07, /* last */ +		    _NOT_USED_, _NOT_USED_, _NOT_USED_, +}; + +/* ------------------------------------------------------------------------- */ + + +/* + * Check Board Identity: + * + * Test TQ ID string (TQM8xx...) + * If present, check for "L" type (no second DRAM bank), + * otherwise "L" type is assumed as default. + * + * Set board_type to 'L' for "L" type, 'M' for "M" type, 0 else. + */ + +int checkboard (void) +{ +	char *s = getenv ("serial#"); + +	puts ("Board: "); + +	if (!s || strncmp (s, "TQM8", 4)) { +		puts ("### No HW ID - assuming TQM8xxL\n"); +		return (0); +	} + +	if ((*(s + 6) == 'L')) {	/* a TQM8xxL type */ +		gd->board_type = 'L'; +	} + +	if ((*(s + 6) == 'M')) {	/* a TQM8xxM type */ +		gd->board_type = 'M'; +	} + +	if ((*(s + 6) == 'D')) {	/* a TQM885D type */ +		gd->board_type = 'D'; +	} + +	for (; *s; ++s) { +		if (*s == ' ') +			break; +		putc (*s); +	} +#ifdef CONFIG_VIRTLAB2 +	puts (" (Virtlab2)"); +#endif +	putc ('\n'); + +	return (0); +} + +/* ------------------------------------------------------------------------- */ + +long int initdram (int board_type) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile memctl8xx_t *memctl = &immap->im_memctl; +	long int size8, size9, size10; +	long int size_b0 = 0; +	long int size_b1 = 0; + +	upmconfig (UPMA, (uint *) sdram_table, +			   sizeof (sdram_table) / sizeof (uint)); + +	/* +	 * Preliminary prescaler for refresh (depends on number of +	 * banks): This value is selected for four cycles every 62.4 us +	 * with two SDRAM banks or four cycles every 31.2 us with one +	 * bank. It will be adjusted after memory sizing. +	 */ +	memctl->memc_mptpr = CFG_MPTPR_2BK_8K; + +	/* +	 * The following value is used as an address (i.e. opcode) for +	 * the LOAD MODE REGISTER COMMAND during SDRAM initialisation. If +	 * the port size is 32bit the SDRAM does NOT "see" the lower two +	 * address lines, i.e. mar=0x00000088 -> opcode=0x00000022 for +	 * MICRON SDRAMs: +	 * ->    0 00 010 0 010 +	 *       |  |   | |   +- Burst Length = 4 +	 *       |  |   | +----- Burst Type   = Sequential +	 *       |  |   +------- CAS Latency  = 2 +	 *       |  +----------- Operating Mode = Standard +	 *       +-------------- Write Burst Mode = Programmed Burst Length +	 */ +	memctl->memc_mar = 0x00000088; + +	/* +	 * Map controller banks 2 and 3 to the SDRAM banks 2 and 3 at +	 * preliminary addresses - these have to be modified after the +	 * SDRAM size has been determined. +	 */ +	memctl->memc_or2 = CFG_OR2_PRELIM; +	memctl->memc_br2 = CFG_BR2_PRELIM; + +#ifndef	CONFIG_CAN_DRIVER +	if ((board_type != 'L') && +	    (board_type != 'M') && +	    (board_type != 'D') ) {	/* only one SDRAM bank on L, M and D modules */ +		memctl->memc_or3 = CFG_OR3_PRELIM; +		memctl->memc_br3 = CFG_BR3_PRELIM; +	} +#endif							/* CONFIG_CAN_DRIVER */ + +	memctl->memc_mamr = CFG_MAMR_8COL & (~(MAMR_PTAE));	/* no refresh yet */ + +	udelay (200); + +	/* perform SDRAM initializsation sequence */ + +	memctl->memc_mcr = 0x80004105;	/* SDRAM bank 0 */ +	udelay (1); +	memctl->memc_mcr = 0x80004230;	/* SDRAM bank 0 - execute twice */ +	udelay (1); + +#ifndef	CONFIG_CAN_DRIVER +	if ((board_type != 'L') && +	    (board_type != 'M') && +	    (board_type != 'D') ) {	/* only one SDRAM bank on L, M and D modules */ +		memctl->memc_mcr = 0x80006105;	/* SDRAM bank 1 */ +		udelay (1); +		memctl->memc_mcr = 0x80006230;	/* SDRAM bank 1 - execute twice */ +		udelay (1); +	} +#endif							/* CONFIG_CAN_DRIVER */ + +	memctl->memc_mamr |= MAMR_PTAE;	/* enable refresh */ + +	udelay (1000); + +	/* +	 * Check Bank 0 Memory Size for re-configuration +	 * +	 * try 8 column mode +	 */ +	size8 = dram_size (CFG_MAMR_8COL, SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE); +	debug ("SDRAM Bank 0 in 8 column mode: %ld MB\n", size8 >> 20); + +	udelay (1000); + +	/* +	 * try 9 column mode +	 */ +	size9 = dram_size (CFG_MAMR_9COL, SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE); +	debug ("SDRAM Bank 0 in 9 column mode: %ld MB\n", size9 >> 20); + +	udelay(1000); + +#if defined(CFG_MAMR_10COL) +	/* +	 * try 10 column mode +	 */ +	size10 = dram_size (CFG_MAMR_10COL, SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE); +	debug ("SDRAM Bank 0 in 10 column mode: %ld MB\n", size10 >> 20); +#else +	size10 = 0; +#endif /* CFG_MAMR_10COL */ + +	if ((size8 < size10) && (size9 < size10)) { +		size_b0 = size10; +	} else if ((size8 < size9) && (size10 < size9)) { +		size_b0 = size9; +		memctl->memc_mamr = CFG_MAMR_9COL; +		udelay (500); +	} else { +		size_b0 = size8; +		memctl->memc_mamr = CFG_MAMR_8COL; +		udelay (500); +	} +	debug ("SDRAM Bank 0: %ld MB\n", size_b0 >> 20); + +#ifndef	CONFIG_CAN_DRIVER +	if ((board_type != 'L') && +	    (board_type != 'M') && +	    (board_type != 'D') ) {	/* only one SDRAM bank on L, M and D modules */ +		/* +		 * Check Bank 1 Memory Size +		 * use current column settings +		 * [9 column SDRAM may also be used in 8 column mode, +		 *  but then only half the real size will be used.] +		 */ +		size_b1 = dram_size (memctl->memc_mamr, (long int *)SDRAM_BASE3_PRELIM, +				     SDRAM_MAX_SIZE); +		debug ("SDRAM Bank 1: %ld MB\n", size_b1 >> 20); +	} else { +		size_b1 = 0; +	} +#endif	/* CONFIG_CAN_DRIVER */ + +	udelay (1000); + +	/* +	 * Adjust refresh rate depending on SDRAM type, both banks +	 * For types > 128 MBit leave it at the current (fast) rate +	 */ +	if ((size_b0 < 0x02000000) && (size_b1 < 0x02000000)) { +		/* reduce to 15.6 us (62.4 us / quad) */ +		memctl->memc_mptpr = CFG_MPTPR_2BK_4K; +		udelay (1000); +	} + +	/* +	 * Final mapping: map bigger bank first +	 */ +	if (size_b1 > size_b0) {	/* SDRAM Bank 1 is bigger - map first   */ + +		memctl->memc_or3 = ((-size_b1) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM; +		memctl->memc_br3 = (CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V; + +		if (size_b0 > 0) { +			/* +			 * Position Bank 0 immediately above Bank 1 +			 */ +			memctl->memc_or2 = ((-size_b0) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM; +			memctl->memc_br2 = ((CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V) +					   + size_b1; +		} else { +			unsigned long reg; + +			/* +			 * No bank 0 +			 * +			 * invalidate bank +			 */ +			memctl->memc_br2 = 0; + +			/* adjust refresh rate depending on SDRAM type, one bank */ +			reg = memctl->memc_mptpr; +			reg >>= 1;			/* reduce to CFG_MPTPR_1BK_8K / _4K */ +			memctl->memc_mptpr = reg; +		} + +	} else {					/* SDRAM Bank 0 is bigger - map first   */ + +		memctl->memc_or2 = ((-size_b0) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM; +		memctl->memc_br2 = +				(CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V; + +		if (size_b1 > 0) { +			/* +			 * Position Bank 1 immediately above Bank 0 +			 */ +			memctl->memc_or3 = +					((-size_b1) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM; +			memctl->memc_br3 = +					((CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V) +					+ size_b0; +		} else { +			unsigned long reg; + +#ifndef	CONFIG_CAN_DRIVER +			/* +			 * No bank 1 +			 * +			 * invalidate bank +			 */ +			memctl->memc_br3 = 0; +#endif							/* CONFIG_CAN_DRIVER */ + +			/* adjust refresh rate depending on SDRAM type, one bank */ +			reg = memctl->memc_mptpr; +			reg >>= 1;			/* reduce to CFG_MPTPR_1BK_8K / _4K */ +			memctl->memc_mptpr = reg; +		} +	} + +	udelay (10000); + +#ifdef	CONFIG_CAN_DRIVER +	/* UPM initialization for CAN @ CLKOUT <= 66 MHz */ + +	/* Initialize OR3 / BR3 */ +	memctl->memc_or3 = CFG_OR3_CAN; +	memctl->memc_br3 = CFG_BR3_CAN; + +	/* Initialize MBMR */ +	memctl->memc_mbmr = MBMR_GPL_B4DIS;	/* GPL_B4 ouput line Disable */ + +	/* Initialize UPMB for CAN: single read */ +	memctl->memc_mdr = 0xFFFFCC04; +	memctl->memc_mcr = 0x0100 | UPMB; + +	memctl->memc_mdr = 0x0FFFD004; +	memctl->memc_mcr = 0x0101 | UPMB; + +	memctl->memc_mdr = 0x0FFFC000; +	memctl->memc_mcr = 0x0102 | UPMB; + +	memctl->memc_mdr = 0x3FFFC004; +	memctl->memc_mcr = 0x0103 | UPMB; + +	memctl->memc_mdr = 0xFFFFDC07; +	memctl->memc_mcr = 0x0104 | UPMB; + +	/* Initialize UPMB for CAN: single write */ +	memctl->memc_mdr = 0xFFFCCC04; +	memctl->memc_mcr = 0x0118 | UPMB; + +	memctl->memc_mdr = 0xCFFCDC04; +	memctl->memc_mcr = 0x0119 | UPMB; + +	memctl->memc_mdr = 0x3FFCC000; +	memctl->memc_mcr = 0x011A | UPMB; + +	memctl->memc_mdr = 0xFFFCC004; +	memctl->memc_mcr = 0x011B | UPMB; + +	memctl->memc_mdr = 0xFFFDC405; +	memctl->memc_mcr = 0x011C | UPMB; +#endif							/* CONFIG_CAN_DRIVER */ + +#ifdef	CONFIG_ISP1362_USB +	/* Initialize OR5 / BR5 */ +	memctl->memc_or5 = CFG_OR5_ISP1362; +	memctl->memc_br5 = CFG_BR5_ISP1362; +#endif							/* CONFIG_ISP1362_USB */ + + +	return (size_b0 + size_b1); +} + +/* ------------------------------------------------------------------------- */ + +/* + * Check memory range for valid RAM. A simple memory test determines + * the actually available RAM size between addresses `base' and + * `base + maxsize'. Some (not all) hardware errors are detected: + * - short between address lines + * - short between data lines + */ + +static long int dram_size (long int mamr_value, long int *base, long int maxsize) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; +	volatile memctl8xx_t *memctl = &immap->im_memctl; + +	memctl->memc_mamr = mamr_value; + +	return (get_ram_size(base, maxsize)); +} + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_PS2MULT + +#ifdef CONFIG_HMI10 +#define BASE_BAUD ( 1843200 / 16 ) +struct serial_state rs_table[] = { +	{ BASE_BAUD, 4,  (void*)0xec140000 }, +	{ BASE_BAUD, 2,  (void*)0xec150000 }, +	{ BASE_BAUD, 6,  (void*)0xec160000 }, +	{ BASE_BAUD, 10, (void*)0xec170000 }, +}; + +#ifdef CONFIG_BOARD_EARLY_INIT_R +int board_early_init_r (void) +{ +	ps2mult_early_init(); +	return (0); +} +#endif +#endif /* CONFIG_HMI10 */ + +#endif /* CONFIG_PS2MULT */ + +/* ---------------------------------------------------------------------------- */ +/* HMI10 specific stuff								*/ +/* ---------------------------------------------------------------------------- */ +#ifdef CONFIG_HMI10 + +int misc_init_r (void) +{ +# ifdef CONFIG_IDE_LED +	volatile immap_t *immap = (immap_t *) CFG_IMMR; + +	/* Configure PA15 as output port */ +	immap->im_ioport.iop_padir |= 0x0001; +	immap->im_ioport.iop_paodr |= 0x0001; +	immap->im_ioport.iop_papar &= ~0x0001; +	immap->im_ioport.iop_padat &= ~0x0001;	/* turn it off */ +# endif +	return (0); +} + +# ifdef CONFIG_IDE_LED +void ide_led (uchar led, uchar status) +{ +	volatile immap_t *immap = (immap_t *) CFG_IMMR; + +	/* We have one led for both pcmcia slots */ +	if (status) {				/* led on */ +		immap->im_ioport.iop_padat |= 0x0001; +	} else { +		immap->im_ioport.iop_padat &= ~0x0001; +	} +} +# endif +#endif	/* CONFIG_HMI10 */ + +/* ---------------------------------------------------------------------------- */ +/* NSCU specific stuff								*/ +/* ---------------------------------------------------------------------------- */ +#ifdef CONFIG_NSCU + +int misc_init_r (void) +{ +	volatile immap_t *immr = (immap_t *) CFG_IMMR; + +	/* wake up ethernet module */ +	immr->im_ioport.iop_pcpar &= ~0x0004; /* GPIO pin	*/ +	immr->im_ioport.iop_pcdir |=  0x0004; /* output		*/ +	immr->im_ioport.iop_pcso  &= ~0x0004; /* for clarity	*/ +	immr->im_ioport.iop_pcdat |=  0x0004; /* enable		*/ + +	return (0); +} +#endif	/* CONFIG_NSCU */ + +/* ---------------------------------------------------------------------------- */ +/* TK885D specific initializaion						*/ +/* ---------------------------------------------------------------------------- */ +#ifdef CONFIG_TK885D +#include <miiphy.h> +int last_stage_init(void) +{ +	const unsigned char phy[] = {CONFIG_FEC1_PHY, CONFIG_FEC2_PHY}; +	unsigned short reg; +	int ret, i = 100; +	char *s; + +	mii_init(); +	/* Without this delay 0xff is read from the UART buffer later in +	 * abortboot() and autoboot is aborted */ +	udelay(10000); +	while (tstc() && i--) +		(void)getc(); + +	/* Check if auto-negotiation is prohibited */ +	s = getenv("phy_auto_nego"); + +	if (!s || !strcmp(s, "on")) +		/* Nothing to do - autonegotiation by default */ +		return 0; + +	for (i = 0; i < 2; i++) { +		ret = miiphy_read("FEC ETHERNET", phy[i], PHY_BMCR, ®); +		if (ret) { +			printf("Cannot read BMCR on PHY %d\n", phy[i]); +			return 0; +		} +		/* Auto-negotiation off, hard set full duplex, 100Mbps */ +		ret = miiphy_write("FEC ETHERNET", phy[i], +				   PHY_BMCR, (reg | PHY_BMCR_100MB | +					      PHY_BMCR_DPLX) & ~PHY_BMCR_AUTON); +		if (ret) { +			printf("Cannot write BMCR on PHY %d\n", phy[i]); +			return 0; +		} +	} + +	return 0; +} + +#endif + +/* ------------------------------------------------------------------------- */ diff --git a/board/tqc/tqm8xx/u-boot.lds b/board/tqc/tqm8xx/u-boot.lds new file mode 100644 index 000000000..8c46e4677 --- /dev/null +++ b/board/tqc/tqm8xx/u-boot.lds @@ -0,0 +1,143 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +/* Do we need any of these for elf? +   __DYNAMIC = 0;    */ +SECTIONS +{ +  /* Read-only sections, merged into text segment: */ +  . = + SIZEOF_HEADERS; +  .interp : { *(.interp) } +  .hash          : { *(.hash)		} +  .dynsym        : { *(.dynsym)		} +  .dynstr        : { *(.dynstr)		} +  .rel.text      : { *(.rel.text)	} +  .rela.text     : { *(.rela.text)	} +  .rel.data      : { *(.rel.data)	} +  .rela.data     : { *(.rela.data)	} +  .rel.rodata    : { *(.rel.rodata)	} +  .rela.rodata   : { *(.rela.rodata)	} +  .rel.got       : { *(.rel.got)	} +  .rela.got      : { *(.rela.got)	} +  .rel.ctors     : { *(.rel.ctors)	} +  .rela.ctors    : { *(.rela.ctors)	} +  .rel.dtors     : { *(.rel.dtors)	} +  .rela.dtors    : { *(.rela.dtors)	} +  .rel.bss       : { *(.rel.bss)	} +  .rela.bss      : { *(.rela.bss)	} +  .rel.plt       : { *(.rel.plt)	} +  .rela.plt      : { *(.rela.plt)	} +  .init          : { *(.init)		} +  .plt : { *(.plt) } +  .text      : +  { +    /* WARNING - the following is hand-optimized to fit within	*/ +    /* the sector layout of our flash chips!	XXX FIXME XXX	*/ + +    cpu/mpc8xx/start.o		(.text) +    cpu/mpc8xx/traps.o		(.text) +    common/dlmalloc.o		(.text) +    lib_ppc/ppcstring.o		(.text) +    lib_generic/vsprintf.o	(.text) +    lib_generic/crc32.o		(.text) +    lib_generic/zlib.o		(.text) +    lib_ppc/cache.o		(.text) +    lib_ppc/time.o		(.text) + +    . = DEFINED(env_offset) ? env_offset : .; +    common/environment.o	(.ppcenv) + +    *(.text) +    *(.fixup) +    *(.got1) +  } +  _etext = .; +  PROVIDE (etext = .); +  .rodata    : +  { +    *(.rodata) +    *(.rodata1) +    *(.rodata.str1.4) +    *(.eh_frame) +  } +  .fini      : { *(.fini)    } =0 +  .ctors     : { *(.ctors)   } +  .dtors     : { *(.dtors)   } + +  /* Read-write section, merged into data segment: */ +  . = (. + 0x00FF) & 0xFFFFFF00; +  _erotext = .; +  PROVIDE (erotext = .); +  .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; +  __fixup_entries = (. - _FIXUP_TABLE_)>>2; + +  .data    : +  { +    *(.data) +    *(.data1) +    *(.sdata) +    *(.sdata2) +    *(.dynamic) +    CONSTRUCTORS +  } +  _edata  =  .; +  PROVIDE (edata = .); + +  . = .; +  __u_boot_cmd_start = .; +  .u_boot_cmd : { *(.u_boot_cmd) } +  __u_boot_cmd_end = .; + + +  . = .; +  __start___ex_table = .; +  __ex_table : { *(__ex_table) } +  __stop___ex_table = .; + +  . = ALIGN(256); +  __init_begin = .; +  .text.init : { *(.text.init) } +  .data.init : { *(.data.init) } +  . = ALIGN(256); +  __init_end = .; + +  __bss_start = .; +  .bss (NOLOAD)       : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +  } +  _end = . ; +  PROVIDE (end = .); +} diff --git a/board/tqc/tqm8xx/u-boot.lds.debug b/board/tqc/tqm8xx/u-boot.lds.debug new file mode 100644 index 000000000..c33581d25 --- /dev/null +++ b/board/tqc/tqm8xx/u-boot.lds.debug @@ -0,0 +1,136 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +/* Do we need any of these for elf? +   __DYNAMIC = 0;    */ +SECTIONS +{ +  /* Read-only sections, merged into text segment: */ +  . = + SIZEOF_HEADERS; +  .interp : { *(.interp) } +  .hash          : { *(.hash)		} +  .dynsym        : { *(.dynsym)		} +  .dynstr        : { *(.dynstr)		} +  .rel.text      : { *(.rel.text)		} +  .rela.text     : { *(.rela.text)	} +  .rel.data      : { *(.rel.data)		} +  .rela.data     : { *(.rela.data)	} +  .rel.rodata    : { *(.rel.rodata)	} +  .rela.rodata   : { *(.rela.rodata)	} +  .rel.got       : { *(.rel.got)		} +  .rela.got      : { *(.rela.got)		} +  .rel.ctors     : { *(.rel.ctors)	} +  .rela.ctors    : { *(.rela.ctors)	} +  .rel.dtors     : { *(.rel.dtors)	} +  .rela.dtors    : { *(.rela.dtors)	} +  .rel.bss       : { *(.rel.bss)		} +  .rela.bss      : { *(.rela.bss)		} +  .rel.plt       : { *(.rel.plt)		} +  .rela.plt      : { *(.rela.plt)		} +  .init          : { *(.init)	} +  .plt : { *(.plt) } +  .text      : +  { +    /* WARNING - the following is hand-optimized to fit within	*/ +    /* the sector layout of our flash chips!	XXX FIXME XXX	*/ + +    cpu/mpc8xx/start.o	(.text) +    common/dlmalloc.o	(.text) +    lib_generic/vsprintf.o	(.text) +    lib_generic/crc32.o		(.text) + +    . = env_offset; +    common/environment.o(.text) + +    *(.text) +    *(.fixup) +    *(.got1) +  } +  _etext = .; +  PROVIDE (etext = .); +  .rodata    : +  { +    *(.rodata) +    *(.rodata1) +    *(.rodata.str1.4) +    *(.eh_frame) +  } +  .fini      : { *(.fini)    } =0 +  .ctors     : { *(.ctors)   } +  .dtors     : { *(.dtors)   } + +  /* Read-write section, merged into data segment: */ +  . = (. + 0x0FFF) & 0xFFFFF000; +  _erotext = .; +  PROVIDE (erotext = .); +  .reloc   : +  { +    *(.got) +    _GOT2_TABLE_ = .; +    *(.got2) +    _FIXUP_TABLE_ = .; +    *(.fixup) +  } +  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; +  __fixup_entries = (. - _FIXUP_TABLE_)>>2; + +  .data    : +  { +    *(.data) +    *(.data1) +    *(.sdata) +    *(.sdata2) +    *(.dynamic) +    CONSTRUCTORS +  } +  _edata  =  .; +  PROVIDE (edata = .); + +  __u_boot_cmd_start = .; +  .u_boot_cmd : { *(.u_boot_cmd) } +  __u_boot_cmd_end = .; + + +  __start___ex_table = .; +  __ex_table : { *(__ex_table) } +  __stop___ex_table = .; + +  . = ALIGN(4096); +  __init_begin = .; +  .text.init : { *(.text.init) } +  .data.init : { *(.data.init) } +  . = ALIGN(4096); +  __init_end = .; + +  __bss_start = .; +  .bss       : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +  } +  _end = . ; +  PROVIDE (end = .); +} |