📄 lld.c
字号:
/* in multi-device configuration */
switch (data_cfg)
{
case X16_AS_X32: /* drop through */
case X8X16_AS_X32:
*device_multiplier_ptr = 0x00010001;
break;
case X8_AS_X16:
*device_multiplier_ptr = 0x0101;
break;
case X8_AS_X32:
*device_multiplier_ptr = 0x01010101;
break;
default:
*err_code_ptr = LLD_E_INVALID_PARAMETER;
MY_SPRINTF(err_buf, "Invalid data config.\n");
status = LLD_ERROR;
break;
}
/* break out of for loop */
break;
}
return (status);
}
/******************************************************************************
*
* lld_StatusGet - Determines Flash Status
*
*
* RETURNS: LLD_OK, or LLD_ERROR
*
* ERRNO:
* LLD_E_INTERNAL_ERROR
* LLD_E_WRITE_BUFFER_LOAD_ERROR;
* LLD_E_FLASH_INTERNAL_TIMEOUT
* errors from Init functions
* errors generated by HAL functions
*/
int lld_StatusGet
(
ADDRESS base_addr, /* device base address in system */
DWORD offset, /* address offset from base address */
PARAM data_cfg, /* flash data width and # of devices */
DEVSTATUS* dev_status_ptr, /* device status */
FLASHDATA* act_data_ptr, /* actual data */
PARAM polling_type, /* type of polling to perform */
PARAM* err_code_ptr, /* variable to store error code */
char* err_buf /* buffer to store error text */
)
{
int status = LLD_OK;
FLASHDATA new_data = 0;
FLASHDATA old_data = 0;
FLASHDATA read_mask = 0;
FLASHDATA active_mask = 0;
FLASHDATA toglbit1_mask = 0;
FLASHDATA toglbit2_mask = 0;
FLASHDATA xcdtimelim_mask = 0;
FLASHDATA wrtbufabort_mask = 0;
int flag;
/* Initialize Masks */
status = ReadMaskInit(&read_mask, data_cfg, err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
/* do the first status read of the device */
status = HalRead(base_addr + offset, &old_data,
err_code_ptr, err_buf);
if (status != LLD_OK)
return (status);
/* do the second status read of the device */
status = HalRead(base_addr + offset, &new_data,
err_code_ptr, err_buf);
if (status != LLD_OK)
return (status);
/* Store most recent read data for caller (before clean-up) */
*act_data_ptr = new_data;
/* clean up data */
old_data &= read_mask;
new_data &= read_mask;
/* Check if steady state */
if (old_data == new_data) /* If you get the same data */
{ /* twice, the device has */
*dev_status_ptr = dev_not_busy; /* obviously finished without */
return (LLD_OK); /* without errors. */
}
/* Spansion flash devices transition from program and erase */
/* operations to reading array data on their own. While polling, */
/* it is common for the first read of status to be status, but */
/* the second read is the actual data itself. Since we must */
/* compare the first and second reads together to determine */
/* whether toggling is occurring, etc., we have chosen to ignore */
/* cases where it appears the first read is status and the */
/* second read is data. If we see transitions on DQ7 or DQ5, */
/* we exits with a busy return value, assuming things will */
/* have settled down by the next set of reads. */
status = AreDevicesInTransition(&flag, old_data, new_data, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
if (flag)
{
*dev_status_ptr = dev_busy;
return (LLD_OK);
}
/* At this point, we have two samples of status/data from all */
/* the devices interleaved together. Some devices may be */
/* reporting status both times while others may be reporting */
/* data both times. */
/* Create some masks for isolating specific bits. */
status = ToggleBit1MaskInit(&toglbit1_mask, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
status = ToggleBit2MaskInit(&toglbit2_mask, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
status = ExceedTimeLimitMaskInit(&xcdtimelim_mask, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
status = WrtBufAbortMaskInit(&wrtbufabort_mask, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
/* This is a special mask for isolating only the busy devices. */
status = ActiveMaskInit(&active_mask, old_data, new_data, data_cfg, polling_type,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
/* check that active devices were identified */
if (active_mask == 0)
{
if (polling_type == LLD_P_POLL_RESUME)
{
*dev_status_ptr = dev_not_busy;
return (LLD_OK);
}
else
{
*dev_status_ptr = dev_status_unknown;
*err_code_ptr = LLD_E_INTERNAL_ERROR;
return (LLD_ERROR);
}
}
/* mask out inactive (ready) devices */
old_data &= active_mask;
new_data &= active_mask;
xcdtimelim_mask &= active_mask;
wrtbufabort_mask &= active_mask;
toglbit1_mask &= active_mask;
toglbit2_mask &= active_mask;
*dev_status_ptr = dev_status_unknown;
/* Check if time limits exceeded:
* if all active devices have their DQ5 bits == 1
* then this is an error condition.
*/
if ((new_data & xcdtimelim_mask) == (xcdtimelim_mask))
{
*dev_status_ptr = dev_exceeded_time_limits;
MY_SPRINTF(err_buf, "Internal Time Limits Exceeded.\n");
*err_code_ptr = LLD_E_FLASH_INTERNAL_TIMEOUT;
return (LLD_OK);
}
/* check for write buffer abort
* Note: if some devices started programming successfully
* then this allows them to finish
* Only when all active devices are in write buffer abort state
* will this function return a "write buffer abort" error
*/
if (polling_type == LLD_P_POLL_WRT_BUF_PGM)
{
if ((new_data & wrtbufabort_mask) == (wrtbufabort_mask))
{
*dev_status_ptr = dev_write_buffer_abort;
*err_code_ptr = LLD_E_WRITE_BUFFER_LOAD_ERROR;
MY_SPRINTF(err_buf, "Write Buffer Load Error.\n");
return (LLD_OK);
}
}
/* check for suspend:
* Toggle Bit 1 has stopped toggling on all active devices
* AND Toggle Bit 2 is toggling on all active devices
*/
if ( ((new_data & toglbit1_mask) == (old_data & toglbit1_mask)) &&
((((new_data ^ old_data) & toglbit2_mask) ^ toglbit2_mask) == 0) &&
(polling_type != LLD_P_POLL_RESUME) )
{
*dev_status_ptr = dev_suspend;
return (LLD_OK);
}
/* note: new default return value is busy.
* this removes "undetermined state" check present in old
* "status get" function
*/
*dev_status_ptr = dev_busy;
return (LLD_OK);
}
/******************************************************************************/
int AreDevicesInTransition(int *flag_ptr,
FLASHDATA data1,
FLASHDATA data2,
PARAM data_cfg,
PARAM *err_code_ptr,
char *err_buf
)
{
int status = LLD_ERROR;
FLASHDATA dev_multiplier;
FLASHDATA dq7_dev_mask;
FLASHDATA dq5_dev_mask;
status = DeviceMultiplierInit(&dev_multiplier, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
dq7_dev_mask = dev_multiplier * DQ7_BIT_MASK;
dq5_dev_mask = dev_multiplier * DQ5_BIT_MASK;
if ((dq7_dev_mask & data1) != (dq7_dev_mask & data2))
{
*flag_ptr = TRUE;
return LLD_OK;
}
if ((dq5_dev_mask & data1) != (dq5_dev_mask & data2))
{
*flag_ptr = TRUE;
return LLD_OK;
}
*flag_ptr = FALSE;
return LLD_OK;
}
/******************************************************************************/
/* ActiveMaskInit Philosophy:
* 1.) identify which devices have DQ6 toggling
* and clean out bits other than DQ6
* 2.) identify which devices have DQ2 toggling
* and clean out bits other than DQ2
* 3.) Shift the DQ6 bits over to the "DQ0" position (e.g. 0x40 --> 0x01)
* and store the result in the "active_mask" variable.
* 4.) Shift the DQ2 bits over to the "DQ0" position (e.g. 0x04 --> 0x01)
* (for suspended devices)
* and OR-in the result to the "active_mask" variable.
*
* Example:
* --------
* X8_AS_X32 configuration DQ6 toggling on device 0
* and DQ2 toggling on device 3: 0x0200 0040
* active mask after DQ6 shift: 0x0000 0001
* active mask after DQ2 shift: 0x0100 0001
* active mask after multiplying by 0xFF: 0xFF00 00FF
*
*/
int ActiveMaskInit(FLASHDATA* active_mask_ptr,
FLASHDATA data1,
FLASHDATA data2,
PARAM data_cfg,
PARAM polling_type,
PARAM* err_code_ptr,
char* err_buf
)
{
FLASHDATA active_mask_tmp = 0;
FLASHDATA read_mask = 0;
FLASHDATA toglbit1_mask = 0;
FLASHDATA toglbit2_mask = 0;
FLASHDATA dq6togl_active = 0;
FLASHDATA dq2togl_active = 0;
FLASHDATA combined_togl_mask = 0;
int status = LLD_ERROR;
status = ToggleBit1MaskInit(&toglbit1_mask, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
status = ToggleBit2MaskInit(&toglbit2_mask, data_cfg,
err_code_ptr, err_buf);
if (status != LLD_OK)
return status;
dq6togl_active = (data1 ^ data2) & toglbit1_mask;
dq2togl_active = (data1 ^ data2) & toglbit2_mask;
combined_togl_mask = (data1 ^ data2) & (toglbit1_mask | toglbit2_mask);
/* when called from lld_EraseResumeCmd, we do not want lld_StatusGet */
/* to return dev_busy when simply erase suspended. */
if (polling_type == LLD_P_POLL_RESUME)
{
/* indirectly determine the number of devices (interleaving) */
status = ReadMaskInit(&read_mask, data_cfg, err_code_ptr, err_buf);
if (status != LLD_OK) return status;
/* determine the size of an individual device */
switch(GetUnitReadMask(data_cfg))
{
case 0xFF:
switch(read_mask)
/* if erase suspended, make it not active */
{
case 0xFF:
if (combined_togl_mask == toglbit2_mask) dq2togl_active = 0;
break;
case 0xFFFF:
if ((combined_togl_mask & 0xFF) == (toglbit2_mask & 0xFF)) dq2togl_active &= 0xFF00;
if ((combined_togl_mask & 0xFF00) == (toglbit2_mask & 0xFF00)) dq2togl_active &= 0x00FF;
break;
case 0xFFFFFFFF:
if ((combined_togl_mask & 0x000000FF) == (toglbit2_mask & 0x000000FF)) dq2togl_active &= 0xFFFFFF00;
if ((combined_togl_mask & 0x0000FF00) == (toglbit2_mask & 0x0000FF00)) dq2togl_active &= 0xFFFF00FF;
if ((combined_togl_mask & 0x00FF0000) == (toglbit2_mask & 0x00FF0000)) dq2togl_active &= 0xFF00FFFF;
if ((combined_togl_mask & 0xFF000000) == (toglbit2_mask & 0xFF000000)) dq2togl_active &= 0x00FFFFFF;
break;
}
break;
case 0xFFFF:
switch(read_mask)
{
case 0xFFFF:
if (combined_togl_mask == toglbit2_mask) dq2togl_active = 0;
break;
case 0xFFFFFFFF:
if ((combined_togl_mask & 0x0000FFFF) == (toglbit2_mask & 0x0000FFFF)) dq2togl_active &= 0xFFFF0000;
if ((com
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -