From 71022a5661b0c08a1c7d94124355228211e4beea Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Wed, 24 Oct 2001 16:13:42 +0000 Subject: [PATCH] added debug option for get_byte to dump every byte. Fix for technoland config Added new anal-retentive DoC code for those who want it to docmil_fill_inbuf added .h files for new DoC code. --- src/include/mtd/doc2000.h | 136 +++++++ src/include/mtd/nand.h | 130 +++++++ src/include/mtd/nand_ids.h | 52 +++ src/include/rom/fill_inbuf.h | 10 + src/lib/inflate.c | 2 +- src/mainboard/technoland/sbc710/Config | 2 +- src/rom/docmil_fill_inbuf.c | 504 ++++++++++++++++++++++++- 7 files changed, 814 insertions(+), 22 deletions(-) create mode 100644 src/include/mtd/doc2000.h create mode 100644 src/include/mtd/nand.h create mode 100644 src/include/mtd/nand_ids.h diff --git a/src/include/mtd/doc2000.h b/src/include/mtd/doc2000.h new file mode 100644 index 0000000000..c482825727 --- /dev/null +++ b/src/include/mtd/doc2000.h @@ -0,0 +1,136 @@ + +/* Linux driver for Disk-On-Chip 2000 */ +/* (c) 1999 Machine Vision Holdings, Inc. */ +/* Author: David Woodhouse */ +/* $Id$ */ + +#ifndef __MTD_DOC2000_H__ +#define __MTD_DOC2000_H__ + +//#include + +#define DoC_Sig1 0 +#define DoC_Sig2 1 + +#define DoC_ChipID 0x1000 +#define DoC_DOCStatus 0x1001 +#define DoC_DOCControl 0x1002 +#define DoC_FloorSelect 0x1003 +#define DoC_CDSNControl 0x1004 +#define DoC_CDSNDeviceSelect 0x1005 +#define DoC_ECCConf 0x1006 +#define DoC_2k_ECCStatus 0x1007 + +#define DoC_CDSNSlowIO 0x100d +#define DoC_ECCSyndrome0 0x1010 +#define DoC_ECCSyndrome1 0x1011 +#define DoC_ECCSyndrome2 0x1012 +#define DoC_ECCSyndrome3 0x1013 +#define DoC_ECCSyndrome4 0x1014 +#define DoC_ECCSyndrome5 0x1015 +#define DoC_AliasResolution 0x101b +#define DoC_ConfigInput 0x101c +#define DoC_ReadPipeInit 0x101d +#define DoC_WritePipeTerm 0x101e +#define DoC_LastDataRead 0x101f +#define DoC_NOP 0x1020 + +#define DoC_Mil_CDSN_IO 0x0800 +#define DoC_2k_CDSN_IO 0x1800 + +/* How to access the device? + * On ARM, it'll be mmap'd directly with 32-bit wide accesses. + * On PPC, it's mmap'd and 16-bit wide. + * Others use readb/writeb + */ +#if defined(__arm__) +#define ReadDOC_(adr, reg) ((unsigned char)(*(__u32 *)(((unsigned long)adr)+(reg<<2)))) +#define WriteDOC_(d, adr, reg) do{ *(__u32 *)(((unsigned long)adr)+(reg<<2)) = (__u32)d} while(0) +#elif defined(__ppc__) +#define ReadDOC_(adr, reg) ((unsigned char)(*(__u16 *)(((unsigned long)adr)+(reg<<1)))) +#define WriteDOC_(d, adr, reg) do{ *(__u16 *)(((unsigned long)adr)+(reg<<1)) = (__u16)d} while(0) +#else +#define ReadDOC_(adr, reg) readb(((unsigned long)adr) + reg) +#define WriteDOC_(d, adr, reg) writeb(d, ((unsigned long)adr) + reg) +#endif + +#if defined(__i386__) +#define USE_MEMCPY +#endif + +/* These are provided to directly use the DoC_xxx defines */ +#define ReadDOC(adr, reg) ReadDOC_(adr,DoC_##reg) +#define WriteDOC(d, adr, reg) WriteDOC_(d,adr,DoC_##reg) + +#define DOC_MODE_RESET 0 +#define DOC_MODE_NORMAL 1 +#define DOC_MODE_RESERVED1 2 +#define DOC_MODE_RESERVED2 3 + +#define DOC_MODE_MDWREN 4 +#define DOC_MODE_CLR_ERR 0x80 + +#define DOC_ChipID_Doc2k 0x20 +#define DOC_ChipID_DocMil 0x30 + +#define CDSN_CTRL_FR_B 0x80 +#define CDSN_CTRL_ECC_IO 0x20 +#define CDSN_CTRL_FLASH_IO 0x10 +#define CDSN_CTRL_WP 0x08 +#define CDSN_CTRL_ALE 0x04 +#define CDSN_CTRL_CLE 0x02 +#define CDSN_CTRL_CE 0x01 + +#define DOC_ECC_RESET 0 +#define DOC_ECC_ERROR 0x80 +#define DOC_ECC_RW 0x20 +#define DOC_ECC__EN 0x08 +#define DOC_TOGGLE_BIT 0x04 +#define DOC_ECC_RESV 0x02 +#define DOC_ECC_IGNORE 0x01 + +/* We have to also set the reserved bit 1 for enable */ +#define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV) +#define DOC_ECC_DIS (DOC_ECC_RESV) + +struct Nand { + char floor, chip; + unsigned long curadr; + unsigned char curmode; + /* Also some erase/write/pipeline info when we get that far */ +}; + +#define MAX_FLOORS 4 +#define MAX_CHIPS 4 + +#define MAX_FLOORS_MIL 4 +#define MAX_CHIPS_MIL 1 + +#define ADDR_COLUMN 1 +#define ADDR_PAGE 2 +#define ADDR_COLUMN_PAGE 3 + +struct DiskOnChip { + unsigned long physadr; + unsigned long virtadr; + unsigned long totlen; + char ChipID; /* Type of DiskOnChip */ + int ioreg; + + unsigned long mfr; /* Flash IDs - only one type of flash per device */ + unsigned long id; + int chipshift; + char page256; + char pageadrlen; + unsigned long erasesize; + + int curfloor; + int curchip; + + int numchips; + struct Nand *chips; + struct mtd_info *nextdoc; +}; + + +#endif /* __MTD_DOC2000_H__ */ diff --git a/src/include/mtd/nand.h b/src/include/mtd/nand.h new file mode 100644 index 0000000000..464ae8cf2c --- /dev/null +++ b/src/include/mtd/nand.h @@ -0,0 +1,130 @@ +/* + * linux/include/linux/mtd/nand.h + * + * Copyright (c) 2000 David Woodhouse + * Steven J. Hill + * + * $Id$ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Info: + * Contains standard defines and IDs for NAND flash devices + * + * Changelog: + * 01-31-2000 DMW Created + * 09-18-2000 SJH Moved structure out of the Disk-On-Chip drivers + * so it can be used by other NAND flash device + * drivers. I also changed the copyright since none + * of the original contents of this file are specific + * to DoC devices. David can whack me with a baseball + * bat later if I did something naughty. + * 10-11-2000 SJH Added private NAND flash structure for driver + */ +#ifndef __LINUX_MTD_NAND_H +#define __LINUX_MTD_NAND_H + + +/* + * Standard NAND flash commands + */ +#define NAND_CMD_READ0 0 +#define NAND_CMD_READ1 1 +#define NAND_CMD_PAGEPROG 0x10 +#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_ERASE1 0x60 +#define NAND_CMD_STATUS 0x70 +#define NAND_CMD_SEQIN 0x80 +#define NAND_CMD_READID 0x90 +#define NAND_CMD_ERASE2 0xd0 +#define NAND_CMD_RESET 0xff + +/* + * Enumeration for NAND flash chip state + */ +typedef enum { + FL_READY, + FL_READING, + FL_WRITING, + FL_ERASING, + FL_SYNCING +} nand_state_t; + +/* + * NAND Private Flash Chip Data + * + * Structure overview: + * + * IO_ADDR - address to access the 8 I/O lines to the flash device + * + * CTRL_ADDR - address where ALE, CLE and CE control bits are accessed + * + * CLE - location in control word for Command Latch Enable bit + * + * ALE - location in control word for Address Latch Enable bit + * + * NCE - location in control word for nChip Enable bit + * + * chip_lock - spinlock used to protect access to this structure + * + * wq - wait queue to sleep on if a NAND operation is in progress + * + * state - give the current state of the NAND device + * + * page_shift - number of address bits in a page (column address bits) + * + * data_buf - data buffer passed to/from MTD user modules + * + * ecc_code_buf - used only for holding calculated or read ECCs for + * a page read or written when ECC is in use + * + * reserved - padding to make structure fall on word boundary if + * when ECC is in use + */ + +/* + * NAND Flash Manufacturer ID Codes + */ +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec + +/* + * NAND Flash Device ID Structure + * + * Structure overview: + * + * name - Complete name of device + * + * manufacture_id - manufacturer ID code of device. + * + * model_id - model ID code of device. + * + * chipshift - total number of address bits for the device which + * is used to calculate address offsets and the total + * number of bytes the device is capable of. + * + * page256 - denotes if flash device has 256 byte pages or not. + * + * pageadrlen - number of bytes minus one needed to hold the + * complete address into the flash array. Keep in + * mind that when a read or write is done to a + * specific address, the address is input serially + * 8 bits at a time. This structure member is used + * by the read/write routines as a loop index for + * shifting the address out 8 bits at a time. + * + * erasesize - size of an erase block in the flash device. + */ +struct nand_flash_dev { + char * name; + int manufacture_id; + int model_id; + int chipshift; + char page256; + char pageadrlen; + unsigned long erasesize; +}; + +#endif /* __LINUX_MTD_NAND_H */ diff --git a/src/include/mtd/nand_ids.h b/src/include/mtd/nand_ids.h new file mode 100644 index 0000000000..fca30b3914 --- /dev/null +++ b/src/include/mtd/nand_ids.h @@ -0,0 +1,52 @@ +/* + * linux/include/linux/mtd/nand_ids.h + * + * Copyright (c) 2000 David Woodhouse + * Steven J. Hill + * + * $Id$ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Info: + * Contains standard defines and IDs for NAND flash devices + * + * Changelog: + * 01-31-2000 DMW Created + * 09-18-2000 SJH Moved structure out of the Disk-On-Chip drivers + * so it can be used by other NAND flash device + * drivers. I also changed the copyright since none + * of the original contents of this file are specific + * to DoC devices. David can whack me with a baseball + * bat later if I did something naughty. + * 10-11-2000 SJH Added private NAND flash structure for driver + * 2000-10-13 BE Moved out of 'nand.h' - avoids duplication. + */ + +#ifndef __LINUX_MTD_NAND_IDS_H +#define __LINUX_MTD_NAND_IDS_H + +static struct nand_flash_dev nand_flash_ids[] = { + {"Toshiba TC5816BDC", NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000}, + {"Toshiba TC5832DC", NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000}, + {"Toshiba TH58V128DC", NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000}, + {"Toshiba TC58256FT/DC", NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000}, + {"Toshiba TH58512FT", NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000}, + {"Toshiba TC58V32DC", NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000}, + {"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000}, + {"Toshiba TC58V16BDC", NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000}, + {"Samsung KM29N16000", NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000}, + {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000}, + {"Samsung KM29U128T", NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000}, + {"Samsung KM29U256T", NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000}, + {"Samsung unknown 64Mb", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000}, + {"Samsung KM29W32000", NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000}, + {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000}, + {"Samsung KM29U64000", NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000}, + {"Samsung KM29W16000", NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000}, + {NULL,} +}; + +#endif /* __LINUX_MTD_NAND_IDS_H */ diff --git a/src/include/rom/fill_inbuf.h b/src/include/rom/fill_inbuf.h index 16f76b7ecb..515e7a20f7 100644 --- a/src/include/rom/fill_inbuf.h +++ b/src/include/rom/fill_inbuf.h @@ -7,7 +7,17 @@ extern unsigned int inptr; /* index of next byte to be processed in inbuf */ extern int fill_inbuf(void); +#ifndef DEBUG_GET_BYTE #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) +#else +#include +static unsigned char get_byte() { + static int byteno = 0; + unsigned char c = (inptr < insize ? inbuf[inptr++] : fill_inbuf()); + printk_debug("get_byte 0x%x 0x%x\n", byteno++, c); + return c; +} +#endif #endif /* ROM_FILL_INBUF_H */ diff --git a/src/lib/inflate.c b/src/lib/inflate.c index 99e796e8c0..8655e307a7 100644 --- a/src/lib/inflate.c +++ b/src/lib/inflate.c @@ -1,4 +1,4 @@ -#define DEBG(x) +#define DEBG(x) #define DEBG1(x) /* Taken from /usr/src/linux/lib/inflate.c [unmodified] Used for start32, 1/11/2000 diff --git a/src/mainboard/technoland/sbc710/Config b/src/mainboard/technoland/sbc710/Config index 6c2e4e75f6..5d5e00dbec 100644 --- a/src/mainboard/technoland/sbc710/Config +++ b/src/mainboard/technoland/sbc710/Config @@ -29,7 +29,7 @@ option ZKERNEL_MASK=0x7f # is we can drop any LinuxBIOS DoC in from any machine and it will work # fine. # option DOC_KERNEL_START 0 -option DOC_MIL_BASE=0xd000 +option DOC_MIL_BASE=0xd0000 option L440BX object mainboard.o diff --git a/src/rom/docmil_fill_inbuf.c b/src/rom/docmil_fill_inbuf.c index 3e1bd278a0..b7856c8370 100644 --- a/src/rom/docmil_fill_inbuf.c +++ b/src/rom/docmil_fill_inbuf.c @@ -7,6 +7,11 @@ #include #include +#ifdef USE_NEW_DOC_CODE +#include +#include +#include +#endif #ifndef DOC_KERNEL_START #define DOC_KERNEL_START 65536 #endif @@ -20,7 +25,7 @@ static int block_count; static int firstfill = 1; static void memcpy_from_doc_mil(void *dest, const void *src, size_t n); -static unsigned char *doc_mil = (unsigned char *) DOC_MIL_BASE; +static volatile unsigned char *doc_mil = (unsigned char *) DOC_MIL_BASE; #ifdef CHECK_DOC_MIL static unsigned char *checkbuf; #endif /* CHECK_DOC_MIL */ @@ -28,11 +33,36 @@ static unsigned char *checkbuf; static unsigned char *ram; #define K64 (64 * 1024) +#ifdef RESET_DOC +void +reset_doc() +{ +#ifdef USE_NEW_DOC_CODE + doc_mil[DoC_DOCControl] = DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET; + doc_mil[DoC_DOCControl] = DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET; + + doc_mil[DoC_DOCControl] = DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL; + doc_mil[DoC_DOCControl] = DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL; + +#else + *(volatile unsigned char *) (doc_mil + 0x1002) = 0x84; + *(volatile unsigned char *) (doc_mil + 0x1002) = 0x84; + *(volatile unsigned char *) (doc_mil + 0x1002) = 0x85; + *(volatile unsigned char *) (doc_mil + 0x1002) = 0x85; +#endif +} +#endif int fill_inbuf(void) { +redo: if (firstfill) { + // it is possible that we can get in here and the + // doc has never been reset. So go ahead and reset it again. +#ifdef RESET_DOC + reset_doc(); +#endif if ((ram = malloc(K64)) == NULL) { printk_emerg("%6d:%s() - ram malloc failed\n", __LINE__, __FUNCTION__); @@ -55,23 +85,36 @@ fill_inbuf(void) nvram = (unsigned char *) DOC_KERNEL_START; } +#ifdef CHECK_DOC_MIL + printk_info("DOC MIL address 0x%x\n", nvram); +#endif memcpy_from_doc_mil(ram, nvram, K64); #ifdef CHECK_DOC_MIL if (checkbuf) { memcpy_from_doc_mil(checkbuf, nvram, K64); if (memcmp(checkbuf, ram, K64)) { + int i; + for(i = 0; i < K64; i++) + if (checkbuf[i] != ram[i]) + printk_info("at %d First read 0x%x check 0x%x\n", + i, ram[i], checkbuf[i]); printk_emerg("CHECKBUF FAILS for doc mil!\n"); printk_emerg( "address 0x%x\n", nvram); + goto redo; } } +#if 0 { - int i; - printk_info( "First 16 bytes of block: "); - for (i = 0; i < 16; i++) - printk_info("0x%x ", ram[i]); - printk_info( "\n"); + int i, j; + for(i = 0; i < K64; i += 16) { + printk_info("0x%x: ", ram + i); + for(j = 0; j < 16; j++) + printk_info("%x ",ram[i+j]); + printk_info( "\n"); + } } +#endif /* 0 */ #endif printk_debug("%6d:%s() - nvram:0x%p block_count:%d\n", @@ -87,6 +130,412 @@ fill_inbuf(void) return inbuf[0]; } + +#ifdef USE_NEW_DOC_CODE +/************************************************************************** + * + * New DoC code for LinxuBIOS. This code is from: + * doctest.c - a quick and dirty test for DoC2001 in MB BIOS socket + * + * compile: gcc -O2 -g -o doctest doctest.c + * + * Copyright Steven James , Linux Labs (www.linuxlabs.com) + * + * License GPL v2 or later (for what it's worth) + * + * DoC access code derived from Linux kernel drivers + * (c) 1999 Machine Vision Holdings, Inc. + * Author: David Woodhouse + * + *************************************************************************/ + + + +/* Access routines for DoC Mil */ +#define _WriteDoC(data, adr, reg) adr[reg] = data +#define WriteDOC(data, adr, reg) _WriteDoC(data, adr, DoC_##reg) + +#define _ReadDoC(adr, reg) adr[reg] +#define ReadDOC(adr, reg) _ReadDoC(adr, DoC_##reg) + + +/* Perform the required delsy cycles by reading from the NOP register */ +static void DoC_Delay(volatile char *docptr, unsigned short cycles) +{ + volatile char dummy; + int i; + + for (i = 0; i < cycles; i++) + dummy = ReadDOC(docptr, NOP); +} + +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ +static int _DoC_WaitReady(volatile char *docptr) +{ + unsigned short c = 0xffff; + + /* Out-of-line routine to wait for chip response */ + while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c) + ; + + return (c == 0); +} + +static __inline__ int DoC_WaitReady(volatile char *docptr) +{ + /* This is inline, to optimise the common case, where it's ready instantly */ + int ret = 0; + + /* 4 read form NOP register should be issued in prior to the read from CDSNControl + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 4); + + if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(docptr); + + /* issue 2 read from NOP register after reading from CDSNControl register + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 2); + + return ret; +} + +/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to + bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is + required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */ +/* SURELY this is wrong what about bit 8? But I could be wrong... SMJ */ + +static __inline__ void DoC_Command(volatile char *docptr, unsigned char command, + unsigned char xtraflags) +{ + /* Assert the CLE (Command Latch Enable) line to the flash chip */ + WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); + + /* Send the command */ + WriteDOC(command, docptr, CDSNSlowIO); + WriteDOC(command, docptr, Mil_CDSN_IO); + + /* Lower the CLE line */ + WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); +} + +/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to + bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is + required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */ +static __inline__ void DoC_Address (volatile char *docptr, int numbytes, unsigned long ofs, + unsigned char xtraflags1, unsigned char xtraflags2) +{ + /* Assert the ALE (Address Latch Enable line to the flash chip */ + WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); + + /* Send the address */ + switch (numbytes) + { + case 1: + /* Send single byte, bits 0-7. */ + WriteDOC(ofs & 0xff, docptr, CDSNSlowIO); + WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO); + break; + case 2: + /* Send bits 9-16 followed by 17-23 */ + WriteDOC((ofs >> 9) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 17) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO); + break; + case 3: + /* Send 0-7, 9-16, then 17-23 */ + WriteDOC(ofs & 0xff, docptr, CDSNSlowIO); + WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 9) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 17) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO); + break; + default: + return; + } + + /* Lower the ALE line */ + WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); +} + +/* DoC_SelectChip: Select a given flash chip within the current floor */ +static int DoC_SelectChip(volatile char *docptr, int chip) +{ + /* Select the individual flash chip requested */ + WriteDOC(chip, docptr, CDSNDeviceSelect); + DoC_Delay(docptr, 4); + + /* Wait for it to be ready */ + return DoC_WaitReady(docptr); +} + +/* DoC_SelectFloor: Select a given floor (bank of flash chips) */ +static int DoC_SelectFloor(volatile char *docptr, int floor) +{ + /* Select the floor (bank) of chips required */ + WriteDOC(floor, docptr, FloorSelect); + + /* Wait for the chip to be ready */ + return DoC_WaitReady(docptr); +} + +/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ +static int DoC_IdentChip(volatile char *docptr, int floor, int chip, int *mfr, int *id) +{ + int i; + volatile char dummy; + + /* Page in the required floor/chip + FIXME: is this supported by Millennium ?? */ + + DoC_SelectFloor(docptr, floor); + DoC_SelectChip(docptr, chip); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_WaitReady(docptr); + + + /* Read the NAND chip ID: 1. Send ReadID command */ + DoC_Command(docptr, NAND_CMD_READID, CDSN_CTRL_WP); + + /* Read the NAND chip ID: 2. Send address byte zero */ + DoC_Address(docptr, 1, 0x00, CDSN_CTRL_WP, 0x00); + + /* Read the manufacturer and device id codes of the flash device through + CDSN Slow IO register see Software Requirement 11.4 item 5.*/ + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(docptr, 2); + *mfr = ReadDOC(docptr, Mil_CDSN_IO); + + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(docptr, 2); + *id = ReadDOC(docptr, Mil_CDSN_IO); + + /* No response - return failure */ + if (*mfr == 0xff || *mfr == 0) + return 0; + + /* FIXME: to deal with mulit-flash on multi-Millennium case more carefully */ + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (*mfr == nand_flash_ids[i].manufacture_id && + *id == nand_flash_ids[i].model_id) { + printk_info("Flash chip found: Manufacture ID: %2.2X, Chip ID: %2.2X (%s)\n", + *mfr, *id, nand_flash_ids[i].name); + break; + } + } + + if (nand_flash_ids[i].name == NULL) + return 0; + else + return 1; +} + +static int DoCMil_is_alias(volatile char *docptr1, volatile char *docptr2) +{ + int tmp1, tmp2, retval; + + if(docptr1 == docptr2) + return(1); + + /* Use the alias resolution register which was set aside for this + * purpose. If it's value is the same on both chips, they might + * be the same chip, and we write to one and check for a change in + * the other. It's unclear if this register is usuable in the + * DoC 2000 (it's in the Millenium docs), but it seems to work. */ + tmp1 = ReadDOC(docptr1, AliasResolution); + tmp2 = ReadDOC(docptr2, AliasResolution); + if (tmp1 != tmp2) + return 0; + + WriteDOC((tmp1+1) % 0xff, docptr1, AliasResolution); + tmp2 = ReadDOC(docptr2, AliasResolution); + if (tmp2 == (tmp1+1) % 0xff) + retval = 1; + else + retval = 0; + + /* Restore register contents. May not be necessary, but do it just to + * be safe. */ + WriteDOC(tmp1, docptr1, AliasResolution); + + return retval; +} + +#if 0 +int WriteBlockECC(volatile char *docptr, unsigned int block, const char *buf) +{ + unsigned char eccbuf[6]; + volatile char dummy; + int i; + + + DoC_SelectFloor(docptr, 0); + DoC_SelectChip(docptr, 0); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0x00); + DoC_WaitReady(docptr); + /* Set device to main plane of flash */ + DoC_Command(docptr, NAND_CMD_READ0, 0x00); + + /* issue the Serial Data In command to initial the Page Program process +*/ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(docptr, 3, block <<9, 0x00, 0x00); + DoC_WaitReady(docptr); + + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); + + /* Write the data via the internal pipeline through CDSN IO register, + see Pipelined Write Operations 11.2 */ + + for (i = 0; i < 512; i++) { + /* N.B. you have to increase the source address in this way or the + ECC logic will not work properly */ + WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); + } + + WriteDOC(0x00, docptr, WritePipeTerm); + + /* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic + see Reed-Solomon EDC/ECC 11.1 */ + + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + + /* Read the ECC data through the DiskOnChip ECC logic */ + for (i = 0; i < 6; i++) { + eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i); + } + + /* ignore the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , ECCConf); + + /* Write the ECC data to flash */ + for (i = 0; i < 6; i++) { + WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i); + } + + /* write the block status BLOCK_USED (0x5555) at the end of ECC data FIXME: this is only a hack for programming the IPL area for LinuxBIOS and should be replace with proper codes in user space utilities */ + + WriteDOC(0x55, docptr, Mil_CDSN_IO); + WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); + + WriteDOC(0x00, docptr, WritePipeTerm); + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN Slow IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP); + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(docptr, 2); + + if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { + printk_info("Error programming flash\n"); + return -EIO; + } + + return(0); +} + +#endif +int ReadBlockECC( volatile unsigned char *docptr, unsigned int block, char *buf) +{ + int i, ret; + volatile char dummy; + unsigned char syndrome[6]; + unsigned char eccbuf[6]; + + /* issue the Read0 or Read1 command depend on which half of the page + we are accessing. Polling the Flash Ready bit after issue 3 bytes + address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/ + + /* This differs from SiS ipl.S which always issues 0! */ + + DoC_Command(docptr, 0, CDSN_CTRL_WP); +// DoC_Command(docptr, block & 1, CDSN_CTRL_WP); + DoC_Address(docptr, 3, block << 9, CDSN_CTRL_WP, 0x00); + DoC_WaitReady(docptr); + + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_EN, docptr, ECCConf); + + dummy = ReadDOC(docptr, ReadPipeInit); + for (i = 0; i < 511; i++) { + buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); + } + + buf[511] = ReadDOC(docptr, LastDataRead); + + /* Read the ECC data from Spare Data Area, + see Reed-Solomon EDC/ECC 11.1 */ + + dummy = ReadDOC(docptr, ReadPipeInit); + for (i = 0; i < 5; i++) { + eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); + } + + eccbuf[i] = ReadDOC(docptr, LastDataRead); + + /* Flush the pipeline */ + dummy = ReadDOC(docptr, ECCConf); + dummy = ReadDOC(docptr, ECCConf); + + /* Check the ECC Status */ + if (ReadDOC(docptr, ECCConf) & 0x80) { + int nb_errors; + + /* There was an ECC error */ + printk_info("ECC error in block %u\n",block); + + /* Read the ECC syndrom through the DiskOnChip ECC logic. + syndrome will be all ZERO when there is no error */ + + for (i = 0; i < 6; i++) { + syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i); + } +#ifdef CHECK_ECC + nb_errors = doc_decode_ecc(buf, syndrome); + + if(nb_errors <0) { + printk_info("ECC errors uncorrectable!\n"); + return(-EIO); + } + + printk_info("Corrected %u errors!\n",nb_errors); +#else + printk_info("ECC Syndrom bytes:\n"); + for(i=0; i<6 ; i++) + printk_info("%02x,",syndrome[i]); + printk_info("\n"); +#endif + } + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , ECCConf); + + return(0); +} + + +#endif static void memcpy_from_doc_mil(void *dest, const void *src, size_t n) { @@ -94,35 +543,50 @@ memcpy_from_doc_mil(void *dest, const void *src, size_t n) unsigned long address = (unsigned long) src; for (i = n; i >= 0; i -= 0x200) { +#ifdef USE_NEW_DOC_CODE + ReadBlockECC(doc_mil,(address >> 9), dest); + +#else unsigned short c = 0x1000; volatile unsigned char dummy; - /* issue Read00 flash command */ - *(unsigned char *) (doc_mil + 0x1004) = 0x03; - *(unsigned char *) (doc_mil + 0x800) = 0x00; - *(unsigned char *) (doc_mil + 0x101e) = 0x00; - *(unsigned char *) (doc_mil + 0x1004) = 0x01; + *(volatile unsigned char *) (doc_mil + 0x1004) = 0x03; + *(volatile unsigned char *) (doc_mil + 0x800) = 0x00; + *(volatile unsigned char *) (doc_mil + 0x101e) = 0x00; + *(volatile unsigned char *) (doc_mil + 0x1004) = 0x01; /* issue Address to flash */ - *(unsigned char *) (doc_mil + 0x1004) = 0x05; - *(unsigned char *) (doc_mil + 0x800) = address & 0xff; - *(unsigned char *) (doc_mil + 0x800) = (address >> 9) & 0xff; - *(unsigned char *) (doc_mil + 0x800) = (address >> 17) & 0xff; - *(unsigned char *) (doc_mil + 0x101e) = 0x00; - *(unsigned char *) (doc_mil + 0x1004) = 0x01; + *(volatile unsigned char *) (doc_mil + 0x1004) = 0x05; + *(volatile unsigned char *) (doc_mil + 0x800) = address & 0xff; + *(volatile unsigned char *) (doc_mil + 0x800) = (address >> 9) & 0xff; + *(volatile unsigned char *) (doc_mil + 0x800) = (address >> 17) & 0xff; + *(volatile unsigned char *) (doc_mil + 0x101e) = 0x00; + *(volatile unsigned char *) (doc_mil + 0x1004) = 0x01; /* We are using the "side effect" of the assignment to force GCC reload * *(doc_mil + 0x1004) on each iteration */ - while (!((dummy = *(unsigned char *) (doc_mil + 0x1004)) & 0x80) && --c) + while (!((dummy = *(volatile unsigned char *) (doc_mil + 0x1004)) & 0x80) && --c) /* wait for chip response */; /* copy 512 bytes of data from CDSN_IO registers */ - dummy = *(unsigned char *) (doc_mil + 0x101d); + dummy = *(volatile unsigned char *) (doc_mil + 0x101d); +#ifdef CHECK_DOC_MIL + { unsigned char val; unsigned char *cp = dest; + for(i = 0; i < 0x200; i++) { + val = *(volatile unsigned char *) (doc_mil + 0x800 + i); + printk_info("0x%x: 0x%x\n", + i + address, val); + cp[i] = val; + } + } +#else memcpy(dest, doc_mil + 0x800, 0x200); +#endif /* CHECK_DOC_MIL */ +#endif /* USE_NEW_DOC_CODE */ dest += 0x200; address += 0x200; } -} +} #endif /* USE_DOC_MIL */