diff options
author | Kevin | 2014-11-15 11:48:36 +0800 |
---|---|---|
committer | Kevin | 2014-11-15 11:48:36 +0800 |
commit | d04075478d378d9e15f3e1abfd14b0bd124077d4 (patch) | |
tree | 733dd964582f388b9e3e367c249946cd32a2851f /board/trab | |
download | FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.tar.gz FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.tar.bz2 FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.zip |
init commit via android 4.4 uboot
Diffstat (limited to 'board/trab')
-rwxr-xr-x | board/trab/Makefile | 65 | ||||
-rwxr-xr-x | board/trab/Pt1000_temp_data.h | 71 | ||||
-rwxr-xr-x | board/trab/README.kbd | 44 | ||||
-rwxr-xr-x | board/trab/auto_update.c | 656 | ||||
-rwxr-xr-x | board/trab/cmd_trab.c | 895 | ||||
-rwxr-xr-x | board/trab/config.mk | 26 | ||||
-rwxr-xr-x | board/trab/flash.c | 568 | ||||
-rwxr-xr-x | board/trab/lowlevel_init.S | 182 | ||||
-rwxr-xr-x | board/trab/memory.c | 485 | ||||
-rwxr-xr-x | board/trab/rs485.c | 203 | ||||
-rwxr-xr-x | board/trab/rs485.h | 37 | ||||
-rwxr-xr-x | board/trab/trab.c | 412 | ||||
-rwxr-xr-x | board/trab/trab_fkt.c | 1411 | ||||
-rwxr-xr-x | board/trab/tsc2000.c | 362 | ||||
-rwxr-xr-x | board/trab/tsc2000.h | 145 | ||||
-rwxr-xr-x | board/trab/u-boot.lds | 65 | ||||
-rwxr-xr-x | board/trab/vfd.c | 571 |
17 files changed, 6198 insertions, 0 deletions
diff --git a/board/trab/Makefile b/board/trab/Makefile new file mode 100755 index 0000000..ced9bc5 --- /dev/null +++ b/board/trab/Makefile @@ -0,0 +1,65 @@ +# +# (C) Copyright 2000-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 $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +OBJS := trab.o flash.o vfd.o cmd_trab.o memory.o tsc2000.o auto_update.o +SOBJS := lowlevel_init.o + +gcclibdir := $(shell dirname `$(CC) -print-libgcc-file-name`) + +LOAD_ADDR = 0xc100000 + +######################################################################### + +all: $(LIB) trab_fkt.srec trab_fkt.bin + +$(LIB): $(OBJS) $(SOBJS) + $(AR) crv $@ $(OBJS) $(SOBJS) + +trab_fkt.srec: trab_fkt.o rs485.o tsc2000.o $(LIB) + $(LD) -g -Ttext $(LOAD_ADDR) -o $(<:.o=) -e $(<:.o=) $^ $(LIB) \ + -L../../examples -lstubs \ + -L../../lib_generic -lgeneric \ + -L$(gcclibdir) -lgcc + $(OBJCOPY) -O srec $(<:.o=) $@ + +trab_fkt.bin: trab_fkt.srec + $(OBJCOPY) -O binary $< $@ 2>/dev/null + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +-include .depend + +######################################################################### diff --git a/board/trab/Pt1000_temp_data.h b/board/trab/Pt1000_temp_data.h new file mode 100755 index 0000000..17e9ed7 --- /dev/null +++ b/board/trab/Pt1000_temp_data.h @@ -0,0 +1,71 @@ +/* + * Data file for tsc2000 driver. + * Copyright (C) 2002, 2003 DENX Software Engineering, Wolfgang Denk, wd@denx.de + */ + +#ifndef _PT1000_TEMP_DATA_H +#define _PT1000_TEMP_DATA_H + +long Pt1000_temp_table[][2] = { + /* For quick range checking the largest element + * is placed at index 0. + * U, nV T, C*100 + */ + { 44000000 , 12165 }, + { -10000000 , -2644 }, + { -9000000 , -2381 }, + { -8000000 , -2118 }, + { -7000000 , -1855 }, + { -6000000 , -1591 }, + { -5000000 , -1327 }, + { -4000000 , -1063 }, + { -3000000 , -798 }, + { -2000000 , -532 }, + { -1000000 , -266 }, + { 0 , 000 }, + { 1000000 , 267 }, + { 2000000 , 534 }, + { 3000000 , 802 }, + { 4000000 , 1070 }, + { 5000000 , 1338 }, + { 6000000 , 1607 }, + { 7000000 , 1876 }, + { 8000000 , 2146 }, + { 9000000 , 2416 }, + { 10000000 , 2687 }, + { 11000000 , 2958 }, + { 12000000 , 3230 }, + { 13000000 , 3502 }, + { 14000000 , 3774 }, + { 15000000 , 4047 }, + { 16000000 , 4321 }, + { 17000000 , 4595 }, + { 18000000 , 4869 }, + { 19000000 , 5144 }, + { 20000000 , 5419 }, + { 21000000 , 5694 }, + { 22000000 , 5971 }, + { 23000000 , 6247 }, + { 24000000 , 6524 }, + { 25000000 , 6802 }, + { 26000000 , 7080 }, + { 27000000 , 7358 }, + { 28000000 , 7637 }, + { 29000000 , 7916 }, + { 30000000 , 8196 }, + { 31000000 , 8476 }, + { 32000000 , 8757 }, + { 33000000 , 9039 }, + { 34000000 , 9320 }, + { 35000000 , 9602 }, + { 36000000 , 9885 }, + { 37000000 , 10168 }, + { 38000000 , 10452 }, + { 39000000 , 10736 }, + { 40000000 , 11021 }, + { 41000000 , 11306 }, + { 42000000 , 11592 }, + { 43000000 , 11879 }, + { 44000000 , 12165 }, +}; +#endif /* _PT1000_TEMP_DATA_H */ diff --git a/board/trab/README.kbd b/board/trab/README.kbd new file mode 100755 index 0000000..3db00bc --- /dev/null +++ b/board/trab/README.kbd @@ -0,0 +1,44 @@ + +The TRAB keyboard implementation is similar to that for LWMON and +R360MPI boards. The only difference concerns key naming. There are 4 +keys on TRAB: 1, 2, 3, 4. + +1) The "kbd" command provides information about the current state of + the keys. For example, + + TRAB # kbd + Keys: 1 0 1 0 + + means that keys 1 and 3 are pressed. The keyboard status is also + stored in the "keybd" environment variable. In this example we get + + keybd=1010 + +2) The "preboot" variable is set according to current environment + settings and keys pressed. This is an example: + + TRAB # setenv magic_keys XY + TRAB # setenv key_magicX 12 + TRAB # setenv key_cmdX echo ## Keys 1 + 2 pressed ##\;echo + TRAB # setenv key_magicY 13 + TRAB # setenv key_cmdY echo ## Keys 1 + 3 pressed ##\;echo + + Here "magic_keys=XY" means that the "key_magicX" and "key_magicY" + variables will be checked for a match. Each variable "key_magic*" + defines a set of keys. In the our example, if keys 1 and 3 are + pressed during reset, then "key_magicY" matches, so the "preboot" + variable will be set to the contents of "key_cmdY": + + preboot=echo ## Keys 1 + 3 pressed ##;echo + +3) The TRAB board has optional modem support. When a certain key + combination is pressed on the keyboard at power-on, the firmware + performs the necessary initialization of the modem and allows for + dial-in. The key combination is specified in the + "include/configs/trab.h" file. For example: + + #define CONFIG_MODEM_KEY_MAGIC "23" + + means that modem will be initialized if and only if both keys 2, 3 + are pressed. Note that the format of this string is similar to the + format of "key_magic*" environment variables described above. diff --git a/board/trab/auto_update.c b/board/trab/auto_update.c new file mode 100755 index 0000000..056e562 --- /dev/null +++ b/board/trab/auto_update.c @@ -0,0 +1,656 @@ +/* + * (C) Copyright 2003 + * Gary Jennejohn, DENX Software Engineering, gj@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 <command.h> +#include <malloc.h> +#include <image.h> +#include <asm/byteorder.h> +#include <usb.h> + +#ifdef CFG_HUSH_PARSER +#include <hush.h> +#endif + +#ifdef CONFIG_AUTO_UPDATE + +#ifndef CONFIG_USB_OHCI +#error "must define CONFIG_USB_OHCI" +#endif + +#ifndef CONFIG_USB_STORAGE +#error "must define CONFIG_USB_STORAGE" +#endif + +#ifndef CFG_HUSH_PARSER +#error "must define CFG_HUSH_PARSER" +#endif + +#if !(CONFIG_COMMANDS & CFG_CMD_FAT) +#error "must define CFG_CMD_FAT" +#endif + +/* + * Check whether a USB memory stick is plugged in. + * If one is found: + * 1) if prepare.img ist found load it into memory. If it is + * valid then run it. + * 2) if preinst.img is found load it into memory. If it is + * valid then run it. Update the EEPROM. + * 3) if firmware.img is found load it into memory. If it is valid, + * burn it into FLASH and update the EEPROM. + * 4) if kernel.img is found load it into memory. If it is valid, + * burn it into FLASH and update the EEPROM. + * 5) if app.img is found load it into memory. If it is valid, + * burn it into FLASH and update the EEPROM. + * 6) if disk.img is found load it into memory. If it is valid, + * burn it into FLASH and update the EEPROM. + * 7) if postinst.img is found load it into memory. If it is + * valid then run it. Update the EEPROM. + */ + +#undef AU_DEBUG + +#undef debug +#ifdef AU_DEBUG +#define debug(fmt,args...) printf (fmt ,##args) +#else +#define debug(fmt,args...) +#endif /* AU_DEBUG */ + +/* possible names of files on the USB stick. */ +#define AU_PREPARE "prepare.img" +#define AU_PREINST "preinst.img" +#define AU_FIRMWARE "firmware.img" +#define AU_KERNEL "kernel.img" +#define AU_APP "app.img" +#define AU_DISK "disk.img" +#define AU_POSTINST "postinst.img" + +struct flash_layout +{ + long start; + long end; +}; + +/* layout of the FLASH. ST = start address, ND = end address. */ +#ifndef CONFIG_FLASH_8MB /* 16 MB Flash, 32 MB RAM */ +#define AU_FL_FIRMWARE_ST 0x00000000 +#define AU_FL_FIRMWARE_ND 0x0009FFFF +#define AU_FL_VFD_ST 0x000A0000 +#define AU_FL_VFD_ND 0x000BFFFF +#define AU_FL_KERNEL_ST 0x000C0000 +#define AU_FL_KERNEL_ND 0x001BFFFF +#define AU_FL_APP_ST 0x001C0000 +#define AU_FL_APP_ND 0x005BFFFF +#define AU_FL_DISK_ST 0x005C0000 +#define AU_FL_DISK_ND 0x00FFFFFF +#else /* 8 MB Flash, 32 MB RAM */ +#define AU_FL_FIRMWARE_ST 0x00000000 +#define AU_FL_FIRMWARE_ND 0x0005FFFF +#define AU_FL_KERNEL_ST 0x00060000 +#define AU_FL_KERNEL_ND 0x0013FFFF +#define AU_FL_APP_ST 0x00140000 +#define AU_FL_APP_ND 0x0067FFFF +#define AU_FL_DISK_ST 0x00680000 +#define AU_FL_DISK_ND 0x007DFFFF +#define AU_FL_VFD_ST 0x007E0000 +#define AU_FL_VFD_ND 0x007FFFFF +#endif /* CONFIG_FLASH_8MB */ + +/* a structure with the offsets to values in the EEPROM */ +struct eeprom_layout +{ + int time; + int size; + int dcrc; +}; + +/* layout of the EEPROM - offset from the start. All entries are 32 bit. */ +#define AU_EEPROM_TIME_PREINST 64 +#define AU_EEPROM_SIZE_PREINST 68 +#define AU_EEPROM_DCRC_PREINST 72 +#define AU_EEPROM_TIME_FIRMWARE 76 +#define AU_EEPROM_SIZE_FIRMWARE 80 +#define AU_EEPROM_DCRC_FIRMWARE 84 +#define AU_EEPROM_TIME_KERNEL 88 +#define AU_EEPROM_SIZE_KERNEL 92 +#define AU_EEPROM_DCRC_KERNEL 96 +#define AU_EEPROM_TIME_APP 100 +#define AU_EEPROM_SIZE_APP 104 +#define AU_EEPROM_DCRC_APP 108 +#define AU_EEPROM_TIME_DISK 112 +#define AU_EEPROM_SIZE_DISK 116 +#define AU_EEPROM_DCRC_DISK 120 +#define AU_EEPROM_TIME_POSTINST 124 +#define AU_EEPROM_SIZE_POSTINST 128 +#define AU_EEPROM_DCRC_POSTINST 132 + +static int au_usb_stor_curr_dev; /* current device */ + +/* index of each file in the following arrays */ +#define IDX_PREPARE 0 +#define IDX_PREINST 1 +#define IDX_FIRMWARE 2 +#define IDX_KERNEL 3 +#define IDX_APP 4 +#define IDX_DISK 5 +#define IDX_POSTINST 6 +/* max. number of files which could interest us */ +#define AU_MAXFILES 7 +/* pointers to file names */ +char *aufile[AU_MAXFILES]; +/* sizes of flash areas for each file */ +long ausize[AU_MAXFILES]; +/* offsets into the EEEPROM */ +struct eeprom_layout auee_off[AU_MAXFILES] = { \ + {0}, \ + {AU_EEPROM_TIME_PREINST, AU_EEPROM_SIZE_PREINST, AU_EEPROM_DCRC_PREINST,}, \ + {AU_EEPROM_TIME_FIRMWARE, AU_EEPROM_SIZE_FIRMWARE, AU_EEPROM_DCRC_FIRMWARE,}, \ + {AU_EEPROM_TIME_KERNEL, AU_EEPROM_SIZE_KERNEL, AU_EEPROM_DCRC_KERNEL,}, \ + {AU_EEPROM_TIME_APP, AU_EEPROM_SIZE_APP, AU_EEPROM_DCRC_APP,}, \ + {AU_EEPROM_TIME_DISK, AU_EEPROM_SIZE_DISK, AU_EEPROM_DCRC_DISK,}, \ + {AU_EEPROM_TIME_POSTINST, AU_EEPROM_SIZE_POSTINST, AU_EEPROM_DCRC_POSTINST,} \ + }; +/* array of flash areas start and end addresses */ +struct flash_layout aufl_layout[AU_MAXFILES - 3] = { \ + {AU_FL_FIRMWARE_ST, AU_FL_FIRMWARE_ND,}, \ + {AU_FL_KERNEL_ST, AU_FL_KERNEL_ND,}, \ + {AU_FL_APP_ST, AU_FL_APP_ND,}, \ + {AU_FL_DISK_ST, AU_FL_DISK_ND,}, \ +}; +/* convert the index into aufile[] to an index into aufl_layout[] */ +#define FIDX_TO_LIDX(idx) ((idx) - 2) + +/* where to load files into memory */ +#define LOAD_ADDR ((unsigned char *)0x0C100000) +/* the app is the largest image */ +#define MAX_LOADSZ ausize[IDX_APP] + +/* externals */ +extern int fat_register_device(block_dev_desc_t *, int); +extern int file_fat_detectfs(void); +extern long file_fat_read(const char *, void *, unsigned long); +extern int i2c_read (unsigned char, unsigned int, int , unsigned char* , int); +extern int i2c_write (uchar, uint, int , uchar* , int); +#ifdef CONFIG_VFD +extern int trab_vfd (ulong); +extern int transfer_pic(unsigned char, unsigned char *, int, int); +#endif +extern int flash_sect_erase(ulong, ulong); +extern int flash_sect_protect (int, ulong, ulong); +extern int flash_write (char *, ulong, ulong); +/* change char* to void* to shutup the compiler */ +extern int i2c_write_multiple (uchar, uint, int, void *, int); +extern int i2c_read_multiple (uchar, uint, int, void *, int); +extern block_dev_desc_t *get_dev (char*, int); +extern int u_boot_hush_start(void); + +int +au_check_cksum_valid(int idx, long nbytes) +{ + image_header_t *hdr; + unsigned long checksum; + + hdr = (image_header_t *)LOAD_ADDR; + + if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) + { + printf ("Image %s bad total SIZE\n", aufile[idx]); + return -1; + } + /* check the data CRC */ + checksum = ntohl(hdr->ih_dcrc); + + if (crc32 (0, (char *)(LOAD_ADDR + sizeof(*hdr)), ntohl(hdr->ih_size)) + != checksum) + { + printf ("Image %s bad data checksum\n", aufile[idx]); + return -1; + } + return 0; +} + +int +au_check_header_valid(int idx, long nbytes) +{ + image_header_t *hdr; + unsigned long checksum; + unsigned char buf[4]; + + hdr = (image_header_t *)LOAD_ADDR; + /* check the easy ones first */ +#undef CHECK_VALID_DEBUG +#ifdef CHECK_VALID_DEBUG + printf("magic %#x %#x ", ntohl(hdr->ih_magic), IH_MAGIC); + printf("arch %#x %#x ", hdr->ih_arch, IH_CPU_ARM); + printf("size %#x %#lx ", ntohl(hdr->ih_size), nbytes); + printf("type %#x %#x ", hdr->ih_type, IH_TYPE_KERNEL); +#endif + if (nbytes < sizeof(*hdr)) + { + printf ("Image %s bad header SIZE\n", aufile[idx]); + return -1; + } + if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_CPU_ARM) + { + printf ("Image %s bad MAGIC or ARCH\n", aufile[idx]); + return -1; + } + /* check the hdr CRC */ + checksum = ntohl(hdr->ih_hcrc); + hdr->ih_hcrc = 0; + + if (crc32 (0, (char *)hdr, sizeof(*hdr)) != checksum) { + printf ("Image %s bad header checksum\n", aufile[idx]); + return -1; + } + hdr->ih_hcrc = htonl(checksum); + /* check the type - could do this all in one gigantic if() */ + if ((idx == IDX_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) { + printf ("Image %s wrong type\n", aufile[idx]); + return -1; + } + if ((idx == IDX_KERNEL) && (hdr->ih_type != IH_TYPE_KERNEL)) { + printf ("Image %s wrong type\n", aufile[idx]); + return -1; + } + if ((idx == IDX_DISK) && (hdr->ih_type != IH_TYPE_FILESYSTEM)) { + printf ("Image %s wrong type\n", aufile[idx]); + return -1; + } + if ((idx == IDX_APP) && (hdr->ih_type != IH_TYPE_RAMDISK) + && (hdr->ih_type != IH_TYPE_FILESYSTEM)) { + printf ("Image %s wrong type\n", aufile[idx]); + return -1; + } + if ((idx == IDX_PREPARE || idx == IDX_PREINST || idx == IDX_POSTINST) + && (hdr->ih_type != IH_TYPE_SCRIPT)) + { + printf ("Image %s wrong type\n", aufile[idx]); + return -1; + } + /* special case for prepare.img */ + if (idx == IDX_PREPARE) + return 0; + /* recycle checksum */ + checksum = ntohl(hdr->ih_size); + /* for kernel and app the image header must also fit into flash */ + if ((idx != IDX_DISK) && (idx != IDX_FIRMWARE)) + checksum += sizeof(*hdr); + /* check the size does not exceed space in flash. HUSH scripts */ + /* all have ausize[] set to 0 */ + if ((ausize[idx] != 0) && (ausize[idx] < checksum)) { + printf ("Image %s is bigger than FLASH\n", aufile[idx]); + return -1; + } + /* check the time stamp from the EEPROM */ + /* read it in */ + i2c_read_multiple(0x54, auee_off[idx].time, 1, buf, sizeof(buf)); +#ifdef CHECK_VALID_DEBUG + printf ("buf[0] %#x buf[1] %#x buf[2] %#x buf[3] %#x " + "as int %#x time %#x\n", + buf[0], buf[1], buf[2], buf[3], + *((unsigned int *)buf), ntohl(hdr->ih_time)); +#endif + /* check it */ + if (*((unsigned int *)buf) >= ntohl(hdr->ih_time)) { + printf ("Image %s is too old\n", aufile[idx]); + return -1; + } + + return 0; +} + +/* power control defines */ +#define CPLD_VFD_BK ((volatile char *)0x04038002) +#define POWER_OFF (1 << 1) + +int +au_do_update(int idx, long sz) +{ + image_header_t *hdr; + char *addr; + long start, end; + int off, rc; + uint nbytes; + + hdr = (image_header_t *)LOAD_ADDR; + + /* disable the power switch */ + *CPLD_VFD_BK |= POWER_OFF; + + /* execute a script */ + if (hdr->ih_type == IH_TYPE_SCRIPT) { + addr = (char *)((char *)hdr + sizeof(*hdr)); + /* stick a NULL at the end of the script, otherwise */ + /* parse_string_outer() runs off the end. */ + addr[ntohl(hdr->ih_size)] = 0; + addr += 8; + parse_string_outer(addr, FLAG_PARSE_SEMICOLON); + return 0; + } + + start = aufl_layout[FIDX_TO_LIDX(idx)].start; + end = aufl_layout[FIDX_TO_LIDX(idx)].end; + + /* unprotect the address range */ + /* this assumes that ONLY the firmware is protected! */ + if (idx == IDX_FIRMWARE) { +#undef AU_UPDATE_TEST +#ifdef AU_UPDATE_TEST + /* erase it where Linux goes */ + start = aufl_layout[1].start; + end = aufl_layout[1].end; +#endif + flash_sect_protect(0, start, end); + } + + /* + * erase the address range. + */ + debug ("flash_sect_erase(%lx, %lx);\n", start, end); + flash_sect_erase(start, end); + wait_ms(100); + /* strip the header - except for the kernel and ramdisk */ + if (hdr->ih_type == IH_TYPE_KERNEL || hdr->ih_type == IH_TYPE_RAMDISK) { + addr = (char *)hdr; + off = sizeof(*hdr); + nbytes = sizeof(*hdr) + ntohl(hdr->ih_size); + } else { + addr = (char *)((char *)hdr + sizeof(*hdr)); +#ifdef AU_UPDATE_TEST + /* copy it to where Linux goes */ + if (idx == IDX_FIRMWARE) + start = aufl_layout[1].start; +#endif + off = 0; + nbytes = ntohl(hdr->ih_size); + } + + /* copy the data from RAM to FLASH */ + debug ("flash_write(%p, %lx %x)\n", addr, start, nbytes); + rc = flash_write(addr, start, nbytes); + if (rc != 0) { + printf("Flashing failed due to error %d\n", rc); + return -1; + } + + /* check the dcrc of the copy */ + if (crc32 (0, (char *)(start + off), ntohl(hdr->ih_size)) != ntohl(hdr->ih_dcrc)) { + printf ("Image %s Bad Data Checksum After COPY\n", aufile[idx]); + return -1; + } + + /* protect the address range */ + /* this assumes that ONLY the firmware is protected! */ + if (idx == IDX_FIRMWARE) + flash_sect_protect(1, start, end); + return 0; +} + +int +au_update_eeprom(int idx) +{ + image_header_t *hdr; + int off; + uint32_t val; + + /* special case for prepare.img */ + if (idx == IDX_PREPARE) { + /* enable the power switch */ + *CPLD_VFD_BK &= ~POWER_OFF; + return 0; + } + + hdr = (image_header_t *)LOAD_ADDR; + /* write the time field into EEPROM */ + off = auee_off[idx].time; + val = ntohl(hdr->ih_time); + i2c_write_multiple(0x54, off, 1, &val, sizeof(val)); + /* write the size field into EEPROM */ + off = auee_off[idx].size; + val = ntohl(hdr->ih_size); + i2c_write_multiple(0x54, off, 1, &val, sizeof(val)); + /* write the dcrc field into EEPROM */ + off = auee_off[idx].dcrc; + val = ntohl(hdr->ih_dcrc); + i2c_write_multiple(0x54, off, 1, &val, sizeof(val)); + /* enable the power switch */ + *CPLD_VFD_BK &= ~POWER_OFF; + return 0; +} + +/* + * this is called from board_init() after the hardware has been set up + * and is usable. That seems like a good time to do this. + * Right now the return value is ignored. + */ +int +do_auto_update(void) +{ + block_dev_desc_t *stor_dev; + long sz; + int i, res, bitmap_first, cnt, old_ctrlc, got_ctrlc; + char *env; + long start, end; + +#undef ERASE_EEPROM +#ifdef ERASE_EEPROM + int arr[18]; + memset(arr, 0, sizeof(arr)); + i2c_write_multiple(0x54, 64, 1, arr, sizeof(arr)); +#endif + au_usb_stor_curr_dev = -1; + /* start USB */ + if (usb_stop() < 0) { + debug ("usb_stop failed\n"); + return -1; + } + if (usb_init() < 0) { + debug ("usb_init failed\n"); + return -1; + } + /* + * check whether a storage device is attached (assume that it's + * a USB memory stick, since nothing else should be attached). + */ + au_usb_stor_curr_dev = usb_stor_scan(0); + if (au_usb_stor_curr_dev == -1) { + debug ("No device found. Not initialized?\n"); + return -1; + } + /* check whether it has a partition table */ + stor_dev = get_dev("usb", 0); + if (stor_dev == NULL) { + debug ("uknown device type\n"); + return -1; + } + if (fat_register_device(stor_dev, 1) != 0) { + debug ("Unable to use USB %d:%d for fatls\n", + au_usb_stor_curr_dev, 1); + return -1; + } + if (file_fat_detectfs() != 0) { + debug ("file_fat_detectfs failed\n"); + } + + /* initialize the array of file names */ + memset(aufile, 0, sizeof(aufile)); + aufile[IDX_PREPARE] = AU_PREPARE; + aufile[IDX_PREINST] = AU_PREINST; + aufile[IDX_FIRMWARE] = AU_FIRMWARE; + aufile[IDX_KERNEL] = AU_KERNEL; + aufile[IDX_APP] = AU_APP; + aufile[IDX_DISK] = AU_DISK; + aufile[IDX_POSTINST] = AU_POSTINST; + /* initialize the array of flash sizes */ + memset(ausize, 0, sizeof(ausize)); + ausize[IDX_FIRMWARE] = (AU_FL_FIRMWARE_ND + 1) - AU_FL_FIRMWARE_ST; + ausize[IDX_KERNEL] = (AU_FL_KERNEL_ND + 1) - AU_FL_KERNEL_ST; + ausize[IDX_APP] = (AU_FL_APP_ND + 1) - AU_FL_APP_ST; + ausize[IDX_DISK] = (AU_FL_DISK_ND + 1) - AU_FL_DISK_ST; + /* + * now check whether start and end are defined using environment + * variables. + */ + start = -1; + end = 0; + env = getenv("firmware_st"); + if (env != NULL) + start = simple_strtoul(env, NULL, 16); + env = getenv("firmware_nd"); + if (env != NULL) + end = simple_strtoul(env, NULL, 16); + if (start >= 0 && end && end > start) { + ausize[IDX_FIRMWARE] = (end + 1) - start; + aufl_layout[0].start = start; + aufl_layout[0].end = end; + } + start = -1; + end = 0; + env = getenv("kernel_st"); + if (env != NULL) + start = simple_strtoul(env, NULL, 16); + env = getenv("kernel_nd"); + if (env != NULL) + end = simple_strtoul(env, NULL, 16); + if (start >= 0 && end && end > start) { + ausize[IDX_KERNEL] = (end + 1) - start; + aufl_layout[1].start = start; + aufl_layout[1].end = end; + } + start = -1; + end = 0; + env = getenv("app_st"); + if (env != NULL) + start = simple_strtoul(env, NULL, 16); + env = getenv("app_nd"); + if (env != NULL) + end = simple_strtoul(env, NULL, 16); + if (start >= 0 && end && end > start) { + ausize[IDX_APP] = (end + 1) - start; + aufl_layout[2].start = start; + aufl_layout[2].end = end; + } + start = -1; + end = 0; + env = getenv("disk_st"); + if (env != NULL) + start = simple_strtoul(env, NULL, 16); + env = getenv("disk_nd"); + if (env != NULL) + end = simple_strtoul(env, NULL, 16); + if (start >= 0 && end && end > start) { + ausize[IDX_DISK] = (end + 1) - start; + aufl_layout[3].start = start; + aufl_layout[3].end = end; + } + /* make certain that HUSH is runnable */ + u_boot_hush_start(); + /* make sure that we see CTRL-C and save the old state */ + old_ctrlc = disable_ctrlc(0); + + bitmap_first = 0; + /* just loop thru all the possible files */ + for (i = 0; i < AU_MAXFILES; i++) { + /* just read the header */ + sz = file_fat_read(aufile[i], LOAD_ADDR, sizeof(image_header_t)); + debug ("read %s sz %ld hdr %d\n", + aufile[i], sz, sizeof(image_header_t)); + if (sz <= 0 || sz < sizeof(image_header_t)) { + debug ("%s not found\n", aufile[i]); + continue; + } + if (au_check_header_valid(i, sz) < 0) { + debug ("%s header not valid\n", aufile[i]); + continue; + } + sz = file_fat_read(aufile[i], LOAD_ADDR, MAX_LOADSZ); + debug ("read %s sz %ld hdr %d\n", + aufile[i], sz, sizeof(image_header_t)); + if (sz <= 0 || sz <= sizeof(image_header_t)) { + debug ("%s not found\n", aufile[i]); + continue; + } + if (au_check_cksum_valid(i, sz) < 0) { + debug ("%s checksum not valid\n", aufile[i]); + continue; + } +#ifdef CONFIG_VFD + /* now that we have a valid file we can display the */ + /* bitmap. */ + if (bitmap_first == 0) { + env = getenv("bitmap2"); + if (env == NULL) { + trab_vfd(0); + } else { + /* not so simple - bitmap2 is supposed to */ + /* contain the address of the bitmap */ + env = (char *)simple_strtoul(env, NULL, 16); +/* NOTE: these are taken from vfd_logo.h. If that file changes then */ +/* these defines MUST also be updated! These may be wrong for bitmap2. */ +#define VFD_LOGO_WIDTH 112 +#define VFD_LOGO_HEIGHT 72 + /* must call transfer_pic directly */ + transfer_pic(3, env, VFD_LOGO_HEIGHT, VFD_LOGO_WIDTH); + } + bitmap_first = 1; + } +#endif + /* this is really not a good idea, but it's what the */ + /* customer wants. */ + cnt = 0; + got_ctrlc = 0; + do { + res = au_do_update(i, sz); + /* let the user break out of the loop */ + if (ctrlc() || had_ctrlc()) { + clear_ctrlc(); + if (res < 0) + got_ctrlc = 1; + break; + } + cnt++; +#ifdef AU_TEST_ONLY + } while (res < 0 && cnt < 3); + if (cnt < 3) +#else + } while (res < 0); +#endif + /* + * it doesn't make sense to update the EEPROM if the + * update was interrupted by the user due to errors. + */ + if (got_ctrlc == 0) + au_update_eeprom(i); + else + /* enable the power switch */ + *CPLD_VFD_BK &= ~POWER_OFF; + } + usb_stop(); + /* restore the old state */ + disable_ctrlc(old_ctrlc); + return 0; +} +#endif /* CONFIG_AUTO_UPDATE */ diff --git a/board/trab/cmd_trab.c b/board/trab/cmd_trab.c new file mode 100755 index 0000000..00eb385 --- /dev/null +++ b/board/trab/cmd_trab.c @@ -0,0 +1,895 @@ +/* + * (C) Copyright 2003 + * 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 + */ + +#undef DEBUG + +#include <common.h> +#include <command.h> +#include <s3c2400.h> +#include <rtc.h> + +/* + * TRAB board specific commands. Especially commands for burn-in and function + * test. + */ +#if (CONFIG_COMMANDS & CFG_CMD_BSP) + +/* limits for valid range of VCC5V in mV */ +#define VCC5V_MIN 4500 +#define VCC5V_MAX 5500 + +/* + * Test strings for EEPROM test. Length of string 2 must not exceed length of + * string 1. Otherwise a buffer overrun could occur! + */ +#define EEPROM_TEST_STRING_1 "0987654321 :tset a si siht" +#define EEPROM_TEST_STRING_2 "this is a test: 1234567890" + +/* + * min/max limits for valid contact temperature during burn in test (in + * degree Centigrade * 100) + */ +#define MIN_CONTACT_TEMP -1000 +#define MAX_CONTACT_TEMP +9000 + +/* blinking frequency of status LED */ +#define LED_BLINK_FREQ 5 + +/* delay time between burn in cycles in seconds */ +#ifndef BURN_IN_CYCLE_DELAY /* if not defined in include/configs/trab.h */ +#define BURN_IN_CYCLE_DELAY 5 +#endif + +/* physical SRAM parameters */ +#define SRAM_ADDR 0x02000000 /* GCS1 */ +#define SRAM_SIZE 0x40000 /* 256 kByte */ + +/* CPLD-Register for controlling TRAB hardware functions */ +#define CPLD_BUTTONS ((volatile unsigned long *)0x04020000) +#define CPLD_FILL_LEVEL ((volatile unsigned long *)0x04008000) +#define CPLD_ROTARY_SWITCH ((volatile unsigned long *)0x04018000) +#define CPLD_RS485_RE ((volatile unsigned long *)0x04028000) + +/* I2C EEPROM device address */ +#define I2C_EEPROM_DEV_ADDR 0x54 + +/* EEPROM address map */ +#define EE_ADDR_TEST 192 +#define EE_ADDR_MAX_CYCLES 256 +#define EE_ADDR_STATUS 258 +#define EE_ADDR_PASS_CYCLES 259 +#define EE_ADDR_FIRST_ERROR_CYCLE 261 +#define EE_ADDR_FIRST_ERROR_NUM 263 +#define EE_ADDR_FIRST_ERROR_NAME 264 +#define EE_ADDR_ACT_CYCLE 280 + +/* Bit definitions for ADCCON */ +#define ADC_ENABLE_START 0x1 +#define ADC_READ_START 0x2 +#define ADC_STDBM 0x4 +#define ADC_INP_AIN0 (0x0 << 3) +#define ADC_INP_AIN1 (0x1 << 3) +#define ADC_INP_AIN2 (0x2 << 3) +#define ADC_INP_AIN3 (0x3 << 3) +#define ADC_INP_AIN4 (0x4 << 3) +#define ADC_INP_AIN5 (0x5 << 3) +#define ADC_INP_AIN6 (0x6 << 3) +#define ADC_INP_AIN7 (0x7 << 3) +#define ADC_PRSCEN 0x4000 +#define ADC_ECFLG 0x800 + +/* misc */ + +/* externals */ +extern int memory_post_tests (unsigned long start, unsigned long size); +extern int i2c_write (uchar, uint, int , uchar* , int); +extern int i2c_read (uchar, uint, int , uchar* , int); +extern void tsc2000_reg_init (void); +extern s32 tsc2000_contact_temp (void); +extern void spi_init(void); + +/* function declarations */ +int do_dip (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +int do_vcc5v (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +int do_burn_in (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +int do_contact_temp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +int do_burn_in_status (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +int i2c_write_multiple (uchar chip, uint addr, int alen, + uchar *buffer, int len); +int i2c_read_multiple (uchar chip, uint addr, int alen, + uchar *buffer, int len); +int do_temp_log (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); + +/* helper functions */ +static void adc_init (void); +static int adc_read (unsigned int channel); +static int read_dip (void); +static int read_vcc5v (void); +static int test_dip (void); +static int test_vcc5v (void); +static int test_rotary_switch (void); +static int test_sram (void); +static int test_eeprom (void); +static int test_contact_temp (void); +static void led_set (unsigned int); +static void led_blink (void); +static void led_init (void); +static void sdelay (unsigned long seconds); /* delay in seconds */ +static int dummy (void); +static int read_max_cycles(void); +static void test_function_table_init (void); +static void global_vars_init (void); +static int global_vars_write_to_eeprom (void); + +/* globals */ +u16 max_cycles; +u8 status; +u16 pass_cycles; +u16 first_error_cycle; +u8 first_error_num; +unsigned char first_error_name[16]; +u16 act_cycle; + +typedef struct test_function_s { + unsigned char *name; + int (*pf)(void); +} test_function_t; + +/* max number of Burn In Functions */ +#define BIF_MAX 6 + +/* table with burn in functions */ +test_function_t test_function[BIF_MAX]; + + +int do_burn_in (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i; + int cycle_status; + + if (argc > 1) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + led_init (); + global_vars_init (); + test_function_table_init (); + spi_init (); + + if (global_vars_write_to_eeprom () != 0) { + printf ("%s: error writing global_vars to eeprom\n", + __FUNCTION__); + return (1); + } + + if (read_max_cycles () != 0) { + printf ("%s: error reading max_cycles from eeprom\n", + __FUNCTION__); + return (1); + } + + if (max_cycles == 0) { + printf ("%s: error, burn in max_cycles = 0\n", __FUNCTION__); + return (1); + } + + status = 0; + for (act_cycle = 1; act_cycle <= max_cycles; act_cycle++) { + + cycle_status = 0; + + /* + * avoid timestamp overflow problem after about 68 minutes of + * udelay() time. + */ + reset_timer_masked (); + for (i = 0; i < BIF_MAX; i++) { + + /* call test function */ + if ((*test_function[i].pf)() != 0) { + printf ("error in %s test\n", + test_function[i].name); + + /* is it the first error? */ + if (status == 0) { + status = 1; + first_error_cycle = act_cycle; + + /* do not use error_num 0 */ + first_error_num = i+1; + strncpy (first_error_name, + test_function[i].name, + sizeof (first_error_name)); + led_set (0); + } + cycle_status = 1; + } + } + /* were all tests of actual cycle OK? */ + if (cycle_status == 0) + pass_cycles++; + + /* set status LED if no error is occoured since yet */ + if (status == 0) + led_set (1); + + printf ("%s: cycle %d finished\n", __FUNCTION__, act_cycle); + + /* pause between cycles */ + sdelay (BURN_IN_CYCLE_DELAY); + } + + if (global_vars_write_to_eeprom () != 0) { + led_set (0); + printf ("%s: error writing global_vars to eeprom\n", + __FUNCTION__); + status = 1; + } + + if (status == 0) { + led_blink (); /* endless loop!! */ + return (0); + } else { + led_set (0); + return (1); + } +} + +U_BOOT_CMD( + burn_in, 1, 1, do_burn_in, + "burn_in - start burn-in test application on TRAB\n", + "\n" + " - start burn-in test application\n" + " The burn-in test could took a while to finish!\n" + " The content of the onboard EEPROM is modified!\n" +); + + +int do_dip (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int i, dip; + + if (argc > 1) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if ((dip = read_dip ()) == -1) { + return 1; + } + + for (i = 0; i < 4; i++) { + if ((dip & (1 << i)) == 0) + printf("0"); + else + printf("1"); + } + printf("\n"); + + return 0; +} + +U_BOOT_CMD( + dip, 1, 1, do_dip, + "dip - read dip switch on TRAB\n", + "\n" + " - read state of dip switch (S1) on TRAB board\n" + " read sequence: 1-2-3-4; ON=1; OFF=0; e.g.: \"0100\"\n" +); + + +int do_vcc5v (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int vcc5v; + + if (argc > 1) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if ((vcc5v = read_vcc5v ()) == -1) { + return (1); + } + + printf ("%d", (vcc5v / 1000)); + printf (".%d", (vcc5v % 1000) / 100); + printf ("%d V\n", (vcc5v % 100) / 10) ; + + return 0; +} + +U_BOOT_CMD( + vcc5v, 1, 1, do_vcc5v, + "vcc5v - read VCC5V on TRAB\n", + "\n" + " - read actual value of voltage VCC5V\n" +); + + +int do_contact_temp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int contact_temp; + + if (argc > 1) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + spi_init (); + + contact_temp = tsc2000_contact_temp(); + printf ("%d degree C * 100\n", contact_temp) ; + + return 0; +} + +U_BOOT_CMD( + c_temp, 1, 1, do_contact_temp, + "c_temp - read contact temperature on TRAB\n", + "\n" + " - reads the onboard temperature (=contact temperature)\n" +); + + +int do_burn_in_status (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + if (argc > 1) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_STATUS, 1, + (unsigned char*) &status, 1)) { + return (1); + } + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_PASS_CYCLES, 1, + (unsigned char*) &pass_cycles, 2)) { + return (1); + } + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_FIRST_ERROR_CYCLE, + 1, (unsigned char*) &first_error_cycle, 2)) { + return (1); + } + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_FIRST_ERROR_NUM, + 1, (unsigned char*) &first_error_num, 1)) { + return (1); + } + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_FIRST_ERROR_NAME, + 1, first_error_name, + sizeof (first_error_name))) { + return (1); + } + + if (read_max_cycles () != 0) { + return (1); + } + + printf ("max_cycles = %d\n", max_cycles); + printf ("status = %d\n", status); + printf ("pass_cycles = %d\n", pass_cycles); + printf ("first_error_cycle = %d\n", first_error_cycle); + printf ("first_error_num = %d\n", first_error_num); + printf ("first_error_name = %.*s\n",(int) sizeof(first_error_name), + first_error_name); + + return 0; +} + +U_BOOT_CMD( + bis, 1, 1, do_burn_in_status, + "bis - print burn in status on TRAB\n", + "\n" + " - prints the status variables of the last burn in test\n" + " stored in the onboard EEPROM on TRAB board\n" +); + +static int read_dip (void) +{ + unsigned int result = 0; + int adc_val; + int i; + + /*********************************************************** + DIP switch connection (according to wa4-cpu.sp.301.pdf, page 3): + SW1 - AIN4 + SW2 - AIN5 + SW3 - AIN6 + SW4 - AIN7 + + "On" DIP switch position short-circuits the voltage from + the input channel (i.e. '0' conversion result means "on"). + *************************************************************/ + + for (i = 7; i > 3; i--) { + + if ((adc_val = adc_read (i)) == -1) { + printf ("%s: Channel %d could not be read\n", + __FUNCTION__, i); + return (-1); + } + + /* + * Input voltage (switch open) is 1.8 V. + * (Vin_High/VRef)*adc_res = (1,8V/2,5V)*1023) = 736 + * Set trigger at halve that value. + */ + if (adc_val < 368) + result |= (1 << (i-4)); + } + return (result); +} + + +static int read_vcc5v (void) +{ + s32 result; + + /* VCC5V is connected to channel 2 */ + + if ((result = adc_read (2)) == -1) { + printf ("%s: VCC5V could not be read\n", __FUNCTION__); + return (-1); + } + /* + * Calculate voltage value. Split in two parts because there is no + * floating point support. VCC5V is connected over an resistor divider: + * VCC5V=ADCval*2,5V/1023*(10K+30K)/10K. + */ + result = result * 10 * 1000 / 1023; /* result in mV */ + + return (result); +} + + +static int test_dip (void) +{ + static int first_run = 1; + static int first_dip; + + if (first_run) { + if ((first_dip = read_dip ()) == -1) { + return (1); + } + first_run = 0; + debug ("%s: first_dip=%d\n", __FUNCTION__, first_dip); + } + if (first_dip != read_dip ()) { + return (1); + } else { + return (0); + } +} + + +static int test_vcc5v (void) +{ + int vcc5v; + + if ((vcc5v = read_vcc5v ()) == -1) { + return (1); + } + + if ((vcc5v > VCC5V_MAX) || (vcc5v < VCC5V_MIN)) { + printf ("%s: vcc5v[V/100]=%d\n", __FUNCTION__, vcc5v); + return (1); + } else { + return (0); + } +} + + +static int test_rotary_switch (void) +{ + static int first_run = 1; + static int first_rs; + + if (first_run) { + /* + * clear bits in CPLD, because they have random values after + * power-up or reset. + */ + *CPLD_ROTARY_SWITCH |= (1 << 16) | (1 << 17); + + first_rs = ((*CPLD_ROTARY_SWITCH >> 16) & 0x7); + first_run = 0; + debug ("%s: first_rs=%d\n", __FUNCTION__, first_rs); + } + + if (first_rs != ((*CPLD_ROTARY_SWITCH >> 16) & 0x7)) { + return (1); + } else { + return (0); + } +} + + +static int test_sram (void) +{ + return (memory_post_tests (SRAM_ADDR, SRAM_SIZE)); +} + + +static int test_eeprom (void) +{ + unsigned char temp[sizeof (EEPROM_TEST_STRING_1)]; + int result = 0; + + /* write test string 1, read back and verify */ + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_TEST, 1, + EEPROM_TEST_STRING_1, + sizeof (EEPROM_TEST_STRING_1))) { + return (1); + } + + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_TEST, 1, + temp, sizeof (EEPROM_TEST_STRING_1))) { + return (1); + } + + if (strcmp (temp, EEPROM_TEST_STRING_1) != 0) { + result = 1; + printf ("%s: error; read_str = \"%s\"\n", __FUNCTION__, temp); + } + + /* write test string 2, read back and verify */ + if (result == 0) { + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_TEST, 1, + EEPROM_TEST_STRING_2, + sizeof (EEPROM_TEST_STRING_2))) { + return (1); + } + + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_TEST, 1, + temp, sizeof (EEPROM_TEST_STRING_2))) { + return (1); + } + + if (strcmp (temp, EEPROM_TEST_STRING_2) != 0) { + result = 1; + printf ("%s: error; read str = \"%s\"\n", + __FUNCTION__, temp); + } + } + return (result); +} + + +static int test_contact_temp (void) +{ + int contact_temp; + + contact_temp = tsc2000_contact_temp (); + + if ((contact_temp < MIN_CONTACT_TEMP) + || (contact_temp > MAX_CONTACT_TEMP)) + return (1); + else + return (0); +} + + +int i2c_write_multiple (uchar chip, uint addr, int alen, + uchar *buffer, int len) +{ + int i; + + if (alen != 1) { + printf ("%s: addr len other than 1 not supported\n", + __FUNCTION__); + return (1); + } + + for (i = 0; i < len; i++) { + if (i2c_write (chip, addr+i, alen, buffer+i, 1)) { + printf ("%s: could not write to i2c device %d" + ", addr %d\n", __FUNCTION__, chip, addr); + return (1); + } +#if 0 + printf ("chip=%#x, addr+i=%#x+%d=%p, alen=%d, *buffer+i=" + "%#x+%d=%p=\"%.1s\"\n", chip, addr, i, addr+i, + alen, buffer, i, buffer+i, buffer+i); +#endif + + udelay (30000); + } + return (0); +} + + +int i2c_read_multiple ( uchar chip, uint addr, int alen, + uchar *buffer, int len) +{ + int i; + + if (alen != 1) { + printf ("%s: addr len other than 1 not supported\n", + __FUNCTION__); + return (1); + } + + for (i = 0; i < len; i++) { + if (i2c_read (chip, addr+i, alen, buffer+i, 1)) { + printf ("%s: could not read from i2c device %#x" + ", addr %d\n", __FUNCTION__, chip, addr); + return (1); + } + } + return (0); +} + + +static int adc_read (unsigned int channel) +{ + int j = 1000; /* timeout value for wait loop in us */ + int result; + S3C2400_ADC *padc; + + padc = S3C2400_GetBase_ADC(); + channel &= 0x7; + + adc_init (); + + padc->ADCCON &= ~ADC_STDBM; /* select normal mode */ + padc->ADCCON &= ~(0x7 << 3); /* clear the channel bits */ + padc->ADCCON |= ((channel << 3) | ADC_ENABLE_START); + + while (j--) { + if ((padc->ADCCON & ADC_ENABLE_START) == 0) + break; + udelay (1); + } + + if (j == 0) { + printf("%s: ADC timeout\n", __FUNCTION__); + padc->ADCCON |= ADC_STDBM; /* select standby mode */ + return -1; + } + + result = padc->ADCDAT & 0x3FF; + + padc->ADCCON |= ADC_STDBM; /* select standby mode */ + + debug ("%s: channel %d, result[DIGIT]=%d\n", __FUNCTION__, + (padc->ADCCON >> 3) & 0x7, result); + + /* + * Wait for ADC to be ready for next conversion. This delay value was + * estimated, because the datasheet does not specify a value. + */ + udelay (1000); + + return (result); +} + + +static void adc_init (void) +{ + S3C2400_ADC *padc; + + padc = S3C2400_GetBase_ADC(); + + padc->ADCCON &= ~(0xff << 6); /* clear prescaler bits */ + padc->ADCCON |= ((65 << 6) | ADC_PRSCEN); /* set prescaler */ + + /* + * Wait some time to avoid problem with very first call of + * adc_read(). Without this delay, sometimes the first read + * adc value is 0. Perhaps because the adjustment of prescaler + * takes some clock cycles? + */ + udelay (1000); + + return; +} + + +static void led_set (unsigned int state) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + led_init (); + + switch (state) { + case 0: /* turn LED off */ + gpio->PADAT |= (1 << 12); + break; + case 1: /* turn LED on */ + gpio->PADAT &= ~(1 << 12); + break; + default: + break; + } +} + +static void led_blink (void) +{ + led_init (); + + /* blink LED. This function does not return! */ + while (1) { + led_set (1); + udelay (1000000 / LED_BLINK_FREQ / 2); + led_set (0); + udelay (1000000 / LED_BLINK_FREQ / 2); + } +} + + +static void led_init (void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* configure GPA12 as output and set to High -> LED off */ + gpio->PACON &= ~(1 << 12); + gpio->PADAT |= (1 << 12); +} + + +static void sdelay (unsigned long seconds) +{ + unsigned long i; + + for (i = 0; i < seconds; i++) { + udelay (1000000); + } +} + + +static int global_vars_write_to_eeprom (void) +{ + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_STATUS, 1, + (unsigned char*) &status, 1)) { + return (1); + } + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_PASS_CYCLES, 1, + (unsigned char*) &pass_cycles, 2)) { + return (1); + } + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_FIRST_ERROR_CYCLE, + 1, (unsigned char*) &first_error_cycle, 2)) { + return (1); + } + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_FIRST_ERROR_NUM, + 1, (unsigned char*) &first_error_num, 1)) { + return (1); + } + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_FIRST_ERROR_NAME, + 1, first_error_name, + sizeof(first_error_name))) { + return (1); + } + return (0); +} + +static void global_vars_init (void) +{ + status = 1; /* error */ + pass_cycles = 0; + first_error_cycle = 0; + first_error_num = 0; + first_error_name[0] = '\0'; + act_cycle = 0; + max_cycles = 0; +} + + +static void test_function_table_init (void) +{ + int i; + + for (i = 0; i < BIF_MAX; i++) + test_function[i].pf = dummy; + + /* + * the length of "name" must not exceed 16, including the '\0' + * termination. See also the EEPROM address map. + */ + test_function[0].pf = test_dip; + test_function[0].name = "dip"; + + test_function[1].pf = test_vcc5v; + test_function[1].name = "vcc5v"; + + test_function[2].pf = test_rotary_switch; + test_function[2].name = "rotary_switch"; + + test_function[3].pf = test_sram; + test_function[3].name = "sram"; + + test_function[4].pf = test_eeprom; + test_function[4].name = "eeprom"; + + test_function[5].pf = test_contact_temp; + test_function[5].name = "contact_temp"; +} + + +static int read_max_cycles (void) +{ + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, EE_ADDR_MAX_CYCLES, 1, + (unsigned char *) &max_cycles, 2) != 0) { + return (1); + } + + return (0); +} + +static int dummy(void) +{ + return (0); +} + +int do_temp_log (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int contact_temp; + int delay = 0; +#if (CONFIG_COMMANDS & CFG_CMD_DATE) + struct rtc_time tm; +#endif + + if (argc > 2) { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if (argc > 1) { + delay = simple_strtoul(argv[1], NULL, 10); + } + + spi_init (); + while (1) { + +#if (CONFIG_COMMANDS & CFG_CMD_DATE) + rtc_get (&tm); + printf ("%4d-%02d-%02d %2d:%02d:%02d - ", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif + + contact_temp = tsc2000_contact_temp(); + printf ("%d\n", contact_temp) ; + + if (delay != 0) + /* + * reset timer to avoid timestamp overflow problem + * after about 68 minutes of udelay() time. + */ + reset_timer_masked (); + sdelay (delay); + } + + return 0; +} + +U_BOOT_CMD( + tlog, 2, 1, do_temp_log, + "tlog - log contact temperature [1/100 C] to console (endlessly)\n", + "delay\n" + " - contact temperature [1/100 C] is printed endlessly to console\n" + " <delay> specifies the seconds to wait between two measurements\n" + " For each measurment a timestamp is printeted\n" +); + +#endif /* CFG_CMD_BSP */ diff --git a/board/trab/config.mk b/board/trab/config.mk new file mode 100755 index 0000000..f2411d0 --- /dev/null +++ b/board/trab/config.mk @@ -0,0 +1,26 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <gj@denx.de> +# +# TRAB board with S3C2400X (arm920t) cpu +# +# see http://www.samsung.com/ for more information on SAMSUNG +# + +# +# TRAB has 1 bank of 16 MB or 32 MB DRAM +# +# 0c00'0000 to 0e00'0000 +# +# Linux-Kernel is expected to be at 0c00'8000, entry 0c00'8000 +# +# we load ourself to 0CF0'0000 / 0DF0'0000 +# +# download areas is 0C80'0000 +# + +sinclude $(TOPDIR)/board/$(BOARDDIR)/config.tmp + +ifndef TEXT_BASE +TEXT_BASE = 0x0DF40000 +endif diff --git a/board/trab/flash.c b/board/trab/flash.c new file mode 100755 index 0000000..b4435e3 --- /dev/null +++ b/board/trab/flash.c @@ -0,0 +1,568 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@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 + */ + +/* #define DEBUG */ + +#include <common.h> +#include <environment.h> + +static ulong flash_get_size (vu_long *addr, flash_info_t *info); + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + + +#define CMD_READ_ARRAY 0x00F000F0 +#define CMD_UNLOCK1 0x00AA00AA +#define CMD_UNLOCK2 0x00550055 +#define CMD_ERASE_SETUP 0x00800080 +#define CMD_ERASE_CONFIRM 0x00300030 +#define CMD_PROGRAM 0x00A000A0 +#define CMD_UNLOCK_BYPASS 0x00200020 +#define CMD_READ_MANF_ID 0x00900090 +#define CMD_UNLOCK_BYPASS_RES1 0x00900090 +#define CMD_UNLOCK_BYPASS_RES2 0x00000000 + +#define MEM_FLASH_ADDR (*(volatile u32 *)CFG_FLASH_BASE) +#define MEM_FLASH_ADDR1 (*(volatile u32 *)(CFG_FLASH_BASE + (0x00000555 << 2))) +#define MEM_FLASH_ADDR2 (*(volatile u32 *)(CFG_FLASH_BASE + (0x000002AA << 2))) + +#define BIT_ERASE_DONE 0x00800080 +#define BIT_RDY_MASK 0x00800080 +#define BIT_PROGRAM_ERROR 0x00200020 +#define BIT_TIMEOUT 0x80000000 /* our flag */ + +#define READY 1 +#define ERR 2 +#define TMO 4 + +/*----------------------------------------------------------------------- + */ + +ulong flash_init (void) +{ + int i, j; + ulong size = 0; + + for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) { + ulong flashbase = 0; + flash_info_t *info = &flash_info[i]; + + /* Init: no FLASHes known */ + info->flash_id = FLASH_UNKNOWN; + + size += flash_get_size (CFG_FLASH_BASE, info); + + if (i == 0) + flashbase = CFG_FLASH_BASE; + else + panic ("configured too many flash banks!\n"); + for (j = 0; j < info->sector_count; j++) { + + info->protect[j] = 0; + info->start[j] = flashbase; + + switch (info->flash_id & FLASH_TYPEMASK) { + case (FLASH_AM320B & FLASH_TYPEMASK): + case (FLASH_MXLV320B & FLASH_TYPEMASK): + /* Boot sector type: 8 x 8 + N x 128 kB */ + flashbase += (j < 8) ? 0x4000 : 0x20000; + break; + case (FLASH_AM640U & FLASH_TYPEMASK): + /* Uniform sector type: 128 kB */ + flashbase += 0x20000; + break; + default: + printf ("## Bad flash chip type 0x%04lX\n", + info->flash_id & FLASH_TYPEMASK); + } + } + } + + /* + * Protect monitor and environment sectors + */ + flash_protect ( FLAG_PROTECT_SET, + CFG_FLASH_BASE, + CFG_FLASH_BASE + monitor_flash_len - 1, + &flash_info[0]); + + flash_protect ( FLAG_PROTECT_SET, + CFG_ENV_ADDR, + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]); + +#ifdef CFG_ENV_ADDR_REDUND + flash_protect ( FLAG_PROTECT_SET, + CFG_ENV_ADDR_REDUND, + CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, + &flash_info[0]); +#endif + + return size; +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info (flash_info_t * info) +{ + int i; + + switch (info->flash_id & FLASH_VENDMASK) { + case (FLASH_MAN_AMD & FLASH_VENDMASK): + printf ("AMD "); break; + case (FLASH_MAN_FUJ & FLASH_VENDMASK): + printf ("FUJITSU "); break; + case (FLASH_MAN_MX & FLASH_VENDMASK): + printf ("MACRONIX "); break; + default: printf ("Unknown Vendor "); break; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case (FLASH_AM320B & FLASH_TYPEMASK): + printf ("2x Am29LV320DB (32Mbit)\n"); + break; + case (FLASH_MXLV320B & FLASH_TYPEMASK): + printf ("2x MX29LV320DB (32Mbit)\n"); + break; + case (FLASH_AM640U & FLASH_TYPEMASK): + printf ("2x Am29LV640D (64Mbit)\n"); + break; + default: + printf ("Unknown Chip Type\n"); + goto Done; + 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"); + +Done: ; +} + +/*----------------------------------------------------------------------- + */ + +int flash_erase (flash_info_t * info, int s_first, int s_last) +{ + ulong result; + +#if 0 + int cflag; +#endif + int iflag, prot, sect; + int rc = ERR_OK; + int chip1, chip2; + + debug ("flash_erase: s_first %d s_last %d\n", s_first, s_last); + + /* first look for protection bits */ + + if (info->flash_id == FLASH_UNKNOWN) + return ERR_UNKNOWN_FLASH_TYPE; + + if ((s_first < 0) || (s_first > s_last)) { + return ERR_INVAL; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case (FLASH_MAN_AMD & FLASH_VENDMASK): break; /* OK */ + case (FLASH_MAN_FUJ & FLASH_VENDMASK): break; /* OK */ + case (FLASH_MAN_MX & FLASH_VENDMASK): break; /* OK */ + default: + debug ("## flash_erase: unknown manufacturer\n"); + return (ERR_UNKNOWN_FLASH_VENDOR); + } + + 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"); + } + + /* + * Disable interrupts which might cause a timeout + * here. Remember that our exception vectors are + * at address 0 in the flash, and we don't want a + * (ticker) exception to happen while the flash + * chip is in programming mode. + */ +#if 0 + cflag = icache_status (); + icache_disable (); +#endif + iflag = disable_interrupts (); + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { + + debug ("Erasing sector %2d @ %08lX... ", + sect, info->start[sect]); + + /* arm simple, non interrupt dependent timer */ + reset_timer_masked (); + + if (info->protect[sect] == 0) { /* not protected */ + vu_long *addr = (vu_long *) (info->start[sect]); + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + *addr = CMD_ERASE_CONFIRM; + + /* wait until flash is ready */ + chip1 = chip2 = 0; + + do { + result = *addr; + + /* check timeout */ + if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) { + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; + chip1 = TMO; + break; + } + + if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE) + chip1 = READY; + + if (!chip1 && (result & 0xFFFF) & BIT_PROGRAM_ERROR) + chip1 = ERR; + + if (!chip2 && (result >> 16) & BIT_ERASE_DONE) + chip2 = READY; + + if (!chip2 && (result >> 16) & BIT_PROGRAM_ERROR) + chip2 = ERR; + + } while (!chip1 || !chip2); + + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; + + if (chip1 == ERR || chip2 == ERR) { + rc = ERR_PROG_ERROR; + goto outahere; + } + if (chip1 == TMO) { + rc = ERR_TIMOUT; + goto outahere; + } + } + } + +outahere: + /* allow flash to settle - wait 10 ms */ + udelay_masked (10000); + + if (iflag) + enable_interrupts (); + +#if 0 + if (cflag) + icache_enable (); +#endif + return rc; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash + */ + +volatile static int write_word (flash_info_t * info, ulong dest, + ulong data) +{ + vu_long *addr = (vu_long *) dest; + ulong result; + int rc = ERR_OK; + +#if 0 + int cflag; +#endif + int iflag; + int chip1, chip2; + + /* + * Check if Flash is (sufficiently) erased + */ + result = *addr; + if ((result & data) != data) + return ERR_NOT_ERASED; + + /* + * Disable interrupts which might cause a timeout + * here. Remember that our exception vectors are + * at address 0 in the flash, and we don't want a + * (ticker) exception to happen while the flash + * chip is in programming mode. + */ +#if 0 + cflag = icache_status (); + icache_disable (); +#endif + iflag = disable_interrupts (); + + *addr = CMD_PROGRAM; + *addr = data; + + /* arm simple, non interrupt dependent timer */ + reset_timer_masked (); + + /* wait until flash is ready */ + chip1 = chip2 = 0; + do { + result = *addr; + + /* check timeout */ + if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) { + chip1 = ERR | TMO; + break; + } + if (!chip1 && ((result & 0x80) == (data & 0x80))) + chip1 = READY; + + if (!chip1 && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) { + result = *addr; + + if ((result & 0x80) == (data & 0x80)) + chip1 = READY; + else + chip1 = ERR; + } + + if (!chip2 && ((result & (0x80 << 16)) == (data & (0x80 << 16)))) + chip2 = READY; + + if (!chip2 && ((result >> 16) & BIT_PROGRAM_ERROR)) { + result = *addr; + + if ((result & (0x80 << 16)) == (data & (0x80 << 16))) + chip2 = READY; + else + chip2 = ERR; + } + + } while (!chip1 || !chip2); + + *addr = CMD_READ_ARRAY; + + if (chip1 == ERR || chip2 == ERR || *addr != data) + rc = ERR_PROG_ERROR; + + if (iflag) + enable_interrupts (); + +#if 0 + if (cflag) + icache_enable (); +#endif + + return rc; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash. + */ + +int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + ulong cp, wp, data; + int l; + int i, rc; + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS; + + 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 << 24); + } + for (; i < 4 && cnt > 0; ++i) { + data = (data >> 8) | (*src++ << 24); + --cnt; + ++cp; + } + for (; cnt == 0 && i < 4; ++i, ++cp) { + data = (data >> 8) | (*(uchar *) cp << 24); + } + + if ((rc = write_word (info, wp, data)) != 0) { + goto Done; + } + wp += 4; + } + + /* + * handle word aligned part + */ + while (cnt >= 4) { + if (((ulong)src) & 0x3) { + for (i = 0; i < 4; i++) { + ((char *)&data)[i] = ((vu_char *)src)[i]; + } + } + else { + data = *((vu_long *) src); + } + + if ((rc = write_word (info, wp, data)) != 0) { + goto Done; + } + src += 4; + wp += 4; + cnt -= 4; + } + + if (cnt == 0) { + rc = ERR_OK; + goto Done; + } + + /* + * handle unaligned tail bytes + */ + data = 0; + for (i = 0, cp = wp; i < 4 && cnt > 0; ++i, ++cp) { + data = (data >> 8) | (*src++ << 24); + --cnt; + } + for (; i < 4; ++i, ++cp) { + data = (data >> 8) | (*(uchar *) cp << 24); + } + + rc = write_word (info, wp, data); + + Done: + + MEM_FLASH_ADDR = CMD_UNLOCK_BYPASS_RES1; + MEM_FLASH_ADDR = CMD_UNLOCK_BYPASS_RES2; + + return (rc); +} + +/*----------------------------------------------------------------------- + */ + +static ulong flash_get_size (vu_long *addr, flash_info_t *info) +{ + ulong value; + + /* Write auto select command sequence and read Manufacturer ID */ + addr[0x0555] = CMD_UNLOCK1; + addr[0x02AA] = CMD_UNLOCK2; + addr[0x0555] = CMD_READ_MANF_ID; + + value = addr[0]; + + debug ("Manuf. ID @ 0x%08lx: 0x%08lx\n", (ulong)addr, value); + + switch (value) { + case AMD_MANUFACT: + info->flash_id = FLASH_MAN_AMD; + break; + case FUJ_MANUFACT: + info->flash_id = FLASH_MAN_FUJ; + break; + case MX_MANUFACT: + info->flash_id = FLASH_MAN_MX; + break; + default: + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + addr[0] = 0x00FF00FF; /* restore read mode */ + debug ("## flash_init: unknown manufacturer\n"); + 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) { + case AMD_ID_LV320B: + info->flash_id += FLASH_AM320B; + info->sector_count = 71; + info->size = 0x00800000; + + addr[0] = 0x00FF00FF; /* restore read mode */ + break; /* => 8 MB */ + + case AMD_ID_LV640U: + info->flash_id += FLASH_AM640U; + info->sector_count = 128; + info->size = 0x01000000; + + addr[0] = 0x00F000F0; /* restore read mode */ + break; /* => 16 MB */ + + case MX_ID_LV320B: + info->flash_id += FLASH_MXLV320B; + info->sector_count = 71; + info->size = 0x00800000; + + addr[0] = 0x00FF00FF; /* restore read mode */ + break; /* => 8 MB */ + + default: + debug ("## flash_init: unknown flash chip\n"); + info->flash_id = FLASH_UNKNOWN; + addr[0] = 0x00FF00FF; /* restore read mode */ + return (0); /* => no or unknown flash */ + + } + + if (info->sector_count > CFG_MAX_FLASH_SECT) { + printf ("** ERROR: sector count %d > max (%d) **\n", + info->sector_count, CFG_MAX_FLASH_SECT); + info->sector_count = CFG_MAX_FLASH_SECT; + } + + return (info->size); +} diff --git a/board/trab/lowlevel_init.S b/board/trab/lowlevel_init.S new file mode 100755 index 0000000..128ae7e --- /dev/null +++ b/board/trab/lowlevel_init.S @@ -0,0 +1,182 @@ +/* + * Memory Setup stuff - taken from blob memsetup.S + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and + * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * + * Modified for the TRAB board by + * (C) Copyright 2002-2003 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <config.h> +#include <version.h> + + +/* some parameters for the board */ + +/* + * + * Copied from linux/arch/arm/boot/compressed/head-s3c2400.S + * + * Copyright (C) 2001 Samsung Electronics by chc, 010406 + * + * TRAB specific tweaks. + * + */ + +/* memory controller */ +#define BWSCON 0x14000000 + +/* Bank0 */ +#define B0_Tacs 0x1 /* 1 clk */ +#define B0_Tcos 0x1 /* 1 clk */ +#define B0_Tacc 0x5 /* 8 clk */ +#define B0_Tcoh 0x1 /* 1 clk */ +#define B0_Tah 0x1 /* 1 clk */ +#define B0_Tacp 0x0 +#define B0_PMC 0x0 /* normal */ + +/* Bank1 - SRAM */ +#define B1_Tacs 0x1 /* 1 clk */ +#define B1_Tcos 0x1 /* 1 clk */ +#define B1_Tacc 0x5 /* 8 clk */ +#define B1_Tcoh 0x1 /* 1 clk */ +#define B1_Tah 0x1 /* 1 clk */ +#define B1_Tacp 0x0 +#define B1_PMC 0x0 /* normal */ + +/* Bank2 - CPLD */ +#define B2_Tacs 0x1 /* 1 clk */ +#define B2_Tcos 0x1 /* 1 clk */ +#define B2_Tacc 0x5 /* 8 clk */ +#define B2_Tcoh 0x1 /* 1 clk */ +#define B2_Tah 0x1 /* 1 clk */ +#define B2_Tacp 0x0 +#define B2_PMC 0x0 /* normal */ + +/* Bank3 - setup for the cs8900 */ +#define B3_Tacs 0x3 /* 4 clk */ +#define B3_Tcos 0x3 /* 4 clk */ +#define B3_Tacc 0x7 /* 14 clk */ +#define B3_Tcoh 0x1 /* 1 clk */ +#define B3_Tah 0x0 /* 0 clk */ +#define B3_Tacp 0x3 /* 6 clk */ +#define B3_PMC 0x0 /* normal */ + +/* Bank4 */ +#define B4_Tacs 0x0 /* 0 clk */ +#define B4_Tcos 0x0 /* 0 clk */ +#define B4_Tacc 0x7 /* 14 clk */ +#define B4_Tcoh 0x0 /* 0 clk */ +#define B4_Tah 0x0 /* 0 clk */ +#define B4_Tacp 0x0 +#define B4_PMC 0x0 /* normal */ + +/* Bank5 */ +#define B5_Tacs 0x0 /* 0 clk */ +#define B5_Tcos 0x0 /* 0 clk */ +#define B5_Tacc 0x7 /* 14 clk */ +#define B5_Tcoh 0x0 /* 0 clk */ +#define B5_Tah 0x0 /* 0 clk */ +#define B5_Tacp 0x0 +#define B5_PMC 0x0 /* normal */ + +#ifndef CONFIG_RAM_16MB /* 32 MB RAM */ +/* Bank6 */ +#define B6_MT 0x3 /* SDRAM */ +#define B6_Trcd 0x0 /* 2clk */ +#define B6_SCAN 0x1 /* 9 bit */ + +/* Bank7 */ +#define B7_MT 0x3 /* SDRAM */ +#define B7_Trcd 0x0 /* 2clk */ +#define B7_SCAN 0x1 /* 9 bit */ +#else /* CONFIG_RAM_16MB = 16 MB RAM */ +/* Bank6 */ +#define B6_MT 0x3 /* SDRAM */ +#define B6_Trcd 0x1 /* 2clk */ +#define B6_SCAN 0x0 /* 8 bit */ + +/* Bank7 */ +#define B7_MT 0x3 /* SDRAM */ +#define B7_Trcd 0x1 /* 2clk */ +#define B7_SCAN 0x0 /* 8 bit */ +#endif /* CONFIG_RAM_16MB */ + +/* refresh parameter */ +#define REFEN 0x1 /* enable refresh */ +#define TREFMD 0x0 /* CBR(CAS before RAS)/auto refresh */ +#define Trp 0x0 /* 2 clk */ +#define Trc 0x3 /* 7 clk */ +#define Tchr 0x2 /* 3 clk */ + +#ifdef CONFIG_TRAB_50MHZ +#define REFCNT 1269 /* period=15.6 us, HCLK=50Mhz, (2048+1-15.6*50) */ +#else +#define REFCNT 1011 /* period=15.6 us, HCLK=66.5Mhz, (2048+1-15.6*66.5) */ +#endif + + +_TEXT_BASE: + .word TEXT_BASE + +.globl lowlevel_init +lowlevel_init: + /* memory control configuration */ + /* make r0 relative the current location so that it */ + /* reads SMRDATA out of FLASH rather than memory ! */ + ldr r0, =SMRDATA + ldr r1, _TEXT_BASE + sub r0, r0, r1 + ldr r1, =BWSCON /* Bus Width Status Controller */ + add r2, r0, #52 +0: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r2, r0 + bne 0b + + /* everything is fine now */ + mov pc, lr + + .ltorg +/* the literal pools origin */ + +SMRDATA: + .word 0x2211d644 /* d->Ethernet, 6->CPLD, 4->SRAM, 4->FLASH */ + .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) /* GCS0 */ + .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) /* GCS1 */ + .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) /* GCS2 */ + .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) /* GCS3 */ + .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) /* GCS4 */ + .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) /* GCS5 */ + .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) /* GCS6 */ + .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) /* GCS7 */ + .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) +#ifndef CONFIG_RAM_16MB /* 32 MB RAM */ + .word 0x10 /* BUSWIDTH=32, SCLK power saving mode, BANKSIZE 32M/32M */ +#else /* CONFIG_RAM_16MB = 16 MB RAM */ + .word 0x17 /* BUSWIDTH=32, SCLK power saving mode, BANKSIZE 16M/16M */ +#endif /* CONFIG_RAM_16MB */ + .word 0x20 /* MRSR6, CL=2clk */ + .word 0x20 /* MRSR7 */ diff --git a/board/trab/memory.c b/board/trab/memory.c new file mode 100755 index 0000000..9104413 --- /dev/null +++ b/board/trab/memory.c @@ -0,0 +1,485 @@ +/* + * (C) Copyright 2002-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +/* Memory test + * + * General observations: + * o The recommended test sequence is to test the data lines: if they are + * broken, nothing else will work properly. Then test the address + * lines. Finally, test the cells in the memory now that the test + * program knows that the address and data lines work properly. + * This sequence also helps isolate and identify what is faulty. + * + * o For the address line test, it is a good idea to use the base + * address of the lowest memory location, which causes a '1' bit to + * walk through a field of zeros on the address lines and the highest + * memory location, which causes a '0' bit to walk through a field of + * '1's on the address line. + * + * o Floating buses can fool memory tests if the test routine writes + * a value and then reads it back immediately. The problem is, the + * write will charge the residual capacitance on the data bus so the + * bus retains its state briefely. When the test program reads the + * value back immediately, the capacitance of the bus can allow it + * to read back what was written, even though the memory circuitry + * is broken. To avoid this, the test program should write a test + * pattern to the target location, write a different pattern elsewhere + * to charge the residual capacitance in a differnt manner, then read + * the target location back. + * + * o Always read the target location EXACTLY ONCE and save it in a local + * variable. The problem with reading the target location more than + * once is that the second and subsequent reads may work properly, + * resulting in a failed test that tells the poor technician that + * "Memory error at 00000000, wrote aaaaaaaa, read aaaaaaaa" which + * doesn't help him one bit and causes puzzled phone calls. Been there, + * done that. + * + * Data line test: + * --------------- + * This tests data lines for shorts and opens by forcing adjacent data + * to opposite states. Because the data lines could be routed in an + * arbitrary manner the must ensure test patterns ensure that every case + * is tested. By using the following series of binary patterns every + * combination of adjacent bits is test regardless of routing. + * + * ...101010101010101010101010 + * ...110011001100110011001100 + * ...111100001111000011110000 + * ...111111110000000011111111 + * + * Carrying this out, gives us six hex patterns as follows: + * + * 0xaaaaaaaaaaaaaaaa + * 0xcccccccccccccccc + * 0xf0f0f0f0f0f0f0f0 + * 0xff00ff00ff00ff00 + * 0xffff0000ffff0000 + * 0xffffffff00000000 + * + * To test for short and opens to other signals on our boards, we + * simply test with the 1's complemnt of the paterns as well, resulting + * in twelve patterns total. + * + * After writing a test pattern. a special pattern 0x0123456789ABCDEF is + * written to a different address in case the data lines are floating. + * Thus, if a byte lane fails, you will see part of the special + * pattern in that byte lane when the test runs. For example, if the + * xx__xxxxxxxxxxxx byte line fails, you will see aa23aaaaaaaaaaaa + * (for the 'a' test pattern). + * + * Address line test: + * ------------------ + * This function performs a test to verify that all the address lines + * hooked up to the RAM work properly. If there is an address line + * fault, it usually shows up as two different locations in the address + * map (related by the faulty address line) mapping to one physical + * memory storage location. The artifact that shows up is writing to + * the first location "changes" the second location. + * + * To test all address lines, we start with the given base address and + * xor the address with a '1' bit to flip one address line. For each + * test, we shift the '1' bit left to test the next address line. + * + * In the actual code, we start with address sizeof(ulong) since our + * test pattern we use is a ulong and thus, if we tried to test lower + * order address bits, it wouldn't work because our pattern would + * overwrite itself. + * + * Example for a 4 bit address space with the base at 0000: + * 0000 <- base + * 0001 <- test 1 + * 0010 <- test 2 + * 0100 <- test 3 + * 1000 <- test 4 + * Example for a 4 bit address space with the base at 0010: + * 0010 <- base + * 0011 <- test 1 + * 0000 <- (below the base address, skipped) + * 0110 <- test 2 + * 1010 <- test 3 + * + * The test locations are successively tested to make sure that they are + * not "mirrored" onto the base address due to a faulty address line. + * Note that the base and each test location are related by one address + * line flipped. Note that the base address need not be all zeros. + * + * Memory tests 1-4: + * ----------------- + * These tests verify RAM using sequential writes and reads + * to/from RAM. There are several test cases that use different patterns to + * verify RAM. Each test case fills a region of RAM with one pattern and + * then reads the region back and compares its contents with the pattern. + * The following patterns are used: + * + * 1a) zero pattern (0x00000000) + * 1b) negative pattern (0xffffffff) + * 1c) checkerboard pattern (0x55555555) + * 1d) checkerboard pattern (0xaaaaaaaa) + * 2) bit-flip pattern ((1 << (offset % 32)) + * 3) address pattern (offset) + * 4) address pattern (~offset) + * + * Being run in normal mode, the test verifies only small 4Kb + * regions of RAM around each 1Mb boundary. For example, for 64Mb + * RAM the following areas are verified: 0x00000000-0x00000800, + * 0x000ff800-0x00100800, 0x001ff800-0x00200800, ..., 0x03fff800- + * 0x04000000. If the test is run in slow-test mode, it verifies + * the whole RAM. + */ + +/* #ifdef CONFIG_POST */ + +#include <post.h> +#include <watchdog.h> + +/* #if CONFIG_POST & CFG_POST_MEMORY */ + +/* + * Define INJECT_*_ERRORS for testing error detection in the presence of + * _good_ hardware. + */ +#undef INJECT_DATA_ERRORS +#undef INJECT_ADDRESS_ERRORS + +#ifdef INJECT_DATA_ERRORS +#warning "Injecting data line errors for testing purposes" +#endif + +#ifdef INJECT_ADDRESS_ERRORS +#warning "Injecting address line errors for testing purposes" +#endif + + +/* + * This function performs a double word move from the data at + * the source pointer to the location at the destination pointer. + * This is helpful for testing memory on processors which have a 64 bit + * wide data bus. + * + * On those PowerPC with FPU, use assembly and a floating point move: + * this does a 64 bit move. + * + * For other processors, let the compiler generate the best code it can. + */ +static void move64(unsigned long long *src, unsigned long long *dest) +{ +#if defined(CONFIG_MPC8260) || defined(CONFIG_MPC824X) + asm ("lfd 0, 0(3)\n\t" /* fpr0 = *scr */ + "stfd 0, 0(4)" /* *dest = fpr0 */ + : : : "fr0" ); /* Clobbers fr0 */ + return; +#else + *dest = *src; +#endif +} + +/* + * This is 64 bit wide test patterns. Note that they reside in ROM + * (which presumably works) and the tests write them to RAM which may + * not work. + * + * The "otherpattern" is written to drive the data bus to values other + * than the test pattern. This is for detecting floating bus lines. + * + */ +const static unsigned long long pattern[] = { + 0xaaaaaaaaaaaaaaaaULL, + 0xccccccccccccccccULL, + 0xf0f0f0f0f0f0f0f0ULL, + 0xff00ff00ff00ff00ULL, + 0xffff0000ffff0000ULL, + 0xffffffff00000000ULL, + 0x00000000ffffffffULL, + 0x0000ffff0000ffffULL, + 0x00ff00ff00ff00ffULL, + 0x0f0f0f0f0f0f0f0fULL, + 0x3333333333333333ULL, + 0x5555555555555555ULL, +}; +const unsigned long long otherpattern = 0x0123456789abcdefULL; + + +static int memory_post_dataline(unsigned long long * pmem) +{ + unsigned long long temp64; + int num_patterns = sizeof(pattern)/ sizeof(pattern[0]); + int i; + unsigned int hi, lo, pathi, patlo; + int ret = 0; + + for ( i = 0; i < num_patterns; i++) { + move64((unsigned long long *)&(pattern[i]), pmem++); + /* + * Put a different pattern on the data lines: otherwise they + * may float long enough to read back what we wrote. + */ + move64((unsigned long long *)&otherpattern, pmem--); + move64(pmem, &temp64); + +#ifdef INJECT_DATA_ERRORS + temp64 ^= 0x00008000; +#endif + + if (temp64 != pattern[i]){ + pathi = (pattern[i]>>32) & 0xffffffff; + patlo = pattern[i] & 0xffffffff; + + hi = (temp64>>32) & 0xffffffff; + lo = temp64 & 0xffffffff; + + printf ("Memory (date line) error at %08lx, " + "wrote %08x%08x, read %08x%08x !\n", + (ulong)pmem, pathi, patlo, hi, lo); + ret = -1; + } + } + return ret; +} + +static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size) +{ + ulong *target; + ulong *end; + ulong readback; + ulong xor; + int ret = 0; + + end = (ulong *)((ulong)base + size); /* pointer arith! */ + xor = 0; + for(xor = sizeof(ulong); xor > 0; xor <<= 1) { + target = (ulong *)((ulong)testaddr ^ xor); + if((target >= base) && (target < end)) { + *testaddr = ~*target; + readback = *target; + +#ifdef INJECT_ADDRESS_ERRORS + if(xor == 0x00008000) { + readback = *testaddr; + } +#endif + if(readback == *testaddr) { + printf ("Memory (address line) error at %08lx<->%08lx, " + "XOR value %08lx !\n", + (ulong)testaddr, (ulong)target, + xor); + ret = -1; + } + } + } + return ret; +} + +static int memory_post_test1 (unsigned long start, + unsigned long size, + unsigned long val) +{ + unsigned long i; + ulong *mem = (ulong *) start; + ulong readback; + int ret = 0; + + for (i = 0; i < size / sizeof (ulong); i++) { + mem[i] = val; + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { + readback = mem[i]; + if (readback != val) { + printf ("Memory error at %08lx, " + "wrote %08lx, read %08lx !\n", + (ulong)(mem + i), val, readback); + + ret = -1; + break; + } + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + return ret; +} + +static int memory_post_test2 (unsigned long start, unsigned long size) +{ + unsigned long i; + ulong *mem = (ulong *) start; + ulong readback; + int ret = 0; + + for (i = 0; i < size / sizeof (ulong); i++) { + mem[i] = 1 << (i % 32); + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { + readback = mem[i]; + if (readback != (1 << (i % 32))) { + printf ("Memory error at %08lx, " + "wrote %08x, read %08lx !\n", + (ulong)(mem + i), 1 << (i % 32), readback); + + ret = -1; + break; + } + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + return ret; +} + +static int memory_post_test3 (unsigned long start, unsigned long size) +{ + unsigned long i; + ulong *mem = (ulong *) start; + ulong readback; + int ret = 0; + + for (i = 0; i < size / sizeof (ulong); i++) { + mem[i] = i; + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { + readback = mem[i]; + if (readback != i) { + printf ("Memory error at %08lx, " + "wrote %08lx, read %08lx !\n", + (ulong)(mem + i), i, readback); + + ret = -1; + break; + } + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + return ret; +} + +static int memory_post_test4 (unsigned long start, unsigned long size) +{ + unsigned long i; + ulong *mem = (ulong *) start; + ulong readback; + int ret = 0; + + for (i = 0; i < size / sizeof (ulong); i++) { + mem[i] = ~i; + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { + readback = mem[i]; + if (readback != ~i) { + printf ("Memory error at %08lx, " + "wrote %08lx, read %08lx !\n", + (ulong)(mem + i), ~i, readback); + + ret = -1; + break; + } + if (i % 1024 == 0) + WATCHDOG_RESET (); + } + + return ret; +} + +int memory_post_tests (unsigned long start, unsigned long size) +{ + int ret = 0; + + if (ret == 0) + ret = memory_post_dataline ((long long *)start); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_addrline ((long *)start, (long *)start, size); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_addrline ((long *)(start + size - 8), + (long *)start, size); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_test1 (start, size, 0x00000000); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_test1 (start, size, 0xffffffff); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_test1 (start, size, 0x55555555); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_test1 (start, size, 0xaaaaaaaa); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_test2 (start, size); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_test3 (start, size); + WATCHDOG_RESET (); + if (ret == 0) + ret = memory_post_test4 (start, size); + WATCHDOG_RESET (); + + return ret; +} + +#if 0 +int memory_post_test (int flags) +{ + int ret = 0; + DECLARE_GLOBAL_DATA_PTR; + bd_t *bd = gd->bd; + unsigned long memsize = (bd->bi_memsize >= 256 << 20 ? + 256 << 20 : bd->bi_memsize) - (1 << 20); + + + if (flags & POST_SLOWTEST) { + ret = memory_post_tests (CFG_SDRAM_BASE, memsize); + } else { /* POST_NORMAL */ + + unsigned long i; + + for (i = 0; i < (memsize >> 20) && ret == 0; i++) { + if (ret == 0) + ret = memory_post_tests (i << 20, 0x800); + if (ret == 0) + ret = memory_post_tests ((i << 20) + 0xff800, 0x800); + } + } + + return ret; +} +#endif /* 0 */ + +/* #endif */ /* CONFIG_POST & CFG_POST_MEMORY */ +/* #endif */ /* CONFIG_POST */ diff --git a/board/trab/rs485.c b/board/trab/rs485.c new file mode 100755 index 0000000..2aedd2d --- /dev/null +++ b/board/trab/rs485.c @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2003 + * Martin Krause, TQ-Systems GmbH, <martin.krause@tqs.de> + * + * Based on cpu/arm920t/serial.c, by Gary Jennejohn + * (C) Copyright 2002 Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * 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 <s3c2400.h> +#include "rs485.h" + +static void rs485_setbrg (void); +static void rs485_cfgio (void); +static void set_rs485re(unsigned char rs485re_state); +static void set_rs485de(unsigned char rs485de_state); +static void rs485_setbrg (void); +#ifdef NOT_USED +static void trab_rs485_disable_tx(void); +static void trab_rs485_disable_rx(void); +#endif + +#define UART_NR S3C24X0_UART1 + +/* CPLD-Register for controlling TRAB hardware functions */ +#define CPLD_RS485_RE ((volatile unsigned long *)0x04028000) + +static void rs485_setbrg (void) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + int i; + unsigned int reg = 0; + + /* value is calculated so : (int)(PCLK/16./baudrate) -1 */ + /* reg = (33000000 / (16 * gd->baudrate)) - 1; */ + reg = (33000000 / (16 * 38400)) - 1; + + /* FIFO enable, Tx/Rx FIFO clear */ + uart->UFCON = 0x07; + uart->UMCON = 0x0; + /* Normal,No parity,1 stop,8 bit */ + uart->ULCON = 0x3; + /* + * tx=level,rx=edge,disable timeout int.,enable rx error int., + * normal,interrupt or polling + */ + uart->UCON = 0x245; + uart->UBRDIV = reg; + + for (i = 0; i < 100; i++); +} + +static void rs485_cfgio (void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + gpio->PFCON &= ~(0x3 << 2); + gpio->PFCON |= (0x2 << 2); /* configure GPF1 as RXD1 */ + + gpio->PFCON &= ~(0x3 << 6); + gpio->PFCON |= (0x2 << 6); /* configure GPF3 as TXD1 */ + + gpio->PFUP |= (1 << 1); /* disable pullup on GPF1 */ + gpio->PFUP |= (1 << 3); /* disable pullup on GPF3 */ + + gpio->PACON &= ~(1 << 11); /* set GPA11 (RS485_DE) to output */ +} + +/* + * Initialise the rs485 port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + * + */ +int rs485_init (void) +{ + rs485_cfgio (); + rs485_setbrg (); + + return (0); +} + +/* + * Read a single byte from the rs485 port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int rs485_getc (void) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + + /* wait for character to arrive */ + while (!(uart->UTRSTAT & 0x1)); + + return uart->URXH & 0xff; +} + +/* + * Output a single byte to the rs485 port. + */ +void rs485_putc (const char c) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + + /* wait for room in the tx FIFO */ + while (!(uart->UTRSTAT & 0x2)); + + uart->UTXH = c; + + /* If \n, also do \r */ + if (c == '\n') + rs485_putc ('\r'); +} + +/* + * Test whether a character is in the RX buffer + */ +int rs485_tstc (void) +{ + S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); + + return uart->UTRSTAT & 0x1; +} + +void rs485_puts (const char *s) +{ + while (*s) { + rs485_putc (*s++); + } +} + + +/* + * State table: + * RE DE Result + * 1 1 XMIT + * 0 0 RCV + * 1 0 Shutdown + */ + +/* function that controls the receiver enable for the rs485 */ +/* rs485re_state reflects the level (0/1) of the RE pin */ + +static void set_rs485re(unsigned char rs485re_state) +{ + if(rs485re_state) + *CPLD_RS485_RE = 0x010000; + else + *CPLD_RS485_RE = 0x0; +} + +/* function that controls the sender enable for the rs485 */ +/* rs485de_state reflects the level (0/1) of the DE pin */ + +static void set_rs485de(unsigned char rs485de_state) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* This is on PORT A bit 11 */ + if(rs485de_state) + gpio->PADAT |= (1 << 11); + else + gpio->PADAT &= ~(1 << 11); +} + + +void trab_rs485_enable_tx(void) +{ + set_rs485de(1); + set_rs485re(1); +} + +void trab_rs485_enable_rx(void) +{ + set_rs485re(0); + set_rs485de(0); +} + +#ifdef NOT_USED +static void trab_rs485_disable_tx(void) +{ + set_rs485de(0); +} + +static void trab_rs485_disable_rx(void) +{ + set_rs485re(1); +} +#endif diff --git a/board/trab/rs485.h b/board/trab/rs485.h new file mode 100755 index 0000000..d4a008a --- /dev/null +++ b/board/trab/rs485.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2003 + * Martin Krause, TQ-Systems GmbH, <martin.krause@tqs.de> + * + * Based on cpu/arm920t/serial.c, by Gary Jennejohn + * (C) Copyright 2002 Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _RS485_H_ +#define _RS485_H_ + +#include <s3c2400.h> + +int rs485_init (void); +int rs485_getc (void); +void rs485_putc (const char c); +int rs485_tstc (void); +void rs485_puts (const char *s); +void trab_rs485_enable_tx(void); +void trab_rs485_enable_rx(void); + +#endif /* _RS485_H_ */ diff --git a/board/trab/trab.c b/board/trab/trab.c new file mode 100755 index 0000000..e8dfd2c --- /dev/null +++ b/board/trab/trab.c @@ -0,0 +1,412 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@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 + */ + +/* #define DEBUG */ + +#include <common.h> +#include <malloc.h> +#include <s3c2400.h> +#include <command.h> + +/* ------------------------------------------------------------------------- */ + +#ifdef CFG_BRIGHTNESS +static void spi_init(void); +static void wait_transmit_done(void); +static void tsc2000_write(unsigned int page, unsigned int reg, + unsigned int data); +static void tsc2000_set_brightness(void); +#endif +#ifdef CONFIG_MODEM_SUPPORT +static int key_pressed(void); +extern void disable_putc(void); +extern int do_mdm_init; /* defined in common/main.c */ + +/* + * We need a delay of at least 500 us after turning on the VFD clock + * before we can read any useful information for the CPLD controlling + * the keyboard switches. Let's play safe and wait 5 ms. The problem + * is that timers are not available yet, so we use a manually timed + * loop. + */ +#define KBD_MDELAY 5000 +static void udelay_no_timer (int usec) +{ + DECLARE_GLOBAL_DATA_PTR; + + int i; + int delay = usec * 3; + + for (i = 0; i < delay; i ++) gd->bd->bi_arch_number = MACH_TYPE_TRAB; +} +#endif /* CONFIG_MODEM_SUPPORT */ + +/* + * Miscellaneous platform dependent initialisations + */ + +int board_init () +{ +#if defined(CONFIG_VFD) + extern int vfd_init_clocks(void); +#endif + DECLARE_GLOBAL_DATA_PTR; + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* memory and cpu-speed are setup before relocation */ +#ifdef CONFIG_TRAB_50MHZ + /* change the clock to be 50 MHz 1:1:1 */ + /* MDIV:0x5c PDIV:4 SDIV:2 */ + clk_power->MPLLCON = 0x5c042; + clk_power->CLKDIVN = 0; +#else + /* change the clock to be 133 MHz 1:2:4 */ + /* MDIV:0x7d PDIV:4 SDIV:1 */ + clk_power->MPLLCON = 0x7d041; + clk_power->CLKDIVN = 3; +#endif + + /* set up the I/O ports */ + gpio->PACON = 0x3ffff; + gpio->PBCON = 0xaaaaaaaa; + gpio->PBUP = 0xffff; + /* INPUT nCTS0 nRTS0 TXD[1] TXD[0] RXD[1] RXD[0] */ + /* 00, 10, 10, 10, 10, 10, 10 */ + gpio->PFCON = (2<<0) | (2<<2) | (2<<4) | (2<<6) | (2<<8) | (2<<10); +#ifdef CONFIG_HWFLOW + /* do not pull up RXD0, RXD1, TXD0, TXD1, CTS0, RTS0 */ + gpio->PFUP = (1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5); +#else + /* do not pull up RXD0, RXD1, TXD0, TXD1 */ + gpio->PFUP = (1<<0) | (1<<1) | (1<<2) | (1<<3); +#endif + gpio->PGCON = 0x0; + gpio->PGUP = 0x0; + gpio->OPENCR= 0x0; + + /* suppress flicker of the VFDs */ + gpio->MISCCR = 0x40; + gpio->PFCON |= (2<<12); + + gd->bd->bi_arch_number = MACH_TYPE_TRAB; + + /* adress of boot parameters */ + gd->bd->bi_boot_params = 0x0c000100; + + /* Make sure both buzzers are turned off */ + gpio->PDCON |= 0x5400; + gpio->PDDAT &= ~0xE0; + +#ifdef CONFIG_VFD + vfd_init_clocks(); +#endif /* CONFIG_VFD */ + +#ifdef CONFIG_MODEM_SUPPORT + udelay_no_timer (KBD_MDELAY); + + if (key_pressed()) { + disable_putc(); /* modem doesn't understand banner etc */ + do_mdm_init = 1; + } +#endif /* CONFIG_MODEM_SUPPORT */ + +#ifdef CONFIG_DRIVER_S3C24X0_I2C + /* Configure I/O ports PG5 und PG6 for I2C */ + gpio->PGCON = (gpio->PGCON & 0x003c00) | 0x003c00; +#endif /* CONFIG_DRIVER_S3C24X0_I2C */ + + return 0; +} + +int dram_init (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + return 0; +} + +/*----------------------------------------------------------------------- + * Keyboard Controller + */ + +/* Maximum key number */ +#define KEYBD_KEY_NUM 4 + +#define KBD_DATA (((*(volatile ulong *)0x04020000) >> 16) & 0xF) + +static uchar *key_match (ulong); + +int misc_init_r (void) +{ + ulong kbd_data = KBD_DATA; + uchar keybd_env[KEYBD_KEY_NUM + 1]; + uchar *str; + int i; + +#ifdef CONFIG_AUTO_UPDATE + extern int do_auto_update(void); + /* this has priority over all else */ + do_auto_update(); +#endif + + for (i = 0; i < KEYBD_KEY_NUM; ++i) { + keybd_env[i] = '0' + ((kbd_data >> i) & 1); + } + keybd_env[i] = '\0'; + debug ("** Setting keybd=\"%s\"\n", keybd_env); + setenv ("keybd", keybd_env); + + str = strdup (key_match (kbd_data)); /* decode keys */ + +#ifdef CONFIG_PREBOOT /* automatically configure "preboot" command on key match */ + debug ("** Setting preboot=\"%s\"\n", str); + setenv ("preboot", str); /* set or delete definition */ +#endif /* CONFIG_PREBOOT */ + if (str != NULL) { + free (str); + } + +#ifdef CFG_BRIGHTNESS + tsc2000_set_brightness(); +#endif + return (0); +} + +#ifdef CONFIG_PREBOOT + +static uchar kbd_magic_prefix[] = "key_magic"; +static uchar kbd_command_prefix[] = "key_cmd"; + +static int compare_magic (ulong kbd_data, uchar *str) +{ + uchar key_mask; + + debug ("compare_magic: kbd: %04lx str: \"%s\"\n",kbd_data,str); + for (; *str; str++) + { + uchar c = *str - '1'; + + if (c >= KEYBD_KEY_NUM) /* bad key number */ + return -1; + + key_mask = 1 << c; + + if (!(kbd_data & key_mask)) { /* key not pressed */ + debug ( "compare_magic: " + "kbd: %04lx mask: %04lx - key not pressed\n", + kbd_data, key_mask ); + return -1; + } + + kbd_data &= ~key_mask; + } + + if (kbd_data) { /* key(s) not released */ + debug ( "compare_magic: " + "kbd: %04lx - key(s) not released\n", kbd_data); + return -1; + } + + return 0; +} + +/*----------------------------------------------------------------------- + * Check if pressed key(s) match magic sequence, + * and return the command string associated with that key(s). + * + * If no key press was decoded, NULL is returned. + * + * Note: the first character of the argument will be overwritten with + * the "magic charcter code" of the decoded key(s), or '\0'. + * + * + * Note: the string points to static environment data and must be + * saved before you call any function that modifies the environment. + */ +static uchar *key_match (ulong kbd_data) +{ + uchar magic[sizeof (kbd_magic_prefix) + 1]; + uchar cmd_name[sizeof (kbd_command_prefix) + 1]; + uchar *suffix; + uchar *kbd_magic_keys; + + /* + * The following string defines the characters that can pe appended + * to "key_magic" to form the names of environment variables that + * hold "magic" key codes, i. e. such key codes that can cause + * pre-boot actions. If the string is empty (""), then only + * "key_magic" is checked (old behaviour); the string "125" causes + * checks for "key_magic1", "key_magic2" and "key_magic5", etc. + */ + if ((kbd_magic_keys = getenv ("magic_keys")) == NULL) + kbd_magic_keys = ""; + + debug ("key_match: magic_keys=\"%s\"\n", kbd_magic_keys); + + /* loop over all magic keys; + * use '\0' suffix in case of empty string + */ + for (suffix=kbd_magic_keys; *suffix || suffix==kbd_magic_keys; ++suffix) + { + sprintf (magic, "%s%c", kbd_magic_prefix, *suffix); + + debug ("key_match: magic=\"%s\"\n", + getenv(magic) ? getenv(magic) : "<UNDEFINED>"); + + if (compare_magic(kbd_data, getenv(magic)) == 0) + { + sprintf (cmd_name, "%s%c", kbd_command_prefix, *suffix); + debug ("key_match: cmdname %s=\"%s\"\n", + cmd_name, + getenv (cmd_name) ? + getenv (cmd_name) : + "<UNDEFINED>"); + return (getenv (cmd_name)); + } + } + debug ("key_match: no match\n"); + return (NULL); +} +#endif /* CONFIG_PREBOOT */ + +/* Read Keyboard status */ +int do_kbd (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + ulong kbd_data = KBD_DATA; + uchar keybd_env[KEYBD_KEY_NUM + 1]; + int i; + + puts ("Keys:"); + for (i = 0; i < KEYBD_KEY_NUM; ++i) { + keybd_env[i] = '0' + ((kbd_data >> i) & 1); + printf (" %c", keybd_env[i]); + } + keybd_env[i] = '\0'; + putc ('\n'); + setenv ("keybd", keybd_env); + return 0; +} + +U_BOOT_CMD( + kbd, 1, 1, do_kbd, + "kbd - read keyboard status\n", + NULL +); + +#ifdef CONFIG_MODEM_SUPPORT +static int key_pressed(void) +{ + return (compare_magic(KBD_DATA, CONFIG_MODEM_KEY_MAGIC) == 0); +} +#endif /* CONFIG_MODEM_SUPPORT */ + +#ifdef CFG_BRIGHTNESS + +static inline void SET_CS_TOUCH(void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + gpio->PDDAT &= 0x5FF; +} + +static inline void CLR_CS_TOUCH(void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + gpio->PDDAT |= 0x200; +} + +static void spi_init(void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); + int i; + + /* Configure I/O ports. */ + gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000; + gpio->PGCON = (gpio->PGCON & 0x0F3FFF) | 0x008000; + gpio->PGCON = (gpio->PGCON & 0x0CFFFF) | 0x020000; + gpio->PGCON = (gpio->PGCON & 0x03FFFF) | 0x080000; + + CLR_CS_TOUCH(); + + spi->ch[0].SPPRE = 0x1F; /* Baudrate ca. 514kHz */ + spi->ch[0].SPPIN = 0x01; /* SPI-MOSI holds Level after last bit */ + spi->ch[0].SPCON = 0x1A; /* Polling, Prescaler, Master, CPOL=0, CPHA=1 */ + + /* Dummy byte ensures clock to be low. */ + for (i = 0; i < 10; i++) { + spi->ch[0].SPTDAT = 0xFF; + } + wait_transmit_done(); +} + +static void wait_transmit_done(void) +{ + S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); + + while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */ +} + +static void tsc2000_write(unsigned int page, unsigned int reg, + unsigned int data) +{ + S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); + unsigned int command; + + SET_CS_TOUCH(); + command = 0x0000; + command |= (page << 11); + command |= (reg << 5); + + spi->ch[0].SPTDAT = (command & 0xFF00) >> 8; + wait_transmit_done(); + spi->ch[0].SPTDAT = (command & 0x00FF); + wait_transmit_done(); + spi->ch[0].SPTDAT = (data & 0xFF00) >> 8; + wait_transmit_done(); + spi->ch[0].SPTDAT = (data & 0x00FF); + wait_transmit_done(); + + CLR_CS_TOUCH(); +} + +static void tsc2000_set_brightness(void) +{ + uchar tmp[10]; + int i, br; + + spi_init(); + tsc2000_write(1, 2, 0x0); /* Power up DAC */ + + i = getenv_r("brightness", tmp, sizeof(tmp)); + br = (i > 0) + ? (int) simple_strtoul (tmp, NULL, 10) + : CFG_BRIGHTNESS; + + tsc2000_write(0, 0xb, br & 0xff); +} +#endif diff --git a/board/trab/trab_fkt.c b/board/trab/trab_fkt.c new file mode 100755 index 0000000..abb3b29 --- /dev/null +++ b/board/trab/trab_fkt.c @@ -0,0 +1,1411 @@ +/* + * (C) Copyright 2003 + * 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 + */ + +#define DEBUG + +#include <common.h> +#include <exports.h> +#include <s3c2400.h> +#include "tsc2000.h" +#include "rs485.h" + +/* + * define, to wait for the touch to be pressed, before reading coordinates in + * command do_touch. If not defined, an error message is printed, when the + * command do_touch is invoked and the touch is not pressed within an specific + * interval. + */ +#undef CONFIG_TOUCH_WAIT_PRESSED + +/* max time to wait for touch is pressed */ +#ifndef CONFIG_TOUCH_WAIT_PRESSED +#define TOUCH_TIMEOUT 5 +#endif /* !CONFIG_TOUCH_WAIT_PRESSED */ + +/* assignment of CPU internal ADC channels with TRAB hardware */ +#define VCC5V 2 +#define VCC12V 3 + +/* CPLD-Register for controlling TRAB hardware functions */ +#define CPLD_BUTTONS ((volatile unsigned long *)0x04020000) +#define CPLD_FILL_LEVEL ((volatile unsigned long *)0x04008000) +#define CPLD_ROTARY_SWITCH ((volatile unsigned long *)0x04018000) +#define CPLD_RS485_RE ((volatile unsigned long *)0x04028000) + +/* timer configuration bits for buzzer and PWM */ +#define START2 (1 << 12) +#define UPDATE2 (1 << 13) +#define INVERT2 (1 << 14) +#define RELOAD2 (1 << 15) +#define START3 (1 << 16) +#define UPDATE3 (1 << 17) +#define INVERT3 (1 << 18) +#define RELOAD3 (1 << 19) + +#define PCLK 66000000 +#define BUZZER_FREQ 1000 /* frequency in Hz */ +#define PWM_FREQ 500 + + +/* definitions of I2C EEPROM device address */ +#define I2C_EEPROM_DEV_ADDR 0x54 + +/* definition for touch panel calibration points */ +#define CALIB_TL 0 /* calibration point in (T)op (L)eft corner */ +#define CALIB_DR 1 /* calibration point in (D)own (R)ight corner */ + +/* EEPROM address map */ +#define SERIAL_NUMBER 8 +#define TOUCH_X0 52 +#define TOUCH_Y0 54 +#define TOUCH_X1 56 +#define TOUCH_Y1 58 +#define CRC16 60 + +/* EEPROM stuff */ +#define EEPROM_MAX_CRC_BUF 64 + +/* RS485 stuff */ +#define RS485_MAX_RECEIVE_BUF_LEN 100 + +/* Bit definitions for ADCCON */ +#define ADC_ENABLE_START 0x1 +#define ADC_READ_START 0x2 +#define ADC_STDBM 0x4 +#define ADC_INP_AIN0 (0x0 << 3) +#define ADC_INP_AIN1 (0x1 << 3) +#define ADC_INP_AIN2 (0x2 << 3) +#define ADC_INP_AIN3 (0x3 << 3) +#define ADC_INP_AIN4 (0x4 << 3) +#define ADC_INP_AIN5 (0x5 << 3) +#define ADC_INP_AIN6 (0x6 << 3) +#define ADC_INP_AIN7 (0x7 << 3) +#define ADC_PRSCEN 0x4000 +#define ADC_ECFLG 0x8000 + +/* function test functions */ +int do_dip (void); +int do_info (void); +int do_vcc5v (void); +int do_vcc12v (void); +int do_buttons (void); +int do_fill_level (void); +int do_rotary_switch (void); +int do_pressure (void); +int do_v_bat (void); +int do_vfd_id (void); +int do_buzzer (char **); +int do_led (char **); +int do_full_bridge (char **); +int do_dac (char **); +int do_motor_contact (void); +int do_motor (char **); +int do_pwm (char **); +int do_thermo (char **); +int do_touch (char **); +int do_rs485 (char **); +int do_serial_number (char **); +int do_crc16 (void); +int do_power_switch (void); +int do_gain (char **); +int do_eeprom (char **); + +/* helper functions */ +static void adc_init (void); +static int adc_read (unsigned int channel); +static void print_identifier (void); + +#ifdef CONFIG_TOUCH_WAIT_PRESSED +static void touch_wait_pressed (void); +#else +static int touch_check_pressed (void); +#endif /* CONFIG_TOUCH_WAIT_PRESSED */ + +static void touch_read_x_y (int *x, int *y); +static int touch_write_clibration_values (int calib_point, int x, int y); +static int rs485_send_line (const char *data); +static int rs485_receive_chars (char *data, int timeout); +static unsigned short updcrc(unsigned short icrc, unsigned char *icp, + unsigned int icnt); + +#if (CONFIG_COMMANDS & CFG_CMD_I2C) +static int trab_eeprom_read (char **argv); +static int trab_eeprom_write (char **argv); +int i2c_write_multiple (uchar chip, uint addr, int alen, uchar *buffer, + int len); +int i2c_read_multiple ( uchar chip, uint addr, int alen, uchar *buffer, + int len); +#endif /* CFG_CMD_I2C */ + +/* + * TRAB board specific commands. Especially commands for burn-in and function + * test. + */ + +int trab_fkt (int argc, char *argv[]) +{ + int i; + + app_startup(argv); + if (get_version () != XF_VERSION) { + printf ("Wrong XF_VERSION. Please re-compile with actual " + "u-boot sources\n"); + printf ("Example expects ABI version %d\n", XF_VERSION); + printf ("Actual U-Boot ABI version %d\n", (int)get_version()); + return 1; + } + + debug ("argc = %d\n", argc); + + for (i=0; i<=argc; ++i) { + debug ("argv[%d] = \"%s\"\n", i, argv[i] ? argv[i] : "<NULL>"); + } + + adc_init (); + + switch (argc) { + + case 0: + case 1: + break; + + case 2: + if (strcmp (argv[1], "info") == 0) { + return (do_info ()); + } + if (strcmp (argv[1], "dip") == 0) { + return (do_dip ()); + } + if (strcmp (argv[1], "vcc5v") == 0) { + return (do_vcc5v ()); + } + if (strcmp (argv[1], "vcc12v") == 0) { + return (do_vcc12v ()); + } + if (strcmp (argv[1], "buttons") == 0) { + return (do_buttons ()); + } + if (strcmp (argv[1], "fill_level") == 0) { + return (do_fill_level ()); + } + if (strcmp (argv[1], "rotary_switch") == 0) { + return (do_rotary_switch ()); + } + if (strcmp (argv[1], "pressure") == 0) { + return (do_pressure ()); + } + if (strcmp (argv[1], "v_bat") == 0) { + return (do_v_bat ()); + } + if (strcmp (argv[1], "vfd_id") == 0) { + return (do_vfd_id ()); + } + if (strcmp (argv[1], "motor_contact") == 0) { + return (do_motor_contact ()); + } + if (strcmp (argv[1], "crc16") == 0) { + return (do_crc16 ()); + } + if (strcmp (argv[1], "power_switch") == 0) { + return (do_power_switch ()); + } + break; + + case 3: + if (strcmp (argv[1], "full_bridge") == 0) { + return (do_full_bridge (argv)); + } + if (strcmp (argv[1], "dac") == 0) { + return (do_dac (argv)); + } + if (strcmp (argv[1], "motor") == 0) { + return (do_motor (argv)); + } + if (strcmp (argv[1], "pwm") == 0) { + return (do_pwm (argv)); + } + if (strcmp (argv[1], "thermo") == 0) { + return (do_thermo (argv)); + } + if (strcmp (argv[1], "touch") == 0) { + return (do_touch (argv)); + } + if (strcmp (argv[1], "serial_number") == 0) { + return (do_serial_number (argv)); + } + if (strcmp (argv[1], "buzzer") == 0) { + return (do_buzzer (argv)); + } + if (strcmp (argv[1], "gain") == 0) { + return (do_gain (argv)); + } + break; + + case 4: + if (strcmp (argv[1], "led") == 0) { + return (do_led (argv)); + } + if (strcmp (argv[1], "rs485") == 0) { + return (do_rs485 (argv)); + } + if (strcmp (argv[1], "serial_number") == 0) { + return (do_serial_number (argv)); + } + break; + + case 5: + if (strcmp (argv[1], "eeprom") == 0) { + return (do_eeprom (argv)); + } + break; + + case 6: + if (strcmp (argv[1], "eeprom") == 0) { + return (do_eeprom (argv)); + } + break; + + default: + break; + } + + printf ("Usage:\n<command> <parameter1> <parameter2> ...\n"); + return 1; +} + +int do_info (void) +{ + printf ("Stand-alone application for TRAB board function test\n"); + printf ("Built: %s at %s\n", __DATE__ , __TIME__ ); + + return 0; +} + +int do_dip (void) +{ + unsigned int result = 0; + int adc_val; + int i; + + /*********************************************************** + DIP switch connection (according to wa4-cpu.sp.301.pdf, page 3): + SW1 - AIN4 + SW2 - AIN5 + SW3 - AIN6 + SW4 - AIN7 + + "On" DIP switch position short-circuits the voltage from + the input channel (i.e. '0' conversion result means "on"). + *************************************************************/ + + for (i = 7; i > 3; i--) { + + if ((adc_val = adc_read (i)) == -1) { + printf ("Channel %d could not be read\n", i); + return 1; + } + + /* + * Input voltage (switch open) is 1.8 V. + * (Vin_High/VRef)*adc_res = (1,8V/2,5V)*1023) = 736 + * Set trigger at halve that value. + */ + if (adc_val < 368) + result |= (1 << (i-4)); + } + + /* print result to console */ + print_identifier (); + for (i = 0; i < 4; i++) { + if ((result & (1 << i)) == 0) + printf("0"); + else + printf("1"); + } + printf("\n"); + + return 0; +} + + +int do_vcc5v (void) +{ + int result; + + /* VCC5V is connected to channel 2 */ + + if ((result = adc_read (VCC5V)) == -1) { + printf ("VCC5V could not be read\n"); + return 1; + } + + /* + * Calculate voltage value. Split in two parts because there is no + * floating point support. VCC5V is connected over an resistor divider: + * VCC5V=ADCval*2,5V/1023*(10K+30K)/10K. + */ + print_identifier (); + printf ("%d", (result & 0x3FF)* 10 / 1023); + printf (".%d", ((result & 0x3FF)* 10 % 1023)* 10 / 1023); + printf ("%d V\n", (((result & 0x3FF) * 10 % 1023 ) * 10 % 1023) + * 10 / 1024); + + return 0; +} + + +int do_vcc12v (void) +{ + int result; + + if ((result = adc_read (VCC12V)) == -1) { + printf ("VCC12V could not be read\n"); + return 1; + } + + /* + * Calculate voltage value. Split in two parts because there is no + * floating point support. VCC5V is connected over an resistor divider: + * VCC12V=ADCval*2,5V/1023*(30K+270K)/30K. + */ + print_identifier (); + printf ("%d", (result & 0x3FF)* 25 / 1023); + printf (".%d V\n", ((result & 0x3FF)* 25 % 1023) * 10 / 1023); + + return 0; +} + +static int adc_read (unsigned int channel) +{ + int j = 1000; /* timeout value for wait loop in us */ + int result; + S3C2400_ADC *padc; + + padc = S3C2400_GetBase_ADC(); + channel &= 0x7; + + padc->ADCCON &= ~ADC_STDBM; /* select normal mode */ + padc->ADCCON &= ~(0x7 << 3); /* clear the channel bits */ + padc->ADCCON |= ((channel << 3) | ADC_ENABLE_START); + + while (j--) { + if ((padc->ADCCON & ADC_ENABLE_START) == 0) + break; + udelay (1); + } + + if (j == 0) { + printf("%s: ADC timeout\n", __FUNCTION__); + padc->ADCCON |= ADC_STDBM; /* select standby mode */ + return -1; + } + + result = padc->ADCDAT & 0x3FF; + + padc->ADCCON |= ADC_STDBM; /* select standby mode */ + + debug ("%s: channel %d, result[DIGIT]=%d\n", __FUNCTION__, + (padc->ADCCON >> 3) & 0x7, result); + + /* + * Wait for ADC to be ready for next conversion. This delay value was + * estimated, because the datasheet does not specify a value. + */ + udelay (1000); + + return (result); +} + + +static void adc_init (void) +{ + S3C2400_ADC *padc; + + padc = S3C2400_GetBase_ADC(); + + padc->ADCCON &= ~(0xff << 6); /* clear prescaler bits */ + padc->ADCCON |= ((65 << 6) | ADC_PRSCEN); /* set prescaler */ + + /* + * Wait some time to avoid problem with very first call of + * adc_read(). Without * this delay, sometimes the first read adc + * value is 0. Perhaps because the * adjustment of prescaler takes + * some clock cycles? + */ + udelay (1000); + + return; +} + + +int do_buttons (void) +{ + int result; + int i; + + result = *CPLD_BUTTONS; /* read CPLD */ + debug ("%s: cpld_taster (32 bit) %#x\n", __FUNCTION__, result); + + /* print result to console */ + print_identifier (); + for (i = 16; i <= 19; i++) { + if ((result & (1 << i)) == 0) + printf("0"); + else + printf("1"); + } + printf("\n"); + return 0; +} + + +int do_power_switch (void) +{ + int result; + + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* configure GPE7 as input */ + gpio->PECON &= ~(0x3 << (2 * 7)); + + /* signal GPE7 from power switch is low active: 0=on , 1=off */ + result = ((gpio->PEDAT & (1 << 7)) == (1 << 7)) ? 0 : 1; + + print_identifier (); + printf("%d\n", result); + return 0; +} + + +int do_fill_level (void) +{ + int result; + + result = *CPLD_FILL_LEVEL; /* read CPLD */ + debug ("%s: cpld_fuellstand (32 bit) %#x\n", __FUNCTION__, result); + + /* print result to console */ + print_identifier (); + if ((result & (1 << 16)) == 0) + printf("0\n"); + else + printf("1\n"); + return 0; +} + + +int do_rotary_switch (void) +{ + int result; + /* + * Please note, that the default values of the direction bits are + * undefined after reset. So it is a good idea, to make first a dummy + * call to this function, to clear the direction bits and set so to + * proper values. + */ + + result = *CPLD_ROTARY_SWITCH; /* read CPLD */ + debug ("%s: cpld_inc (32 bit) %#x\n", __FUNCTION__, result); + + *CPLD_ROTARY_SWITCH |= (3 << 16); /* clear direction bits in CPLD */ + + /* print result to console */ + print_identifier (); + if ((result & (1 << 16)) == (1 << 16)) + printf("R"); + if ((result & (1 << 17)) == (1 << 17)) + printf("L"); + if (((result & (1 << 16)) == 0) && ((result & (1 << 17)) == 0)) + printf("0"); + if ((result & (1 << 18)) == 0) + printf("0\n"); + else + printf("1\n"); + return 0; +} + + +int do_vfd_id (void) +{ + int i; + long int pcup_old, pccon_old; + int vfd_board_id; + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* try to red vfd board id from the value defined by pull-ups */ + + pcup_old = gpio->PCUP; + pccon_old = gpio->PCCON; + + gpio->PCUP = (gpio->PCUP & 0xFFF0); /* activate GPC0...GPC3 pull-ups */ + gpio->PCCON = (gpio->PCCON & 0xFFFFFF00); /* configure GPC0...GPC3 as + * inputs */ + udelay (10); /* allow signals to settle */ + vfd_board_id = (~gpio->PCDAT) & 0x000F; /* read GPC0...GPC3 port pins */ + + gpio->PCCON = pccon_old; + gpio->PCUP = pcup_old; + + /* print vfd_board_id to console */ + print_identifier (); + for (i = 0; i < 4; i++) { + if ((vfd_board_id & (1 << i)) == 0) + printf("0"); + else + printf("1"); + } + printf("\n"); + return 0; +} + +int do_buzzer (char **argv) +{ + int counter; + + S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS(); + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* set prescaler for timer 2, 3 and 4 */ + timers->TCFG0 &= ~0xFF00; + timers->TCFG0 |= 0x0F00; + + /* set divider for timer 2 */ + timers->TCFG1 &= ~0xF00; + timers->TCFG1 |= 0x300; + + /* set frequency */ + counter = (PCLK / BUZZER_FREQ) >> 9; + timers->ch[2].TCNTB = counter; + timers->ch[2].TCMPB = counter / 2; + + if (strcmp (argv[2], "on") == 0) { + debug ("%s: frequency: %d\n", __FUNCTION__, + BUZZER_FREQ); + + /* configure pin GPD7 as TOUT2 */ + gpio->PDCON &= ~0xC000; + gpio->PDCON |= 0x8000; + + /* start */ + timers->TCON = (timers->TCON | UPDATE2 | RELOAD2) & + ~INVERT2; + timers->TCON = (timers->TCON | START2) & ~UPDATE2; + return (0); + } + else if (strcmp (argv[2], "off") == 0) { + /* stop */ + timers->TCON &= ~(START2 | RELOAD2); + + /* configure GPD7 as output and set to low */ + gpio->PDCON &= ~0xC000; + gpio->PDCON |= 0x4000; + gpio->PDDAT &= ~0x80; + return (0); + } + + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return 1; +} + + +int do_led (char **argv) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* configure PC14 and PC15 as output */ + gpio->PCCON &= ~(0xF << 28); + gpio->PCCON |= (0x5 << 28); + + /* configure PD0 and PD4 as output */ + gpio->PDCON &= ~((0x3 << 8) | 0x3); + gpio->PDCON |= ((0x1 << 8) | 0x1); + + switch (simple_strtoul(argv[2], NULL, 10)) { + + case 0: + case 1: + break; + + case 2: + if (strcmp (argv[3], "on") == 0) + gpio->PCDAT |= (1 << 14); + else + gpio->PCDAT &= ~(1 << 14); + return 0; + + case 3: + if (strcmp (argv[3], "on") == 0) + gpio->PCDAT |= (1 << 15); + else + gpio->PCDAT &= ~(1 << 15); + return 0; + + case 4: + if (strcmp (argv[3], "on") == 0) + gpio->PDDAT |= (1 << 0); + else + gpio->PDDAT &= ~(1 << 0); + return 0; + + case 5: + if (strcmp (argv[3], "on") == 0) + gpio->PDDAT |= (1 << 4); + else + gpio->PDDAT &= ~(1 << 4); + return 0; + + default: + break; + + } + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return 1; +} + + +int do_full_bridge (char **argv) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* configure PD5 and PD6 as output */ + gpio->PDCON &= ~((0x3 << 5*2) | (0x3 << 6*2)); + gpio->PDCON |= ((0x1 << 5*2) | (0x1 << 6*2)); + + if (strcmp (argv[2], "+") == 0) { + gpio->PDDAT |= (1 << 5); + gpio->PDDAT |= (1 << 6); + return 0; + } + else if (strcmp (argv[2], "-") == 0) { + gpio->PDDAT &= ~(1 << 5); + gpio->PDDAT |= (1 << 6); + return 0; + } + else if (strcmp (argv[2], "off") == 0) { + gpio->PDDAT &= ~(1 << 5); + gpio->PDDAT &= ~(1 << 6); + return 0; + } + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return 1; +} + +/* val must be in [0, 4095] */ +static inline unsigned long tsc2000_to_uv (u16 val) +{ + return ((250000 * val) / 4096) * 10; +} + + +int do_dac (char **argv) +{ + int brightness; + + /* initialize SPI */ + spi_init (); + + if (((brightness = simple_strtoul (argv[2], NULL, 10)) < 0) || + (brightness > 255)) { + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return 1; + } + tsc2000_write(TSC2000_REG_DACCTL, 0x0); /* Power up DAC */ + tsc2000_write(TSC2000_REG_DAC, brightness & 0xff); + + return 0; +} + + +int do_v_bat (void) +{ + unsigned long ret, res; + + /* initialize SPI */ + spi_init (); + + tsc2000_write(TSC2000_REG_ADC, 0x1836); + + /* now wait for data available */ + adc_wait_conversion_done(); + + ret = tsc2000_read(TSC2000_REG_BAT1); + res = (tsc2000_to_uv(ret) + 1250) / 2500; + res += (ERROR_BATTERY * res) / 1000; + + print_identifier (); + printf ("%ld", (res / 100)); + printf (".%ld", ((res % 100) / 10)); + printf ("%ld V\n", (res % 10)); + return 0; +} + + +int do_pressure (void) +{ + /* initialize SPI */ + spi_init (); + + tsc2000_write(TSC2000_REG_ADC, 0x2436); + + /* now wait for data available */ + adc_wait_conversion_done(); + + print_identifier (); + printf ("%d\n", tsc2000_read(TSC2000_REG_AUX2)); + return 0; +} + + +int do_motor_contact (void) +{ + int result; + + result = *CPLD_FILL_LEVEL; /* read CPLD */ + debug ("%s: cpld_fuellstand (32 bit) %#x\n", __FUNCTION__, result); + + /* print result to console */ + print_identifier (); + if ((result & (1 << 17)) == 0) + printf("0\n"); + else + printf("1\n"); + return 0; +} + +int do_motor (char **argv) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* Configure I/O port */ + gpio->PGCON &= ~(0x3 << 0); + gpio->PGCON |= (0x1 << 0); + + if (strcmp (argv[2], "on") == 0) { + gpio->PGDAT &= ~(1 << 0); + return 0; + } + if (strcmp (argv[2], "off") == 0) { + gpio->PGDAT |= (1 << 0); + return 0; + } + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return 1; +} + +static void print_identifier (void) +{ + printf ("## FKT: "); +} + +int do_pwm (char **argv) +{ + int counter; + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS(); + + if (strcmp (argv[2], "on") == 0) { + /* configure pin GPD8 as TOUT3 */ + gpio->PDCON &= ~(0x3 << 8*2); + gpio->PDCON |= (0x2 << 8*2); + + /* set prescaler for timer 2, 3 and 4 */ + timers->TCFG0 &= ~0xFF00; + timers->TCFG0 |= 0x0F00; + + /* set divider for timer 3 */ + timers->TCFG1 &= ~(0xf << 12); + timers->TCFG1 |= (0x3 << 12); + + /* set frequency */ + counter = (PCLK / PWM_FREQ) >> 9; + timers->ch[3].TCNTB = counter; + timers->ch[3].TCMPB = counter / 2; + + /* start timer */ + timers->TCON = (timers->TCON | UPDATE3 | RELOAD3) & ~INVERT3; + timers->TCON = (timers->TCON | START3) & ~UPDATE3; + return 0; + } + if (strcmp (argv[2], "off") == 0) { + + /* stop timer */ + timers->TCON &= ~(START2 | RELOAD2); + + /* configure pin GPD8 as output and set to 0 */ + gpio->PDCON &= ~(0x3 << 8*2); + gpio->PDCON |= (0x1 << 8*2); + gpio->PDDAT &= ~(1 << 8); + return 0; + } + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return 1; +} + + +int do_thermo (char **argv) +{ + int channel, res; + + tsc2000_reg_init (); + + if (strcmp (argv[2], "all") == 0) { + int i; + for (i=0; i <= 15; i++) { + res = tsc2000_read_channel(i); + print_identifier (); + printf ("c%d: %d\n", i, res); + } + return 0; + } + channel = simple_strtoul (argv[2], NULL, 10); + res = tsc2000_read_channel(channel); + print_identifier (); + printf ("%d\n", res); + return 0; /* return OK */ +} + + +int do_touch (char **argv) +{ + int x, y; + + if (strcmp (argv[2], "tl") == 0) { +#ifdef CONFIG_TOUCH_WAIT_PRESSED + touch_wait_pressed(); +#else + { + int i; + for (i = 0; i < (TOUCH_TIMEOUT * 1000); i++) { + if (touch_check_pressed ()) { + break; + } + udelay (1000); /* pause 1 ms */ + } + } + if (!touch_check_pressed()) { + print_identifier (); + printf ("error: touch not pressed\n"); + return 1; + } +#endif /* CONFIG_TOUCH_WAIT_PRESSED */ + touch_read_x_y (&x, &y); + + print_identifier (); + printf ("x=%d y=%d\n", x, y); + return touch_write_clibration_values (CALIB_TL, x, y); + } + else if (strcmp (argv[2], "dr") == 0) { +#ifdef CONFIG_TOUCH_WAIT_PRESSED + touch_wait_pressed(); +#else + { + int i; + for (i = 0; i < (TOUCH_TIMEOUT * 1000); i++) { + if (touch_check_pressed ()) { + break; + } + udelay (1000); /* pause 1 ms */ + } + } + if (!touch_check_pressed()) { + print_identifier (); + printf ("error: touch not pressed\n"); + return 1; + } +#endif /* CONFIG_TOUCH_WAIT_PRESSED */ + touch_read_x_y (&x, &y); + + print_identifier (); + printf ("x=%d y=%d\n", x, y); + + return touch_write_clibration_values (CALIB_DR, x, y); + } + return 1; /* not "tl", nor "dr", so return error */ +} + + +#ifdef CONFIG_TOUCH_WAIT_PRESSED +static void touch_wait_pressed (void) +{ + while (!(tsc2000_read(TSC2000_REG_ADC) & TC_PSM)); +} + +#else +static int touch_check_pressed (void) +{ + return (tsc2000_read(TSC2000_REG_ADC) & TC_PSM); +} +#endif /* CONFIG_TOUCH_WAIT_PRESSED */ + +static int touch_write_clibration_values (int calib_point, int x, int y) +{ +#if (CONFIG_COMMANDS & CFG_CMD_I2C) + int x_verify = 0; + int y_verify = 0; + + tsc2000_reg_init (); + + if (calib_point == CALIB_TL) { + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_X0, 1, + (char *)&x, 2)) { + return 1; + } + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_Y0, 1, + (char *)&y, 2)) { + return 1; + } + + /* verify written values */ + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_X0, 1, + (char *)&x_verify, 2)) { + return 1; + } + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_Y0, 1, + (char *)&y_verify, 2)) { + return 1; + } + if ((y != y_verify) || (x != x_verify)) { + print_identifier (); + printf ("error: verify error\n"); + return 1; + } + return 0; /* no error */ + } + else if (calib_point == CALIB_DR) { + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_X1, 1, + (char *)&x, 2)) { + return 1; + } + if (i2c_write_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_Y1, 1, + (char *)&y, 2)) { + return 1; + } + + /* verify written values */ + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_X1, 1, + (char *)&x_verify, 2)) { + return 1; + } + if (i2c_read_multiple (I2C_EEPROM_DEV_ADDR, TOUCH_Y1, 1, + (char *)&y_verify, 2)) { + return 1; + } + if ((y != y_verify) || (x != x_verify)) { + print_identifier (); + printf ("error: verify error\n"); + return 1; + } + return 0; + } + return 1; +#else + printf ("No I2C support enabled (CFG_CMD_I2C), could not write " + "to EEPROM\n"); + return (1); +#endif /* CFG_CMD_I2C */ +} + + +static void touch_read_x_y (int *px, int *py) +{ + tsc2000_write(TSC2000_REG_ADC, DEFAULT_ADC | TC_AD0 | TC_AD1); + adc_wait_conversion_done(); + *px = tsc2000_read(TSC2000_REG_X); + + tsc2000_write(TSC2000_REG_ADC, DEFAULT_ADC | TC_AD2); + adc_wait_conversion_done(); + *py = tsc2000_read(TSC2000_REG_Y); +} + + +int do_rs485 (char **argv) +{ + int timeout; + char data[RS485_MAX_RECEIVE_BUF_LEN]; + + if (strcmp (argv[2], "send") == 0) { + return (rs485_send_line (argv[3])); + } + else if (strcmp (argv[2], "receive") == 0) { + timeout = simple_strtoul(argv[3], NULL, 10); + if (rs485_receive_chars (data, timeout) != 0) { + print_identifier (); + printf ("## nothing received\n"); + return (1); + } + else { + print_identifier (); + printf ("%s\n", data); + return (0); + } + } + printf ("%s: unknown command %s\n", __FUNCTION__, argv[2]); + return (1); /* unknown command, return error */ +} + + +static int rs485_send_line (const char *data) +{ + rs485_init (); + trab_rs485_enable_tx (); + rs485_puts (data); + rs485_putc ('\n'); + + return (0); +} + + +static int rs485_receive_chars (char *data, int timeout) +{ + int i; + int receive_count = 0; + + rs485_init (); + trab_rs485_enable_rx (); + + /* test every 1 ms for received characters to avoid a receive FIFO + * overrun (@ 38.400 Baud) */ + for (i = 0; i < (timeout * 1000); i++) { + while (rs485_tstc ()) { + if (receive_count >= RS485_MAX_RECEIVE_BUF_LEN-1) + break; + *data++ = rs485_getc (); + receive_count++; + } + udelay (1000); /* pause 1 ms */ + } + *data = '\0'; /* terminate string */ + + if (receive_count == 0) + return (1); + else + return (0); +} + + +int do_serial_number (char **argv) +{ +#if (CONFIG_COMMANDS & CFG_CMD_I2C) + unsigned int serial_number; + + if (strcmp (argv[2], "read") == 0) { + if (i2c_read (I2C_EEPROM_DEV_ADDR, SERIAL_NUMBER, 1, + (char *)&serial_number, 4)) { + printf ("could not read from eeprom\n"); + return (1); + } + print_identifier (); + printf ("%08d\n", serial_number); + return (0); + } + else if (strcmp (argv[2], "write") == 0) { + serial_number = simple_strtoul(argv[3], NULL, 10); + if (i2c_write (I2C_EEPROM_DEV_ADDR, SERIAL_NUMBER, 1, + (char *)&serial_number, 4)) { + printf ("could not write to eeprom\n"); + return (1); + } + return (0); + } + printf ("%s: unknown command %s\n", __FUNCTION__, argv[2]); + return (1); /* unknown command, return error */ +#else + printf ("No I2C support enabled (CFG_CMD_I2C), could not write " + "to EEPROM\n"); + return (1); +#endif /* CFG_CMD_I2C */ +} + + +int do_crc16 (void) +{ +#if (CONFIG_COMMANDS & CFG_CMD_I2C) + int crc; + char buf[EEPROM_MAX_CRC_BUF]; + + if (i2c_read (I2C_EEPROM_DEV_ADDR, 0, 1, buf, 60)) { + printf ("could not read from eeprom\n"); + return (1); + } + crc = 0; /* start value of crc calculation */ + crc = updcrc (crc, buf, 60); + + print_identifier (); + printf ("crc16=%#04x\n", crc); + + if (i2c_write (I2C_EEPROM_DEV_ADDR, CRC16, 1, (char *)&crc, + sizeof (crc))) { + printf ("could not read from eeprom\n"); + return (1); + } + return (0); +#else + printf ("No I2C support enabled (CFG_CMD_I2C), could not write " + "to EEPROM\n"); + return (1); +#endif /* CFG_CMD_I2C */ +} + + +/* + * Calculate, intelligently, the CRC of a dataset incrementally given a + * buffer full at a time. + * Initialize crc to 0 for XMODEM, -1 for CCITT. + * + * Usage: + * newcrc = updcrc( oldcrc, bufadr, buflen ) + * unsigned int oldcrc, buflen; + * char *bufadr; + * + * Compile with -DTEST to generate program that prints CRC of stdin to stdout. + * Compile with -DMAKETAB to print values for crctab to stdout + */ + + /* the CRC polynomial. This is used by XMODEM (almost CCITT). + * If you change P, you must change crctab[]'s initial value to what is + * printed by initcrctab() + */ +#define P 0x1021 + + /* number of bits in CRC: don't change it. */ +#define W 16 + + /* this the number of bits per char: don't change it. */ +#define B 8 + +static unsigned short crctab[1<<B] = { /* as calculated by initcrctab() */ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 + }; + +static unsigned short updcrc(unsigned short icrc, unsigned char *icp, + unsigned int icnt ) +{ + register unsigned short crc = icrc; + register unsigned char *cp = icp; + register unsigned int cnt = icnt; + + while (cnt--) + crc = (crc<<B) ^ crctab[(crc>>(W-B)) ^ *cp++]; + + return (crc); +} + + +int do_gain (char **argv) +{ + int range; + + range = simple_strtoul (argv[2], NULL, 10); + if ((range < 1) || (range > 3)) + { + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return 1; + } + + tsc2000_set_range (range); + return (0); +} + + +int do_eeprom (char **argv) +{ +#if (CONFIG_COMMANDS & CFG_CMD_I2C) + if (strcmp (argv[2], "read") == 0) { + return (trab_eeprom_read (argv)); + } + + else if (strcmp (argv[2], "write") == 0) { + return (trab_eeprom_write (argv)); + } + + printf ("%s: invalid parameter %s\n", __FUNCTION__, argv[2]); + return (1); +#else + printf ("No I2C support enabled (CFG_CMD_I2C), could not write " + "to EEPROM\n"); + return (1); +#endif /* CFG_CMD_I2C */ +} + +#if (CONFIG_COMMANDS & CFG_CMD_I2C) +static int trab_eeprom_read (char **argv) +{ + int i; + int len; + unsigned int addr; + long int value = 0; + uchar *buffer; + + buffer = (uchar *) &value; + addr = simple_strtoul (argv[3], NULL, 10); + addr &= 0xfff; + len = simple_strtoul (argv[4], NULL, 10); + if ((len < 1) || (len > 4)) { + printf ("%s: invalid parameter %s\n", __FUNCTION__, + argv[4]); + return (1); + } + for (i = 0; i < len; i++) { + if (i2c_read (I2C_EEPROM_DEV_ADDR, addr+i, 1, buffer+i, 1)) { + printf ("%s: could not read from i2c device %#x" + ", addr %d\n", __FUNCTION__, + I2C_EEPROM_DEV_ADDR, addr); + return (1); + } + } + print_identifier (); + if (strcmp (argv[5], "-") == 0) { + if (len == 1) + printf ("%d\n", (signed char) value); + else if (len == 2) + printf ("%d\n", (signed short int) value); + else + printf ("%ld\n", value); + } + else { + if (len == 1) + printf ("%d\n", (unsigned char) value); + else if (len == 2) + printf ("%d\n", (unsigned short int) value); + else + printf ("%ld\n", (unsigned long int) value); + } + return (0); +} + +static int trab_eeprom_write (char **argv) +{ + int i; + int len; + unsigned int addr; + long int value = 0; + uchar *buffer; + + buffer = (uchar *) &value; + addr = simple_strtoul (argv[3], NULL, 10); + addr &= 0xfff; + len = simple_strtoul (argv[4], NULL, 10); + if ((len < 1) || (len > 4)) { + printf ("%s: invalid parameter %s\n", __FUNCTION__, + argv[4]); + return (1); + } + value = simple_strtol (argv[5], NULL, 10); + debug ("value=%ld\n", value); + for (i = 0; i < len; i++) { + if (i2c_write (I2C_EEPROM_DEV_ADDR, addr+i, 1, buffer+i, 1)) { + printf ("%s: could not write to i2c device %d" + ", addr %d\n", __FUNCTION__, + I2C_EEPROM_DEV_ADDR, addr); + return (1); + } +#if 0 + printf ("chip=%#x, addr+i=%#x+%d=%p, alen=%d, *buffer+i=" + "%#x+%d=%p=%#x \n",I2C_EEPROM_DEV_ADDR_DEV_ADDR , addr, + i, addr+i, 1, buffer, i, buffer+i, *(buffer+i)); +#endif + udelay (30000); /* wait for EEPROM ready */ + } + return (0); +} + +int i2c_write_multiple (uchar chip, uint addr, int alen, + uchar *buffer, int len) +{ + int i; + + if (alen != 1) { + printf ("%s: addr len other than 1 not supported\n", + __FUNCTION__); + return (1); + } + + for (i = 0; i < len; i++) { + if (i2c_write (chip, addr+i, alen, buffer+i, 1)) { + printf ("%s: could not write to i2c device %d" + ", addr %d\n", __FUNCTION__, chip, addr); + return (1); + } +#if 0 + printf ("chip=%#x, addr+i=%#x+%d=%p, alen=%d, *buffer+i=" + "%#x+%d=%p=\"%.1s\"\n", chip, addr, i, addr+i, + alen, buffer, i, buffer+i, buffer+i); +#endif + + udelay (30000); + } + return (0); +} + +int i2c_read_multiple ( uchar chip, uint addr, int alen, + uchar *buffer, int len) +{ + int i; + + if (alen != 1) { + printf ("%s: addr len other than 1 not supported\n", + __FUNCTION__); + return (1); + } + + for (i = 0; i < len; i++) { + if (i2c_read (chip, addr+i, alen, buffer+i, 1)) { + printf ("%s: could not read from i2c device %#x" + ", addr %d\n", __FUNCTION__, chip, addr); + return (1); + } + } + return (0); +} +#endif /* CFG_CMD_I2C */ diff --git a/board/trab/tsc2000.c b/board/trab/tsc2000.c new file mode 100755 index 0000000..ca68682 --- /dev/null +++ b/board/trab/tsc2000.c @@ -0,0 +1,362 @@ +/* + * Functions to access the TSC2000 controller on TRAB board (used for scanning + * thermo sensors) + * + * Copyright (C) 2003 Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de + * + * Copyright (C) 2002 DENX Software Engineering, Wolfgang Denk, wd@denx.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <s3c2400.h> +#include "tsc2000.h" + +#include "Pt1000_temp_data.h" + +/* helper function */ +#define abs(value) (((value) < 0) ? ((value)*-1) : (value)) + +/* + * Maximal allowed deviation between two immediate meassurments of an analog + * thermo channel. 1 DIGIT = 0.0276 °C. This is used to filter sporadic + * "jumps" in measurment. + */ +#define MAX_DEVIATION 18 /* unit: DIGITs of adc; 18 DIGIT = 0.5 °C */ + +void spi_init(void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); + int i; + + /* Configure I/O ports. */ + gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000; + gpio->PGCON = (gpio->PGCON & 0x0F3FFF) | 0x008000; + gpio->PGCON = (gpio->PGCON & 0x0CFFFF) | 0x020000; + gpio->PGCON = (gpio->PGCON & 0x03FFFF) | 0x080000; + + CLR_CS_TOUCH(); + + spi->ch[0].SPPRE = 0x1F; /* Baud-rate ca. 514kHz */ + spi->ch[0].SPPIN = 0x01; /* SPI-MOSI holds Level after last bit */ + spi->ch[0].SPCON = 0x1A; /* Polling, Prescaler, Master, CPOL=0, + CPHA=1 */ + + /* Dummy byte ensures clock to be low. */ + for (i = 0; i < 10; i++) { + spi->ch[0].SPTDAT = 0xFF; + } + spi_wait_transmit_done(); +} + + +void spi_wait_transmit_done(void) +{ + S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); + + while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */ +} + + +void tsc2000_write(unsigned short reg, unsigned short data) +{ + S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); + unsigned int command; + + SET_CS_TOUCH(); + command = reg; + spi->ch[0].SPTDAT = (command & 0xFF00) >> 8; + spi_wait_transmit_done(); + spi->ch[0].SPTDAT = (command & 0x00FF); + spi_wait_transmit_done(); + spi->ch[0].SPTDAT = (data & 0xFF00) >> 8; + spi_wait_transmit_done(); + spi->ch[0].SPTDAT = (data & 0x00FF); + spi_wait_transmit_done(); + + CLR_CS_TOUCH(); +} + + +unsigned short tsc2000_read (unsigned short reg) +{ + unsigned short command, data; + S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); + + SET_CS_TOUCH(); + command = 0x8000 | reg; + + spi->ch[0].SPTDAT = (command & 0xFF00) >> 8; + spi_wait_transmit_done(); + spi->ch[0].SPTDAT = (command & 0x00FF); + spi_wait_transmit_done(); + + spi->ch[0].SPTDAT = 0xFF; + spi_wait_transmit_done(); + data = spi->ch[0].SPRDAT; + spi->ch[0].SPTDAT = 0xFF; + spi_wait_transmit_done(); + + CLR_CS_TOUCH(); + return (spi->ch[0].SPRDAT & 0x0FF) | (data << 8); +} + + +void tsc2000_set_mux (unsigned int channel) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + CLR_MUX1_ENABLE; CLR_MUX2_ENABLE; + CLR_MUX3_ENABLE; CLR_MUX4_ENABLE; + switch (channel) { + case 0: + CLR_MUX0; CLR_MUX1; + SET_MUX1_ENABLE; + break; + case 1: + SET_MUX0; CLR_MUX1; + SET_MUX1_ENABLE; + break; + case 2: + CLR_MUX0; SET_MUX1; + SET_MUX1_ENABLE; + break; + case 3: + SET_MUX0; SET_MUX1; + SET_MUX1_ENABLE; + break; + case 4: + CLR_MUX0; CLR_MUX1; + SET_MUX2_ENABLE; + break; + case 5: + SET_MUX0; CLR_MUX1; + SET_MUX2_ENABLE; + break; + case 6: + CLR_MUX0; SET_MUX1; + SET_MUX2_ENABLE; + break; + case 7: + SET_MUX0; SET_MUX1; + SET_MUX2_ENABLE; + break; + case 8: + CLR_MUX0; CLR_MUX1; + SET_MUX3_ENABLE; + break; + case 9: + SET_MUX0; CLR_MUX1; + SET_MUX3_ENABLE; + break; + case 10: + CLR_MUX0; SET_MUX1; + SET_MUX3_ENABLE; + break; + case 11: + SET_MUX0; SET_MUX1; + SET_MUX3_ENABLE; + break; + case 12: + CLR_MUX0; CLR_MUX1; + SET_MUX4_ENABLE; + break; + case 13: + SET_MUX0; CLR_MUX1; + SET_MUX4_ENABLE; + break; + case 14: + CLR_MUX0; SET_MUX1; + SET_MUX4_ENABLE; + break; + case 15: + SET_MUX0; SET_MUX1; + SET_MUX4_ENABLE; + break; + default: + CLR_MUX0; CLR_MUX1; + } +} + + +void tsc2000_set_range (unsigned int range) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + switch (range) { + case 1: + CLR_SEL_TEMP_V_0; SET_SEL_TEMP_V_1; + CLR_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3; + break; + case 2: + CLR_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1; + CLR_SEL_TEMP_V_2; SET_SEL_TEMP_V_3; + break; + case 3: + SET_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1; + SET_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3; + break; + } +} + + +u16 tsc2000_read_channel (unsigned int channel) +{ + u16 res; + + tsc2000_set_mux(channel); + udelay(3 * TSC2000_DELAY_BASE); + + tsc2000_write(TSC2000_REG_ADC, 0x2036); + adc_wait_conversion_done (); + res = tsc2000_read(TSC2000_REG_AUX1); + return res; +} + + +s32 tsc2000_contact_temp (void) +{ + long adc_pt1000, offset; + long u_pt1000; + long contact_temp; + long temp1, temp2; + + tsc2000_reg_init (); + tsc2000_set_range (3); + + /* + * Because of sporadic "jumps" in the measured adc values every + * channel is read two times. If there is a significant difference + * between the two measurements, then print an error and do a third + * measurement, because it is very unlikely that a successive third + * measurement goes also wrong. + */ + temp1 = tsc2000_read_channel (14); + temp2 = tsc2000_read_channel (14); + if (abs(temp2 - temp1) < MAX_DEVIATION) + adc_pt1000 = temp2; + else { + printf ("%s: read adc value (channel 14) exceeded max allowed " + "deviation: %d * 0.0276 °C\n", + __FUNCTION__, MAX_DEVIATION); + printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n", + temp1, temp2); + adc_pt1000 = tsc2000_read_channel (14); + printf ("use (third read) adc value: adc_pt1000 = " + "%ld DIGITs\n", adc_pt1000); + } + debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000); + + temp1 = tsc2000_read_channel (15); + temp2 = tsc2000_read_channel (15); + if (abs(temp2 - temp1) < MAX_DEVIATION) + offset = temp2; + else { + printf ("%s: read adc value (channel 15) exceeded max allowed " + "deviation: %d * 0.0276 °C\n", + __FUNCTION__, MAX_DEVIATION); + printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n", + temp1, temp2); + offset = tsc2000_read_channel (15); + printf ("use (third read) adc value: offset = %ld DIGITs\n", + offset); + } + debug ("read channel 15 (offset): %ld\n", offset); + + /* + * Formula for calculating voltage drop on PT1000 resistor: u_pt1000 = + * x_range3 * (adc_raw - offset) / 10. Formula to calculate x_range3: + * x_range3 = (2500 * (1000000 + err_vref + err_amp3)) / (4095*6). The + * error correction Values err_vref and err_amp3 are assumed as 0 in + * u-boot, because this could cause only a very small error (< 1%). + */ + u_pt1000 = (101750 * (adc_pt1000 - offset)) / 10; + debug ("u_pt1000: %ld\n", u_pt1000); + + if (tsc2000_interpolate(u_pt1000, Pt1000_temp_table, + &contact_temp) == -1) { + printf ("%s: error interpolating PT1000 vlaue\n", + __FUNCTION__); + return (-1000); + } + debug ("contact_temp: %ld\n", contact_temp); + + return contact_temp; +} + + +void tsc2000_reg_init (void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + tsc2000_write(TSC2000_REG_ADC, 0x2036); + tsc2000_write(TSC2000_REG_REF, 0x0011); + tsc2000_write(TSC2000_REG_DACCTL, 0x0000); + + CON_MUX0; + CON_MUX1; + + CON_MUX1_ENABLE; + CON_MUX2_ENABLE; + CON_MUX3_ENABLE; + CON_MUX4_ENABLE; + + CON_SEL_TEMP_V_0; + CON_SEL_TEMP_V_1; + CON_SEL_TEMP_V_2; + CON_SEL_TEMP_V_3; + + tsc2000_set_mux(0); + tsc2000_set_range(0); +} + + +int tsc2000_interpolate(long value, long data[][2], long *result) +{ + int i; + + /* the data is sorted and the first element is upper + * limit so we can easily check for out-of-band values + */ + if (data[0][0] < value || data[1][0] > value) + return -1; + + i = 1; + while (data[i][0] < value) + i++; + + /* To prevent overflow we have to store the intermediate + result in 'long long'. + */ + + *result = data[i-1][1] + + ((unsigned long long)(data[i][1] - data[i-1][1]) + * (unsigned long long)(value - data[i-1][0])) + / (data[i][0] - data[i-1][0]); + + return 0; +} + + +void adc_wait_conversion_done(void) +{ + while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14))); +} diff --git a/board/trab/tsc2000.h b/board/trab/tsc2000.h new file mode 100755 index 0000000..aac9c0c --- /dev/null +++ b/board/trab/tsc2000.h @@ -0,0 +1,145 @@ +/* + * Functions to access the TSC2000 controller on TRAB board (used for scanning + * thermo sensors) + * + * Copyright (C) 2003 Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de + * + * Copyright (C) 2002 DENX Software Engineering, Wolfgang Denk, wd@denx.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TSC2000_H_ +#define _TSC2000_H_ + +/* temperature channel multiplexer definitions */ +#define CON_MUX0 (gpio->PCCON = (gpio->PCCON & 0x0FFFFFCFF) | 0x00000100) +#define CLR_MUX0 (gpio->PCDAT &= 0x0FFEF) +#define SET_MUX0 (gpio->PCDAT |= 0x00010) + +#define CON_MUX1 (gpio->PCCON = (gpio->PCCON & 0x0FFFFF3FF) | 0x00000400) +#define CLR_MUX1 (gpio->PCDAT &= 0x0FFDF) +#define SET_MUX1 (gpio->PCDAT |= 0x00020) + +#define CON_MUX1_ENABLE (gpio->PCCON = (gpio->PCCON & 0x0FFFFCFFF) | 0x00001000) +#define CLR_MUX1_ENABLE (gpio->PCDAT |= 0x00040) +#define SET_MUX1_ENABLE (gpio->PCDAT &= 0x0FFBF) + +#define CON_MUX2_ENABLE (gpio->PCCON = (gpio->PCCON & 0x0FFFF3FFF) | 0x00004000) +#define CLR_MUX2_ENABLE (gpio->PCDAT |= 0x00080) +#define SET_MUX2_ENABLE (gpio->PCDAT &= 0x0FF7F) + +#define CON_MUX3_ENABLE (gpio->PCCON = (gpio->PCCON & 0x0FFFCFFFF) | 0x00010000) +#define CLR_MUX3_ENABLE (gpio->PCDAT |= 0x00100) +#define SET_MUX3_ENABLE (gpio->PCDAT &= 0x0FEFF) + +#define CON_MUX4_ENABLE (gpio->PCCON = (gpio->PCCON & 0x0FFF3FFFF) | 0x00040000) +#define CLR_MUX4_ENABLE (gpio->PCDAT |= 0x00200) +#define SET_MUX4_ENABLE (gpio->PCDAT &= 0x0FDFF) + +#define CON_SEL_TEMP_V_0 (gpio->PCCON = (gpio->PCCON & 0x0FFCFFFFF) | 0x00100000) +#define CLR_SEL_TEMP_V_0 (gpio->PCDAT &= 0x0FBFF) +#define SET_SEL_TEMP_V_0 (gpio->PCDAT |= 0x00400) + +#define CON_SEL_TEMP_V_1 (gpio->PCCON = (gpio->PCCON & 0x0FF3FFFFF) | 0x00400000) +#define CLR_SEL_TEMP_V_1 (gpio->PCDAT &= 0x0F7FF) +#define SET_SEL_TEMP_V_1 (gpio->PCDAT |= 0x00800) + +#define CON_SEL_TEMP_V_2 (gpio->PCCON = (gpio->PCCON & 0x0FCFFFFFF) | 0x01000000) +#define CLR_SEL_TEMP_V_2 (gpio->PCDAT &= 0x0EFFF) +#define SET_SEL_TEMP_V_2 (gpio->PCDAT |= 0x01000) + +#define CON_SEL_TEMP_V_3 (gpio->PCCON = (gpio->PCCON & 0x0F3FFFFFF) | 0x04000000) +#define CLR_SEL_TEMP_V_3 (gpio->PCDAT &= 0x0DFFF) +#define SET_SEL_TEMP_V_3 (gpio->PCDAT |= 0x02000) + +/* TSC2000 register definition */ +#define TSC2000_REG_X ((0 << 11) | (0 << 5)) +#define TSC2000_REG_Y ((0 << 11) | (1 << 5)) +#define TSC2000_REG_Z1 ((0 << 11) | (2 << 5)) +#define TSC2000_REG_Z2 ((0 << 11) | (3 << 5)) +#define TSC2000_REG_BAT1 ((0 << 11) | (5 << 5)) +#define TSC2000_REG_BAT2 ((0 << 11) | (6 << 5)) +#define TSC2000_REG_AUX1 ((0 << 11) | (7 << 5)) +#define TSC2000_REG_AUX2 ((0 << 11) | (8 << 5)) +#define TSC2000_REG_TEMP1 ((0 << 11) | (9 << 5)) +#define TSC2000_REG_TEMP2 ((0 << 11) | (0xA << 5)) +#define TSC2000_REG_DAC ((0 << 11) | (0xB << 5)) +#define TSC2000_REG_ZERO ((0 << 11) | (0x10 << 5)) +#define TSC2000_REG_ADC ((1 << 11) | (0 << 5)) +#define TSC2000_REG_DACCTL ((1 << 11) | (2 << 5)) +#define TSC2000_REG_REF ((1 << 11) | (3 << 5)) +#define TSC2000_REG_RESET ((1 << 11) | (4 << 5)) +#define TSC2000_REG_CONFIG ((1 << 11) | (5 << 5)) + +/* bit definition of TSC2000 ADC register */ +#define TC_PSM (1 << 15) +#define TC_STS (1 << 14) +#define TC_AD3 (1 << 13) +#define TC_AD2 (1 << 12) +#define TC_AD1 (1 << 11) +#define TC_AD0 (1 << 10) +#define TC_RS1 (1 << 9) +#define TC_RS0 (1 << 8) +#define TC_AV1 (1 << 7) +#define TC_AV0 (1 << 6) +#define TC_CL1 (1 << 5) +#define TC_CL0 (1 << 4) +#define TC_PV2 (1 << 3) +#define TC_PV1 (1 << 2) +#define TC_PV0 (1 << 1) + +/* default value for TSC2000 ADC register for use with touch functions */ +#define DEFAULT_ADC (TC_PV1 | TC_AV0 | TC_AV1 | TC_RS0) + +#define TSC2000_DELAY_BASE 500 +#define TSC2000_NO_SENSOR -0x10000 + +#define ERROR_BATTERY 220 /* must be adjusted, if R68 is changed on + * TRAB */ + +void tsc2000_write(unsigned short, unsigned short); +unsigned short tsc2000_read (unsigned short); +u16 tsc2000_read_channel (unsigned int); +void tsc2000_set_mux (unsigned int); +void tsc2000_set_range (unsigned int); +void tsc2000_reg_init (void); +s32 tsc2000_contact_temp (void); +void spi_wait_transmit_done (void); +void spi_init(void); +int tsc2000_interpolate(long value, long data[][2], long *result); +void adc_wait_conversion_done(void); + + +static inline void SET_CS_TOUCH(void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + gpio->PDDAT &= 0x5FF; +} + + +static inline void CLR_CS_TOUCH(void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + gpio->PDDAT |= 0x200; +} + +#endif /* _TSC2000_H_ */ diff --git a/board/trab/u-boot.lds b/board/trab/u-boot.lds new file mode 100755 index 0000000..e56cdd3 --- /dev/null +++ b/board/trab/u-boot.lds @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@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_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + cpu/arm920t/start.o (.text) + lib_arm/_umodsi3.o (.text) + lib_generic/zlib.o (.text) + lib_generic/crc32.o (.text) + lib_generic/string.o (.text) + + . = DEFINED(env_offset) ? env_offset : .; + common/environment.o (.ppcenv) + + *(.text) + } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + .got : { *(.got) } + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/board/trab/vfd.c b/board/trab/vfd.c new file mode 100755 index 0000000..f510ee5 --- /dev/null +++ b/board/trab/vfd.c @@ -0,0 +1,571 @@ +/* + * (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 + */ + +/************************************************************************/ +/* ** DEBUG SETTINGS */ +/************************************************************************/ + +/* #define DEBUG */ + +/************************************************************************/ +/* ** HEADER FILES */ +/************************************************************************/ + +#include <config.h> +#include <common.h> +#include <version.h> +#include <stdarg.h> +#include <linux/types.h> +#include <devices.h> +#include <s3c2400.h> + +#ifdef CONFIG_VFD + +/************************************************************************/ +/* ** CONFIG STUFF -- should be moved to board config file */ +/************************************************************************/ + +/************************************************************************/ + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +#define ROT 0x09 +#define BLAU 0x0C +#define VIOLETT 0X0D + +/* MAGIC */ +#define FRAME_BUF_SIZE ((256*4*56)/8) +#define frame_buf_offs 4 + +/* defines for starting Timer3 as CPLD-Clk */ +#define START3 (1 << 16) +#define UPDATE3 (1 << 17) +#define INVERT3 (1 << 18) +#define RELOAD3 (1 << 19) + +/* CPLD-Register for controlling vfd-blank-signal */ +#define VFD_DISABLE (*(volatile uchar *)0x04038000=0x0000) +#define VFD_ENABLE (*(volatile uchar *)0x04038000=0x0001) + +/* Supported VFD Types */ +#define VFD_TYPE_T119C 1 /* Noritake T119C VFD */ +#define VFD_TYPE_MN11236 2 + +/*#define NEW_CPLD_CLK*/ + +int vfd_board_id; + +/* taken from armboot/common/vfd.c */ +unsigned long adr_vfd_table[112][18][2][4][2]; +unsigned char bit_vfd_table[112][18][2][4][2]; + +/* + * initialize the values for the VFD-grid-control in the framebuffer + */ +void init_grid_ctrl(void) +{ + DECLARE_GLOBAL_DATA_PTR; + ulong adr, grid_cycle; + unsigned int bit, display; + unsigned char temp, bit_nr; + + /* + * clear frame buffer (logical clear => set to "black") + */ + memset ((void *)(gd->fb_base), 0, FRAME_BUF_SIZE); + + switch (gd->vfd_type) { + case VFD_TYPE_T119C: + for (display=0; display<4; display++) { + for(grid_cycle=0; grid_cycle<56; grid_cycle++) { + bit = grid_cycle * 256 * 4 + + (grid_cycle + 200) * 4 + + frame_buf_offs + display; + /* wrap arround if offset (see manual S3C2400) */ + if (bit>=FRAME_BUF_SIZE*8) + bit = bit - (FRAME_BUF_SIZE * 8); + adr = gd->fb_base + (bit/32) * 4 + (3 - (bit%32) / 8); + bit_nr = bit % 8; + bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4; + temp=(*(volatile unsigned char*)(adr)); + temp |= (1<<bit_nr); + (*(volatile unsigned char*)(adr))=temp; + + if(grid_cycle<55) + bit = grid_cycle*256*4+(grid_cycle+201)*4+frame_buf_offs+display; + else + bit = grid_cycle*256*4+200*4+frame_buf_offs+display-4; /* grid nr. 0 */ + /* wrap arround if offset (see manual S3C2400) */ + if (bit>=FRAME_BUF_SIZE*8) + bit = bit-(FRAME_BUF_SIZE*8); + adr = gd->fb_base+(bit/32)*4+(3-(bit%32)/8); + bit_nr = bit%8; + bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4; + temp=(*(volatile unsigned char*)(adr)); + temp |= (1<<bit_nr); + (*(volatile unsigned char*)(adr))=temp; + } + } + break; + case VFD_TYPE_MN11236: + for (display=0; display<4; display++) { + for (grid_cycle=0; grid_cycle<38; grid_cycle++) { + bit = grid_cycle * 256 * 4 + + (253 - grid_cycle) * 4 + + frame_buf_offs + display; + /* wrap arround if offset (see manual S3C2400) */ + if (bit>=FRAME_BUF_SIZE*8) + bit = bit - (FRAME_BUF_SIZE * 8); + adr = gd->fb_base + (bit/32) * 4 + (3 - (bit%32) / 8); + bit_nr = bit % 8; + bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4; + temp=(*(volatile unsigned char*)(adr)); + temp |= (1<<bit_nr); + (*(volatile unsigned char*)(adr))=temp; + + if(grid_cycle<37) + bit = grid_cycle*256*4+(252-grid_cycle)*4+frame_buf_offs+display; + + /* wrap arround if offset (see manual S3C2400) */ + if (bit>=FRAME_BUF_SIZE*8) + bit = bit-(FRAME_BUF_SIZE*8); + adr = gd->fb_base+(bit/32)*4+(3-(bit%32)/8); + bit_nr = bit%8; + bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4; + temp=(*(volatile unsigned char*)(adr)); + temp |= (1<<bit_nr); + (*(volatile unsigned char*)(adr))=temp; + } + } + break; + default: + printf ("Warning: unknown display type\n"); + break; + } +} + +/* + *create translation table for getting easy the right position in the + *physical framebuffer for some x/y-coordinates of the VFDs + */ +void create_vfd_table(void) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned long vfd_table[112][18][2][4][2]; + unsigned int x, y, color, display, entry, pixel; + unsigned int x_abcdef = 0; + + switch (gd->vfd_type) { + case VFD_TYPE_T119C: + for(y=0; y<=17; y++) { /* Line */ + for(x=0; x<=111; x++) { /* Column */ + for(display=0; display <=3; display++) { + + /* Display 0 blue pixels */ + vfd_table[x][y][0][display][0] = + (x==0) ? y*16+display + : (x%4)*4+y*16+((x-1)/2)*1024+display; + /* Display 0 red pixels */ + vfd_table[x][y][1][display][0] = + (x==0) ? y*16+512+display + : (x%4)*4+y*16+((x-1)/2)*1024+512+display; + } + } + } + break; + case VFD_TYPE_MN11236: + for(y=0; y<=17; y++) { /* Line */ + for(x=0; x<=111; x++) { /* Column */ + for(display=0; display <=3; display++) { + + vfd_table[x][y][0][display][0]=0; + vfd_table[x][y][0][display][1]=0; + vfd_table[x][y][1][display][0]=0; + vfd_table[x][y][1][display][1]=0; + + switch (x%6) { + case 0: x_abcdef=0; break; /* a -> a */ + case 1: x_abcdef=2; break; /* b -> c */ + case 2: x_abcdef=4; break; /* c -> e */ + case 3: x_abcdef=5; break; /* d -> f */ + case 4: x_abcdef=3; break; /* e -> d */ + case 5: x_abcdef=1; break; /* f -> b */ + } + + /* blue pixels */ + vfd_table[x][y][0][display][0] = + (x>1) ? x_abcdef*4+((x-1)/3)*1024+y*48+display + : x_abcdef*4+ 0+y*48+display; + /* blue pixels */ + if (x>1 && (x-1)%3) + vfd_table[x][y][0][display][1] = x_abcdef*4+((x-1)/3+1)*1024+y*48+display; + + /* red pixels */ + vfd_table[x][y][1][display][0] = + (x>1) ? x_abcdef*4+24+((x-1)/3)*1024+y*48+display + : x_abcdef*4+24+ 0+y*48+display; + /* red pixels */ + if (x>1 && (x-1)%3) + vfd_table[x][y][1][display][1] = x_abcdef*4+24+((x-1)/3+1)*1024+y*48+display; + } + } + } + break; + default: + /* do nothing */ + return; + } + + /* + * Create table with entries for physical byte adresses and + * bit-number within the byte + * from table with bit-numbers within the total framebuffer + */ + for(y=0;y<18;y++) { + for(x=0;x<112;x++) { + for(color=0;color<2;color++) { + for(display=0;display<4;display++) { + for(entry=0;entry<2;entry++) { + unsigned long adr = gd->fb_base; + unsigned int bit_nr = 0; + + if (vfd_table[x][y][color][display][entry]) { + + pixel = vfd_table[x][y][color][display][entry] + frame_buf_offs; + /* + * wrap arround if offset + * (see manual S3C2400) + */ + if (pixel>=FRAME_BUF_SIZE*8) + pixel = pixel-(FRAME_BUF_SIZE*8); + adr = gd->fb_base+(pixel/32)*4+(3-(pixel%32)/8); + bit_nr = pixel%8; + bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4; + } + adr_vfd_table[x][y][color][display][entry] = adr; + bit_vfd_table[x][y][color][display][entry] = bit_nr; + } + } + } + } + } +} + +/* + * Set/clear pixel of the VFDs + */ +void set_vfd_pixel(unsigned char x, unsigned char y, + unsigned char color, unsigned char display, + unsigned char value) +{ + DECLARE_GLOBAL_DATA_PTR; + ulong adr; + unsigned char bit_nr, temp; + + if (! gd->vfd_type) { + /* Unknown type. */ + return; + } + + /* Pixel-Eintrag Nr. 1 */ + adr = adr_vfd_table[x][y][color][display][0]; + /* Pixel-Eintrag Nr. 1 */ + bit_nr = bit_vfd_table[x][y][color][display][0]; + temp=(*(volatile unsigned char*)(adr)); + + if (value) + temp |= (1<<bit_nr); + else + temp &= ~(1<<bit_nr); + + (*(volatile unsigned char*)(adr))=temp; +} + +/* + * transfer image from BMP-File + */ +void transfer_pic(int display, unsigned char *adr, int height, int width) +{ + int x, y; + unsigned char temp; + + for (; height > 0; height -= 18) + { + if (height > 18) + y = 18; + else + y = height; + for (; y > 0; y--) + { + for (x = 0; x < width; x += 2) + { + temp = *adr++; + set_vfd_pixel(x, y-1, 0, display, 0); + set_vfd_pixel(x, y-1, 1, display, 0); + if ((temp >> 4) == BLAU) + set_vfd_pixel(x, y-1, 0, display, 1); + else if ((temp >> 4) == ROT) + set_vfd_pixel(x, y-1, 1, display, 1); + else if ((temp >> 4) == VIOLETT) + { + set_vfd_pixel(x, y-1, 0, display, 1); + set_vfd_pixel(x, y-1, 1, display, 1); + } + set_vfd_pixel(x+1, y-1, 0, display, 0); + set_vfd_pixel(x+1, y-1, 1, display, 0); + if ((temp & 0x0F) == BLAU) + set_vfd_pixel(x+1, y-1, 0, display, 1); + else if ((temp & 0x0F) == ROT) + set_vfd_pixel(x+1, y-1, 1, display, 1); + else if ((temp & 0x0F) == VIOLETT) + { + set_vfd_pixel(x+1, y-1, 0, display, 1); + set_vfd_pixel(x+1, y-1, 1, display, 1); + } + } + } + if (display > 0) + display--; + else + display = 3; + } +} + +/* + * This function initializes VFD clock that is needed for the CPLD that + * manages the keyboard. + */ +int vfd_init_clocks (void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS(); + S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD(); + + /* try to determine display type from the value + * defined by pull-ups + */ + gpio->PCUP = (gpio->PCUP & 0xFFF0); /* activate GPC0...GPC3 pullups */ + gpio->PCCON = (gpio->PCCON & 0xFFFFFF00); /* configure GPC0...GPC3 as inputs */ + udelay (10); /* allow signals to settle */ + vfd_board_id = (~gpio->PCDAT) & 0x000F; /* read GPC0...GPC3 port pins */ + + VFD_DISABLE; /* activate blank for the vfd */ + +#define NEW_CPLD_CLK + +#ifdef NEW_CPLD_CLK + if (vfd_board_id) { + /* If new board revision, then use PWM 3 as cpld-clock */ + /* Enable 500 Hz timer for fill level sensor to operate properly */ + /* Configure TOUT3 as functional pin, disable pull-up */ + gpio->PDCON &= ~0x30000; + gpio->PDCON |= 0x20000; + gpio->PDUP |= (1 << 8); + + /* Configure the prescaler */ + timers->TCFG0 &= ~0xff00; + timers->TCFG0 |= 0x0f00; + + /* Select MUX input (divider) for timer3 (1/16) */ + timers->TCFG1 &= ~0xf000; + timers->TCFG1 |= 0x3000; + + /* Enable autoreload and set the counter and compare + * registers to values for the 500 Hz clock + * (for a given prescaler (15) and divider (16)): + * counter = (66000000 / 500) >> 9; + */ + timers->ch[3].TCNTB = 0x101; + timers->ch[3].TCMPB = 0x101 / 2; + + /* Start timer */ + timers->TCON = (timers->TCON | UPDATE3 | RELOAD3) & ~INVERT3; + timers->TCON = (timers->TCON | START3) & ~UPDATE3; + } +#endif + /* If old board revision, then use vm-signal as cpld-clock */ + lcd->LCDCON2 = 0x00FFC000; + lcd->LCDCON3 = 0x0007FF00; + lcd->LCDCON4 = 0x00000000; + lcd->LCDCON5 = 0x00000400; + lcd->LCDCON1 = 0x00000B75; + /* VM (GPD1) is used as clock for the CPLD */ + gpio->PDCON = (gpio->PDCON & 0xFFFFFFF3) | 0x00000008; + + return 0; +} + +/* + * initialize LCD-Controller of the S3C2400 for using VFDs + * + * VFD detection depends on the board revision: + * starting from Rev. 200 a type code can be read from the data pins, + * driven by some pull-up resistors; all earlier systems must be + * manually configured. The type is set in the "vfd_type" environment + * variable. + */ +int drv_vfd_init(void) +{ + S3C24X0_LCD * const lcd = S3C24X0_GetBase_LCD(); + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + char *tmp; + ulong palette; + static int vfd_init_done = 0; + int vfd_inv_data = 0; + + DECLARE_GLOBAL_DATA_PTR; + + if (vfd_init_done != 0) + return (0); + vfd_init_done = 1; + + debug("Detecting Revison of WA4-VFD: ID=0x%X\n", vfd_board_id); + + switch (vfd_board_id) { + case 0: /* board revision < Rev.200 */ + if ((tmp = getenv ("vfd_type")) == NULL) { + break; + } + if (strcmp(tmp, "T119C") == 0) { + gd->vfd_type = VFD_TYPE_T119C; + } else if (strcmp(tmp, "MN11236") == 0) { + gd->vfd_type = VFD_TYPE_MN11236; + } else { + /* cannot use printf for a warning here */ + gd->vfd_type = 0; /* unknown */ + } + + break; + default: /* default to MN11236, data inverted */ + gd->vfd_type = VFD_TYPE_MN11236; + vfd_inv_data = 1; + setenv ("vfd_type", "MN11236"); + } + debug ("VFD type: %s%s\n", + (gd->vfd_type == VFD_TYPE_T119C) ? "T119C" : + (gd->vfd_type == VFD_TYPE_MN11236) ? "MN11236" : + "unknown", + vfd_inv_data ? ", inverted data" : ""); + + gd->fb_base = gd->fb_base; + create_vfd_table(); + init_grid_ctrl(); + + for (palette=0; palette < 16; palette++) + (*(volatile unsigned int*)(PALETTE+(palette*4)))=palette; + for (palette=16; palette < 256; palette++) + (*(volatile unsigned int*)(PALETTE+(palette*4)))=0x00; + + /* + * Hinweis: Der Framebuffer ist um genau ein Nibble verschoben + * Das erste angezeigte Pixel wird aus dem zweiten Nibble geholt + * das letzte angezeigte Pixel wird aus dem ersten Nibble geholt + * (wrap around) + * see manual S3C2400 + */ + /* Stopp LCD-Controller */ + lcd->LCDCON1 = 0x00000000; + /* frame buffer startadr */ + lcd->LCDSADDR1 = gd->fb_base >> 1; + /* frame buffer endadr */ + lcd->LCDSADDR2 = (gd->fb_base + FRAME_BUF_SIZE) >> 1; + lcd->LCDSADDR3 = ((256/4)); + lcd->LCDCON2 = 0x000DC000; + if(gd->vfd_type == VFD_TYPE_MN11236) + lcd->LCDCON2 = 37 << 14; /* MN11236: 38 lines */ + else + lcd->LCDCON2 = 55 << 14; /* T119C: 56 lines */ + lcd->LCDCON3 = 0x0051000A; + lcd->LCDCON4 = 0x00000001; + if (gd->vfd_type && vfd_inv_data) + lcd->LCDCON5 = 0x000004C0; + else + lcd->LCDCON5 = 0x00000440; + + /* Port pins as LCD output */ + gpio->PCCON = (gpio->PCCON & 0xFFFFFF00)| 0x000000AA; + gpio->PDCON = (gpio->PDCON & 0xFFFFFF03)| 0x000000A8; + + /* Synchronize VFD enable with LCD controller to avoid flicker */ + lcd->LCDCON1 = 0x00000B75; /* Start LCD-Controller */ + while((lcd->LCDCON5 & 0x180000)!=0x100000); /* Wait for end of VSYNC */ + while((lcd->LCDCON5 & 0x060000)!=0x040000); /* Wait for next HSYNC */ + while((lcd->LCDCON5 & 0x060000)==0x040000); + while((lcd->LCDCON5 & 0x060000)!=0x000000); + if(gd->vfd_type) + VFD_ENABLE; + + debug ("LCDSADDR1: %lX\n", lcd->LCDSADDR1); + debug ("LCDSADDR2: %lX\n", lcd->LCDSADDR2); + debug ("LCDSADDR3: %lX\n", lcd->LCDSADDR3); + + return 0; +} + +/* + * Disable VFD: should be run before resetting the system: + * disable VM, enable pull-up + */ +void disable_vfd (void) +{ + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + VFD_DISABLE; + gpio->PDCON &= ~0xC; + gpio->PDUP &= ~0x2; +} + +/************************************************************************/ +/* ** ROM capable initialization part - needed to reserve FB memory */ +/************************************************************************/ + +/* + * This is called early in the system initialization to grab memory + * for the VFD controller. + * + * Note that this is running from ROM, so no write access to global data. + */ +ulong vfd_setmem (ulong addr) +{ + ulong size; + + /* Round up to nearest full page */ + size = (FRAME_BUF_SIZE + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); + + debug ("Reserving %ldk for VFD Framebuffer at: %08lx\n", size>>10, addr); + + return (size); +} + +/* + * Calculate fb size for VIDEOLFB_ATAG. Size returned contains fb, + * descriptors and palette areas. + */ +ulong calc_fbsize (void) +{ + return FRAME_BUF_SIZE; +} + +#endif /* CONFIG_VFD */ |