/*
 * (C) Copyright 2002
 * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
 *
 * adapted for VCMA9
 * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
 *
 * 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 "vcma9.h"
#include "../common/common_util.h"

#if defined(CONFIG_DRIVER_CS8900)
#include <../drivers/net/cs8900.h>

static uchar cs8900_chksum(ushort data)
{
	return((data >> 8) & 0x00FF) + (data & 0x00FF);
}

#endif

DECLARE_GLOBAL_DATA_PTR;

extern void print_vcma9_info(void);
extern int vcma9_cantest(int);
extern int vcma9_nandtest(void);
extern int vcma9_nanderase(void);
extern int vcma9_nandread(ulong);
extern int vcma9_nandwrite(ulong);
extern int vcma9_dactest(int);
extern int do_mplcommon(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);

/* ------------------------------------------------------------------------- */

int do_vcma9(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	if (strcmp(argv[1], "info") == 0)
	{
		print_vcma9_info();
	 	return 0;
   	}
#if defined(CONFIG_DRIVER_CS8900)
	if (strcmp(argv[1], "cs8900") == 0) {
		if (strcmp(argv[2], "read") == 0) {
			uchar addr; ushort data;

			addr = simple_strtoul(argv[3], NULL, 16);
			cs8900_e2prom_read(addr, &data);
			printf("0x%2.2X: 0x%4.4X\n", addr, data);
		} else if (strcmp(argv[2], "write") == 0) {
			uchar addr; ushort data;

			addr = simple_strtoul(argv[3], NULL, 16);
			data = simple_strtoul(argv[4], NULL, 16);
			cs8900_e2prom_write(addr, data);
		} else if (strcmp(argv[2], "setaddr") == 0) {
			uchar addr, i, csum; ushort data;

			/* check for valid ethaddr */
			for (i = 0; i < 6; i++)
				if (gd->bd->bi_enetaddr[i] != 0)
					break;

			if (i < 6) {
				addr = 1;
				data = 0x2158;
				cs8900_e2prom_write(addr, data);
				csum = cs8900_chksum(data);
				addr++;
				for (i = 0; i < 6; i+=2) {
					data = gd->bd->bi_enetaddr[i+1] << 8 |
					       gd->bd->bi_enetaddr[i];
					cs8900_e2prom_write(addr, data);
					csum += cs8900_chksum(data);
					addr++;
				}
				/* calculate header link byte */
				data = 0xA100 | (addr * 2);
				cs8900_e2prom_write(0, data);
				csum += cs8900_chksum(data);
				/* write checksum word */
				cs8900_e2prom_write(addr, (0 - csum) << 8);
			} else {
				puts("\nplease defined 'ethaddr'\n");
			}
		} else if (strcmp(argv[2], "dump") == 0) {
			uchar addr = 0, endaddr, csum; ushort data;

			puts("Dump of CS8900 config device: ");
			cs8900_e2prom_read(addr, &data);
			if ((data & 0xE000) == 0xA000) {
				endaddr = (data & 0x00FF) / 2;
				csum = cs8900_chksum(data);
				for (addr = 1; addr <= endaddr; addr++) {
					cs8900_e2prom_read(addr, &data);
					printf("\n0x%2.2X: 0x%4.4X", addr, data);
					csum += cs8900_chksum(data);
				}
				printf("\nChecksum: %s", (csum == 0) ? "ok" : "wrong");
			} else {
				puts("no valid config found");
			}
			puts("\n");
		}

		return 0;
	}
#endif
#if 0
	if (strcmp(argv[1], "cantest") == 0) {
		if (argc >= 3)
			vcma9_cantest(strcmp(argv[2], "s") ? 0 : 1);
		else
			vcma9_cantest(0);
		return 0;
	}
	if (strcmp(argv[1], "nandtest") == 0) {
		vcma9_nandtest();
		return 0;
	}
	if (strcmp(argv[1], "nanderase") == 0) {
		vcma9_nanderase();
		return 0;
	}
	if (strcmp(argv[1], "nandread") == 0) {
		ulong offset = 0;

		if (argc >= 3)
			offset = simple_strtoul(argv[2], NULL, 16);

		vcma9_nandread(offset);
		return 0;
	}
	if (strcmp(argv[1], "nandwrite") == 0) {
		ulong offset = 0;

		if (argc >= 3)
			offset = simple_strtoul(argv[2], NULL, 16);

		vcma9_nandwrite(offset);
		return 0;
	}
	if (strcmp(argv[1], "dactest") == 0) {
		if (argc >= 3)
			vcma9_dactest(strcmp(argv[2], "s") ? 0 : 1);
		else
		vcma9_dactest(0);
		return 0;
	}
#endif

	return (do_mplcommon(cmdtp, flag, argc, argv));
}

U_BOOT_CMD(
	vcma9, 6, 1, do_vcma9,
	"vcma9   - VCMA9 specific commands\n",
	"flash mem [SrcAddr]\n    - updates U-Boot with image in memory\n"
);
