Writing TCMU and L in Linux iMX7

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Writing TCMU and L in Linux iMX7

3,324 Views
dogisfat
Contributor IV

I am trying to write the TCM to load the M4 and boot it from Linux and can load the DDR and OCRAM_S but I cannot load the TCM. When I try to ioremap_uncached() the address I get a valid pointer back and then when I go to do an iowrite or an memcpy_toio linux freezes.

Any ideas? Code example below:

    if ((request_mem_region(0x007f8000,0x8000, "TCML")) == NULL) {
        printk(KERN_ERR "Failed to get TCML region\n");
        return -EIO;
    }
    printk(KERN_INFO "ioremapping TCML 0x007f8000 size 0x8000\n");
    mem = ioremap_nocache(0x007f8000, 0x8000);
    if(mem) {
        printk(KERN_INFO "ioremap successful\n");
        // First we need to set the region to be zero
        for(m4_data = 0; m4_data < 1 /*0x8000*/; ++m4_data)
        {
            printk(KERN_INFO "attempting memset %d @ 0x%p\n",m4_data,mem + m4_data);
            iowrite8(0, mem + m4_data);
            printk(KERN_INFO "memset %d @ 0x%p successful \n",m4_data,mem + m4_data);
        }
        // Now we copy in the data
        printk(KERN_INFO "memset successful\n");
        // Cleanup
        iounmap(mem);   
        printk(KERN_INFO "iounmap successful\n");
    } else {
        printk(KERN_ERR "error ioremapping TCML 0x007f8000 size 0x8000\n");
    }
    release_mem_region(0x007f8000, 0x8000);
Labels (3)
Tags (3)
13 Replies

2,459 Views
erikfriedel
Contributor III

Hi,

In Linux you can use "devmem" to set single bits in the Registers.

Restarting the M4 with this method is possible. But how can I load a binary file in the Memory with Linux?

Is there a command you can use, to copy a whole file into the memory or do I have to write a script first?

Erik

0 Kudos

2,459 Views
dogisfat
Contributor IV

This thread describes a kernel module that is used for loading the m4:

https://community.nxp.com/thread/454996 

2,459 Views
dogisfat
Contributor IV

On thought I had was that the clock may not be enabled so I tried writing to CCGR1 as follows though I am not confident it is correct:

    if ( (request_mem_region(0x30384010, 32, "CCM_CCGR1")) == NULL) {
        dev_err(&m4_dev->pdev->dev, "Failed to get CCM_CCGR1 region\n");
        return -1;
    }

    ccgr = ioremap_nocache(0x30384010, 32);
    m4_data = ioread16(ccgr);

    iowrite16(m4_data | (0x3333), ccgr);
    dev_info(&m4_dev->pdev->dev, "Starting M4 clock...\n");

    iounmap(ccgr);
    release_mem_region(0x30384010, 32);‍‍‍‍‍‍‍‍‍‍‍‍‍

To be clear this didn't work either.

0 Kudos

2,459 Views
igorpadykov
NXP Employee
NXP Employee

Hi Allen

one can check in dts file for presence:

tcml@007f8000 {
        compatible = "fsl, m4_tcml";
        reg = <0x007f8000 0x8000>;
    };

as in example: linux/arch/arm/boot/dts/imx7d-sdb-m4.dtsi

imx7d-sdb-m4.dtsi\dts\boot\arm\arch - linux-imx - i.MX Linux kernel 

Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

2,459 Views
dogisfat
Contributor IV

Igor,

I do have that present in my dts file. Does it enable any clocks as part of the boot up process. I found if I attach a debugger to the M4 and then boot the process works so I strongly suspect a clock is not enabled that should be. Are there additional clock configurations that need to be set up to write to the TCM?

0 Kudos

2,459 Views
igorpadykov
NXP Employee
NXP Employee

Hi Allen

was m4 enabled in SRC_M4RCR

Best regards
igor

0 Kudos

2,459 Views
dogisfat
Contributor IV

Igor,

Here is the code that is executed before writing to the TCM:

    void __iomem* m4rcr;
    void __iomem* ccgr;
    void __iomem* mem;
    uint32_t m4_data;
    struct m4loader_drv* m4_dev = to_m4loader_drv(filep);
    /* Reset the buffer index, we assume if it is being opened we are getting a 
     * new ELF to load.
     */
    m4_dev->current_buffer_index = 0;

    if ((request_mem_region(0x3039000C, 32, "SRC_M4RCR")) == NULL)
    {
        dev_err(&m4_dev->pdev->dev, "Failed to get m4rcr region\n");
        return -1;
    }

    m4rcr = ioremap_nocache(0x3039000C, 32);
    m4_data = ioread8(m4rcr);
    iowrite8(m4_data | (1 << 2), m4rcr);
    dev_info(&m4_dev->pdev->dev, "Waiting for reset..\n");

    while (m4_data & 0x04)
    {
        m4_data = ioread8(m4rcr);
    }
    dev_info(&m4_dev->pdev->dev, "Reset Finished\n");
    iounmap(m4rcr);
    release_mem_region(0x3039000C, 32);

    if ((request_mem_region(0x30384014, 32, "CCM_CCGR1")) == NULL)
    {
        dev_err(&m4_dev->pdev->dev, "Failed to get CCM_CCGR3 region\n");
        return -1;
    }

    ccgr = ioremap_nocache(0x30384014, 32);
    m4_data = ioread16(ccgr);
    printk(KERN_INFO "Read 0x%08x from CCGR1", m4_data);

    iowrite16(m4_data | (0x3), ccgr);
    dev_info(&m4_dev->pdev->dev, "Starting M4 clock...\n");
    m4_data = ioread16(ccgr);
    printk(KERN_INFO "Read 0x%08x from CCGR1", m4_data);
    if ((m4_data & 0x3) != 0x3)
    {
        dev_err(&m4_dev->pdev->dev, "Unable to start M4 clock...\n");
        return -EIO;
    }

    iounmap(ccgr);
    release_mem_region(0x30384014, 32);

    return 0;

I have found that with clk_unused_ignore and just calling bootaux on the tcm in uboot allows the write to TCM to work. 
Any idea which clocks I need to enable in arch/arm/mach-imx/clk-imx7d.c that would allow linux to properly configure the 
system without uboot being involved?
0 Kudos

2,459 Views
dry
Senior Contributor I

Is this your own custom driver to load m4 firmware? 

Because there is already imx firmware loader driver in mainline kernel (for elfs), and also there is imx f4 loader 'app' (from user space) which does it (binary blobs).

0 Kudos

2,459 Views
dogisfat
Contributor IV

This is for my own custom driver that loads elfs. At the time we wrote it the mainline module wasn't available. We will explore it in the future.

0 Kudos

2,459 Views
stephenfrench
Contributor I

I am having the same issue. 

0 Kudos

2,459 Views
dogisfat
Contributor IV

I also had to call bootaux 7f80000 in uboot before booting. This still seems like a pretty unsatisfactory solution. I would like to be able to set up all of the clocking in linux in the event that uboot isnt properly set up.

0 Kudos

2,459 Views
EAI
Contributor IV

I also had the same issue trying to load code from Linux to the M4 on an imx6sx. I have investigated why, and have found the following. When Linux boots, it checks to see if the  M4 is running or not, and performs additional initialization if the M4 is running. This additional initialization, among other things, allows the A9 to write to the M4's TCM. This is why running the bootaux command in uBoot allows Linux to write to the TCM. There is nothing in particular that the bootaux command does to enable A9 to write to the TCM, other than start the M4 and allow Linux to perform the additional initialization.

The file arch/arm/mach-imx/src.c contains a function imx_src_is_m4_enabled. As a test, I have patched this function to always return true, and I am now able to load firmware from the A9 to the M4 without running the bootaux command.

I have yet to investigate if there are any negative side effects of doing this.

2,459 Views
igorpadykov
NXP Employee
NXP Employee

bootaux sets vectors addresses, stack pointer and the reset handler of M4, so one

can check if it configured properly if bootaux not used .

Best regards
igor

0 Kudos