view packages/devs/nand/samsung_k9/current/include/k9_generic_lp.inl @ 3373:62b2c0f5902b

devs/nand/samsung_k9: Add K9F2G08U0A subtype.
author Nick Garnett <nickg@ecoscentric.com>
date Wed, 14 Jul 2010 11:18:08 +0100
parents fad1849d4bb6
children
line wrap: on
line source

//=============================================================================
//
//      k9_generic_lp.inl
//
//      Inline include file for the large page members of the Samsung K9F family
//      NOTE: This file should only be included by k9_generic.inl.
//
//=============================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 2010 eCosCentric Limited.
//
// eCos 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 or (at your option) any later      
// version.                                                                 
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
//
// As a special exception, if other files instantiate templates or use      
// macros or inline functions from this file, or you compile this file      
// and link it with other works to produce a work based on this file,       
// this file does not by itself cause the resulting work to be covered by   
// the GNU General Public License. However the source code for this file    
// must still be made available in accordance with section (3) of the GNU   
// General Public License v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):   wry
// Date:        2010-03-16
//
//####DESCRIPTIONEND####
//=============================================================================

#ifndef CYGFUN_NAND_SAMSUNG_K9_LP
#error k9_generic_lp.inl unexpectedly included
#endif

static inline void write_addr_col_lp(cyg_nand_device *ctx, cyg_nand_column_addr col)
{
    // All supported large-page chips are 8-bit, 2112 bytes per page,
    // column addesses encoded as two bytes.
    CYG_BYTE addr[2] = { col & 0xff, (col>>8) & 0xff };
    write_addrbytes(ctx, &addr[0], 2);
}

static inline void write_addr_col_row_lp(cyg_nand_device *ctx,
        cyg_nand_column_addr c, cyg_uint32 r)
{
    write_addr_col_lp(ctx, c);
    write_addr_row(ctx, r);
}

static inline void change_read_column_lp(cyg_nand_device *dev, cyg_nand_column_addr col)
{
    write_cmd(dev,0x05);
    write_addr_col_lp(dev,col);
    write_cmd(dev,0xe0);
    // wait tREA before reading further. 
    // This is 18ns, less than an instruction.
}

static inline void change_write_column_lp(cyg_nand_device *dev, cyg_nand_column_addr col)
{
    write_cmd(dev,0x85);
    write_addr_col_lp(dev,col);
    // We must wait at least tADL (100ns) before writing further. 
    HAL_DELAY_US(1); // TODO: 1us is a bit wasteful; prefer a tighter sleep duration
}

int nand_k9_read_begin(cyg_nand_device *dev, cyg_nand_page_addr page)
{
    //k9_priv *priv = dev->priv;

    NAND_CHATTER(7,dev,"Reading page %d\n",page);
    LOCK(dev);

    write_cmd(dev,0x00);
    write_addr_col_row_lp(dev, 0, page);
    write_cmd(dev,0x30);
    wait_ready_or_time(dev, 1, 25 /* tR */);
    return 0;
}

int nand_k9_read_stride(cyg_nand_device *dev, void * dest, size_t size)
{
    read_data_bulk(dev, dest, size);
    return 0;
}

int nand_k9_read_finish(cyg_nand_device *dev, void * spare, size_t spare_size)
{

    if (spare && spare_size) {
        change_read_column_lp(dev, 1 << dev->page_bits);
        read_data_bulk(dev, spare, spare_size);
    }
    //k9_reset(dev,5); // Unnecessary.
    UNLOCK(dev);
    return 0;
}

int nand_k9_read_part(cyg_nand_device *dev, void *dest,
                        cyg_nand_page_addr page, size_t offset, size_t length)
{
    //k9_priv *priv = dev->priv;
    NAND_CHATTER(7,dev,"Reading page %d (partial; offset %d, length %d)\n",
                 page, offset, length);
    LOCK(dev);

    write_cmd(dev,0x00);
    write_addr_col_row_lp(dev, offset, page);
    write_cmd(dev,0x30);
    wait_ready_or_time(dev, 1, 25 /* tR */);

    read_data_bulk(dev, dest, length);

    UNLOCK(dev);
    return 0;
}

int nand_k9_write_begin(cyg_nand_device *dev, cyg_nand_page_addr page)
{
    k9_priv *priv = dev->priv;
    // NB: Program with random data input takes a _five_ byte address,
    // according to spec p24. This doesn't make sense - everything else
    // about this chip takes a four-byte address - and is contradicted by p32.

    LOCK(dev);
    priv->pagestash = page;
    write_cmd(dev,0x80);
    write_addr_col_row_lp(dev, 0, page);

    return 0;
}

int nand_k9_write_stride(cyg_nand_device *dev, const void * src, size_t size)
{
    write_data_bulk(dev, src, size);
    return 0;
}

int nand_k9_write_finish(cyg_nand_device *dev, const void * spare, size_t spare_size)
{
    k9_priv *priv = dev->priv;
    int rv = 0;
    if (spare && spare_size) {
        change_write_column_lp(dev, 1 << dev->page_bits);
        write_data_bulk(dev, spare, spare_size);
    }
    write_cmd(dev,0x10);
    wait_ready_or_status(dev, 1<<6);

    if (read_status(dev) & 1) {
        NAND_ERROR(dev, "k9fxx08x0x: Programming failed! Page %u", priv->pagestash);
        rv =-EIO;
        goto done;
    } else {
        NAND_CHATTER(7,dev, "Programmed %u OK\n", priv->pagestash);
    }
done:
    //k9_reset(dev,5); // Unnecessary.
    UNLOCK(dev);
    return rv;
}

#define K9_FACTORY_BAD_COLUMN_ADDR 2048

// The spec sheet says to check the 1st OOB byte (address 2048) in
// both the 1st and 2nd page of the block. If both are 0xFF, the block is OK;
// else it's bad.
// N.B. This is good for at least K9F1G and K9F2G but might need to be tweaked later.
int nand_k9_factorybad_lp(cyg_nand_device *dev, cyg_nand_block_addr blk)
{
    cyg_nand_page_addr page,
                       pagebase = blk * (1<<dev->block_page_bits);
    const int col = K9_FACTORY_BAD_COLUMN_ADDR;
    int rv = 0, i;

    LOCK(dev);

    for (i=0; i<2; i++) {
        page = pagebase+i;
        write_cmd(dev,0x00);
        write_addr_col_row_lp(dev, col, page);
        write_cmd(dev,0x30);
        wait_ready_or_time(dev, 1, 25 /* tR */);
        unsigned char t = read_data_1(dev);
        if (t != 0xff) rv=1;
        //k9_reset(dev,5); // Unnecessary.
    }

    UNLOCK(dev);
    return rv;
}

CYG_NAND_FUNS_V2(nand_k9_funs, nand_k9_devinit,
        nand_k9_read_begin, nand_k9_read_stride, nand_k9_read_finish,
        nand_k9_read_part,
        nand_k9_write_begin, nand_k9_write_stride, nand_k9_write_finish,
        nand_k9_erase_block, nand_k9_factorybad_lp);

// key: SUBTYPE( id[1], id[3],   // ReadID response, 2nd and 4th bytes
//              descriptive string,
//              log2(number of blocks),
//              log2(total chip size in BYTES),
//              width of a row address in bytes)

#ifdef CYGFUN_NAND_SAMSUNG_K9_F2G
#define K9F2G08Q0x K9_SUBTYPE(0xaa, 0x15, "K9F2G08Q0x", 11, 28, 3)
#define K9F2G08U0x K9_SUBTYPE(0xda, 0x15, "K9F2G08U0x", 11, 28, 3), \
                   K9_SUBTYPE(0xda, 0x95, "K9F2G08U0A", 11, 28, 3)
#endif

#ifdef CYGFUN_NAND_SAMSUNG_K9_F1G
#define K9F1G08U0x K9_SUBTYPE(0xf1, 0x15, "K9F1G08U0x", 10, 27, 2)
#endif

// EOF k9_generic_lp.inl