This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM4376: PRU access of some McSPI fails

Part Number: AM4376

Tool/software: Linux

Team,

my customer is trying to access MCSPI peripheral from PRU. They are testing all 5 McSPI instances at addresses

0x4803 0000

0x481A 0000

0x481A 2000

0x481A 4000

0x4834 5000

But only the first one works. If they access the other regs from PRU (read only so far) they see access violations in Linux. I wasn't aware that Linux would even be able to detect PRU access... According to the customer all McSPI are enabled in device tree. Is there any other thing required to power on the peripherals?

General PRU mem access is enabled:

               /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */

               CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

And that should allow PRU to go to full mem range of SoC. Or does Linux use firewalls HW and protect some peripherals?

Let us know if more info from customer is required here.

Best regards,

Frank

  • Hello Frank,

    I am not aware of any firewalls to protect only some of the McSPI peripherals from the PRU. The PRU should be able to access all of the McSPIs. Could you get these from the customer?

    1) Processor SDK version / HW if using TI board
    2) code they're using to access the McSPI from the PRU
    3) output error

    Regards,
    Nick
  • Hello Nick,

    we are using our own hardware and it is possible to work with McSPI from Linux. I think the McSPI is just not switched on when I try to access it from PRU, and I can´t figure out what is missing. The error message (on Linux side) is something like

    L3 Custom Error: MASTER ICSS0 TARGET L4_PER_1 (Read): Data Access in User Mode during Functional access

    I just read the adress 0x4, Hardware Info, from the respective McSPI, just to establish if I can access the interface. It is possible to do so for the first MCSPI, which is then actively used from the Linux side.

    If I can access all adresses through PRU, I should be able to switch the MCSPI on, but I can´t find how to do this.

    Regards, Annette

  • Hello Annette,

    Have you enabled the clocks for the other McSPI modules before trying to read the addresses? This is in the "Module Initialization" section of the McSPI chapter in the Technical Reference Manual.

    Regards,
    Nick
  • Additional information:
    The clocks are enabled using the PRCM_CM_PER_SPIn_CLKCTRL registers in the PRCM Clock Module, where n = 0, 1, 2, 3, 4.

    Regards,
    Nick
  • Hi Nick,

    I think the Clock initialization was the problem. I can now sometimes send data through SPI, but it is not reliable. Do you have an example code, complete initialization sequence, which could be used on PRU?

    Regards, Annette

  • Hi Nick,

    thanks for your help.

    My understanding is that device tree file is used to enable peripherals (including clocks). Or is there a need to enable clocks using low level register writes even in Linux?

    I am not a device tree expert and would like to see an example how this can be done.

    Annette,

    can you post your DTB here so we can check? Thanks.


    Frank 

  • Hello Annette,

    I am wondering if we need to set status=disabled in the device tree for the SPIs to ensure that the Linux kernel isn't messing with the SPI while the PRU is trying to communicate with it.

    I will have some sample code here before the end of the week.

    Regards,
    Nick
  • Hello Annette, 

    This is the test code I used. I was able to replicate your error if I tried reading from the registers prior to enabling the clocks.

    #include <stdint.h>
    #include <pru_cfg.h>
    #include "resource_table_empty.h"
    
    #define PCRM_CM_PER_SPI0_CLKCTRL    (*((volatile unsigned int *)0x44DF8D00))
    #define PCRM_CM_PER_SPI1_CLKCTRL    (*((volatile unsigned int *)0x44DF8D08))
    #define PCRM_CM_PER_SPI2_CLKCTRL    (*((volatile unsigned int *)0x44DF8D10))
    #define PCRM_CM_PER_SPI3_CLKCTRL    (*((volatile unsigned int *)0x44DF8D18))
    #define PCRM_CM_PER_SPI4_CLKCTRL    (*((volatile unsigned int *)0x44DF8D20))
    
    #define McSPI0_HL_HWINFO    (*((volatile unsigned int *)0x48030004))
    #define McSPI1_HL_HWINFO    (*((volatile unsigned int *)0x481A0004))
    #define McSPI2_HL_HWINFO    (*((volatile unsigned int *)0x481A2004))
    #define McSPI3_HL_HWINFO    (*((volatile unsigned int *)0x481A4004))
    #define McSPI4_HL_HWINFO    (*((volatile unsigned int *)0x48345004))
    
    /* functions */
    void init_spi();
    void test_spi();
    
    int main(void)
    {
        /* allow OCP master port access by the PRU so the PRU can read external memories */
        CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
        
        /* initialize the 5 McSPIs */
        init_spi();
    
        /* try to read offset 0x4 (HW info) from each SPI */
        test_spi();
    
    } 
    
    /* 
     * Init McSPIs
     */
    void init_spi(){
    
        /* Enable clock for SPI0: PRCM_CM_PER_SPI0_CLKCTRL */
        while(!(PCRM_CM_PER_SPI0_CLKCTRL == 0x02)){
            PCRM_CM_PER_SPI0_CLKCTRL = 0x02;
        }
    
        /* Enable clock for SPI1: PRCM_CM_PER_SPI1_CLKCTRL */
        while(!(PCRM_CM_PER_SPI1_CLKCTRL == 0x02)){
            PCRM_CM_PER_SPI1_CLKCTRL = 0x02;
        }
    
        /* Enable clock for SPI2: PRCM_CM_PER_SPI2_CLKCTRL */
        while(!(PCRM_CM_PER_SPI2_CLKCTRL == 0x02)){
            PCRM_CM_PER_SPI2_CLKCTRL = 0x02;
        }
    
        /* Enable clock for SPI3: PRCM_CM_PER_SPI3_CLKCTRL */
        while(!(PCRM_CM_PER_SPI3_CLKCTRL == 0x02)){
            PCRM_CM_PER_SPI3_CLKCTRL = 0x02;
        }
    
        /* Enable clock for SPI4: PRCM_CM_PER_SPI4_CLKCTRL */
        while(!(PCRM_CM_PER_SPI4_CLKCTRL == 0x02)){
            PCRM_CM_PER_SPI4_CLKCTRL = 0x02;
        }
    }
    
    /* 
     * Test if McSPIs can be read
     */
    void test_spi(){
        unsigned int test;
        test = McSPI0_HL_HWINFO;
        test = McSPI1_HL_HWINFO;
        test = McSPI2_HL_HWINFO;
        test = McSPI3_HL_HWINFO;
        test = McSPI4_HL_HWINFO;
    }

    Let me know if there's anything further that is needed, 

    Nick

  • Hello Frank & Annette,

    I am going to mark this resolved. If there is any additional assistance we can provide, please comment!

    Regards,
    Nick