Part Number: PROCESSOR-SDK-AM62X
Other Parts Discussed in Thread: SK-AM62-LP
Tool/software:
Dear TI team,
Kindly support on the following topic:
1) GPMC Nand speed configurations from U-Boot device tree:
Context:
We are trying to optimize DFU flashing time in U-Boot, and we are using SDKLA v8.6, and GPMC Nand write speed in U-Boot is not as excepted (very low).
Expected behavior:
We expected to achieve at least minimum 8 MB/s (Miga byte / second) for GPMC Nand chip write speed in U-Boot.
Actual behavior:
The Nand chip write speed in U-Boot during copying data from DDR RAM to GPMC Nand is 0.4MB/s (Miga byte / second).
Questions:
1.a) How to configure U-Boot device tree to set max Nand chip read/write speed?
1.b) How to apply our application NAND/GPMC configuration (shown below) in U-Boot device tree? Check footnote [1] for our failed trial to do so.

/*
* Copyright (C) 2021 Texas Instruments Incorporated
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Auto generated file
*/
#include "ti_drivers_config.h"
#include <drivers/device_manager/sciclient.h>
/*
* GPMC
*/
/* Regions restricted for DMA. We should use CPU memcpy in these cases */
static GPMC_AddrRegion gGpmcDmaRestrictRegions[] =
{
{
.regionStartAddr = CSL_WKUP_R5FSS0_ATCM_BASE,
.regionSize = CSL_WKUP_R5FSS0_ATCM_SIZE,
},
{
.regionStartAddr = CSL_WKUP_R5FSS0_BTCM_BASE,
.regionSize = CSL_WKUP_R5FSS0_BTCM_SIZE,
},
{
.regionStartAddr = CSL_MCU_M4FSS0_IRAM_BASE,
.regionSize = CSL_MCU_M4FSS0_IRAM_SIZE,
},
{
.regionStartAddr = CSL_MCU_M4FSS0_DRAM_BASE,
.regionSize = CSL_MCU_M4FSS0_DRAM_SIZE,
},
{
.regionStartAddr = 0xFFFFFFFFU,
.regionSize = 0U,
}
};
/* GPMC attributes */
static GPMC_HwAttrs gGpmcAttrs[CONFIG_GPMC_NUM_INSTANCES] =
{
{
.gpmcBaseAddr = CSL_GPMC0_CFG_BASE,
.dataBaseAddr = CSL_GPMC0_DATA_BASE,
.elmBaseAddr = CSL_ELM0_BASE,
.inputClkFreq = 133333333U,
.intrNum = 103U,
.intrPriority = 4U,
.chipSelBaseAddr = 0x50000000U,
.chipSelAddrSize = GPMC_CS_MASK_ADDR_SIZE_16MB,
.clkDivider = CSL_GPMC_CONFIG1_GPMCFCLKDIVIDER_DIVBY1,
.waitPinNum = CSL_GPMC_CONFIG1_WAITPINSELECT_W0,
.addrDataMux = CSL_GPMC_CONFIG1_MUXADDDATA_NONMUX,
.timeLatency = CSL_GPMC_CONFIG1_TIMEPARAGRANULARITY_X1,
.waitPinPol = CSL_GPMC_CONFIG_WAIT0PINPOLARITY_W0ACTIVEL,
.timingParams =
{
.csOnTime = 0U,
.csRdOffTime = 5U,
.csWrOffTime = 6U,
.advOnTime = 0U,
.advRdOffTime = 4U,
.advWrOffTime = 4U,
.advAadMuxOnTime = 0U,
.advAadMuxRdOffTime = 0U,
.advAadMuxWrOffTime = 0U,
.weOnTtime = 0U,
.weOffTime = 3U,
.oeOnTime = 1U,
.oeOffTime = 4U,
.oeAadMuxOnTime = 0U,
.oeAadMuxOffTime = 0U,
.pageBurstAccess = 0U,
.rdAccessTime = 5U,
.wrAcessTime = 6U,
.rdCycleTime = 5U,
.wrCycleTime = 5U,
.wrDataOnMuxBusTime = 0U,
.cycle2CycleDelay = 0U,
.busTurnAroundTime = 0U,
.cycleDelaySameChipSel = CSL_GPMC_CONFIG6_CYCLE2CYCLESAMECSEN_NOC2CDELAY,
.cycleDelayDiffChipSel = CSL_GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN_NOC2CDELAY,
},
.eccAlgo = GPMC_NAND_ECC_ALGO_BCH_8BIT,
.readType = CSL_GPMC_CONFIG1_READTYPE_RDASYNC,
.csExDelay = CSL_GPMC_CONFIG2_CSEXTRADELAY_NOTDELAYED,
.accessType = CSL_GPMC_CONFIG1_READMULTIPLE_RDSINGLE,
.optimisedAccess = CSL_GPMC_PREFETCH_CONFIG1_ENABLEOPTIMIZEDACCESS_OPTDISABLED,
.dmaRestrictedRegions = gGpmcDmaRestrictRegions,
},
};
/* GPMC objects - initialized by the driver */
static GPMC_Object gGpmcObjects[CONFIG_GPMC_NUM_INSTANCES];
/* GPMC driver configuration */
GPMC_Config gGpmcConfig[CONFIG_GPMC_NUM_INSTANCES] =
{
{
&gGpmcAttrs[CONFIG_GPMC0],
&gGpmcObjects[CONFIG_GPMC0],
},
};
uint32_t gGpmcConfigNum = CONFIG_GPMC_NUM_INSTANCES;
#include <drivers/gpmc/v0/dma/gpmc_dma.h>
#include <drivers/gpmc/v0/dma/udma/gpmc_dma_udma.h>
#include <drivers/udma.h>
/*
* GPMC UDMA Blockcopy Parameters
*/
#define GPMC_UDMA_BLK_COPY_CH_RING_ELEM_CNT (1U)
#define GPMC_UDMA_BLK_COPY_CH_RING_MEM_SIZE (((GPMC_UDMA_BLK_COPY_CH_RING_ELEM_CNT * 8U) + UDMA_CACHELINE_ALIGNMENT) & ~(UDMA_CACHELINE_ALIGNMENT - 1U))
#define GPMC_UDMA_BLK_COPY_CH_TRPD_MEM_SIZE (UDMA_GET_TRPD_TR15_SIZE(1U))
#define GPMC_UDMA_NUM_BLKCOPY_CH (1U)
/* GPMC UDMA Blockcopy Channel Objects */
static Udma_ChObject gGpmcUdmaBlkCopyChObj[GPMC_UDMA_NUM_BLKCOPY_CH];
/* GPMC UDMA Blockcopy Channel Ring Mem */
static uint8_t gGpmcUdmaBlkCopyCh0RingMem[GPMC_UDMA_BLK_COPY_CH_RING_MEM_SIZE] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));
/* GPMC UDMA Blockcopy Channel TRPD Mem */
static uint8_t gGpmcUdmaBlkCopyCh0TrpdMem[GPMC_UDMA_BLK_COPY_CH_TRPD_MEM_SIZE] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));
GpmcDma_UdmaArgs gGpmcUdma0Args =
{
.drvHandle = &gUdmaDrvObj[CONFIG_UDMA0],
.chHandle = &gGpmcUdmaBlkCopyChObj[0],
.trpdMem = &gGpmcUdmaBlkCopyCh0TrpdMem,
.trpdMemSize = GPMC_UDMA_BLK_COPY_CH_TRPD_MEM_SIZE,
.ringMem = &gGpmcUdmaBlkCopyCh0RingMem,
.ringMemSize = GPMC_UDMA_BLK_COPY_CH_RING_MEM_SIZE,
.ringElemCount = GPMC_UDMA_BLK_COPY_CH_RING_ELEM_CNT,
.localEventID = 26,
};
GPMC_DmaConfig gGpmcDmaConfig[CONFIG_GPMC_NUM_DMA_INSTANCES] =
{
{
.fxns = &gGpmcDmaUdmaFxns,
.gpmcDmaArgs = (void *)&gGpmcUdma0Args,
}
};
uint32_t gGpmcDmaConfigNum = CONFIG_GPMC_NUM_DMA_INSTANCES;
/*
* UDMA
*/
/* UDMA driver instance object */
Udma_DrvObject gUdmaDrvObj[CONFIG_UDMA_NUM_INSTANCES];
/* UDMA driver instance init params */
static Udma_InitPrms gUdmaInitPrms[CONFIG_UDMA_NUM_INSTANCES] =
{
{
.instId = UDMA_INST_ID_BCDMA_0,
.skipGlobalEventReg = TRUE,
.virtToPhyFxn = Udma_defaultVirtToPhyFxn,
.phyToVirtFxn = Udma_defaultPhyToVirtFxn,
},
};
/*
* I2C
*/
/* I2C atrributes */
static I2C_HwAttrs gI2cHwAttrs[CONFIG_I2C_NUM_INSTANCES] =
{
{
.baseAddr = CSL_I2C0_CFG_BASE,
.intNum = 193,
.eventId = 0,
.funcClk = 96000000U,
.enableIntr = 0,
.ownTargetAddr =
{
0x1C,
0x1C,
0x1C,
0x1C,
},
},
};
/* I2C objects - initialized by the driver */
static I2C_Object gI2cObjects[CONFIG_I2C_NUM_INSTANCES];
/* I2C driver configuration */
I2C_Config gI2cConfig[CONFIG_I2C_NUM_INSTANCES] =
{
{
.object = &gI2cObjects[CONFIG_I2C0],
.hwAttrs = &gI2cHwAttrs[CONFIG_I2C0]
},
};
uint32_t gI2cConfigNum = CONFIG_I2C_NUM_INSTANCES;
/*
* UART
*/
/* UART atrributes */
static UART_Attrs gUartAttrs[CONFIG_UART_NUM_INSTANCES] =
{
{
.baseAddr = CSL_WKUP_UART0_BASE,
.inputClkFreq = 96000000U,
},
};
/* UART objects - initialized by the driver */
static UART_Object gUartObjects[CONFIG_UART_NUM_INSTANCES];
/* UART driver configuration */
UART_Config gUartConfig[CONFIG_UART_NUM_INSTANCES] =
{
{
&gUartAttrs[CONFIG_UART0],
&gUartObjects[CONFIG_UART0],
},
};
uint32_t gUartConfigNum = CONFIG_UART_NUM_INSTANCES;
#include <drivers/uart/v0/dma/uart_dma.h>
UART_DmaConfig gUartDmaConfig[CONFIG_UART_NUM_DMA_INSTANCES] =
{
};
uint32_t gUartDmaConfigNum = CONFIG_UART_NUM_DMA_INSTANCES;
void Drivers_uartInit(void)
{
UART_init();
}
void Pinmux_init();
void PowerClock_init(void);
void PowerClock_deinit(void);
/*
* Common Functions
*/
void System_init(void)
{
/* DPL init sets up address transalation unit, on some CPUs this is needed
* to access SCICLIENT services, hence this needs to happen first
*/
Dpl_init();
/* We should do sciclient init before we enable power and clock to the peripherals */
/* SCICLIENT init */
{
int32_t retVal = SystemP_SUCCESS;
retVal = Sciclient_direct_init();
DebugP_assertNoLog(SystemP_SUCCESS == retVal);
}
PowerClock_init();
/* Now we can do pinmux */
Pinmux_init();
/* finally we initialize all peripheral drivers */
GPMC_init();
/* UDMA */
{
uint32_t instId;
int32_t retVal = UDMA_SOK;
for(instId = 0U; instId < CONFIG_UDMA_NUM_INSTANCES; instId++)
{
retVal += Udma_init(&gUdmaDrvObj[instId], &gUdmaInitPrms[instId]);
DebugP_assert(UDMA_SOK == retVal);
}
}
I2C_init();
Drivers_uartInit();
}
void System_deinit(void)
{
GPMC_deinit();
/* UDMA */
{
uint32_t instId;
int32_t retVal = UDMA_SOK;
for(instId = 0U; instId < CONFIG_UDMA_NUM_INSTANCES; instId++)
{
retVal += Udma_deinit(&gUdmaDrvObj[instId]);
DebugP_assert(UDMA_SOK == retVal);
}
}
I2C_deinit();
UART_deinit();
PowerClock_deinit();
/* SCICLIENT deinit */
{
int32_t retVal = SystemP_SUCCESS;
retVal = Sciclient_deinit();
DebugP_assertNoLog(SystemP_SUCCESS == retVal);
}
Dpl_deinit();
}
This is the uboot device tree code:
// SPDX-License-Identifier: GPL-2.0
/**
* DT overlay for HSE NAND expansion card on AM62X LP-SK
*
* Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
*/
#ifdef CONFIG_NAND_OMAP_GPMC
&elm0 {
u-boot,dm-spl;
status = "okay";
};
&main_pmx0 {
gpmc0_pins_default: gpmc0-pins-default {
pinctrl-single,pins = <
AM62X_IOPAD(0x003c, PIN_INPUT, 0) /* (M25) GPMC0_AD0 */
AM62X_IOPAD(0x0040, PIN_INPUT, 0) /* (N23) GPMC0_AD1 */
AM62X_IOPAD(0x0044, PIN_INPUT, 0) /* (N24) GPMC0_AD2 */
AM62X_IOPAD(0x0048, PIN_INPUT, 0) /* (N25) GPMC0_AD3 */
AM62X_IOPAD(0x004c, PIN_INPUT, 0) /* (P24) GPMC0_AD4 */
AM62X_IOPAD(0x0050, PIN_INPUT, 0) /* (P22) GPMC0_AD5 */
AM62X_IOPAD(0x0054, PIN_INPUT, 0) /* (P21) GPMC0_AD6 */
AM62X_IOPAD(0x0058, PIN_INPUT, 0) /* (R23) GPMC0_AD7 */
AM62X_IOPAD(0x0084, PIN_OUTPUT, 0) /* (L23) GPMC0_ADVn_ALE */
AM62X_IOPAD(0x0088, PIN_OUTPUT, 0) /* (L24) GPMC0_OEn_REn */
AM62X_IOPAD(0x008c, PIN_OUTPUT, 0) /* (L25) GPMC0_WEn */
AM62X_IOPAD(0x0090, PIN_OUTPUT, 0) /* (M24) GPMC0_BE0n_CLE */
AM62X_IOPAD(0x00a8, PIN_OUTPUT, 0) /* (M21) GPMC0_CSn0 */
AM62X_IOPAD(0x0098, PIN_INPUT, 0) /* (U23) GPMC0_WAIT0 */
>;
u-boot,dm-spl;
};
};
&gpmc0 {
pinctrl-names = "default";
status = "okay";
pinctrl-0 = <&gpmc0_pins_default>;
ranges = <0 0 0x00 0x51000000 0x01000000>; /* CS0 space. Min partition = 16MB */
#address-cells = <2>;
#size-cells = <1>;
u-boot,dm-spl;
nand0_0: nand@0,0 {
compatible = "ti,am64-nand";
reg = <0 0 64>; /* device IO registers */
interrupt-parent = <&gpmc0>;
interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */
<1 IRQ_TYPE_NONE>; /* termcount */
rb-gpios = <&gpmc0 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */
ti,nand-xfer-type = "prefetch-polled";
ti,nand-ecc-opt = "bch8"; /* BCH8: Bootrom limitation */
ti,elm-id = <&elm0>;
nand-bus-width = <8>;
gpmc,device-width = <1>;
gpmc,sync-clk-ps = <0>;
gpmc,cs-on-ns = <0>;
gpmc,cs-rd-off-ns = <40>;
gpmc,cs-wr-off-ns = <40>;
gpmc,adv-on-ns = <0>;
gpmc,adv-rd-off-ns = <25>;
gpmc,adv-wr-off-ns = <25>;
gpmc,we-on-ns = <0>;
gpmc,we-off-ns = <20>;
gpmc,oe-on-ns = <3>;
gpmc,oe-off-ns = <30>;
gpmc,access-ns = <30>;
gpmc,rd-cycle-ns = <40>;
gpmc,wr-cycle-ns = <40>;
gpmc,bus-turnaround-ns = <0>;
gpmc,cycle2cycle-delay-ns = <0>;
gpmc,clk-activation-ns = <0>;
gpmc,wr-access-ns = <40>;
gpmc,wr-data-mux-bus-ns = <0>;
u-boot,dm-spl;
};
};
#endif
Thanks in advance.
This thread is created upon request from TI team in this previous thread:
https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1456727/processor-sdk-am62x-dfu-u-boot-flashing-speed-optimization-questions/5593398#5593398
FYI: Islam NEGM
_________________________________________________________________________________________
Foot notes:
[1] I applied the nand chip configurations in uboot device tree as follow:

But I founded that I'm receiving wrong information from nand chip it seems that I'm reading wrong block size.
So, that I'm getting a bad block error because I'm reading the bad block marker from wrong location.

Attached Nand chip Datasheet:
2023_05_31-m79a_2gb_parallel_nand_auto (1).pdf