📄 amd.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on
// your install media.
//
//-----------------------------------------------------------------------------
//
// Copyright (C) 2004, Motorola Inc. All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Copyright (C) 2004-2006, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//-----------------------------------------------------------------------------
//
// File: amd.c
//
// Provides the implementation of the AMD lower layer flash drivers.
// Notes:
// USE_OS_SERVICES needs the following delay functions:
// 1. void StallExecution(DWORD dwMicroSec), CalibrateStallCounter()
//
//-----------------------------------------------------------------------------
#include <windows.h>
#include <ceddk.h>
#include "nor.h"
#include "amd.h"
//------------------------------------------------------------------------------
// External Variables
//------------------------------------------------------------------------------
// Defines
#define DEFAULT_CMD_DELAY_US 4
#define POLLING_WRBUFR_LIFETIME_US 1000
#define POLLING_WRBUFR_LIFETIME_FACTOR 10
#define POLLING_WRBYPASS_LIFETIME_US 1000
#define POLLING_WRBYPASS_LIFETIME_FACTOR 10
#define ERASE_BLOCK_TIMEOUT_MS 20000
#define ERASE_BLOCK_TIMEOUT_FACTOR 10
#define ERASE_CHIP_TIMEOUT_MS 20000
#define ERASE_CHIP_TIMEOUT_FACTOR 10
// Set to 1 to enable CFI support with Spansion S29WSxxxN devices.
#define S29WSxxxN_CFI_SUPPORT 1
// Set to 1 to enable buffer programming with Spansion S29WSxxxN devices.
#define S29WSxxxN_BUFFER_PROG_SUPPORT 0
//------------------------------------------------------------------------------
// Types
typedef struct _FLASH_PROG_INFO {
ULONG ulDatumProgTO_us; // Typical datum write timeout
ULONG ulMaxDatumProgTOFactor; // Max = factor x typical timeout
ULONG ulBufferProgTO_us; // Typical write buffer timeout
ULONG ulMaxBufferProgTOFactor; // Max = factor x typical timeout
ULONG ulSectorEraseTO_ms; // Typical sector erase timeout
ULONG ulMaxSectorEraseTOFactor; // Max = factor x typical timeout
ULONG ulChipEraseTO_ms; // Typical chip erase timeout
ULONG ulMaxChipEraseTOFactor; // Max = factor x typical timeout
BOOL bUnlockBypassSupport;
} FLASH_PROG_INFO, *PFLASH_PROG_INFO;
//------------------------------------------------------------------------------
// Global Variables
//------------------------------------------------------------------------------
// Local Variables
static FLASH_PROG_INFO g_FlashProgInfo;
//------------------------------------------------------------------------------
// Local Functions
static void PrintPriExtTable(AMD_PET_QUERY_INFO *pPET);
static void PrintFlashProgInfo(FLASH_PROG_INFO *pInfo);
//-----------------------------------------------------------------------------
// EXPORTED FUNCTIONS
//-----------------------------------------------------------------------------
// WARNING: for relocation purpose. Do not move!
void AMDx16_RelocateBegin(void)
{
}
//-----------------------------------------------------------------------------
//
// Function: AMDx16_IsFlashSupported
//
// Function performs check to see if flash is present and if device is
// supported. For 16bit mode flash devices.
//
// Parameters:
// pFlashDesc
// [in/out] pointer to NOR flash descriptor
//
// Returns:
// FALSE if device not supported/present
//
//-----------------------------------------------------------------------------
BOOL AMDx16_IsFlashSupported(NOR_FLASH_DESC *pFlashDesc)
{
ULONG ulFlashBase;
BOOL bIsPaired;
BOOL bSuccess;
DWORD i;
USHORT *pusSiID;
DWORD dwBusWidth;
DEBUGMSG(ZONE_HAL_FUNCTION, (TEXT("AMD_IsFlashSupported+\r\n")));
if (!pFlashDesc) {
DEBUGMSG(ZONE_HAL_ERROR, (TEXT("AMD_IsFlashSupported: null param\r\n")));
return FALSE;
}
ulFlashBase = pFlashDesc->FlashBase;
bSuccess = TRUE;
for (i = 0; i < sizeof(NOR_FLASH_ID_DESC) / sizeof(ULONG); i++)
*((ULONG *)&pFlashDesc->FlashID + i) = 0;
// This flash is not paired
bIsPaired = FALSE;
// Check for manufacturer ID
// issue a soft reset to the device
// ********************************
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_RESET, CYCLE_1_DATA_RESET);
// enter autoselect mode and determine if the manufacturer is supported
// ********************************************************************
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_UNLOCK_x16, CYCLE_1_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_2_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_3_ADDR_CMD_x16, CYCLE_3_DATA_AUTOSELECT);
if (!CHECK_FLASH_STATUS_INDEXED16(bIsPaired, ulFlashBase, CYCLE_4_ADDR_MFG_ID, AMD_MFG_ID_x16)) {
ERRORMSG(1, (TEXT("No supported AMD flash detected\r\n")));
ERRORMSG(1, (TEXT("Manufacturer: 0x%x Device: 0x%x Paired %c\r\n"),
pFlashDesc->FlashID.ManufacturerID, *(ULONG *)pFlashDesc->FlashID.DeviceID,
bIsPaired ? 'T' : 'F'));
bSuccess = FALSE;
goto _exit;
}
pFlashDesc->FlashID.ManufacturerID = (USHORT)RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, CYCLE_4_ADDR_MFG_ID);
// Note: after the device is in autoselect mode the system may read at any
// address any number of times without initiating another autoselect
// command sequence. In this context the following offset definition
// may appear to be is a misnomer.
// ***********************************************************************
pFlashDesc->FlashID.DeviceID[0] = (USHORT)RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, CYCLE_4_ADDR_DEV_ID);
pFlashDesc->FlashID.DeviceID[1] = (USHORT)RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, CYCLE_5_ADDR_DEV_ID);
pFlashDesc->FlashID.DeviceID[2] = (USHORT)RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, CYCLE_6_ADDR_DEV_ID);
// exit autoselect mode by issuing a soft reset
// ********************************************
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_RESET, CYCLE_1_DATA_RESET);
DEBUGMSG(ZONE_HAL_INFO, (TEXT("Manufacturer: 0x%x Device: 0x%x Paired %c\r\n"),
pFlashDesc->FlashID.ManufacturerID, *(ULONG *)pFlashDesc->FlashID.DeviceID,
bIsPaired ? 'T' : 'F'));
// Look for a Common Flash Interface (CFI) device.
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CFI_QUERY_ADDR, CFI_QUERY_DATA);
#if S29WSxxxN_CFI_SUPPORT
// From S29WSxxxN spec:
// CFI query command is valid when device is ready to read array data or
// when device is in autoselect mode. Address will equal 55h on all
// future devices, but 555h for WS256N/128N/064N.
// So we do both just to be compatible.
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, 0x555, CFI_QUERY_DATA);
#endif
if (!CHECK_FLASH_STATUS_INDEXED16(bIsPaired, ulFlashBase, CFI_QS_OFFSET_QRY_ID_Q, CFI_DATA_QUERY_ID_Q) ||
!CHECK_FLASH_STATUS_INDEXED16(bIsPaired, ulFlashBase, CFI_QS_OFFSET_QRY_ID_R, CFI_DATA_QUERY_ID_R) ||
!CHECK_FLASH_STATUS_INDEXED16(bIsPaired, ulFlashBase, CFI_QS_OFFSET_QRY_ID_Y, CFI_DATA_QUERY_ID_Y))
{
// TODO - add JEDEC check & fake CFI info to support.
// This flash doesn't support CFI.
ERRORMSG(ZONE_ERROR, (TEXT("ERROR: AMD: CFI not supported\r\n")));
bSuccess = FALSE;
goto _exit;
}
DEBUGMSG(ZONE_HAL_INFO, (TEXT("INFO: CFI device detected at 0x%x. Paired(%c)\r\n"),
ulFlashBase, bIsPaired? 'T':'F'));
// Use the CFI to collect information on it. Also, assume that both
// high and low word flash parts are the same if paired.
for (i = 0; i < sizeof(CFI_FLASH_QUERY_ID_STRING); i++) {
*((UCHAR *)&pFlashDesc->QryIDStr + i) =
(UCHAR)(RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, CFI_QS_OFFSET_QRY_ID + i) & 0xFF);
}
for (i = 0; i < sizeof(CFI_FLASH_SYSINTERFACE_INFO); i++) {
*((UCHAR *)&pFlashDesc->SysInt + i) =
(UCHAR)(RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, CFI_QS_OFFSET_SYSINTF + i) & 0xFF);
}
for (i = 0; i < sizeof(CFI_FLASH_GEOMETRY_INFO); i++) {
*((UCHAR *)&pFlashDesc->Geometry + i) =
(UCHAR)(RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, CFI_QS_OFFSET_DEVGEOM + i) & 0xFF);
}
// Get Primary extended table
if (pFlashDesc->QryIDStr.PriExtTableAddr != 0) {
AMD_PET_QUERY_INFO pet;
for (i = 0; i < sizeof(AMD_PET_QUERY_INFO); i++) {
*((PUCHAR)&pet + i) =
(UCHAR)((RD_FLASH_INDEXED16(bIsPaired, ulFlashBase,
pFlashDesc->QryIDStr.PriExtTableAddr + i)) & 0xFF);
}
if (!CHECK_FLASH_STATUS_INDEXED16(bIsPaired, ulFlashBase,
pFlashDesc->QryIDStr.PriExtTableAddr, CFI_DATA_PET_ID_P) ||
!CHECK_FLASH_STATUS_INDEXED16(bIsPaired, ulFlashBase,
pFlashDesc->QryIDStr.PriExtTableAddr+1, CFI_DATA_PET_ID_R) ||
!CHECK_FLASH_STATUS_INDEXED16(bIsPaired, ulFlashBase,
pFlashDesc->QryIDStr.PriExtTableAddr+2, CFI_DATA_PET_ID_I)) {
DEBUGMSG(ZONE_HAL_ERROR, (TEXT("INFO: invalid Primary vendor extended table data!\r\n")));
// Default unlock bypass support to TRUE since most part do support
// nowadays.
// TODO: enable unlock bypass support based on JEDEC device ID
g_FlashProgInfo.bUnlockBypassSupport = TRUE;
DEBUGMSG(ZONE_HAL_INFO, (TEXT("INFO: Default unlock bypass support: %s!\r\n"),
g_FlashProgInfo.bUnlockBypassSupport? L"TRUE" : L"FALSE"));
} else {
if (pet.UnlockBypassSupport || pet.ACCVmin || pet.ACCVmax) {
g_FlashProgInfo.bUnlockBypassSupport = TRUE;
DEBUGMSG(ZONE_HAL_INFO, (TEXT("INFO: Unlock bypass supported.\r\n")));
} else {
g_FlashProgInfo.bUnlockBypassSupport = FALSE;
DEBUGMSG(ZONE_HAL_INFO, (TEXT("INFO: Unlock bypass not supported.\r\n")));
}
PrintPriExtTable(&pet);
}
}
// TODO: If CPU is not little endian, need to take care of endianess in
// the structures.
// Check for at least 1 erase region
if (pFlashDesc->Geometry.NumEraseBlockRegions == 0) {
ERRORMSG(ZONE_ERROR, (TEXT("ERROR: NORInit32: invalid geometry info!\r\n")));
bSuccess = FALSE;
goto _exit;
}
// Check for device with supported interface
if (pFlashDesc->Geometry.DevInterface != CFI_DEV_INTF_x8x16_ASYNC &&
pFlashDesc->Geometry.DevInterface != CFI_DEV_INTF_x16_ASYNC &&
pFlashDesc->Geometry.DevInterface != CFI_DEV_INTF_x16x32_ASYNC) {
DEBUGMSG(ZONE_HAL_INFO, (TEXT("INFO: Unsupported device interface 0x%x\r\n"),
pFlashDesc->Geometry.DevInterface));
bSuccess = FALSE;
goto _exit;
}
// Check for supported command set.
if (pFlashDesc->QryIDStr.PriOEMCmdSetID != AMD_CMD_SET_ID) {
DEBUGMSG(ZONE_HAL_INFO, (TEXT("Unsupported Pri Cmd Set: 0x%x\r\n"),
pFlashDesc->QryIDStr.PriOEMCmdSetID));
bSuccess = FALSE;
goto _exit;
}
// Get device unique silicon ID
pusSiID = (USHORT *)(pFlashDesc->FlashID.SiliconID);
dwBusWidth = bIsPaired ? sizeof(ULONG): sizeof(USHORT);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_UNLOCK_x16, CYCLE_1_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_2_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_3_DATA_ENTER_SECSI);
for (i = 0; i < 8; i++)
*(pusSiID + i) = (USHORT)(RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, i) & 0xFFFF);
// Exit Sec Si area
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_UNLOCK_x16, CYCLE_1_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_2_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_3_DATA_EXIT_SECSI);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -