Issues with GMI registers

We are using the Toradex CE libraries for converting the tegra T30 (X1 module connector) pins to GMI registers and use those to write/read data from an external board. We are using version 1.1 of the library. So far it had been working great for us, but recently we started seeing data corruptions on the bus. Below is a code snippet to show how we were using the library:

#include "Toradex_Includes\headers\coproclib.h"
#include "Toradex_Includes\headers\MapReglib.h"
#include "Toradex_Includes\headers\gpiolib.h"
#include "Toradex_Includes\headers\clklib.h"
#include "Toradex_Includes\headers\TegraT30.h"

Setup()
{
ClkLibInit(); 
ClkLibSetClockFrequency(SLINK_SPI4_CLK_TEG, 101000, 103000, ClockOptimiseForPrecision);
ClkLibSetClockFrequency(SNOR_CLK_TEG, 101000, 103000, tClockOptimise::ClockOptimiseForPrecision);

WORD* dataRegister = (WORD*)MapMemory(T30_SNOR_ADDR, TEST_DATA_SIZE);

GMI_REGISTERS* gmiRegisters = (GMI_REGISTERS*)MapRegister(GMI_CONF_BASE);
InitGPIOLib();
	for (DWORD pin : listOfPins)
	{
		PIN_INSTANCE pinInst;
		GetGPIOFromPin(pin, FALSE, &pinInst);
		SetGPIOAltFn(pinInst.inst1, 2, DIR_IN); // AltFn always 2
		TegraSetPullStatePinGroup(pinInst.inst1, 0); //Pull state: nothing (normal)
		TegraSetTristatePinGroup(pinInst.inst1, 0); //Tristate: no
	}
	gmiRegisters->SNOR_CONFIG_0 = MST_ENB_ENABLE | NMUX_ASYNC_IO_ENABLE | SNOR_SEL_CS2;
}

writeData(addressOffset , valueToWrite_16Bit)
{
	gmiRegisters->SNOR_CONFIG_0 |= GO_NOR_ENABLE;
	*(dataRegister + addressOffset) = valueToWrite_16Bit;
	gmiRegisters->SNOR_CONFIG_0 &= ~GO_NOR_ENABLE;
}

readData(addressOffset , valueToRead_16Bit)
{
	gmiRegisters->SNOR_CONFIG_0 |= GO_NOR_ENABLE;
       valueToRead_16Bit = *(dataRegister + addressOffset);
	gmiRegisters->SNOR_CONFIG_0 &= ~GO_NOR_ENABLE;
}

Once the data corruption started happening I started digging deeper and realized these libraries are obsolete now. Version 2.3 is the latest release and we are using 1.1. Looking at the release notes nothing pointed towards an explanation of the data corruption but I would like to upgrade to the new libraries anyway.

The problem is the libraries are not backwards compatible and I am having a hard time finding the replacement functions/enums for my existing code. I was able to figure out how to setup the Alt functions using the new gpio_teg.h file:

//******************************************************************************
/// Get the Alternative function setting of the specified SODIMM pin number or GPIO number or Apalis pin number
/// @param[in]  hGpio           HANDLE received from TegGpio_Init()
/// @param[in]  io              GPIO number or SODIMM pin number or Apalis pin number
/// @return                     Alternative function setting number
tIoAltFn TegGpio_GetAltFn(HANDLE hGpio, uIo io);

//******************************************************************************
/// Set the Alternative function setting of the specified io
/// @param[in]  hGpio           HANDLE received from TegGpio_Init()
/// @param[in]  io              GPIO or Colibri pin or Apalis pin number in uIo format
/// @param[in]  altFn           Alternative function setting, (tIoAltFn)use -1 to configure as GPIO.
void TegGpio_SetAltFn(HANDLE hGpio, uIo io, tIoAltFn altFn);

But I am not sure where to look for GMI related functions which used to exist in the MapRegLib.h e.g. :

//******************************************************************************
/// Map Registers at a physical address (map areas up to the PAGE_SIZE).
/// @param[in]            pa          Physical address             
/// @retval               Virtual address           
void *MapRegister(DWORD pa);

//******************************************************************************
/// Same as MapRegister() but can also map larger sections
/// @param[in]            pa              Physical address.
/// @param[in]            size            Size to map in bytes.         
/// @retval               Virtual address            
void *MapMemory(DWORD pa, DWORD size);

Also some of the parameters used in the code snippet (e.g. GMI_CONF_BASE, T30_MIO_ADDR, GMI_REGISTERS struct etc.) are from the TegraT30.h file. This file was not part of the new library. I am not sure where to find the latest version of this file.

Thank you for your time.

Dear @gngig

Library migration

As an initial comment: I don’t expect that migrating to the new library does help you to solve the data corruption problem. But as you mentioned, you wanted to do the conversion anyway. The migration questions are the easy ones, let’s start with them:

The new function Map_MapMemory() can be used to replace both previous functions MapRegister() and MapMemory().

//******************************************************************************
/// Setup a virtual-to-physical memory mapping.
/// The mapped region will be accessed uncached and strongly ordered.
/// @param[in]            pa                Physical address, start of region to map
/// @param[in]            size              Size to map in bytes.
/// @return               Virtual address pointing to the virtual equivalent of pa.
void *Map_MapMemory(DWORD pa, DWORD size);

The TegraT30.h was also not part of the legacy libraries (I quickly ckecked the latest legacy package), so I’m not sure where you got it from. However, the examples you mentioned were hardware specific addresses and data structures. There’s no reason why this would need an update. I expect these definitions to work with the new libraries without any modifications. Let me know if you face issues in this context.

Data Corruption

Do you have any hint what has changed when you started to see data corruptions. Did you maybe switch to a newer release of WEC2013?

I currently don’t know the reason for the change. The most likely explanation for me would be a change in the drive-strength settings of all or some of the GMI pins.
Can you compare a working and a non-working system:

  • Oscilloscope measurements on the signals which face corruptions, and on GMI control signals which could also be responsible for the corruption
  • Using the GpioConfig tool to compare the drive strength settings between the two systems.

I hope this will bring us closer to the root cause of the problem.

Regards, Andy

Hello Andy,
Thank you for the response. I have a few more questions. My legacy clock setup looked like this:

 ClkLibInit(); 

 ClkLibSetClockFrequency(SLINK_SPI4_CLK_TEG, 101000, 103000, ClockOptimiseForPrecision);

 ClkLibSetClockFrequency(SNOR_CLK_TEG, 101000, 103000, tClockOptimise::ClockOptimiseForPrecision);

My new setup function looks like this:

myProperty.tegraClockHandle = TegClk_Init(NULL);

actualFrequency = TegClk_SetClockFrequency(myProperty.tegraClockHandle, SLINK_SPI4_CLK_TEG, 101000, 103000, tClockOptimise::ClockOptimiseForPrecision);

actualFrequency = TegClk_SetClockFrequency(myProperty.tegraClockHandle, SNOR_CLK_TEG, 101000, 103000, tClockOptimise::ClockOptimiseForPrecision);

These two defines existed in the legacy clklib.h but do not exist in clk_teg.h:

#define SNOR_CLK_TEG              (42)
#define SLINK_SPI4_CLK_TEG        (68)

How can I get access to them?

Another issue I am facing is when I am setting the GPIO pins. Legacy code looked like this:

   for (DWORD pin : listOfPins)
     {
         PIN_INSTANCE pinInst;
         GetGPIOFromPin(pin, FALSE, &pinInst);
         SetGPIOAltFn(pinInst.inst1, 2, DIR_IN); // AltFn always 2
         TegraSetPullStatePinGroup(pinInst.inst1, 0); //Pull state: nothing (normal)
         TegraSetTristatePinGroup(pinInst.inst1, 0); //Tristate: no
     }

New code looks like this:

for (DWORD pin : listOfPins)
 {
		uIo pinInstance = COLIBRI_PIN(pin);
		TegGpio_SetAltFn(gpioHandle, pinInstance, tIoAltFn::ioAltFn2);
		TegGpio_SetDir(gpioHandle, pinInstance, tIoDirection::ioInput);
}

I am not able to find replacement functions for these in the new gpio_teg.h or gpio.h:

     TegraSetPullStatePinGroup(pinInst.inst1, 0); //Pull state: nothing (normal)
     TegraSetTristatePinGroup(pinInst.inst1, 0); //Tristate: no

Thanks again for your time.

Dear @gngig

ClockLib

We moved definitions of SNOR_CLK_TEG and SLINK_SPI4_CLK_TEG into an internal header file, because we assumed they were used only internally in our libraries, but were not used by customers. I’m attaching the header file here:

The two defines are hardware-specific constants which will never change. So if you want it is also safe to add the definitions to your source code instead of including the header file.

GpioLib

For the GPIOs we changed the concept completely. For most parameters we went for a string-based configuration concept:

TegGpio_SetConfigString(gpioHandle, pinInstance, NULL, 
                        L"altfn=-1,dir=in,pull=down", StoreVolatile);

We only kept specific additional functions for parameters which are performance critical.

For details about the particular configuration options, please refer to the .chm help file which is part of the library package.

Regards, Andy