#include "lm5710.h"
#define NVRAM_TIMEOUT_COUNT 100000
static lm_status_t
acquire_nvram_lock(
lm_device_t *pdev)
{
lm_status_t lm_status;
u32_t j, cnt;
u32_t val;
u8_t port_num = PORT_ID(pdev);
DbgMessage(pdev, VERBOSEnv, "### acquire_nvram_lock\n");
cnt = NVRAM_TIMEOUT_COUNT;
if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
val = 0;
REG_WR(pdev, MCP_REG_MCPR_NVM_SW_ARB, (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port_num ));
for(j = 0; j < cnt*10; j++)
{
val=REG_RD(pdev, MCP_REG_MCPR_NVM_SW_ARB);
if(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num))
{
break;
}
mm_wait(pdev, 5);
}
if(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num))
{
lm_status = LM_STATUS_SUCCESS;
}
else
{
DbgMessage(NULL, FATAL, "Value of MCP_REG_MCPR_NVM_SW_ARB is 0x%x\n", val);
DbgBreakMsg("Cannot get access to nvram interface.\n");
lm_status = LM_STATUS_BUSY;
}
return lm_status;
}
static void
release_nvram_lock(
lm_device_t *pdev)
{
u32_t j, cnt;
u32_t val;
u8_t port_num = PORT_ID(pdev);
DbgMessage(pdev, VERBOSEnv, "### release_nvram_lock\n");
cnt = NVRAM_TIMEOUT_COUNT;
if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
REG_WR(pdev, MCP_REG_MCPR_NVM_SW_ARB, (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port_num));
val = 0;
for(j = 0; j < cnt; j++)
{
val=REG_RD(pdev, MCP_REG_MCPR_NVM_SW_ARB);
if(!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num)))
{
break;
}
mm_wait(pdev, 5);
}
DbgBreakIf(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port_num));
}
#if 0
static lm_status_t
enable_nvram_write(
lm_device_t *pdev)
{
u32_t val, j, cnt;
lm_status_t lm_status;
lm_status = LM_STATUS_SUCCESS;
DbgMessage(pdev, INFORMnv, "### enable_nvram_write\n");
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WREN);
cnt = NVRAM_TIMEOUT_COUNT;
if (CHIP_REV(pdev) == CHIP_REV_EMUL) cnt *= 100;
lm_status = LM_STATUS_BUSY;
for(j = 0; j < cnt; j++)
{
mm_wait(pdev, 5);
val=REG_RD(pdev, MCP_REG_MCPR_NVM_COMMAND);
if(val & MCPR_NVM_COMMAND_DONE)
{
lm_status = LM_STATUS_SUCCESS;
break;
}
}
return lm_status;
}
static lm_status_t
disable_nvram_write(
lm_device_t *pdev)
{
lm_status_t lm_status;
u32_t cnt,j,val;
DbgMessage(pdev, INFORMnv, "### disable_nvram_write\n");
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WRDI);
cnt = NVRAM_TIMEOUT_COUNT;
if (CHIP_REV(pdev) == CHIP_REV_EMUL) cnt *= 100;
lm_status = LM_STATUS_BUSY;
for(j = 0; j < cnt; j++)
{
mm_wait(pdev, 5);
val=REG_RD(pdev, MCP_REG_MCPR_NVM_COMMAND);
if(val & MCPR_NVM_COMMAND_DONE)
{
lm_status = LM_STATUS_SUCCESS;
break;
}
}
return lm_status;
}
#endif
static lm_status_t
enable_nvram_access(
lm_device_t *pdev)
{
u32_t val;
DbgMessage(pdev, VERBOSEnv, "### enable_nvram_access\n");
val=REG_RD(pdev, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
REG_WR(pdev, MCP_REG_MCPR_NVM_ACCESS_ENABLE, val | MCPR_NVM_ACCESS_ENABLE_EN | MCPR_NVM_ACCESS_ENABLE_WR_EN);
return LM_STATUS_SUCCESS;
}
static lm_status_t
disable_nvram_access(
lm_device_t *pdev)
{
u32_t val;
DbgMessage(pdev, VERBOSEnv, "### disable_nvram_access\n");
val=REG_RD(pdev, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
REG_WR(pdev, MCP_REG_MCPR_NVM_ACCESS_ENABLE, val & ~(MCPR_NVM_ACCESS_ENABLE_EN | MCPR_NVM_ACCESS_ENABLE_WR_EN));
return LM_STATUS_SUCCESS;
}
static lm_status_t
nvram_read_dword(
lm_device_t *pdev,
u32_t offset,
u32_t *ret_val,
u32_t nvram_flags)
{
lm_status_t lm_status;
u32_t cmd_flags;
u32_t val;
u32_t j, cnt;
DbgMessage(pdev, VERBOSEnv, "### nvram_read_dword\n");
DbgMessage(pdev, VERBOSEnv, "offset %d flags %d\n",offset,nvram_flags);
cmd_flags = nvram_flags | MCPR_NVM_COMMAND_DOIT;
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
REG_WR(pdev, MCP_REG_MCPR_NVM_ADDR, offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE);
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
cnt = NVRAM_TIMEOUT_COUNT;
if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
lm_status = LM_STATUS_BUSY;
for(j = 0; j < cnt; j++)
{
mm_wait(pdev, 5);
val=REG_RD(pdev, MCP_REG_MCPR_NVM_COMMAND);
if(val & MCPR_NVM_COMMAND_DONE)
{
val=REG_RD(pdev, MCP_REG_MCPR_NVM_READ);
#if defined(LITTLE_ENDIAN)
val = ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
((val & 0xff0000) >> 8) | ((val >> 24) & 0xff);
#endif
*ret_val = val;
lm_status = LM_STATUS_SUCCESS;
break;
}
}
return lm_status;
}
static lm_status_t
nvram_write_dword(
lm_device_t *pdev,
u32_t offset,
u32_t val,
u32_t nvram_flags)
{
lm_status_t lm_status;
u32_t cmd_flags;
u32_t j, cnt;
DbgMessage(pdev, VERBOSEnv, "### nvram_write_dword\n");
cmd_flags = nvram_flags | MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
#if defined(LITTLE_ENDIAN)
val = ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
((val & 0xff0000) >> 8) | ((val >> 24) & 0xff);
#endif
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
REG_WR(pdev, MCP_REG_MCPR_NVM_WRITE, val);
REG_WR(pdev, MCP_REG_MCPR_NVM_ADDR, offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE);
REG_WR(pdev, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
cnt = NVRAM_TIMEOUT_COUNT;
if (CHIP_REV_IS_EMUL(pdev)) cnt *= 100;
lm_status = LM_STATUS_BUSY;
for(j = 0; j < cnt; j++)
{
mm_wait(pdev, 5);
val=REG_RD(pdev, MCP_REG_MCPR_NVM_COMMAND);
if(val & MCPR_NVM_COMMAND_DONE)
{
lm_status = LM_STATUS_SUCCESS;
break;
}
}
return lm_status;
}
lm_status_t
lm_nvram_read(
lm_device_t *pdev,
u32_t offset,
u32_t *ret_buf,
u32_t buf_size)
{
lm_status_t lm_status;
u32_t cmd_flags;
DbgMessage(pdev, VERBOSEnv, "### lm_nvram_read\n");
DbgMessage(pdev, VERBOSEnv, "offset %d size %d\n",offset,buf_size);
if((buf_size & 0x03) || (offset & 0x03))
{
DbgBreakMsg("Invalid paramter.\n");
return LM_STATUS_FAILURE;
}
if(offset + buf_size > pdev->hw_info.flash_spec.total_size)
{
DbgBreakMsg("Invalid paramter.\n");
return LM_STATUS_FAILURE;
}
lm_status = acquire_nvram_lock(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_status = enable_nvram_access(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
release_nvram_lock(pdev);
return lm_status;
}
cmd_flags = MCPR_NVM_COMMAND_FIRST;
while(buf_size > sizeof(u32_t) && lm_status == LM_STATUS_SUCCESS)
{
lm_status = nvram_read_dword(pdev, offset, ret_buf, cmd_flags);
offset += sizeof(u32_t);
ret_buf++;
buf_size -= sizeof(u32_t);
cmd_flags = 0;
}
if(lm_status == LM_STATUS_SUCCESS)
{
cmd_flags |= MCPR_NVM_COMMAND_LAST;
lm_status = nvram_read_dword(pdev, offset, ret_buf, cmd_flags);
}
disable_nvram_access(pdev);
release_nvram_lock(pdev);
return lm_status;
}
lm_status_t
lm_nvram_write(
lm_device_t *pdev,
u32_t offset,
u32_t *data_buf,
u32_t buf_size)
{
lm_status_t lm_status;
u32_t written_so_far;
u32_t cmd_flags;
u32_t *ptr32, addr;
DbgMessage(pdev, VERBOSEnv, "### lm_nvram_write\n");
if(offset & 0x03)
{
DbgBreakMsg("Invalid paramter.\n");
return LM_STATUS_FAILURE;
}
if(offset + buf_size > pdev->hw_info.flash_spec.total_size)
{
DbgMessage(pdev, FATAL, "lm_nvram_write failed ! buf_size %d larger than NVM total_size %d\n", buf_size, pdev->hw_info.flash_spec.total_size);
DbgBreakMsg("Failed to write to NVM! Attemp to write to offset larger than NVM total size !\n");
return LM_STATUS_FAILURE;
}
lm_status = LM_STATUS_SUCCESS;
lm_status = acquire_nvram_lock(pdev);
if(lm_status != LM_STATUS_SUCCESS)
return lm_status;
lm_status = enable_nvram_access(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
release_nvram_lock(pdev);
return lm_status;
}
written_so_far = 0;
cmd_flags = MCPR_NVM_COMMAND_FIRST;
addr = offset;
ptr32 = data_buf;
while (written_so_far < buf_size)
{
if (written_so_far == (buf_size - 4))
cmd_flags |= MCPR_NVM_COMMAND_LAST;
else if (((addr & 0xff) + 4) == NVRAM_PAGE_SIZE)
cmd_flags |= MCPR_NVM_COMMAND_LAST;
else if ((addr & 0xff) == 0)
cmd_flags |= MCPR_NVM_COMMAND_FIRST;
nvram_write_dword(pdev, addr, *ptr32, cmd_flags);
ptr32++;
addr += 4;
written_so_far += 4;
cmd_flags = 0;
}
disable_nvram_access(pdev);
release_nvram_lock(pdev);
return lm_status;
}