📄 skgespi.c
字号:
/****************************************************************************** * * Name: skspi.c * Project: Flash Programmer, Manufacturing and Diagnostic Tools * Version: $Revision: 1.1.2.7 $ * Date: $Date: 2007/11/20 10:22:20 $ * Purpose: Contains SPI-Flash EEPROM specific functions * ******************************************************************************//****************************************************************************** * * (C)Copyright 1998-2002 SysKonnect GmbH. * (C)Copyright 2002-2007 Marvell. * * Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet * Server Adapters. * * Address all question to: gr-msgg-linux@marvell.com * * LICENSE: * (C)Copyright Marvell. * * 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. * * The information in this file is provided "AS IS" without warranty. * /LICENSE * *****************************************************************************/static const char SysKonnectFileId[] = "@(#) $Id: skgespi.c,v 1.1.2.7 2007/11/20 10:22:20 mlindner Exp $ (C) Marvell.";/*#include <stdio.h>#include <malloc.h>#include <assert.h>*/#include "h/skdrv1st.h"#include "h/skdrv2nd.h"#include "h/skgespi.h"#ifdef Core #include "h/skdrv1st.h" #include "h/skdrv2nd.h" #define fl_print pAC->Gui.WPrint#else extern void fl_print(char *msg, ...); #endif /* Core */extern int fl_type;extern long max_pages;extern long max_faddr;/* low level SPI programming external interface */extern void spi_in8(unsigned short, unsigned char *);extern void spi_in16(unsigned short, unsigned short *);extern void spi_in32(unsigned short, unsigned long *);extern void spi_out8(unsigned short, unsigned char);extern void spi_out16(unsigned short, unsigned short);extern void spi_out32(unsigned short, unsigned long);extern int spi_timer(unsigned int);extern void *spi_malloc(unsigned long);extern void spi_free(void *);/* global variables */unsigned char chip_id;/* local variables */static int spi_yuk2_dev = -1;/* * Yukon 2/EC SPI flash device structure/table */static struct { char *man_name; unsigned char man_id; char *dev_name; unsigned char dev_id; unsigned long sector_size; unsigned long sector_num; char set_protocol; struct { unsigned char op_read; unsigned char op_write; unsigned char op_write_enable; unsigned char op_write_disable; unsigned char op_read_status; unsigned char op_read_id; unsigned char op_sector_erase; unsigned char op_chip_erase; } opcodes;} spi_yuk2_dev_table[] = { { "Atmel", SPI_MAN_ID_ATMEL, "AT25F2048", 0x63, 0x10000, 4, 0, {0x03,0x02,0x06,0x04,0x05,0x15,0x52,0x62} } , { "Atmel", SPI_MAN_ID_ATMEL, "AT25F1024", 0x60, 0x8000, 4, 0, {0x03,0x02,0x06,0x04,0x05,0x15,0x52,0x62} } , { "Intel", SPI_MAN_ID_INTEL, "QB25F016S33B8", 0x89, 0x10000, 32, 0, {0x03,0x02,0x06,0x04,0x05,0x9f,0xd8,0xc7} }, { "SST", SPI_MAN_ID_SST, "SST25VF512", 0x48, 0x1000, 16, 1, {0x03,0x02,0x06,0x04,0x05,0x90,0x20,0x60} } , { "SST", SPI_MAN_ID_SST, "SST25VF010", 0x49, 0x1000, 32, 1, {0x03,0x02,0x06,0x04,0x05,0x90,0x20,0x60} } , { "SST", SPI_MAN_ID_SST, "SST25VF020", 0x43, 0x1000, 64, 1, {0x03,0x02,0x06,0x04,0x05,0x90,0x20,0x60} } , { "SST", SPI_MAN_ID_SST, "SST25VF040", 0x44, 0x1000, 128, 1, {0x03,0x02,0x06,0x04,0x05,0x90,0x20,0x60} } , { "ST", SPI_MAN_ID_ST_M25P20, "M25P20", 0x11, 0x10000, 4, 1, {0x03,0x02,0x06,0x04,0x05,0xab,0xd8,0xc7} } , { "ST", SPI_MAN_ID_ST_M25P10, "M25P10", 0x10, 0x8000, 4, 1, {0x03,0x02,0x06,0x04,0x05,0xab,0xd8,0xc7} }};/* * BEGIN_MANUAL_ENTRY() * * int spi_yuk_flash_erase(unsigned long off,unsigned long len) * * Send chip erase command to SPI Eprom * * Uses: spi_in32, spi_out32, spi_in8, spi_timer * * IN: * off start offset in flash eprom for erase * len length in flash eprom for erase * (all nessesory sectors will be erased) * * return: * 0 Success * 1 Timeout * * END_MANUAL_ENTRY() */static int spi_yuk_flash_erase(unsigned long off,unsigned long len){ char cr; unsigned long creg, i; /* Save SPI control register */ spi_in32(SPI_CTRL_REG, &creg); if ((off+len-1) > 0x1ffffL) { return(1); /* more than 4 segments for erase */ }#ifdef XXX /* there is some problem with chip erase. dr */ /* use faster chip erase command if all sectors should be erased */ if(len > SPI_SECT_SIZE*3L) { spi_out32(SPI_CTRL_REG, SPI_CHIP_ERASE); spi_timer(SPI_TIMER_SET); do { /* Read device status */ spi_in8(SPI_CTRL_REG, &cr); if (spi_timer(SPI_TIMEOUT)) { fl_print("\nSPI chip erase timeout: %d sec\n", SPI_TIMER_SET); return(1); } } while (cr & 1); /* is chip busy ? */ /* Restore SPI control register */ spi_out32(SPI_CTRL_REG, creg); return(0); }#endif for (i = (off >> 15); i <= ((off + len - 1) >> 15); i++) { /* Clear chip command */ spi_out32(SPI_CTRL_REG, (i << 22) | SPI_SECT_ERASE); spi_timer(SPI_TIMER_SET); do { /* Read device status */ spi_in8(SPI_CTRL_REG, &cr); if (spi_timer(SPI_TIMEOUT)) { fl_print("\nSPI chip erase timeout: %d sec\n", SPI_TIMER_SET); return(1); } } while (cr & 1); /* is chip busy ? */ } /* Restore SPI control register */ spi_out32(SPI_CTRL_REG, creg); return(0);}/* * BEGIN_MANUAL_ENTRY() * * int spi_yuk_flash_manage( * unsigned char *data, * unsigned long off, * unsigned long len, * int flag) * * Read, Verify or Write SPI Eprom * * Uses: spi_in32, spi_out32, spi_in8, spi_out8, spi_in16, spi_out16, spi_timer * * IN: * data data buffer * off start offset in flash eprom for operation * len length in flash eprom * flag SPI_READ * SPI_VERIFY * SPI_WRITE * * return: * 0 Success * 1 Timeout * * END_MANUAL_ENTRY() */static unsigned short rol2(unsigned short adr){ unsigned short adr2; /* YUKON-Lite Rev. A1 */ if (chip_id == CHIP_ID_YUKON_LITE || chip_id == CHIP_ID_YUKON_LP) { /* switch address bits [1:0] with [14:13] */ adr2 = adr & 0x6000; adr2 = adr2 >> 13; adr2 = adr2 & 0x0003; adr = adr << 2; adr = adr & 0x7ffc; adr = adr | adr2; } return(adr);}static int spi_yuk_flash_manage(unsigned char *data,unsigned long off,unsigned long len,int flag){ unsigned long a1, a2, cr, i; unsigned short adr, as, ret=0; unsigned char ch, tr; unsigned long progress; unsigned long last_progress; /* Save VPD lower address */ spi_in32(SPI_ADR_REG1, &a1); /* Save VPD higher address */ spi_in32(SPI_ADR_REG2, &a2); /* Set VPD lower address to 0 (15 higher bit)*/ spi_out32(SPI_ADR_REG1, SPI_VPD_MIN); /* Set VPD higher address to 0x7fff (15 higher bit)*/ spi_out32(SPI_ADR_REG2, SPI_VPD_MAX); /* Save SPI control register */ spi_in32(SPI_CTRL_REG, &cr); /* Enable VPD to SPI mapping (set bit 19) */ spi_out32(SPI_CTRL_REG, SPI_VPD_MAP); /* Save Test Control Register 1 */ spi_in8(B2_TST_REG1, &tr); /* Enable write to mapped PCI config register file */ spi_out8(B2_TST_REG1, 2); progress = last_progress = 0; for (i = off, adr = (unsigned short)(off >> 2); i < off + len; i++) { progress = (i * 100) / len; if((progress - last_progress) >= 10) { fl_print("."); last_progress += 10; } /* Set new address to VPD Address reg, initiate reading */ if ((i % 4) == 0) { spi_out16(VPD_ADR_REG, rol2(adr++)); /* Wait for termination */ spi_timer(SPI_TIMER_SET); do { /* Read VPD_ADDR reg for flag check */ spi_in16(VPD_ADR_REG, &as); if (spi_timer(SPI_TIMEOUT)) { fl_print("\nSPI read timeout: %d sec. Offset:0x%05lx\n", SPI_TIMER_SET, i); ret = 1; break; } } while (!(as & VPD_FLAG_MASK)); /* check flag */ if (ret) { break; } } switch (flag) { case SPI_READ: /* Read byte from VPD port */ spi_in8((unsigned short)(VPD_DATA_PORT + (unsigned short)(i % 4)), &ch); *(data++) = ch; break; case SPI_VERIFY: /* Read and verify byte from VPD port */ spi_in8((unsigned short)(VPD_DATA_PORT + (unsigned short)(i % 4)), &ch); if (ch != *(data++)) { fl_print("\n*** SPI data verify error at address 0x%05lx, ", "is %x, should %x\n", i, ch, *(data - 1)); ret = 1; } break; case SPI_WRITE: /* Write byte to VPD port */ spi_out8((unsigned short)(VPD_DATA_PORT + (unsigned short)(i % 4)), *(data++)); if ((i % 4) == 3) { /* Set old Address to VPD_ADDR reg, initiate writing */ spi_out16((unsigned short)VPD_ADR_REG, (unsigned short)(rol2((unsigned short)(adr - 1)) | VPD_FLAG_MASK)); /* Wait for termination */ spi_timer(SPI_TIMER_SET); do { /* Read VPD_ADDR reg for flag check*/ spi_in16(VPD_ADR_REG, &as); if (spi_timer(SPI_TIMEOUT)) { fl_print("\nSPI write timeout: %d sec. Offset:0x%05lx\n", SPI_TIMER_SET, i); ret = 1; break; } } while (as & VPD_FLAG_MASK); /* check flag */ } break; } if (ret) { break; } } /* Restore Test Control Register 1 */ spi_out8(B2_TST_REG1, tr); /* Restore VPD lower address*/ spi_out32(SPI_ADR_REG1, a1); /* Restore VPD higher address*/ spi_out32(SPI_ADR_REG2, a2); /* Restore SPI control register */ spi_out32(SPI_CTRL_REG, cr); fl_print("."); return(ret); }/* * BEGIN_MANUAL_ENTRY() * * int spi_yuk_update_config( * unsigned char *data, * unsigned long off, * unsigned long len) * * Update part of config area * * Uses: spi_flash_manage, spi_flash_erase * * IN: * data data buffer * off start offset in flash eprom (config area) for operation * len length of changing data * * return: * 0 Success * 1 Timeout * * END_MANUAL_ENTRY() */static int spi_yuk_update_config(unsigned char *data,unsigned long off,unsigned long len){ unsigned char *spibuf; unsigned long i; spibuf = spi_malloc((unsigned long)SPI_SECT_SIZE); if(spibuf == NULL) { return(51); } if (spi_flash_manage(spibuf, SPI_LSECT_OFF, SPI_SECT_SIZE, SPI_READ)) { spi_free(spibuf); return(1); } for (i = 0; i < len; i++) { spibuf[off + i - SPI_LSECT_OFF] = data[i]; } if (spi_flash_erase(SPI_LSECT_OFF, SPI_SECT_SIZE)) { spi_free(spibuf); return(7); } if (spi_flash_manage(spibuf, SPI_LSECT_OFF, SPI_SECT_SIZE, SPI_WRITE)) { spi_free(spibuf); return(8); } spi_free(spibuf); return(0);} /* * BEGIN_MANUAL_ENTRY() * * void spi_yuk2_write_enable() * * This function will set the Write enable setting of the SPI EPROM * * Uses: * * IN: * * return: * nothing * * END_MANUAL_ENTRY() */void spi_yuk2_write_enable(){ unsigned long spi_ctrl_reg; /* execute write enable command */ spi_in32(SPI_Y2_CONTROL_REG, &spi_ctrl_reg); spi_ctrl_reg &= ~SPI_Y2_CMD_MASK; spi_ctrl_reg |= SPI_Y2_WEN; spi_out32(SPI_Y2_CONTROL_REG, spi_ctrl_reg); /* wait for the SPI to finish command */ SPI_Y2_WAIT_SE_FINISH_WR();}/* * BEGIN_MANUAL_ENTRY() * * static unsigned long spi_yuk2_read_dword( * unsigned long address) * * The function reads a dword from the specified address in the SPI EPROM. * * Uses: * * IN: * * return: * dword read from given address * * END_MANUAL_ENTRY() */static unsigned long spi_yuk2_read_dword(unsigned long address) /* addres in the SPI EPROM to read from */{ unsigned long reg_val = 0; unsigned long spi_ctrl_reg; /* write spi address */ spi_out32(SPI_Y2_ADDRESS_REG, address); /* execute spi read command */ spi_in32(SPI_Y2_CONTROL_REG, &spi_ctrl_reg); spi_ctrl_reg &= ~SPI_Y2_CMD_MASK; spi_ctrl_reg |= SPI_Y2_RD; spi_out32(SPI_Y2_CONTROL_REG, spi_ctrl_reg); /* wait for the SPI to finish RD operation */ SPI_Y2_WAIT_SE_FINISH_CMD(); /* read the returned data */ spi_in32(SPI_Y2_DATA_REG, ®_val); return reg_val;}/* * BEGIN_MANUAL_ENTRY() * * static int spi_yuk2_write_dword( * unsigned long address, * unsigned long value) * * This function writes the specified dword in the specified SPI EPROM location. * The SPI EPROM should have been put previously in write enable mode and * the target sector erased for the access to succeed. * * Uses: * * IN: * * return: * 0 - if successful * 1 - if fails * * END_MANUAL_ENTRY() */static int spi_yuk2_write_dword(unsigned long address, /* address to write to */unsigned long value) /* new value to be written */{ unsigned long spi_ctrl_reg; unsigned long verify_value; spi_yuk2_write_enable(); /* write spi address */ spi_out32(SPI_Y2_ADDRESS_REG, address); /* write the new value */ spi_out32(SPI_Y2_DATA_REG, value); /* execute the spi write command */ spi_in32(SPI_Y2_CONTROL_REG, &spi_ctrl_reg); spi_ctrl_reg &= ~SPI_Y2_CMD_MASK; spi_ctrl_reg |= SPI_Y2_WR; spi_out32(SPI_Y2_CONTROL_REG, spi_ctrl_reg); /* wait for write to finish */ SPI_Y2_WAIT_SE_FINISH_WR(); verify_value = spi_yuk2_read_dword(address); /* verify if write was successful*/ if ( verify_value == value ) { return 0; } else { fl_print("\n*** SPI data write error at address 0x%08x, ","is 0x%08x, should 0x%08x\n", address, verify_value, value); return 1; }}/* * BEGIN_MANUAL_ENTRY() * * static int spi_yuk2_sst_write_dword( * unsigned long address, * unsigned long value) * * This function writes the specified dword in the specified SPI EPROM location. * The SPI EPROM should have been put previously in write enable mode and * the target sector erased for the access to succeed. * * Uses: * * IN: *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -