Exposing general-purpose-timers in device-tree

Hi! I am working on a project where I need to use one the GPT1 timer that is available on the IMX8QM. So far I have been trying to modify the device-tree and add the GPT node as follows:

    lsio_gpt1: gpt@5d150000 {
        #address-cells = <1>;
		#size-cells = <1>;
        compatible = "fsl,imx8qm-gpt";    
        reg = <0x5d150000 0x10000>;   
        interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;    
        clocks = <&gpt1_lpcg 0>, <&clk_gpt_3m 0>;    
        clock-names = "ipg", "per";
        power-domains = <&pd IMX_SC_R_GPT_1>;
        status = "okay";
    };

The device-tree compiles just fine using the torizoncore-builder tool and torizon-core-docker 5.7.2. The device-tree base I have been trying to use is the arm64/boot/dts/freescale/imx8qm-apalis-v1.1-ixora-v1.2.dts from the toradex-linux repository on branch toradex_5.4-2.3.x-imx as I was not able to get the 5.15 version to boot.

When I try to access memory from GPT1 at address 0x5D150000 using the /dev/mem driver and mmap, I get a bus error, and if I use my custom GPT driver to access it, the device crashes and reboots.
I have been investigating the use of the /dev/mem device a bit as well, and have found that i get the same bus-error when i try to access some of the peripherals that should be enabled in the device-tree by default (such as pwm). So maybe I am using this in a way that it is not intended?

In short; I am unable to access the memory of GPT1 at 0x5D150000 even if I have enabled it through the device-tree. I am using an apalis IMX8QM on an Ixora-v1.2 board.

Most likely that access to GPT1 memory has been disabled by the Resource Domain Controller (RDC). The RDC is a security feature on the i.MX8QM SoC that allows you to partition the system resources into domains and control access to those resources from different software components running on the system. Please refer to this document for details .
Please also verify if the GPT1 clock and power domain are enabled for GPT1.

1 Like

Thank you so much for your response @alex.tx! It does seem like this could be it from the document you shared with me. Using a few additional articles; build-custom-scfw and build boot-container, I think I have managed to create a custom SCFW and put it into my image that I deploy to the apalis.
Taking a look at the mx8qm_apalis/board.c file I find these two structures that I believe are used to specify the resources that are partitioned for the cortex-m4 0 and 1.

M4_0 resource list

static const sc_rsrc_t rsrc_list[9U] =
{
    SC_R_IRQSTR_M4_1,
    SC_R_UART_2,
    SC_R_MU_6B,
    SC_R_MU_7B,
    SC_R_MU_9B,
    SC_R_GPT_3,
    RM_RANGE(SC_R_CAN_0, SC_R_CAN_2),
    SC_R_FSPI_0
};

M4_1 resource list

static const sc_rsrc_t rsrc_list[4U] =
{
    RM_RANGE(SC_R_M4_0_PID1, SC_R_M4_0_PID4),
    RM_RANGE(SC_R_M4_1_PID1, SC_R_M4_1_PID4)
};

However, neither of these mention the GPT1, not does it seem like the GPT1 is in the ranges. I was thinking maybe the memory regions could be locked, but I think these are only to specify the RAM for the m4. From the article that was initially shared they say “That way the resources/pads won’t be marked to be moved to the M4_1 partition and they will be left on the pt_boot partition (A core partition).” So since the GPT1 isnt specifically mentioned in the board.c file I would’ve expected these to be available from linux. So it seems like I am missing something


Edit:
Maybe it is the clock and/or power that is not enabled for these peripherals. I’ve been attempting to enable those using:

sc_pm_clock_rate_t rate = SC_24MHZ;

sc_ipc_t ipc_sc; 
sc_ipc_open(&ipc_sc, (sc_ipc_id_t) GPT0_BASE); 
sc_pm_set_resource_power_mode(ipc_sc, SC_R_GPT_0, SC_PM_PW_MODE_ON);
sc_pm_set_clock_rate(ipc_sc, SC_R_GPT_0, SC_PM_CLK_PER, &rate);
sc_pm_clock_enable(ipc_sc, SC_R_GPT_0, SC_PM_CLK_PER, SC_TRUE, SC_FALSE);
sc_ipc_close(ipc_sc); 

but no luck so far. However, the apalis did start to crash instead of giving a bus-error. So something seems to be happening ¯\_(ツ)_/¯

I continued trying to modify the SCFW, but none of my changes seem to be taking place. I tried to disable GPT0 (just ot confirm that I am able to do anything) and enable the other peripherals using both the sc_pm_set functions and the pm_force functions like this:

sc_ipc_t ipc_sc;
sc_ipc_open(&ipc_sc, (sc_ipc_id_t) MU_LSIO_0A); //Unsure which MU I am supposed to use here..
sc_pm_set_resource_power_mode(ipc_sc, SC_R_GPT_0, SC_PM_PW_MODE_OFF);
sc_pm_set_clock_rate(ipc_sc, SC_R_GPT_0, SC_PM_CLK_PER, &rate);
sc_pm_clock_enable(ipc_sc, SC_R_GPT_0, SC_PM_CLK_PER, SC_TRUE, SC_FALSE);
sc_ipc_close(ipc_sc);
pm_force_resource_power_mode_v( SC_R_GPT_0, SC_PM_PW_MODE_OFF );
pm_set_clock_rate(SC_PT, SC_R_GPT_0, SC_PM_CLK_PER, &rate);
pm_force_clock_enable( SC_R_GPT_0, SC_PM_CLK_PER, SC_FALSE );

These blocks are placed within the board_system_config function in the mx8qm_apalis/board.c file. I compile this using make SOC=MX8QM B=apalis DL=2 R=b0 U=0 V=0 qm, add the output scfw_tcm.bin file to the iMX8QM folder in imx-mkimage (the other files: bl31.bin, u-boot.bin, and the seco firmware were built once and placed in the folder already as I dont think I need to change them actively), and then i build the flash.bin file using make SOC=iMX8QM flash_b0 . This file is then copied to a unpacked torizon-core-docker-apalis-imx8-Tezi_5.7.2+build.20.tar to replace the imx-boot file, and then repacked into a .tar file. This tar is then used as the source for torizoncore-builder, where I also add the device-tree as described in the initial post; and then build, unpack, and deploy a new image to the Apalis.

Anything in this process or use of SCFW API that seems to be wrong or misunderstood @alex.tx (or other community members)? :slight_smile:

Hi @aleksw !

Sorry for the delay.

I couldn’t find much information on how to deal with GPT, but I have some questions/comments.

I could not find this driver compatible fsl,imx8qm-gpt in linux-toradex’s branch toradex-5.4-2.3.x-imx. Are you sure this exists?
I could find several compatibles fsl,imx*-gpt in the file timer-imx-gpt.c « clocksource « drivers - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules, but no fsl,imx8qm-gpt, unfortunately. The related Linux documentation for this file is at fsl,imxgpt.txt « timer « bindings « devicetree « Documentation - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

A successful device tree compilation doesn’t mean that it will actually work. For example, the Device Tree Compiler (dtc) doesn’t check for the driver’s existence.

When I need fiddle/investigate using /dev/mem, I use devmem2 (reference from OpenEmbedded: OpenEmbedded Layer Index - devmem2). Are you using it?

Just to be sure, (as far as I know) i.MX8QM has two sets of GPT:

  • Low Speed GPTs
    • Some references from NXP’s RM
      • Section 8.16.4
      • Section 19.4
  • Audio Subsystem GPTs
    • Some references from NXP’s RM
      • Section 8.6.5
      • Section 18.10

Which one are you targeting?


Looking into Linux Kernel and Apalis iMX8QM’s device tree (specifically the file imx8qm.dtsi), the compatible string for the clock is fsl,imx8qm-clk. Therefore the driver is clk-imx8qxp.c. In this driver, we see some stuff related to IMX_SC_R_GPT_1: clk-imx8qxp.c « imx « clk « drivers - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules.

You can see that NXP drivers (like the clk-imx8qxp) use SCFW API calls, so I am not sure that you actually need to modify SCFW itself directly (but maybe you need
 I am just not sure).

The i.MX Linux Reference Manual (for NXP’s BSP 5.4.70, in which Toradex’s BSP 5 is based) has some information:


I didn’t try anything myself yet. If I find anything else, I will let you know.

Best regards,

Thank you for your reponse @henrique.tx!

For the compatibility parameter question: I am definitely not sure about this parameter. I have a custom gpt driver with the name apalis-gpt[0-3], but maybe this is not good enough? Do you have a suggestion of what I could use instead of the current value? From some of the information you gave at the end, maybe the driver should be called something like : gpt-imx8qm.c ? But if the compatibility of the driver name is problematic, why doesn’t the /dev/mem driver work? Is there a compatibility value for that driver?

When I need fiddle/investigate using /dev/mem , I use devmem2 (reference from OpenEmbedded: OpenEmbedded Layer Index - devmem2). Are you using it?

I have not tried to use this tool. I’ve kept it quite simple and used some simple python lines when trying to access the peripheral memory:

import mmap

fd = open("/dev/mem", "r+b")
gpt1_addr = 0x5D150000
map = mmap.mmap(fd.fileno(), 4, offset=gpt1_addr) 

print(map[0])

Which currently results in a bus-error

Just to be sure, (as far as I know) i.MX8QM has two sets of GPT

Which one are you targeting?

I have been targeting the GPTs in LSIO, so the first one you pointed out.

I looked a bit further into the compatibility question and I do believe that there must be something wrong in the value I set. The u-boot-toradex drivers implement linux drivers slightly different than the standard linux drivers adding information on compatibility within the driver itself. This is how the lpi2c adds its compatibility:

static const struct udevice_id imx_lpi2c_ids[] = {
	{ .compatible = "fsl,imx7ulp-lpi2c", },
	{ .compatible = "fsl,imx8qm-lpi2c", },
	{}
};

So this answers my questions for how and where the compatibility value is from.

The reason to believe that the SCU could be the reason for this problem is due to the bus-error that I get when I try to read from the peripheral memory. The i.MX documentation says:

Before any hardware in the SoC can be used, SW must first power up the resource
and enable any clocks that it requires, otherwise access will generate a bus error

However, no matter the modifications I add to the board.c file I am not able to change the behavior.

In the end I got GPT1 to work and finally found out why GPT0 was always enabled. Per default it seems like GPT1 is off, either by having its clock or power gated (or both), which must be enabled in either the SCFW or in the ATF. These files are included in a boot container that is compiled and added to a custom image following the instructions the the toradex documentation.

GPT0 is enabled in the ATF and used during boot for some stuff. This can be seen in the files

imx-atf/plat/imx/imx8qm/imx8qm_bl31_setup.c
imx-atf/plat/imx/imx8qm/imx8qm_psci.c

One of the challenges I had was that even though I changed the imx-boot file in the .tar file that I used for the easy-installer of torizoncore-builder, the new boot container didnt seem to change. The first time I got it to work was when I installed it from a USB-stick instead of using torizoncore-builder deploy. There are some commit hashes for the various firmwares in the boot-container that are printed to the serial console during the boot procedure of the imx8. These can be used to see if the boot-container has changed.

I spent a lot of time trying to understand the compatibility parameter of the device-tree, but in the end, it doesn’t seem like this one matter. I can access the GPT peripherals from linux suing both /dev/mem and a custom built linux-device-driver, even though I havent added or changed any compatibility parameters in the drivers.

TL;DR:
If you get a bus-error when accessing memory it is likely that the peripheral/hardware you are trying to access is disabled. The SCU (system control unit) is used to control the peripherals, and so the SCFW (SCU firmware) must be modified in order to enable the peripherals.