mirror of
https://github.com/LIV2/A4092-dev.git
synced 2025-12-06 00:32:49 +00:00
Adjust flash.c for A4092 flash memory mapping
This commit is contained in:
parent
f5d57d43b4
commit
fa989bfd10
@ -25,6 +25,69 @@
|
||||
|
||||
volatile ULONG flashbase;
|
||||
|
||||
/**
|
||||
* @brief Reads a single byte from the flash memory at the given byte address,
|
||||
* applying the custom 32-bit word mapping.
|
||||
* The mapping assumes:
|
||||
* - Each 32-bit word at (flashbase + byte_address * 4) corresponds to a single byte.
|
||||
* - Bits 28-31 of the 32-bit word contain the higher nibble of the byte.
|
||||
* - Bits 12-15 of the 32-bit word contain the lower nibble of the byte.
|
||||
*
|
||||
* @param byte_address The byte address (0x000000 - 0x7FFFFF) to read from.
|
||||
* @return The UBYTE value read from the flash.
|
||||
*/
|
||||
static UBYTE flash_read_byte(ULONG byte_address) {
|
||||
// Calculate the physical 32-bit word address in memory.
|
||||
// Each byte address maps to a unique 32-bit word in the underlying memory.
|
||||
volatile ULONG *word_ptr = (volatile ULONG *)(flashbase + (byte_address * 4));
|
||||
|
||||
// Read the full 32-bit word value from the memory-mapped flash.
|
||||
ULONG word_value = *word_ptr;
|
||||
|
||||
// Extract the higher nibble (bits 28-31) and shift it into the correct position
|
||||
// (most significant 4 bits of the UBYTE).
|
||||
UBYTE high_nibble = (UBYTE)((word_value >> 28) & 0x0F);
|
||||
|
||||
// Extract the lower nibble (bits 12-15) and keep it in its correct position
|
||||
// (least significant 4 bits of the UBYTE).
|
||||
UBYTE low_nibble = (UBYTE)((word_value >> 12) & 0x0F);
|
||||
|
||||
// Combine the two nibbles to form the complete 8-bit byte.
|
||||
return (high_nibble << 4) | low_nibble;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a single byte to the flash memory at the given byte address,
|
||||
* applying the custom 32-bit word mapping.
|
||||
* The mapping assumes:
|
||||
* - Each 32-bit word at (flashbase + byte_address * 4) corresponds to a single byte.
|
||||
* - The higher nibble of the byte should be written to bits 28-31 of the 32-bit word.
|
||||
* - The lower nibble of the byte should be written to bits 12-15 of the 32-bit word.
|
||||
*
|
||||
* @param byte_address The byte address (0x000000 - 0x7FFFFF) to write to.
|
||||
* @param data The UBYTE value to write to the flash.
|
||||
*/
|
||||
static void flash_write_byte(ULONG byte_address, UBYTE data) {
|
||||
// Calculate the physical 32-bit word address in memory.
|
||||
// Each byte address maps to a unique 32-bit word in the underlying memory.
|
||||
volatile ULONG *word_ptr = (volatile ULONG *)(flashbase + (byte_address * 4));
|
||||
|
||||
// Extract the higher 4 bits (nibble) and lower 4 bits (nibble) from the data byte.
|
||||
UBYTE high_nibble_to_write = (data >> 4) & 0x0F;
|
||||
UBYTE low_nibble_to_write = data & 0x0F;
|
||||
|
||||
// Prepare the new high nibble value, shifting it to bit positions 28-31.
|
||||
ULONG new_high_nibble_part = ((ULONG)high_nibble_to_write) << 28;
|
||||
// Prepare the new low nibble value, shifting it to bit positions 12-15.
|
||||
ULONG new_low_nibble_part = ((ULONG)low_nibble_to_write) << 12;
|
||||
|
||||
// Combine the preserved bits with the newly prepared high and low nibble parts.
|
||||
ULONG new_word_value = new_high_nibble_part | new_low_nibble_part;
|
||||
|
||||
// Write the modified 32-bit word back to the memory-mapped flash.
|
||||
*word_ptr = new_word_value;
|
||||
}
|
||||
|
||||
static inline void flash_command(UBYTE);
|
||||
static inline void flash_poll(ULONG);
|
||||
|
||||
@ -48,10 +111,10 @@ static const LONG devices_supported[] = {
|
||||
* @param manufacturer the manufacturer ID
|
||||
* @param device the device id
|
||||
* @returns boolean result
|
||||
*/
|
||||
*/
|
||||
static bool flash_is_supported(UBYTE manufacturer, UBYTE device) {
|
||||
ULONG deviceId = (manufacturer << 8) | device;
|
||||
int i=0;
|
||||
int i = 0;
|
||||
|
||||
while (devices_supported[i] != 0) {
|
||||
if (devices_supported[i] == deviceId)
|
||||
@ -64,7 +127,7 @@ static bool flash_is_supported(UBYTE manufacturer, UBYTE device) {
|
||||
}
|
||||
|
||||
/** flash_get_sectorSize
|
||||
*
|
||||
*
|
||||
* @brief return the sector size for this device type if known
|
||||
* @param manufacturer the manufacturer ID
|
||||
* @param device the device id
|
||||
@ -86,7 +149,7 @@ static UWORD flash_get_sectorSize(UBYTE manufacturer, UBYTE device) {
|
||||
case 0x0120: // AM29F010
|
||||
sectorSize = 16384;
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
// Unknown/Unsupported/Too large
|
||||
// If the device's sectorSize is greater than 32K don't bother
|
||||
sectorSize = 0;
|
||||
@ -100,44 +163,44 @@ static UWORD flash_get_sectorSize(UBYTE manufacturer, UBYTE device) {
|
||||
* @brief Write a byte to the Flash
|
||||
* @param address Address to write to
|
||||
* @param data The data to be written
|
||||
*/
|
||||
*/
|
||||
void flash_writeByte(ULONG address, UBYTE data) {
|
||||
address &= (FLASH_SIZE-1);
|
||||
address <<= 1;
|
||||
// Mask address to ensure it is within the valid flash size.
|
||||
address &= (FLASH_SIZE - 1);
|
||||
|
||||
flash_unlock_sdp();
|
||||
flash_command(CMD_BYTE_PROGRAM);
|
||||
*(volatile UBYTE *)(flashbase + address) = data;
|
||||
flash_poll(address);
|
||||
|
||||
flash_write_byte(address, data);
|
||||
flash_poll(address); // Poll the status using the byte address
|
||||
return;
|
||||
}
|
||||
|
||||
/** flash_command
|
||||
*
|
||||
* @brief send a command to the Flash
|
||||
* @param command
|
||||
*/
|
||||
* @param command The command byte to send.
|
||||
*/
|
||||
static inline void flash_command(UBYTE command) {
|
||||
*(volatile UBYTE *)(flashbase + ADDR_CMD_STEP_1) = command;
|
||||
|
||||
// Write command byte to the specific command address
|
||||
flash_write_byte(ADDR_CMD_STEP_1, command);
|
||||
return;
|
||||
}
|
||||
|
||||
/** flash_unlock_sdp
|
||||
*
|
||||
* @brief Send the SDP command sequence
|
||||
*/
|
||||
*/
|
||||
void flash_unlock_sdp() {
|
||||
*(volatile UBYTE *)(flashbase + ADDR_CMD_STEP_1) = CMD_SDP_STEP_1;
|
||||
*(volatile UBYTE *)(flashbase + ADDR_CMD_STEP_2) = CMD_SDP_STEP_2;
|
||||
|
||||
// Write the sequence bytes to the specific addresses
|
||||
flash_write_byte(ADDR_CMD_STEP_1, CMD_SDP_STEP_1);
|
||||
flash_write_byte(ADDR_CMD_STEP_2, CMD_SDP_STEP_2);
|
||||
return;
|
||||
}
|
||||
|
||||
/** flash_erase_chip
|
||||
*
|
||||
* @brief Perform a chip erase
|
||||
*/
|
||||
* @brief Perform a chip erase.
|
||||
*/
|
||||
void flash_erase_chip() {
|
||||
flash_unlock_sdp();
|
||||
flash_command(CMD_ERASE);
|
||||
@ -147,16 +210,15 @@ void flash_erase_chip() {
|
||||
flash_poll(0);
|
||||
}
|
||||
|
||||
|
||||
/** flash_erase_bank
|
||||
*
|
||||
* Erase the currently selected 32KB bank
|
||||
*
|
||||
*/
|
||||
*/
|
||||
void flash_erase_bank(UWORD sectorSize) {
|
||||
if (sectorSize > 0) {
|
||||
int count = 32768 / sectorSize;
|
||||
for (int i=0; i < count; i++) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
flash_erase_sector(i * sectorSize);
|
||||
}
|
||||
}
|
||||
@ -167,14 +229,16 @@ void flash_erase_bank(UWORD sectorSize) {
|
||||
* @brief Erase a sector
|
||||
* @param address Address of sector to erase
|
||||
*
|
||||
*/
|
||||
*/
|
||||
void flash_erase_sector(ULONG address) {
|
||||
address &= (FLASH_SIZE-1);
|
||||
address <<= 1;
|
||||
// Mask address to ensure it is within the valid flash size.
|
||||
address &= (FLASH_SIZE - 1);
|
||||
|
||||
flash_unlock_sdp();
|
||||
flash_command(CMD_ERASE);
|
||||
flash_unlock_sdp();
|
||||
*(volatile UBYTE *)(flashbase + address) = CMD_ERASE_SECTOR;
|
||||
// Write erase sector command to the specific sector address
|
||||
flash_write_byte(address, CMD_ERASE_SECTOR);
|
||||
flash_poll(address);
|
||||
}
|
||||
|
||||
@ -182,13 +246,18 @@ void flash_erase_sector(ULONG address) {
|
||||
*
|
||||
* @brief Poll the status bits at address, until they indicate that the operation has completed.
|
||||
* @param address Address to poll
|
||||
*/
|
||||
*/
|
||||
static inline void flash_poll(ULONG address) {
|
||||
address &= (FLASH_SIZE-1);
|
||||
address <<= 1;
|
||||
volatile UBYTE *read1 = ((void *)flashbase + address);
|
||||
volatile UBYTE *read2 = ((void *)flashbase + address);
|
||||
while (((*read1 & 1<<6) != (*read2 & 1<<6))) {;;}
|
||||
// Mask address to ensure it is within the valid flash size.
|
||||
address &= (FLASH_SIZE - 1);
|
||||
|
||||
UBYTE val1, val2;
|
||||
// Continuously read the status byte twice until the status bit 6 (DQ6) matches,
|
||||
// indicating the operation has completed.
|
||||
do {
|
||||
val1 = flash_read_byte(address);
|
||||
val2 = flash_read_byte(address);
|
||||
} while (((val1 & (1 << 6)) != (val2 & (1 << 6))));
|
||||
}
|
||||
|
||||
/** flash_init
|
||||
@ -197,32 +266,37 @@ static inline void flash_poll(ULONG address) {
|
||||
* @param manuf Pointer to a UBYTE that will be updated with the returned manufacturer id
|
||||
* @param devid Pointer to a UBYTE that will be updatet with the returned device id
|
||||
* @param flashbase Pointer to the Flash base address
|
||||
* @return True if the manufacturer ID matches the expected value
|
||||
*/
|
||||
* @return True if the manufacturer ID matches the expected value and flashbase is valid.
|
||||
*/
|
||||
bool flash_init(UBYTE *manuf, UBYTE *devid, ULONG *base, UWORD *sectorSize) {
|
||||
bool ret = false;
|
||||
UBYTE manufId;
|
||||
UBYTE deviceId;
|
||||
|
||||
// Set the global flashbase pointer.
|
||||
flashbase = (ULONG)base;
|
||||
|
||||
flash_unlock_sdp();
|
||||
flash_command(CMD_ID_ENTRY);
|
||||
|
||||
manufId = *(volatile UBYTE *)flashbase;
|
||||
deviceId = *(volatile UBYTE *)(flashbase + 2);
|
||||
// Read manufacturer ID from byte address 0
|
||||
manufId = flash_read_byte(0);
|
||||
// Read device ID from byte address 2
|
||||
deviceId = flash_read_byte(2);
|
||||
|
||||
flash_command(CMD_CFI_ID_EXIT);
|
||||
|
||||
// Update the output parameters if pointers are valid.
|
||||
if (manuf) *manuf = manufId;
|
||||
if (devid) *devid = deviceId;
|
||||
|
||||
|
||||
if (flash_is_supported(manufId,deviceId) && flashbase) {
|
||||
// Check if the device is supported and flashbase is valid.
|
||||
if (flash_is_supported(manufId, deviceId) && flashbase) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (sectorSize) *sectorSize = flash_get_sectorSize(manufId,deviceId);
|
||||
// Update the sector size if pointer is valid.
|
||||
if (sectorSize) *sectorSize = flash_get_sectorSize(manufId, deviceId);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user