Need help on GPMI write page ( BCH )

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Need help on GPMI write page ( BCH )

695 Views
Babylone
Contributor I

Hello,

I'm currently developping a baremetal application using GPMI. The functions read_raw and write_raw, read_page and some others are working. Now I want to develop the write_page function but I doesn't work properly. I've ge GPMI bch interrupt rising but nothing appends on the data of the NAND. Can someone have a look to my function ? :

int8_t GPMI_WritePage(uint32_t p_PageNumber, uint8_t * p_Buffer)
{
 
dmaCmd_t l_DescCle1Address, l_DescCle2;
dmaCmd_t l_DescWaitForReady1Wait, l_DescWaitForReady1Sense;
dmaCmd_t l_DescWaitForReady2Wait, l_DescWaitForReady2Sense;
dmaCmd_t l_DescTerminatorSuccess, l_DescTerminatorFail;
dmaCmd_t l_DescCommandAddress, l_DescReadResult;
dmaCmd_t l_DescWriteData;
 
uint8_t l_cle1AddressBuffer[1+MAX_ROWS+MAX_COLUMNS] __attribute__((aligned(4)));
uint8_t l_cle2Buffer __attribute__((aligned(4)));
uint8_t l_commandAddressBuffer[2] __attribute__((aligned(4)));
uint8_t l_StatusResult __attribute__((aligned(4)));
uint8_t oob[64] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
portBaseType xWasRunningPrivileged;
 
g_IsDmaInterruptNeeded = false;
 
l_cle2Buffer = NandCommandCode_WritePage;
 
l_cle1AddressBuffer[0] = NandCommandCode_SerialDataInput;
l_cle1AddressBuffer[1] = 0;
l_cle1AddressBuffer[2] = 0;
l_cle1AddressBuffer[3] = p_PageNumber & 0xff;
l_cle1AddressBuffer[4] = (p_PageNumber >> & 0xFF;
l_cle1AddressBuffer[5] = (p_PageNumber >> 16) & 0xFF;
 
l_DescCle1Address.data = (BF_APBH_CHn_CMD_XFER_COUNT(6)
| BF_APBH_CHn_CMD_CMDWORDS(3)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(1)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_READ));
 
l_DescCle1Address.address = (uint32_t)&l_cle1AddressBuffer;
 
// Need to set CLE high, then send command, then clear CLE, set ALE high
// send # address bytes (Column then row).
// Address increment is only enabled if there is at least one address byte.
l_DescCle1Address.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_LOCK_CS(1)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_CLE)
| BF_GPMI_CTRL0_ADDRESS_INCREMENT(BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED)
| BF_GPMI_CTRL0_XFER_COUNT(6));
 
l_DescCle1Address.pio_words[1] = 0;
l_DescCle1Address.pio_words[2] = 0;
 
l_DescCle1Address.next = &l_DescWriteData;
 
// nxt pointer is not set here
l_DescWriteData.data = BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER) | BF_APBH_CHn_CMD_CHAIN(1) |
BF_APBH_CHn_CMD_WAIT4ENDCMD(1) | BF_APBH_CHn_CMD_SEMAPHORE(1) | BF_APBH_CHn_CMD_CMDWORDS(6);
 
l_DescWriteData.address = 0;
 
l_DescWriteData.pio_words[0] =  (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA));
l_DescWriteData.pio_words[1] = 0;
 
l_DescWriteData.pio_words[2] = (BV_FLD(GPMI_ECCCTRL, ENABLE_ECC, ENABLE) |
BV_FLD(GPMI_ECCCTRL, ECC_CMD, ENCODE) |
BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE);
 
l_DescWriteData.pio_words[3] = 2048 + 64 ;
l_DescWriteData.pio_words[4] = (uint32_t)p_Buffer;
l_DescWriteData.pio_words[5] = (uint32_t)oob;
l_DescWriteData.next = &l_DescCle2;
 
l_DescCle2.address = (uint32_t)&l_cle2Buffer;
 
// Need to set CLE high, then send command, then clear CLE, set ALE high
// send # address bytes (Column then row).
// Address increment is only enabled if there is at least one address byte.
l_DescCle2.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_LOCK_CS(1)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_CLE)
| BF_GPMI_CTRL0_ADDRESS_INCREMENT(0)
| BF_GPMI_CTRL0_XFER_COUNT(1));
 
l_DescCle2.pio_words[1] = 0;
l_DescCle2.pio_words[2] = 0;
 
l_DescCle2.next = &l_DescWaitForReady1Wait;
 
// First we want to wait for Ready. Set GPMI wait for ready.
l_DescWaitForReady1Wait.next = &l_DescWaitForReady1Sense;
l_DescWaitForReady1Wait.data = (BF_APBH_CHn_CMD_CMDWORDS(1)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_NANDWAIT4READY(1)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
l_DescWaitForReady1Wait.address = 0;
l_DescWaitForReady1Wait.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WAIT_FOR_READY)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA)
| BF_GPMI_CTRL0_CS(NAND_CS));
 
l_DescWaitForReady1Sense.data = (BF_APBH_CHn_CMD_CMDWORDS(0)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_SENSE));
l_DescWaitForReady1Sense.address = (uint32_t)&l_DescTerminatorFail;
l_DescWaitForReady1Sense.pio_words[0] = 0;
l_DescWaitForReady1Sense.next = &l_DescTerminatorSuccess;
 
// No next descriptor in the chain.
l_DescTerminatorSuccess.next = &l_commandAddressBuffer;
l_DescTerminatorFail.next = NULL;
 
// Decrement semaphore, set IRQ, no DMA transfer.
l_DescTerminatorSuccess.data = (BF_APBH_CHn_CMD_IRQONCMPLT(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(0) //1)   XXX changed on MX6
| BF_APBH_CHn_CMD_SEMAPHORE(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
 
// The failure descriptor uses exactly the same DMA command as success.
l_DescTerminatorFail.data = l_DescTerminatorSuccess.data;
 
// The bar holds the result code, either success or an error code. It is up to
// the DMA handling code to read the result code out of the APBH register.
l_DescTerminatorSuccess.address = (void *)SUCCESS;
l_DescTerminatorFail.address = (void *)FAIL;
 
 
l_commandAddressBuffer[0] = NandCommandCode_ReadStatus;
l_commandAddressBuffer[1] = 0x00;
 
l_DescWaitForReady2Wait.next = &l_DescWaitForReady1Sense;
l_DescWaitForReady2Wait.data = (BF_APBH_CHn_CMD_CMDWORDS(1)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_NANDWAIT4READY(1)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
l_DescWaitForReady2Wait.address = 0;
l_DescWaitForReady2Wait.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WAIT_FOR_READY)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA)
| BF_GPMI_CTRL0_CS(NAND_CS));
 
l_DescWaitForReady2Sense.data = (BF_APBH_CHn_CMD_CMDWORDS(0)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_SENSE));
l_DescWaitForReady2Sense.address = (uint32_t)&l_DescTerminatorFail;
l_DescWaitForReady2Sense.pio_words[0] = 0;
l_DescWaitForReady2Sense.next = &l_DescCommandAddress;
 
//    tx_dma.nxt = 0;
l_DescCommandAddress.data = (BF_APBH_CHn_CMD_XFER_COUNT(1)
| BF_APBH_CHn_CMD_CMDWORDS(3)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(1)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_READ));
 
l_DescCommandAddress.address = (uint32_t)&l_commandAddressBuffer;
 
// Need to set CLE high, then send command, then clear CLE, set ALE high
// send # address bytes (Column then row).
// Address increment is only enabled if there is at least one address byte.
l_DescCommandAddress.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_LOCK_CS(1)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_CLE)
| BF_GPMI_CTRL0_ADDRESS_INCREMENT(0)
| BF_GPMI_CTRL0_XFER_COUNT(1));
 
l_DescCommandAddress.pio_words[1] = 0;
l_DescCommandAddress.pio_words[2] = 0;
l_DescCommandAddress.next = &l_DescReadResult;
 
 
l_DescReadResult.data = (BF_APBH_CHn_CMD_XFER_COUNT( NAND_READ_ID_RESULT_SIZE )
| BF_APBH_CHn_CMD_CMDWORDS(1)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_WRITE));
 
// Save Data into buffer.
assert((((uint32_t)l_StatusResult) & 0x3) == 0);
l_DescReadResult.address = (uint32_t)&l_StatusResult;
 
// Setup GPMI for 8-bit read.
l_DescReadResult.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, READ)
| BV_FLD(GPMI_CTRL0, WORD_LENGTH, 8_BIT)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BF_GPMI_CTRL0_LOCK_CS(0)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA)
| BF_GPMI_CTRL0_XFER_COUNT(NAND_READ_STATUS_RESULT_SIZE));
l_DescReadResult.next = &l_DescTerminatorSuccess;
 
 
// No next descriptor in the chain.
l_DescTerminatorSuccess.next = NULL;
l_DescTerminatorFail.next = NULL;
 
// Decrement semaphore, set IRQ, no DMA transfer.
l_DescTerminatorSuccess.data = (BF_APBH_CHn_CMD_IRQONCMPLT(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(0) //1)   XXX changed on MX6
| BF_APBH_CHn_CMD_SEMAPHORE(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
 
// The failure descriptor uses exactly the same DMA command as success.
l_DescTerminatorFail.data = l_DescTerminatorSuccess.data;
 
// The bar holds the result code, either success or an error code. It is up to
// the DMA handling code to read the result code out of the APBH register.
l_DescTerminatorSuccess.address = (void *)SUCCESS;
l_DescTerminatorFail.address = (void *)FAIL;
 
xWasRunningPrivileged = xPortRaisePrivilege();
 
vMmuArmLevel1DataCacheCleanAndInvalidate();
vMmuArmLevel2DataCacheCleanAndInvalidate();
 
portRESTORE_PRIVILEGE( xWasRunningPrivileged );
 
DMA_Run(&l_DescCle1Address);
 
return (l_StatusResult & 1) == 0 ? SUCCESS : -1;
 
}
 
Best regards
0 Kudos
Reply
3 Replies

669 Views
AldoG
NXP TechSupport
NXP TechSupport

Hello,

Could you share the i.MX device that you are using?

Best regards,
Aldo.

0 Kudos
Reply

657 Views
Babylone
Contributor I
Hello,

I’m using IMX6 solo processor.

Regards,
0 Kudos
Reply

612 Views
AldoG
NXP TechSupport
NXP TechSupport

Hello,

Unfortunately we do not support bare metal code, but you may take as a reference our GPMI driver code for Linux, available here:
https://github.com/nxp-imx/linux-imx/blob/lf-6.1.y/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c

Best regards,
Aldo.

0 Kudos
Reply