NAND part id detection problem

Hello Everyone,

I am having some trouble with Nand part id detection on my beagleboard
rev C2 board.

Strangely the problem only exist using iPhone SDK tool chain. If I
compile with ARM RVCT tool chain then everything seems to work fine.

With iPhone SDK tool chain, when I query the part, I am not getting
Manufacture ID and Device ID information. Below is the result summary
using 2 different compiler tool chain. It looks like I am losing
Device id and manufacture id information and rest of the bytes look
the same (Bytes 2, 3 & 4 in case of RVCT tool chain can be found at
Bytes 0, 1 & 2 in iPhone SDK results.)

ARM RVCT tool chain:

PartInfo[0]: 2C
PartInfo[1]: BA
PartInfo[2]: 80
PartInfo[3]: 55
PartInfo[4]: 50

iPhone SDK tool chain:

PartInfo[0]: 80
PartInfo[1]: 55
PartInfo[2]: 50
PartInfo[3]: 40
PartInfo[4]: 0

Below is my code snippet. I also tried sending Reset command prior to
sending Read ID command but that didn't help..

   //Send READ ID command
   NandSendCommand(READ_ID_CMD);

   //Send one address cycle.
   NandSendAddress(0);

   //Read 5-bytes to idenfity code programmed into the NAND flash
devices.
   //BYTE 0 = Manufacture ID
   //Byte 1 = Device ID
   //Byte 2, 3, 4 = Nand part specific information (Page size, Block
size etc)
   for (Index = 0; Index < sizeof(PartInfo); Index++) {
     PartInfo[Index] = MmioRead16(GPMC_NAND_DATA_0);
   }

Any thoughts?

- Hardik

Below is my code snippet. I also tried sending Reset command prior to
sending Read ID command but that didn't help..

   //Send READ ID command
   NandSendCommand(READ_ID_CMD);

   //Send one address cycle.
   NandSendAddress(0);

   //Read 5-bytes to idenfity code programmed into the NAND flash
devices.
   for (Index = 0; Index < sizeof(PartInfo); Index++) {
     PartInfo[Index] = MmioRead16(GPMC_NAND_DATA_0);
   }

Hi Hardik,

Hmm - This sound a little weird - Have you tried to:

1) Single step the code to check if this gives same result for both
compilers?
2) Check the generated assembly from the two different compilers?
3) Insert a delay (for testing - to check if it has any effect)
   between the NandSendAddress(0) and the reading loop?
4) check for differences in compiler options in general
   - Mainly related to timing/optimization

Hope this helps - Please let us know when you find the root cause
  Søren

After debugging further, I found out the issue.

Below is the MmioWrite16 API and appropriate assembly from iPhone SDK tool chain and ARM RVCT 3.1 tool chain.

If you see in the case of iPhone SDK, we are first storing the value to register and then reading it back. GPMC Address, Command and Data registers are FIFO based so once you read any of these registers then its throwing away 2-bytes at a time (due to x16 NAND). In case of ARM tool chain, it just returns the Value we are passing to the API… its not reading the content of the register after writing to it.

Now, the question is which one is the correct way according to C standards? It looks like the way iPhone SDK is generating the assembly makes more sense to me.

MmioWrite16 API.

Now, the question is which one is the correct way according to C standards? It looks like the way iPhone

SDK is generating the assembly makes more sense to me.

MmioWrite16 API.

==============

UINT16 EFIAPI

MmioWrite16 (

IN UINTN Address,

IN UINT16 Value)

{ ASSERT ((Address & 1) == 0);

return (volatile UINT16)Address = Value; }

iPhone SDK tool chain assembly.

==========================

_MmioWrite16:

strh r3, [r2, #0] @ movhi

ldrh r3, [r2, #0] @ movhi

ARM RVCT 3.1 assembly

====================

MmioWrite16 PROC

STRH r5,[r4,#0]

Hmm – This is definitely on the edge of the C specification and I’m really in doubt what’s correct, although I tend to agree most with the iPhone version because of the volatile declaration for the address pointer. In case that one wasn’t there I think both version would be equally valid, but I’m definitely not 100% sure.

That being said: What’s the reason that the MmioWrite16-function returns the value it’s writing? I would normally not expect a register-write-kind-of-function to return anything – Especially not the value it’s writing, which is already known to the caller J. Any good reason for doing this?

Best regards – Try to not go this close to the edge of the C specification next time J

Søren

Søren Steen Christensen <sorenschristensen@stofanet.dk> writes:

Now, the question is which one is the correct way according to C
standards? It looks like the way iPhone

SDK is generating the assembly makes more sense to me.

MmioWrite16 API.

UINT16 EFIAPI
MmioWrite16 (
IN UINTN Address,
IN UINT16 Value)
{ ASSERT ((Address & 1) == 0);
return *(volatile UINT16*)Address = Value;
}

iPhone SDK tool chain assembly.

_MmioWrite16:
                   strh r3, [r2, #0] @ movhi
                   ldrh r3, [r2, #0] @ movhi

ARM RVCT 3.1 assembly

MmioWrite16 PROC
       STRH r5,[r4,#0]

Hmm - This is definitely on the edge of the C specification and I'm
really in doubt what's correct, although I tend to agree most with
the iPhone version because of the volatile declaration for the
address pointer. In case that one wasn't there I think both version
would be equally valid, but I'm definitely not 100% sure.

Both are correct. The gcc (iphone) version works merely by accident.

ARM has a weakly ordered memory model, which means the CPU may reorder
memory accesses as it sees fit. A load following a store to the same
address does however force the store to be flushed.

A volatile object is only required to be re-read at sequence points,
so there is no need to load the stored valued back from memory in
order to return it.

Doing these things right is generally impossible in plain C.