diff options
author | wdenk <wdenk> | 2002-11-02 23:30:20 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2002-11-02 23:30:20 +0000 |
commit | e221174377d7e3ee848e014b96430d4c97023e93 (patch) | |
tree | cfaa85f367bc58b8770b3dabf4e9fd64121127bf /board/lwmon | |
parent | 7ebf7443ad018a0647f549a835a55f0c08d7a15d (diff) | |
download | bootable_bootloader_goldelico_gta04-e221174377d7e3ee848e014b96430d4c97023e93.zip bootable_bootloader_goldelico_gta04-e221174377d7e3ee848e014b96430d4c97023e93.tar.gz bootable_bootloader_goldelico_gta04-e221174377d7e3ee848e014b96430d4c97023e93.tar.bz2 |
Initial revision
Diffstat (limited to 'board/lwmon')
-rw-r--r-- | board/lwmon/lwmon.c | 966 |
1 files changed, 966 insertions, 0 deletions
diff --git a/board/lwmon/lwmon.c b/board/lwmon/lwmon.c new file mode 100644 index 0000000..e797b36 --- /dev/null +++ b/board/lwmon/lwmon.c @@ -0,0 +1,966 @@ +/*********************************************************************** + * +M* Modul: lwmon.c +M* +M* Content: LWMON specific U-Boot commands. + * + * (C) Copyright 2001, 2002 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * All rights reserved. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@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 + ***********************************************************************/ + +/*---------------------------- Headerfiles ----------------------------*/ +#include <common.h> +#include <mpc8xx.h> +#include <commproc.h> +#include <i2c.h> +#include <command.h> +#include <cmd_bsp.h> +#include <malloc.h> +#include <post.h> + +#include <linux/types.h> +#include <linux/string.h> /* for strdup */ + +/*------------------------ Local prototypes ---------------------------*/ +static long int dram_size (long int, long int *, long int); + + +/*--------------------- Local macros and constants --------------------*/ +#define _NOT_USED_ 0xFFFFFFFF + +/* + * 66 MHz SDRAM access using UPM A + */ +const uint sdram_table[] = +{ +#if defined(CFG_MEMORY_75) || defined(CFG_MEMORY_8E) + /* + * Single Read. (Offset 0 in UPM RAM) + */ + 0x1F0DFC04, 0xEEAFBC04, 0x11AF7C04, 0xEFBAFC00, + 0x1FF5FC47, /* last */ + /* + * SDRAM Initialization (offset 5 in UPM RAM) + * + * This is no UPM entry point. The following definition uses + * the remaining space to establish an initialization + * sequence, which is executed by a RUN command. + * + */ + 0x1FF5FC34, 0xEFEABC34, 0x1FB57C35, /* last */ + /* + * Burst Read. (Offset 8 in UPM RAM) + */ + 0x1F0DFC04, 0xEEAFBC04, 0x10AF7C04, 0xF0AFFC00, + 0xF0AFFC00, 0xF1AFFC00, 0xEFBAFC00, 0x1FF5FC47, /* last */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Single Write. (Offset 18 in UPM RAM) + */ + 0x1F2DFC04, 0xEEABBC00, 0x01B27C04, 0x1FF5FC47, /* last */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Burst Write. (Offset 20 in UPM RAM) + */ + 0x1F0DFC04, 0xEEABBC00, 0x10A77C00, 0xF0AFFC00, + 0xF0AFFC00, 0xE1BAFC04, 0x01FF5FC47, /* last */ + _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Refresh (Offset 30 in UPM RAM) + */ + 0x1FFD7C84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, + 0xFFFFFC84, 0xFFFFFC07, /* last */ + _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Exception. (Offset 3c in UPM RAM) + */ + 0x7FFFFC07, /* last */ + 0xFFFFFCFF, 0xFFFFFCFF, 0xFFFFFCFF, +#endif +#ifdef CFG_MEMORY_7E + /* + * Single Read. (Offset 0 in UPM RAM) + */ + 0x0E2DBC04, 0x11AF7C04, 0xEFBAFC00, 0x1FF5FC47, /* last */ + _NOT_USED_, + /* + * SDRAM Initialization (offset 5 in UPM RAM) + * + * This is no UPM entry point. The following definition uses + * the remaining space to establish an initialization + * sequence, which is executed by a RUN command. + * + */ + 0x1FF5FC34, 0xEFEABC34, 0x1FB57C35, /* last */ + /* + * Burst Read. (Offset 8 in UPM RAM) + */ + 0x0E2DBC04, 0x10AF7C04, 0xF0AFFC00, 0xF0AFFC00, + 0xF1AFFC00, 0xEFBAFC00, 0x1FF5FC47, /* last */ + _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Single Write. (Offset 18 in UPM RAM) + */ + 0x0E29BC04, 0x01B27C04, 0x1FF5FC47, /* last */ + _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Burst Write. (Offset 20 in UPM RAM) + */ + 0x0E29BC04, 0x10A77C00, 0xF0AFFC00, 0xF0AFFC00, + 0xE1BAFC04, 0x1FF5FC47, /* last */ + _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Refresh (Offset 30 in UPM RAM) + */ + 0x1FFD7C84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, + 0xFFFFFC84, 0xFFFFFC07, /* last */ + _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Exception. (Offset 3c in UPM RAM) + */ + 0x7FFFFC07, /* last */ + 0xFFFFFCFF, 0xFFFFFCFF, 0xFFFFFCFF, +#endif +}; + +/* + * Check Board Identity: + * + */ + +/*********************************************************************** +F* Function: int checkboard (void) P*A*Z* + * +P* Parameters: none +P* +P* Returnvalue: int - 0 is always returned + * +Z* Intention: This function is the checkboard() method implementation +Z* for the lwmon board. Only a standard message is printed. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +int checkboard (void) +{ + puts ("Board: Litronic Monitor IV\n"); + return (0); +} + +/*********************************************************************** +F* Function: long int initdram (int board_type) P*A*Z* + * +P* Parameters: int board_type +P* - Usually type of the board - ignored here. +P* +P* Returnvalue: long int +P* - Size of initialized memory + * +Z* Intention: This function is the initdram() method implementation +Z* for the lwmon board. +Z* The memory controller is initialized to access the +Z* DRAM. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +long int initdram (int board_type) +{ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + volatile memctl8xx_t *memctl = &immr->im_memctl; + long int size_b0; + long int size8, size9; + int i; + + /* + * Configure UPMA for SDRAM + */ + upmconfig (UPMA, (uint *)sdram_table, sizeof(sdram_table)/sizeof(uint)); + + memctl->memc_mptpr = CFG_MPTPR; + + /* burst length=4, burst type=sequential, CAS latency=2 */ + memctl->memc_mar = CFG_MAR; + + /* + * Map controller bank 3 to the SDRAM bank at preliminary address. + */ + memctl->memc_or3 = CFG_OR3_PRELIM; + memctl->memc_br3 = CFG_BR3_PRELIM; + + /* initialize memory address register */ + memctl->memc_mamr = CFG_MAMR_8COL; /* refresh not enabled yet */ + + /* mode initialization (offset 5) */ + udelay (200); /* 0x80006105 */ + memctl->memc_mcr = MCR_OP_RUN | MCR_MB_CS3 | MCR_MLCF (1) | MCR_MAD (0x05); + + /* run 2 refresh sequence with 4-beat refresh burst (offset 0x30) */ + udelay (1); /* 0x80006130 */ + memctl->memc_mcr = MCR_OP_RUN | MCR_MB_CS3 | MCR_MLCF (1) | MCR_MAD (0x30); + udelay (1); /* 0x80006130 */ + memctl->memc_mcr = MCR_OP_RUN | MCR_MB_CS3 | MCR_MLCF (1) | MCR_MAD (0x30); + + udelay (1); /* 0x80006106 */ + memctl->memc_mcr = MCR_OP_RUN | MCR_MB_CS3 | MCR_MLCF (1) | MCR_MAD (0x06); + + memctl->memc_mamr |= MAMR_PTBE; /* refresh enabled */ + + udelay (200); + + /* Need at least 10 DRAM accesses to stabilize */ + for (i = 0; i < 10; ++i) { + volatile unsigned long *addr = + (volatile unsigned long *) SDRAM_BASE3_PRELIM; + unsigned long val; + + val = *(addr + i); + *(addr + i) = val; + } + + /* + * Check Bank 0 Memory Size for re-configuration + * + * try 8 column mode + */ + size8 = dram_size (CFG_MAMR_8COL, (ulong *)SDRAM_BASE3_PRELIM, SDRAM_MAX_SIZE); + + udelay (1000); + + /* + * try 9 column mode + */ + size9 = dram_size (CFG_MAMR_9COL, (ulong *)SDRAM_BASE3_PRELIM, SDRAM_MAX_SIZE); + + if (size8 < size9) { /* leave configuration at 9 columns */ + size_b0 = size9; + memctl->memc_mamr = CFG_MAMR_9COL | MAMR_PTBE; + udelay (500); + } else { /* back to 8 columns */ + size_b0 = size8; + memctl->memc_mamr = CFG_MAMR_8COL | MAMR_PTBE; + udelay (500); + } + + /* + * Final mapping: + */ + + memctl->memc_or3 = ((-size_b0) & 0xFFFF0000) | + OR_CSNT_SAM | OR_G5LS | SDRAM_TIMING; + memctl->memc_br3 = (CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V; + udelay (1000); + + return (size_b0); +} + +/*********************************************************************** +F* Function: static long int dram_size (long int mamr_value, +F* long int *base, +F* long int maxsize) P*A*Z* + * +P* Parameters: long int mamr_value +P* - Value for MAMR for the test +P* long int *base +P* - Base address for the test +P* long int maxsize +P* - Maximum size to test for +P* +P* Returnvalue: long int +P* - Size of probed memory + * +Z* Intention: Check memory range for valid RAM. A simple memory test +Z* determines the actually available RAM size between +Z* addresses `base' and `base + maxsize'. Some (not all) +Z* hardware errors are detected: +Z* - short between address lines +Z* - short between data lines + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +static long int dram_size (long int mamr_value, long int *base, long int maxsize) +{ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + volatile memctl8xx_t *memctl = &immr->im_memctl; + volatile long int *addr; + ulong cnt, val; + ulong save[32]; /* to make test non-destructive */ + unsigned char i = 0; + + memctl->memc_mamr = mamr_value; + + for (cnt = maxsize / sizeof (long); cnt > 0; cnt >>= 1) { + addr = base + cnt; /* pointer arith! */ + + save[i++] = *addr; + *addr = ~cnt; + } + + /* write 0 to base address */ + addr = base; + save[i] = *addr; + *addr = 0; + + /* check at base address */ + if ((val = *addr) != 0) { + *addr = save[i]; + return (0); + } + + for (cnt = 1; cnt <= maxsize / sizeof (long); cnt <<= 1) { + addr = base + cnt; /* pointer arith! */ + + val = *addr; + *addr = save[--i]; + + if (val != (~cnt)) { + return (cnt * sizeof (long)); + } + } + return (maxsize); +} + +/* ------------------------------------------------------------------------- */ + +#ifndef PB_ENET_TENA +# define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */ +#endif + +/*********************************************************************** +F* Function: int board_pre_init (void) P*A*Z* + * +P* Parameters: none +P* +P* Returnvalue: int +P* - 0 is always returned. + * +Z* Intention: This function is the board_pre_init() method implementation +Z* for the lwmon board. +Z* Disable Ethernet TENA on Port B. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +int board_pre_init (void) +{ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + + /* Disable Ethernet TENA on Port B + * Necessary because of pull up in COM3 port. + * + * This is just a preliminary fix, intended to turn off TENA + * as soon as possible to avoid noise on the network. Once + * I²C is running we will make sure the interface is + * correctly initialized. + */ + immr->im_cpm.cp_pbpar &= ~PB_ENET_TENA; + immr->im_cpm.cp_pbodr &= ~PB_ENET_TENA; + immr->im_cpm.cp_pbdat &= ~PB_ENET_TENA; /* set to 0 = disabled */ + immr->im_cpm.cp_pbdir |= PB_ENET_TENA; + return (0); +} + +/* ------------------------------------------------------------------------- */ + +/*********************************************************************** +F* Function: void reset_phy (void) P*A*Z* + * +P* Parameters: none +P* +P* Returnvalue: none + * +Z* Intention: Reset the PHY. In the lwmon case we do this by the +Z* signaling the PIC I/O expander. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +void reset_phy (void) +{ + uchar c; + +#ifdef DEBUG + printf ("### Switch on Ethernet for SCC2 ###\n"); +#endif + c = pic_read (0x61); +#ifdef DEBUG + printf ("Old PIC read: reg_61 = 0x%02x\n", c); +#endif + c |= 0x40; /* disable COM3 */ + c &= ~0x80; /* enable Ethernet */ + pic_write (0x61, c); +#ifdef DEBUG + c = pic_read (0x61); + printf ("New PIC read: reg_61 = 0x%02x\n", c); +#endif + udelay (1000); +} + + +/*------------------------- Keyboard controller -----------------------*/ +/* command codes */ +#define KEYBD_CMD_READ_KEYS 0x01 +#define KEYBD_CMD_READ_VERSION 0x02 +#define KEYBD_CMD_READ_STATUS 0x03 +#define KEYBD_CMD_RESET_ERRORS 0x10 + +/* status codes */ +#define KEYBD_STATUS_MASK 0x3F +#define KEYBD_STATUS_H_RESET 0x20 +#define KEYBD_STATUS_BROWNOUT 0x10 +#define KEYBD_STATUS_WD_RESET 0x08 +#define KEYBD_STATUS_OVERLOAD 0x04 +#define KEYBD_STATUS_ILLEGAL_WR 0x02 +#define KEYBD_STATUS_ILLEGAL_RD 0x01 + +/* Number of bytes returned from Keyboard Controller */ +#define KEYBD_VERSIONLEN 2 /* version information */ +#define KEYBD_DATALEN 9 /* normal key scan data */ + +/* maximum number of "magic" key codes that can be assigned */ + +static uchar kbd_addr = CFG_I2C_KEYBD_ADDR; + +static uchar *key_match (uchar *); + +#define KEYBD_SET_DEBUGMODE '#' /* Magic key to enable debug output */ + +/*********************************************************************** +F* Function: int misc_init_r (void) P*A*Z* + * +P* Parameters: none +P* +P* Returnvalue: int +P* - 0 is always returned, even in the case of a keyboard +P* error. + * +Z* Intention: This function is the misc_init_r() method implementation +Z* for the lwmon board. +Z* The keyboard controller is initialized and the result +Z* of a read copied to the environment variable "keybd". +Z* If KEYBD_SET_DEBUGMODE is defined, a check is made for +Z* this key, and if found display to the LCD will be enabled. +Z* The keys in "keybd" are checked against the magic +Z* keycommands defined in the environment. +Z* See also key_match(). + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +int misc_init_r (void) +{ + uchar kbd_data[KEYBD_DATALEN]; + uchar tmp_data[KEYBD_DATALEN]; + uchar keybd_env[2 * KEYBD_DATALEN + 1]; + uchar val, errcd; + uchar *str; + int i; + + i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE); + + /* Read initial keyboard error code */ + val = KEYBD_CMD_READ_STATUS; + i2c_write (kbd_addr, 0, 0, &val, 1); + i2c_read (kbd_addr, 0, 0, &errcd, 1); + /* clear unused bits */ + errcd &= KEYBD_STATUS_MASK; + /* clear "irrelevant" bits. Recommended by Martin Rajek, LWN */ + errcd &= ~(KEYBD_STATUS_H_RESET|KEYBD_STATUS_BROWNOUT); + if (errcd) { + printf ("KEYBD: Error %02X\n", errcd); + } + /* Reset error code and verify */ + val = KEYBD_CMD_RESET_ERRORS; + i2c_write (kbd_addr, 0, 0, &val, 1); + udelay(1000); /* delay NEEDED by keyboard PIC !!! */ + + val = KEYBD_CMD_READ_STATUS; + i2c_write (kbd_addr, 0, 0, &val, 1); + i2c_read (kbd_addr, 0, 0, &val, 1); + + val &= KEYBD_STATUS_MASK; /* clear unused bits */ + if (val) { /* permanent error, report it */ + printf ("*** Keyboard error code %02X ***\n", val); + sprintf (keybd_env, "%02X", val); + setenv ("keybd", keybd_env); + return 0; + } + + /* + * Now we know that we have a working keyboard, so disable + * all output to the LCD except when a key press is detected. + */ + + if ((console_assign (stdout, "serial") < 0) || + (console_assign (stderr, "serial") < 0)) { + printf ("Can't assign serial port as output device\n"); + } + + /* Read Version */ + val = KEYBD_CMD_READ_VERSION; + i2c_write (kbd_addr, 0, 0, &val, 1); + i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_VERSIONLEN); + printf ("KEYBD: Version %d.%d\n", kbd_data[0], kbd_data[1]); + + /* + * Read current keyboard state. + * + * After the error reset it may take some time before the + * keyboard PIC picks up a valid keyboard scan - the total + * scan time is approx. 1.6 ms (information by Martin Rajek, + * 28 Sep 2002). We read a couple of times for the keyboard + * to stabilize, using a big enough delay. + * 10 times should be enough. If the data is still changing, + * we use what we get :-( + */ + + memset (tmp_data, 0xFF, KEYBD_DATALEN); /* impossible value */ + for (i=0; i<10; ++i) { + val = KEYBD_CMD_READ_KEYS; + i2c_write (kbd_addr, 0, 0, &val, 1); + i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN); + + if (memcmp(kbd_data, tmp_data, KEYBD_DATALEN) == 0) { + /* consistent state, done */ + break; + } + /* remeber last state, delay, and retry */ + memcpy (tmp_data, kbd_data, KEYBD_DATALEN); + udelay (5000); + } + + for (i = 0; i < KEYBD_DATALEN; ++i) { + sprintf (keybd_env + i + i, "%02X", kbd_data[i]); + } + setenv ("keybd", keybd_env); + + str = strdup (key_match (kbd_data)); /* decode keys */ +#ifdef KEYBD_SET_DEBUGMODE + if (kbd_data[0] == KEYBD_SET_DEBUGMODE) { /* set debug mode */ + if ((console_assign (stdout, "lcd") < 0) || + (console_assign (stderr, "lcd") < 0)) { + printf ("Can't assign LCD display as output device\n"); + } + } +#endif /* KEYBD_SET_DEBUGMODE */ +#ifdef CONFIG_PREBOOT /* automatically configure "preboot" command on key match */ + setenv ("preboot", str); /* set or delete definition */ +#endif /* CONFIG_PREBOOT */ + if (str != NULL) { + free (str); + } + return (0); +} + +#ifdef CONFIG_PREBOOT + +static uchar kbd_magic_prefix[] = "key_magic"; +static uchar kbd_command_prefix[] = "key_cmd"; + +/*********************************************************************** +F* Function: static uchar *key_match (uchar *kbd_data) P*A*Z* + * +P* Parameters: uchar *kbd_data +P* - The keys to match against our magic definitions +P* +P* Returnvalue: uchar * +P* - != NULL: Pointer to the corresponding command(s) +P* NULL: No magic is about to happen + * +Z* Intention: Check if pressed key(s) match magic sequence, +Z* and return the command string associated with that key(s). +Z* +Z* If no key press was decoded, NULL is returned. +Z* +Z* Note: the first character of the argument will be +Z* overwritten with the "magic charcter code" of the +Z* decoded key(s), or '\0'. +Z* +Z* Note: the string points to static environment data +Z* and must be saved before you call any function that +Z* modifies the environment. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +static uchar *key_match (uchar *kbd_data) +{ + uchar compare[KEYBD_DATALEN-1]; + uchar magic[sizeof (kbd_magic_prefix) + 1]; + uchar extra; + uchar *str, *nxt, *suffix; + uchar *kbd_magic_keys; + int i; + + /* + * 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 = ""; + + /* 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); +#if 0 + printf ("### Check magic \"%s\"\n", magic); +#endif + /* Don't include modifier byte */ + memcpy (compare, kbd_data+1, KEYBD_DATALEN-1); + + extra = 0; + + for (str= getenv(magic); str != NULL; str = (*nxt) ? nxt+1 : nxt) { + uchar c; + int k; + + c = (uchar) simple_strtoul (str, (char **) (&nxt), 16); + + if (str == nxt) { /* invalid character */ + break; + } + + /* + * Check if this key matches the input. + * Set matches to zero, so they match only once + * and we can find duplicates or extra keys + */ + for (k = 0; k < sizeof(compare); ++k) { + if (compare[k] == '\0') /* only non-zero entries */ + continue; + if (c == compare[k]) { /* found matching key */ + compare[k] = '\0'; + break; + } + } + if (k == sizeof(compare)) { + extra = 1; /* unmatched key */ + } + } + + /* + * A full match leaves no keys in the `compare' array, + * and has no extra keys + */ + + for (i = 0; i < sizeof(compare); ++i) { + if (compare[i]) + break; + } + + if ((i == sizeof(compare)) && (extra == 0)) { + uchar cmd_name[sizeof (kbd_command_prefix) + 1]; + char *cmd; + + sprintf (cmd_name, "%s%c", kbd_command_prefix, *suffix); + + cmd = getenv (cmd_name); +#if 0 + printf ("### Set PREBOOT to $(%s): \"%s\"\n", + cmd_name, cmd ? cmd : "<<NULL>>"); +#endif + *kbd_data = *suffix; + return (cmd); + } + } +#if 0 + printf ("### Delete PREBOOT\n"); +#endif + *kbd_data = '\0'; + return (NULL); +} +#endif /* CONFIG_PREBOOT */ + +/*---------------Board Special Commands: PIC read/write ---------------*/ + +#if (CONFIG_COMMANDS & CFG_CMD_BSP) +/*********************************************************************** +F* Function: int do_pic (cmd_tbl_t *cmdtp, int flag, +F* int argc, char *argv[]) P*A*Z* + * +P* Parameters: cmd_tbl_t *cmdtp +P* - Pointer to our command table entry +P* int flag +P* - If the CMD_FLAG_REPEAT bit is set, then this call is +P* a repetition +P* int argc +P* - Argument count +P* char *argv[] +P* - Array of the actual arguments +P* +P* Returnvalue: int +P* - 0 The command was handled successfully +P* 1 An error occurred + * +Z* Intention: Implement the "pic [read|write]" commands. +Z* The read subcommand takes one argument, the register, +Z* whereas the write command takes two, the register and +Z* the new value. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +int do_pic (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + uchar reg, val; + + switch (argc) { + case 3: /* PIC read reg */ + if (strcmp (argv[1], "read") != 0) + break; + + reg = simple_strtoul (argv[2], NULL, 16); + + printf ("PIC read: reg %02x: %02x\n\n", reg, pic_read (reg)); + + return 0; + case 4: /* PIC write reg val */ + if (strcmp (argv[1], "write") != 0) + break; + + reg = simple_strtoul (argv[2], NULL, 16); + val = simple_strtoul (argv[3], NULL, 16); + + printf ("PIC write: reg %02x val 0x%02x: %02x => ", + reg, val, pic_read (reg)); + pic_write (reg, val); + printf ("%02x\n\n", pic_read (reg)); + return 0; + default: + break; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +/*********************************************************************** +F* Function: int do_kbd (cmd_tbl_t *cmdtp, int flag, +F* int argc, char *argv[]) P*A*Z* + * +P* Parameters: cmd_tbl_t *cmdtp +P* - Pointer to our command table entry +P* int flag +P* - If the CMD_FLAG_REPEAT bit is set, then this call is +P* a repetition +P* int argc +P* - Argument count +P* char *argv[] +P* - Array of the actual arguments +P* +P* Returnvalue: int +P* - 0 is always returned. + * +Z* Intention: Implement the "kbd" command. +Z* The keyboard status is read. The result is printed on +Z* the console and written into the "keybd" environment +Z* variable. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +int do_kbd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + uchar kbd_data[KEYBD_DATALEN]; + uchar keybd_env[2 * KEYBD_DATALEN + 1]; + uchar val; + int i; + + i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE); + + /* Read keys */ + val = KEYBD_CMD_READ_KEYS; + i2c_write (kbd_addr, 0, 0, &val, 1); + i2c_read (kbd_addr, 0, 0, kbd_data, KEYBD_DATALEN); + + puts ("Keys:"); + for (i = 0; i < KEYBD_DATALEN; ++i) { + sprintf (keybd_env + i + i, "%02X", kbd_data[i]); + printf (" %02x", kbd_data[i]); + } + putc ('\n'); + setenv ("keybd", keybd_env); + return 0; +} + +/* Read and set LSB switch */ +#define CFG_PC_TXD1_ENA 0x0008 + +/*********************************************************************** +F* Function: int do_lsb (cmd_tbl_t *cmdtp, int flag, +F* int argc, char *argv[]) P*A*Z* + * +P* Parameters: cmd_tbl_t *cmdtp +P* - Pointer to our command table entry +P* int flag +P* - If the CMD_FLAG_REPEAT bit is set, then this call is +P* a repetition +P* int argc +P* - Argument count +P* char *argv[] +P* - Array of the actual arguments +P* +P* Returnvalue: int +P* - 0 The command was handled successfully +P* 1 An error occurred + * +Z* Intention: Implement the "lsb [on|off]" commands. +Z* The lsb is switched according to the first parameter by +Z* by signaling the PIC I/O expander. +Z* Called with no arguments, the current setting is +Z* printed. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +int do_lsb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + uchar val; + immap_t *immr = (immap_t *) CFG_IMMR; + + switch (argc) { + case 1: /* lsb - print setting */ + val = pic_read (0x60); + printf ("LSB is o%s\n", (val & 0x20) ? "n" : "ff"); + return 0; + case 2: /* lsb on or lsb off - set switch */ + val = pic_read (0x60); + + if (strcmp (argv[1], "on") == 0) { + val |= 0x20; + immr->im_ioport.iop_pcpar &= ~(CFG_PC_TXD1_ENA); + immr->im_ioport.iop_pcdat |= CFG_PC_TXD1_ENA; + immr->im_ioport.iop_pcdir |= CFG_PC_TXD1_ENA; + } else if (strcmp (argv[1], "off") == 0) { + val &= ~0x20; + immr->im_ioport.iop_pcpar &= ~(CFG_PC_TXD1_ENA); + immr->im_ioport.iop_pcdat &= ~(CFG_PC_TXD1_ENA); + immr->im_ioport.iop_pcdir |= CFG_PC_TXD1_ENA; + } else { + break; + } + pic_write (0x60, val); + return 0; + default: + break; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +#endif /* CFG_CMD_BSP */ + +/*----------------------------- Utilities -----------------------------*/ +/*********************************************************************** +F* Function: uchar pic_read (uchar reg) P*A*Z* + * +P* Parameters: uchar reg +P* - Register to read +P* +P* Returnvalue: uchar +P* - Value read from register + * +Z* Intention: Read a register from the PIC I/O expander. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +uchar pic_read (uchar reg) +{ + return (i2c_reg_read (CFG_I2C_PICIO_ADDR, reg)); +} + +/*********************************************************************** +F* Function: void pic_write (uchar reg, uchar val) P*A*Z* + * +P* Parameters: uchar reg +P* - Register to read +P* uchar val +P* - Value to write +P* +P* Returnvalue: none + * +Z* Intention: Write to a register on the PIC I/O expander. + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +void pic_write (uchar reg, uchar val) +{ + i2c_reg_write (CFG_I2C_PICIO_ADDR, reg, val); +} + +/*---------------------- Board Control Functions ----------------------*/ +/*********************************************************************** +F* Function: void board_poweroff (void) P*A*Z* + * +P* Parameters: none +P* +P* Returnvalue: none + * +Z* Intention: Turn off the battery power and loop endless, so this +Z* should better be the last function you call... + * +D* Design: wd@denx.de +C* Coding: wd@denx.de +V* Verification: dzu@denx.de + ***********************************************************************/ +void board_poweroff (void) +{ + /* Turn battery off */ + ((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat &= ~(1 << (31 - 13)); + + while (1); +} |