Because of the Thanksgiving holiday in the U.S., TI E2E™ design support forum responses may be delayed from November 25 through December 2. Thank you for your patience.

PROCESSOR-SDK-AM62X: PHY enabling failed

Part Number: PROCESSOR-SDK-AM62X
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hi TI,

We are having an error sometime of "PHY enabling failed" in stage2. and have a custom implementation of sbl_ospi_linux_stage2.
The hardware is a board custom use nor S28HS02GT (256MB)
Boot process is OSPI bootmode: Rom_code_ospi -> SBL1 -> SBL2 -> R5_app -> linux

The bootup of Rom_code_ospi and SBL1 without PHY enabling failed, SBL2 has PHY enabling failed
The difference of SBL1 and SBL2, The SBL2 have read data at address 0x0FFE0000 in mode 1-1-1 of nor, befor enable PHY.

You can support us in debugging and finding the cause.

teraterm_11_04.log

Best Regards,
Huy

  • Hello,

    The log which you have sent me I am assuming it is repeating as in its not the logs as a result of one experiment, like you tried running it several times and collected all the logs and sent it. Please correct my understanding.

    Apart from this, allow me sometime to comment on the Phy Tuning failure as this could be due to few reasons and I would need to narrow it down.

    Can you please help me understand which MCU PLUS SDK AM62x you are currently using?

    Regards,

    Vaibhav

  • Hi Vaibhav,

    "The log which you have sent me I am assuming it is repeating as in its not the logs as a result of one experiment, like you tried running it several times and collected all the logs and sent it. Please correct my understanding."

    => It is testing the boot-up by turning the power on and off. and sometimes it just gets "PHY enabling failed"

    "Can you please help me understand which MCU PLUS SDK AM62x you are currently using?"

    => Yes, I use MCU SDK AM62x with version 09.00.00.19

    Regards,

    Huy

  • Hello,

    Thanks for your patience.

    Yes, I use MCU SDK AM62x with version 09.00.00.19

    The Phy Tuning algorithm used for AM62x MCU PLUS SDK 9.00 is pretty old, I would suggest moving on to the latest SDK.

    This way you would not be seeing any phy enabling failures.

    Please refer this: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1431856/faq-am62a7-ospi-phy-tuning-algorithm

    Regards,

    Vaibhav

  • Hello,

    Please note, that if you wish to continue with the SDK which you are using right now, I would suggest you to port the newer algorithm from latest SDK to older one.

    The algorithm or the API which you would need to port is basically the API named as OSPI_phyTuneDDR and OSPI_phyFindOTP1.

    Regards,

    Vaibhav

  • Hi,

    I tried porting the API named as OSPI_phyTuneDDR and OSPI_phyFindOTP1. it still shows error PHY enabling failed"

    Regards,

    Huy

  • Hi,

    Thanks for your patience.

    I tried porting the API named as OSPI_phyTuneDDR and OSPI_phyFindOTP1. it still shows error PHY enabling failed"

    Although unexpected, but let me put on next steps here.

    So while porting the latest OTP1 from SDK 10.0 to 9.0 did you not face build challenges?

    For example: 

    const OSPI_Attrs *attrs = ((OSPI_Config *)handle)->attrs;
    OSPI_PhyTuneWindowParams *phyTuneWindowParams = \
    (OSPI_PhyTuneWindowParams *)&attrs->phyConfiguration.tuningWindowParams;

    The above is written inside OTP1 for 10.0 and if you put this straight up in SDK 9.0 and you go to source/drivers in cmd and run:

    gmake -s -f makefile.am62x.r5f.ti-arm-clang

    Then it should give you build issues/errors, so my question is were you able to resolve those build errors and move past?

    Regards,

    Vaibhav

  • Hi,

    I replace file ospi_phy.c from sdk 10.0 to sdk 9.0, and fix build errors based on this file. then test on us board, process boot up success,

    And I attached my patch, you can see. 

    patch_portting_OTP.zip

    Regards,

    Huy

  • process boot up success,

    So there is no phy enabling failures as of now, is that a correct understanding.

  • No, It is error sometime, sometimes bootup succeeds sometimes phy enabling failures.

  • Hi,

    No, It is error sometime, sometimes bootup succeeds sometimes phy enabling failures.

    So if this is happening sometimes, then it would be hard to debug the failure.

    Can you share the example.syscfg file?

    Regards,

    Vaibhav

  • Hello Vaibhav,

     I attached the example.syscfg file below.

    7103.example.zip

    Regards,

    Huy

  • Hello,

    I am going to go through the sysconfig file and update you with the next step of actions.

    Regards,

    Vaibhav

  • phy enabling failures.

    You see that when it says phy enabling fails then it means that the failure is isolated to OSPI_phyTuneDDR() for sure.

    So the flash configurations should not act as faulty here, because sometimes you do not get Phy Tuning failures.

    Can you please tell me the frequency of this failure, like out of how many cycles you see a failure?

    Regards,

    Vaibhav

  • Hi Vaibhav,

    As log teraterm_11_04.log file I attached at head of this ticket, have 144/413 time of this failure.

    Regards,

    Huy

  • Hello,

    Please also do the following.

    int32_t OSPI_phyFindOTP1(OSPI_Handle handle, uint32_t flashOffset, OSPI_PhyConfig *otp)
    {
        int32_t status = SystemP_SUCCESS;
        OSPI_PhyConfig searchPoint;
        OSPI_PhyConfig bottomLeft = {0,0,0}, topRight = {0,0,0};
        OSPI_PhyConfig gapLow = {0,0,0}, gapHigh = {0,0,0};
        OSPI_PhyConfig rxLow = {0,0,0}, rxHigh = {0,0,0};
        OSPI_PhyConfig txLow = {0,0,0}, txHigh = {0,0,0};
        OSPI_PhyConfig backupPoint = {0,0,0}, backupCornerPoint = {0,0,0};
        OSPI_PhyConfig sec_rxLow = {0,0,0}, sec_rxHigh = {0,0,0};
        float slope;
        float temperature = 0;
    
        const OSPI_Attrs *attrs = ((OSPI_Config *)handle)->attrs;
        OSPI_PhyTuneWindowParams *phyTuneWindowParams = \
                (OSPI_PhyTuneWindowParams *)&attrs->phyConfiguration.tuningWindowParams;
    
        /*
         * Finding RxDLL fails at some of the TxDLL values based on the HW platform.
         * A window of TxDLL values is used to find the RxDLL without errors.
         * This can increase the number of CPU cycles taken for the PHY tuning
         * in the cases where more TxDLL values need to be parsed to find a stable RxDLL.
         */
    
        /***************************** GOLDEN Primary Rx_Low Search **************/
        /*
         * To find the RxDLL boundaries, we fix a valid TxDLL and search through RxDLL range, rdDelay values
         * As we are not sure of a valid TxDLL we use a window of TxDLL values to find the RxDLL boundaries.
         */
        /*
               Rx_DLL
                  ▲
                  │   ++++++++++++++++
              127 │     ++++++++++++++
                  │   x   ++++++++++++
                  │   xx   +++++++++++
                  │   xxx   ++++++++++
                  │   xxxx   +++++++++
                  │   xxxxx   ++++++++
                  │ │ xxx│xx   +++++++
                  │ │ xxx│xxx   ++++++
                  │ │ xxx│xxxx   +++++
                  │ │ xxx│xxxxx   ++++
                  │ │ xxx│xxxxxx   +++
         Search   │ │ xxx│xxxxxxx   ++
         Rx_Low ──┼─┤►xxx│xxxxxxxx   +
                  │ │    │
                 ─┼─┼────┼────────────►  Tx_DLL
                 0│ │    │           127
                    │    │
                    │    │
    
                Tx_Low   Tx_Low
                Start    End
        */
    
        searchPoint.txDLL = phyTuneWindowParams->txDllLowWindowStart;
    
        while(searchPoint.txDLL <= phyTuneWindowParams->txDllLowWindowEnd)
        {
            searchPoint.rdDelay = phyTuneWindowParams->rdDelayMin;
            searchPoint.rxDLL = phyTuneWindowParams->rxLowSearchStart;
            OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &rxLow);
    
            while(rxLow.rxDLL == 128U)
            {
                searchPoint.rdDelay++;
                if(searchPoint.rdDelay > phyTuneWindowParams->rdDelayMax)
                {
                    if(searchPoint.txDLL >= phyTuneWindowParams->txDllLowWindowEnd)
                    {
                        status = SystemP_FAILURE;
                        DebugP_log("Failure in finding primary rx low \n\r");
                        return status;
                    }
                    else
                    {
                        break;
                    }
                }
                OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &rxLow);
            }
    
            if(rxLow.rxDLL != 128U)
            {
                break;
            }
    
            searchPoint.txDLL += phyTuneWindowParams->rxTxDLLSearchStep;
        }
    
        /***************************** GOLDEN Secondary Rx_Low Search *****************************/
        /* Search for one more rxLow at different txDll*/
        if(searchPoint.txDLL <= (phyTuneWindowParams->txDllLowWindowEnd - phyTuneWindowParams->txDLLSearchOffset))
        {
            searchPoint.txDLL += phyTuneWindowParams->txDLLSearchOffset;
        }
        else
        {
            searchPoint.txDLL = phyTuneWindowParams->txDllLowWindowEnd;
        }
    
        searchPoint.rdDelay = phyTuneWindowParams->rdDelayMin;
        searchPoint.rxDLL   = phyTuneWindowParams->rxLowSearchStart;
        OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &sec_rxLow);
        while(sec_rxLow.rxDLL == 128U)
        {
            searchPoint.rdDelay++;  /* For each TxDLL in the window, go through all the valid rdDelays until we find the RxLow */
            if(searchPoint.rdDelay > phyTuneWindowParams->rdDelayMax)
            {
                if(searchPoint.txDLL >= phyTuneWindowParams->txDllLowWindowEnd)
                {
                    status = SystemP_FAILURE;
                    DebugP_log("Failure in finding secondary rx low \n\r");
                    return status; /* Not able to find RxLow as there is no valid TxDLL in the TxDLL window */
                }
                else
                {
                    break;
                }
            }
            OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &sec_rxLow);
        }
    
        /*
         * Pick Minimum value of rxDLL between rxLow and sec_rxLow
         * Pick Minimum value of rdDelay(read_delay) between rxLow and sec_rxLow
        ┌────────┬───────────┬────────────────────────────────────┐
        │Primary │ Secondary │   Final  Point                     │
        │ Search │  Search   │                                    │
        │        │           │                                    │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Fail   │   Fail    │  Return Fail                       │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Fail   │   Pass    │  Return Fail                       │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Pass   │   Fail    │  Return Fail                       │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Pass   │   Pass    │ RxDll = Min(Primary, Secondary)    │
        │        │           │ RdDelay = Min(Primary, Secondary)  │
        │        │           │ TxDll = Primary                    │
        │        │           │                                    │
        └────────┴───────────┴────────────────────────────────────┘
         */
    
        rxLow.rxDLL = MIN(rxLow.rxDLL, sec_rxLow.rxDLL);
        rxLow.rdDelay = MIN(rxLow.rdDelay, sec_rxLow.rdDelay);
    
        /*
         * Reset the search point txDLL to continue the Rx_High search
         */
        searchPoint.txDLL = rxLow.txDLL;
    
        /***************************** GOLDEN Primary Rx_High Search *********************/
        /*
         * To find rxHigh we use the txDLL values of rxLow
         * Start the rdDelay (Read delay) from maximum and decrement it.
         * As these are valid values and rxHigh rdDelay is always >= rxLow rdDelay
         */
        /*
                   Rx_DLL
                      ▲
                  127 │   ▲+++++++++++++++
            Search    │   │ ++++++++++++++
           Rx_High────┼──►│   ++++++++++++
     on Fixed Tx_DLL  │   │x   +++++++++++
                      │   │xx   ++++++++++
                      │   │xxx   +++++++++
                      │   │xxxx   ++++++++
                      │   ▼xxxxx   +++++++
                      │   Xxxxxxx   ++++++
                      │   Xxxxxxxx   +++++
                      │   Xxxxxxxxx   ++++
                      │   Xxxxxxxxxx   +++
                      │   Xxxxxxxxxxx   ++
                      │   Xxxxxxxxxxxx   +
                      │
                     ─┼───────────────────►  Tx_DLL
                     0│                  127
        */
    
        searchPoint.rxDLL = phyTuneWindowParams->rxHighSearchEnd;
        searchPoint.rdDelay = phyTuneWindowParams->rdDelayMax;
    
        OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &rxHigh);
    
        while(rxHigh.rxDLL == 128U)
        {
            searchPoint.rdDelay--;
            if(searchPoint.rdDelay < phyTuneWindowParams->rdDelayMin)
            {
                status = SystemP_FAILURE;
                DebugP_log("Failure in finding primary rx high \n\r");
                break;
            }
            OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &rxHigh);
        }
    
    
        /***************************** GOLDEN Secondary Rx_High Search *********************/
        /*
         * To find Secondary rxHigh we use the txDLL + Search_offset value of rxLow
         * Start the rdDelay (Read delay) from maximum and decrement it.
         * As these are valid values and rxHigh rdDelay is always >= rxLow rdDelay
         */
        if(searchPoint.txDLL <= (phyTuneWindowParams->txDllLowWindowEnd - phyTuneWindowParams->txDLLSearchOffset))
        {
            searchPoint.txDLL += phyTuneWindowParams->txDLLSearchOffset;
        }
        else
        {
            searchPoint.txDLL = phyTuneWindowParams->txDllLowWindowEnd;
        }
    
        searchPoint.rxDLL = phyTuneWindowParams->rxHighSearchEnd;
        searchPoint.rdDelay = phyTuneWindowParams->rdDelayMax;
    
        OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &sec_rxHigh);
    
        while(sec_rxHigh.rxDLL == 128U)
        {
            searchPoint.rdDelay--;
            if(searchPoint.rdDelay < phyTuneWindowParams->rdDelayMin)
            {
                status = SystemP_FAILURE;
                DebugP_log("Failure in finding secondary rx high \n\r");
                break;
                /*
                 * If we don't find a valid Secondary Rx_High, Don't return from tuning function
                 * Check whether we have a valid Primary Rx_High and then take decision.
                 */
            }
            OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &sec_rxHigh);
        }
    
        /*
         * Compare the Primary and Secondary point
         * Pick the point which has passing maximum rxDll
        ┌────────┬───────────┬────────────────────────────────────┐
        │Primary │ Secondary │   Final  Point                     │
        │ Search │  Search   │                                    │
        │        │           │                                    │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Fail   │   Fail    │  Return Fail                       │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Fail   │   Pass    │  Pick Secondary search             │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Pass   │   Fail    │  Pick Primary search               │
        ├────────┼───────────┼────────────────────────────────────┤
        │ Pass   │   Pass    │ If(secondary.rxDll > primary.rxDll)│
        │        │           │ Pick Secondary search point        │
        │        │           │ Else                               │
        │        │           │ Pick Primary search point          │
        └────────┴───────────┴────────────────────────────────────┘
        */
    
        if(sec_rxHigh.rxDLL != 128U)
        {
            if(rxHigh.rxDLL == 128U)
            {
                rxHigh = sec_rxHigh;
            }
            else
            {
                if(sec_rxHigh.rxDLL > rxHigh.rxDLL)
                {
                    rxHigh = sec_rxHigh;
                }
            }
        }
        else
        {
            if(rxHigh.rxDLL == 128)
            {
                status = SystemP_FAILURE;
                return status;
            }
        }
    
        /*
         * Check a different point if the rxLow and rxHigh are on the same rdDelay.
         * This avoids mistaking the metastability gap for an rxDLL boundary
         */
        if(rxLow.rdDelay == rxHigh.rdDelay)
        {
            /***************************** BACKUP Primary Rx_Low Search *********************/
            /*
             * Find the rxDLL boundaries using the TxDLL window at the higher end .
             * we start the window_end and decrement the TxDLL value until we find the valid point.
             */
            /*
               Rx_DLL
                ▲
                │   ++++++++++++++++
            127 │   ++++++++++++++++
                │   ++++++++++++++++
                │    +++++++++++++++
                │     +++++++++│++++│
                │      ++++++++│++++│
                │   x   +++++++│++++│
                │   xx   ++++++│++++%E2%94%82
                │   xxx   +++++│++++│
                │   xxxx   ++++│++++│
                │   xxxxx   +++│++++│
                │   xxxxxx   ++│++++│
                │   xxxxxxx   +│++++│         Search
                │   xxxxxxxx   │++++◄───────  Rx_Low
                │              │    │
               ─┼──────────────┼────┤► Tx_DLL
               0│              │    │   127
                               │    │
                       Tx_High        Tx_High
                       Start          End
            */
    
            searchPoint.txDLL = phyTuneWindowParams->txDllHighWindowEnd;
    
            /* Find rxDLL Min */
            while(searchPoint.txDLL >= phyTuneWindowParams->txDllHighWindowStart)
            {
                searchPoint.rdDelay = phyTuneWindowParams->rdDelayMin;
                searchPoint.rxDLL = phyTuneWindowParams->rxLowSearchStart;
                OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &backupPoint);
    
                while(backupPoint.rxDLL == 128U)
                {
                    searchPoint.rdDelay++;
                    if(searchPoint.rdDelay > phyTuneWindowParams->rdDelayMax)
                    {
                        if(searchPoint.txDLL <= phyTuneWindowParams->txDllHighWindowStart)
                        {
                            status = SystemP_FAILURE;
                            DebugP_log("Failure in finding backup primary rx low \n\r");
                            return status;
                        }
                        else
                        {
                            break;
                        }
                    }
                    OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &backupPoint);
                }
    
                if(backupPoint.rxDLL != 128U)
                {
                    break;
                }
    
                searchPoint.txDLL -= phyTuneWindowParams->rxTxDLLSearchStep;
            }
    
            /***************************** BACKUP Secondary Rx_Low Search *********************/
            /* Search for one more rxLow at different txDll*/
            if (searchPoint.txDLL >= (phyTuneWindowParams->txDllHighWindowStart + phyTuneWindowParams->txDLLSearchOffset ))
            {
                searchPoint.txDLL -= phyTuneWindowParams->txDLLSearchOffset;
            }
            else
            {
                searchPoint.txDLL = phyTuneWindowParams->txDllHighWindowStart;
            }
    
            searchPoint.rdDelay = phyTuneWindowParams->rdDelayMin;
            searchPoint.rxDLL   = phyTuneWindowParams->rxLowSearchStart;
            OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &sec_rxLow);
            while(sec_rxLow.rxDLL == 128U)
            {
                searchPoint.rdDelay++;  /* For each TxDLL in the window, go through all the valid rdDelays until we find the RxLow */
                if(searchPoint.rdDelay > phyTuneWindowParams->rdDelayMax)
                {
                    if(searchPoint.txDLL <= phyTuneWindowParams->txDllHighWindowStart)
                    {
                        status = SystemP_FAILURE;
                        DebugP_log("Failure in finding backup secondary rx low \n\r");
                        return status; /* Not able to find RxLow as there is no valid TxDLL in the TxDLL window */
                    }
                    else
                    {
                        break;
                    }
                }
                OSPI_phyFindRxLow(handle, &searchPoint, flashOffset, &sec_rxLow);
            }
    
            backupPoint.rxDLL = MIN(backupPoint.rxDLL, sec_rxLow.rxDLL);
            backupPoint.rdDelay = MIN(backupPoint.rdDelay, sec_rxLow.rdDelay);
    
            if(backupPoint.rxDLL < rxLow.rxDLL)
            {
                rxLow = backupPoint;
            }
    
            /*
             * Reset the search point txDLL to continue the Rx_High search
             */
            searchPoint.txDLL = backupPoint.txDLL;
    
            /***************************** BACKUP Primary Rx_High Search *********************/
            /*
             * Find rxDLL Max
             * Start the rdDelay (Read delay) from maximum and decrement it.
             */
            /*
            Rx_DLL
            127 ▲
                │   +++++++++++++++▲                Search Rx_High
                │   +++++++++++++++│◄────────────   on Fixed Tx_DLL
                │   +++++++++++++++│
                │    ++++++++++++++│
                │     +++++++++++++│
                │      ++++++++++++│
                │   x   +++++++++++▼
                │   xx   +++++++++++
                │   xxx   ++++++++++
                │   xxxx   +++++++++
                │   xxxxx   ++++++++
                │   xxxxxx   +++++++
                │   xxxxxxx   ++++++
                │   xxxxxxxx    ++++
                │
               ─┼────────────────────► Tx_DLL
               0│                       127
            */
    
            searchPoint.rxDLL = phyTuneWindowParams->rxHighSearchEnd;
            searchPoint.rdDelay = phyTuneWindowParams->rdDelayMax;
            OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &backupPoint);
    
            while(backupPoint.rxDLL == 128U)
            {
                searchPoint.rdDelay--;
                if(searchPoint.rdDelay < phyTuneWindowParams->rdDelayMin)
                {
                    status = SystemP_FAILURE;
                    DebugP_log("Failure in finding backup primary rx high \n\r");
                    break;
                }
                OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &backupPoint);
            }
    
            /***************************** BACKUP Secondary Rx_High Search *********************/
            /*
             * Find rxDLL Max
             * Start the rdDelay (Read delay) from maximum and decrement it.
             */
    
            if (searchPoint.txDLL >= (phyTuneWindowParams->txDllHighWindowStart + phyTuneWindowParams->txDLLSearchOffset )){
                searchPoint.txDLL -= phyTuneWindowParams->txDLLSearchOffset;
            }
            else
            {
                searchPoint.txDLL = phyTuneWindowParams->txDllHighWindowStart;
            }
    
            searchPoint.rxDLL = phyTuneWindowParams->rxHighSearchEnd;
            searchPoint.rdDelay = phyTuneWindowParams->rdDelayMax;
            OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &sec_rxHigh);
    
            while(sec_rxHigh.rxDLL == 128U)
            {
                searchPoint.rdDelay--;
                if(searchPoint.rdDelay < phyTuneWindowParams->rdDelayMin)
                {
                    status = SystemP_FAILURE;
                    DebugP_log("Failure in finding backup secondary rx high \n\r");
                    break;
                }
                OSPI_phyFindRxHigh(handle, &searchPoint, flashOffset, &sec_rxHigh);
            }
    
            /*
             * Compare the Primary and Secondary point
             * Pick the point which has passing maximum rxDll
            ┌────────┬───────────┬────────────────────────────────────┐
            │Primary │ Secondary │   Final  Point                     │
            │ Search │  Search   │                                    │
            │        │           │                                    │
            ├────────┼───────────┼────────────────────────────────────┤
            │ Fail   │   Fail    │  Return Fail                       │
            ├────────┼───────────┼────────────────────────────────────┤
            │ Fail   │   Pass    │  Pick Secondary search             │
            ├────────┼───────────┼────────────────────────────────────┤
            │ Pass   │   Fail    │  Pick Primary search               │
            ├────────┼───────────┼────────────────────────────────────┤
            │ Pass   │   Pass    │ If(secondary.rxDll > primary.rxDll)│
            │        │           │ Pick Secondary search point        │
            │        │           │ Else                               │
            │        │           │ Pick Primary search point          │
            └────────┴───────────┴────────────────────────────────────┘
            */
    
            if(sec_rxHigh.rxDLL != 128U)
            {
                if(backupPoint.rxDLL == 128U)
                {
                    backupPoint = sec_rxHigh;
                }
                else
                {
                    if(sec_rxHigh.rxDLL > backupPoint.rxDLL)
                    {
                        backupPoint = sec_rxHigh;
                    }
                }
            }
            else
            {
                if(backupPoint.rxDLL == 128)
                {
                    status = SystemP_FAILURE;
                    DebugP_log("Failure in finding backup rx high \n\r");
                    return status;
                }
            }
    
            if(backupPoint.rxDLL > rxHigh.rxDLL)
            {
                rxHigh = backupPoint;
            }
        }
    
        /***************************** GOLDEN Tx_Low Search *********************/
        /*
         * Look for txDLL boundaries at 1/4 of rxDLL window
         * Find txDLL Min
         */
        /*
                      Rx_DLL
                     127 ▲
                         │   ++++++++++++++++
              Rx_High    │     ++++++++++++++
                  ───────┼──►x   ++++++++++++
                         │   xx   +++++++++++
                         │   xxx   ++++++++++
                         │   xxxx   +++++++++
                         │   xxxxx   ++++++++
          Fix Rx_DLL     │   xxxxxx   +++++++
         1/4 between     │   xxxxxxx   ++++++
      Rx_High and Rx_Low │   xxxxxxxx   +++++
                   ──────┼─► ◄───┬──►    ++++
                         │   xxxx│xxxxx   +++
               Rx_Low    │   xxxx│xxxxxx   ++
                   ──────┼──►xxxx│xxxxxxx   +
                         │       │
                        ─┼───────┼───────────►  Tx_DLL
                        0│       │          127
                                 │
                            Search Tx_Low
         */
    
        searchPoint.rdDelay = phyTuneWindowParams->rdDelayMin;
        searchPoint.rxDLL = rxLow.rxDLL+(rxHigh.rxDLL-rxLow.rxDLL)/4U;
        searchPoint.txDLL = phyTuneWindowParams->txLowSearchStart;
        OSPI_phyFindTxLow(handle, &searchPoint, flashOffset, &txLow);
    
        while(txLow.txDLL == 128U)
        {
            searchPoint.rdDelay++;
            OSPI_phyFindTxLow(handle, &searchPoint, flashOffset, &txLow);
    
            if(searchPoint.rdDelay > phyTuneWindowParams->rdDelayMax)
            {
                status = SystemP_FAILURE;
                DebugP_log("Failure in finding primary tx low \n\r");
                return status;
            }
        }
    
        /***************************** GOLDEN Tx_High Search *********************/
        /*
         * Find txDLL Max
         * Start the rdDelay (Read delay) from maximum and decrement it.
         */
        /*
                    Rx_DLL
                   127 ▲
                       │   +++++++++++++++++
            Rx_High    │     +++++++++++++++
                ───────┼──►x   +++++++++++++
                       │   xx   ++++++++++++
                       │   xxx   +++++++++++
                       │   xxxx   ++++++++++
                       │   xxxxx   +++++++++
         Fix Rx_DLL    │   xxxxxx   ++++++++
        1/4 between    │   xxxxxxx   +++++++
     Rx_High and Rx_Low│   xxxxxxxx   ++++++
                 ──────┼─► xxxxxxxxx   ◄─┬─►
                       │   xxxxxxxxxx   +│++
             Rx_Low    │   xxxxxxxxxxx   │++
                 ──────┼──►xxxxxxxxxxxx  │++
                       │                 │
                      ─┼─────────────────┼─►  Tx_DLL
                      0│                 │127
                                      Search Tx_Max
        */
    
        searchPoint.txDLL = phyTuneWindowParams->txHighSearchEnd;
        searchPoint.rdDelay = phyTuneWindowParams->rdDelayMax;
        OSPI_phyFindTxHigh(handle, &searchPoint, flashOffset, &txHigh);
    
        while(txHigh.txDLL == 128U)
        {
            searchPoint.rdDelay--;
            OSPI_phyFindTxHigh(handle, &searchPoint, flashOffset, &txHigh);
    
            if(searchPoint.rdDelay < phyTuneWindowParams->rdDelayMin)
            {
                status = SystemP_FAILURE;
                DebugP_log("Failure in finding primary tx high \n\r");
                return status;
            }
        }
    
        /*
         * Check a different point if the txLow and txHigh are on the same rdDelay.
         * This avoids mistaking the metastability gap for a txDLL boundary
         */
        if(txLow.rdDelay == txHigh.rdDelay)
        {
    
            /***************************** BACKUP Tx_Low Search *********************/
            /* Look for txDLL boundaries at 3/4 of rxDLL window */
            /* Find txDLL Min */
            /*
                 Rx_DLL
                127 ▲
                    │
           Rx_High──┼──►+++++++++++++++++
                    │   +++++++++++++++++
        Fix Rx_DLL  │   +++++++++++++++++
    3/4 of Rx_High ─┼─► ◄───┬───►++++++++
        and Rx_Low  │     ++│++++++++++++
                    │      +│++++++++++++
                    │   x   │++++++++++++
                    │   xx  │++++++++++++
                    │   xxx │ +++++++++++
                    │   xxxx│  ++++++++++
                    │   xxxx│   +++++++++
                    │   xxxx│x   ++++++++
                    │   xxxx│xx   +++++++
            Rx_Low──┼──►xxxx│xxx   ++++++
                    │       │
                   ─┼───────┼────────────► Tx_DLL
                   0│       │               127
                       Search Tx_Min
            */
    
            searchPoint.rdDelay = phyTuneWindowParams->rdDelayMin;
            searchPoint.rxDLL = rxLow.rxDLL + 3U*(rxHigh.rxDLL-rxLow.rxDLL)/4U;
            searchPoint.txDLL = phyTuneWindowParams->txLowSearchStart;
            OSPI_phyFindTxLow(handle, &searchPoint, flashOffset, &backupPoint);
            while(backupPoint.txDLL==128U)
            {
                searchPoint.rdDelay++;
                OSPI_phyFindTxLow(handle, &searchPoint, flashOffset, &backupPoint);
                if(searchPoint.rdDelay > phyTuneWindowParams->rdDelayMax)
                {
                    status = SystemP_FAILURE;
                    DebugP_log("Failure in finding backup primary tx low \n\r");
                    return status;
                }
            }
            if(backupPoint.txDLL < txLow.txDLL)
            {
                txLow = backupPoint;
            }
    
            /***************************** BACKUP Tx_High Search *********************/
            /*
             * Find txDLL Max
             * Start the rdDelay (Read delay) from maximum and decrement it.
             */
            /*
             Rx_DLL
              127
                ▲
                │
       Rx_High──┼──►+++++++++++++++++
                │   +++++++++++++++++
     Fix Rx_DLL │   +++++++++++++++++
     3/4 of ────┼─► +++++++◄────┬───►
      Rx_High   │     ++++++++++│++++
       and      │      +++++++++│++++
      Rx_Low    │   x   ++++++++│++++
                │   xx   +++++++│++++
                │   xxx   ++++++│++++
                │   xxxx   +++++│++++
                │   xxxxx   ++++│++++
                │   xxxxxx   +++│++++
                │   xxxxxxx   ++│++++
        Rx_Low──┼──►xxxxxxxx   +│++++
                │               │
               ─┼───────────────┼────► Tx_DLL
               0│               │       127
                             Search Tx_Max
            */
    
            searchPoint.txDLL = phyTuneWindowParams->txHighSearchEnd;
            searchPoint.rdDelay = phyTuneWindowParams->rdDelayMax;
            OSPI_phyFindTxHigh(handle, &searchPoint, flashOffset, &backupPoint);
            while(backupPoint.txDLL==128U)
            {
                searchPoint.rdDelay--;
                OSPI_phyFindTxHigh(handle, &searchPoint, flashOffset, &backupPoint);
                if(searchPoint.rdDelay < phyTuneWindowParams->rdDelayMin)
                {
                    status = SystemP_FAILURE;
                    DebugP_log("Failure in finding backup primary tx high \n\r");
                    return status;
                }
            }
            if(backupPoint.txDLL > txHigh.txDLL)
            {
                txHigh = backupPoint;
            }
        }
    
        /*
         * Set bottom left and top right right corners.  These are theoretical corners. They may not actually be "good" points.
         * But the longest diagonal of the shmoo will be between these corners.
         */
    
        /* Bottom Left */
        bottomLeft.txDLL = txLow.txDLL;
        bottomLeft.rxDLL = rxLow.rxDLL;
    
        if(txLow.rdDelay <= rxLow.rdDelay)
        {
            bottomLeft.rdDelay = txLow.rdDelay;
        }
        else
        {
            bottomLeft.rdDelay = rxLow.rdDelay;
        }
    
        backupCornerPoint = bottomLeft;
        backupCornerPoint.txDLL += 4U;
        backupCornerPoint.rxDLL += 4U;
    
        OSPI_phySetRdDelayTxRxDLL(handle, &backupCornerPoint);
    
        status = OSPI_phyReadAttackVector(handle, flashOffset);
    
        if(status == SystemP_FAILURE)
        {
            backupCornerPoint.rdDelay--;
            OSPI_phySetRdDelayTxRxDLL(handle, &backupCornerPoint);
            status = OSPI_phyReadAttackVector(handle, flashOffset);
        }
    
        if(status == SystemP_SUCCESS)
        {
            bottomLeft.rdDelay = backupCornerPoint.rdDelay;
        }
    
        topRight.txDLL = txHigh.txDLL;
        topRight.rxDLL = rxHigh.rxDLL;
    
        if(txHigh.rdDelay > rxHigh.rdDelay)
        {
            topRight.rdDelay = txHigh.rdDelay;
        }
        else
        {
            topRight.rdDelay = rxHigh.rdDelay;
        }
    
        backupCornerPoint = topRight;
        backupCornerPoint.txDLL -= 4U;
        backupCornerPoint.rxDLL -= 4U;
    
        OSPI_phySetRdDelayTxRxDLL(handle, &backupCornerPoint);
    
        status = OSPI_phyReadAttackVector(handle, flashOffset);
    
        if(status == SystemP_FAILURE)
        {
            backupCornerPoint.rdDelay++;
            OSPI_phySetRdDelayTxRxDLL(handle, &backupCornerPoint);
            status = OSPI_phyReadAttackVector(handle, flashOffset);
        }
    
        if(status == SystemP_SUCCESS)
        {
            topRight.rdDelay = backupCornerPoint.rdDelay;
        }
    
        /* Find the equation of diagonal between topRight and bottomLeft */
    
        /* Slope and Intercept*/
        slope = ((float)topRight.rxDLL-(float)bottomLeft.rxDLL)/((float)topRight.txDLL-(float)bottomLeft.txDLL);
        /* Binary Search */
        OSPI_PhyConfig left, right;
        /* Search along the diagonal between corners */
        left = bottomLeft;
        right = topRight;
        searchPoint.txDLL = left.txDLL + ((right.txDLL - left.txDLL) / 2);
        searchPoint.rxDLL = left.rxDLL + ((right.rxDLL - left.rxDLL) / 2);
        searchPoint.rdDelay = left.rdDelay;
    
        do
        {
            OSPI_phySetRdDelayTxRxDLL(handle, &searchPoint);
    
            status = OSPI_phyReadAttackVector(handle, flashOffset);
            if(status == SystemP_FAILURE)
            {
                /*
                * As the read failed, we go to the lower half for finding the gap low
                */
                right.txDLL = searchPoint.txDLL;
                right.rxDLL = searchPoint.rxDLL;
    
                searchPoint.txDLL = left.txDLL + ((searchPoint.txDLL - left.txDLL)/2);
                searchPoint.rxDLL = left.rxDLL + ((searchPoint.rxDLL - left.rxDLL)/2);
            } else
            {
                /*
                * As the read is a success we go to the upper half for finding the gap low
                */
                left.txDLL = searchPoint.txDLL;
                left.rxDLL = searchPoint.rxDLL;
    
                searchPoint.txDLL = searchPoint.txDLL + ((right.txDLL - searchPoint.txDLL)/2);
                searchPoint.rxDLL = searchPoint.rxDLL + ((right.rxDLL - searchPoint.rxDLL)/2);
            }
        /* Break the loop if the window has closed. */
        } while ((right.txDLL - left.txDLL >= 2) && (right.rxDLL - left.rxDLL >= 2));
    
        gapLow = searchPoint;
    
        /* If there's only one segment, put tuning point in the middle and adjust for temperature */
        if(bottomLeft.rdDelay == topRight.rdDelay)
        {
            /* Start of the metastability gap is a good approximation for the topRight */
            topRight = gapLow;
            searchPoint.rdDelay = bottomLeft.rdDelay;
            searchPoint.txDLL = (bottomLeft.txDLL+topRight.txDLL)/2U;
            searchPoint.rxDLL = (bottomLeft.rxDLL+topRight.rxDLL)/2U;
    
            status = VTM_getAverageTemperature(&temperature);
            if(status == SystemP_SUCCESS)
            {
                searchPoint.txDLL += (topRight.txDLL - bottomLeft.txDLL) * (0.5*(temperature-42.5)/165);
                searchPoint.rxDLL += (topRight.rxDLL - bottomLeft.rxDLL) * (0.5*(temperature-42.5)/165);
            }
        }
        else
        {
            /* If there are two segments, find the start and end of the second one */
            left = bottomLeft;
            right = topRight;
            searchPoint.txDLL = left.txDLL + ((right.txDLL - left.txDLL) / 2);
            searchPoint.rxDLL = left.rxDLL + ((right.rxDLL - left.rxDLL) / 2);
            searchPoint.rdDelay = right.rdDelay;
            do{
    
                OSPI_phySetRdDelayTxRxDLL(handle, &searchPoint);
                status = OSPI_phyReadAttackVector(handle, flashOffset);
                if(status == SystemP_FAILURE)
                {
                    /*
                    * As the read failed, we go to the upper half for finding the gap high
                    */
                    left.txDLL = searchPoint.txDLL;
                    left.rxDLL = searchPoint.rxDLL;
    
                    searchPoint.txDLL = searchPoint.txDLL + ((right.txDLL - searchPoint.txDLL)/2);
                    searchPoint.rxDLL = searchPoint.rxDLL + ((right.rxDLL - searchPoint.rxDLL)/2);
                }
                else
                {
                    /*
                    * As the read is a success we go to the lower half for finding the gap high
                    */
                    right.txDLL = searchPoint.txDLL;
                    right.rxDLL = searchPoint.rxDLL;
    
                    searchPoint.txDLL = left.txDLL + ((searchPoint.txDLL - left.txDLL)/2);
                    searchPoint.rxDLL = left.rxDLL + ((searchPoint.rxDLL - left.rxDLL)/2);
                }
                /* Break the loop if the window has closed. */
            } while ((right.txDLL - left.txDLL >= 2) && (right.rxDLL - left.rxDLL >= 2));
            gapHigh = searchPoint;
    
            /* Place the final tuning point of the PHY in the corner furthest from the gap */
            int len1 = abs(gapLow.txDLL-bottomLeft.txDLL) + abs(gapLow.rxDLL-bottomLeft.rxDLL);
            int len2 = abs(gapHigh.txDLL-topRight.txDLL) + abs(gapHigh.rxDLL-topRight.rxDLL);
    
            if(len2 > len1)
            {
                searchPoint = topRight;
                searchPoint.txDLL -= 16;
                searchPoint.rxDLL -= (int32_t)((float)16*slope);
            }
            else
            {
                searchPoint = bottomLeft;
                searchPoint.txDLL += 16;
                searchPoint.rxDLL += (int32_t)((float)16*slope);
            }
        }
    
        OSPI_phySetRdDelayTxRxDLL(handle, &searchPoint);
    
        status = OSPI_phyReadAttackVector(handle, flashOffset);
    
        if(status == SystemP_SUCCESS)
        {
            otp->rxDLL = searchPoint.rxDLL;
            otp->txDLL = searchPoint.txDLL;
            otp->rdDelay = searchPoint.rdDelay;
        }
        else
        {
            otp->rxDLL = 0;
            otp->txDLL = 0;
            otp->rdDelay = 0;
        }
        
        DebugP_log("OTP point is: rdDelay: %u rxDLL: %u txDLL: %u \n\r", otp->rdDelay, otp->rxDLL, otp->txDLL);
    
        return status;
    }

    Please replace the above OTP1 code, as I have added logging statements at correct places for us to figure out in failure case, where exactly the failure happens.

    Regards,

    Vaibhav

  • Hello Vaibhav,

    I can not reproduce the error at the moment. When I get it I will send you the information again.

    Thanks,

    Huy

  • Hello Khuat-san,

    Okay I will wait for your results.

    Regards,

    Vaibhav