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.

PROCESSOR-SDK-AM437X: QSPI register access

Part Number: PROCESSOR-SDK-AM437X

The code to access QSPI registers: 

/////////////////////////////////////////////////////////////////////////////////////////

int i,fd;
unsigned int val;
void *g_addr=NULL,*prcm_addr=NULL;

fd=open("/dev/mem",O_RDWR|O_SYNC);
if(fd==-1){
    printf("@E:open /dev/mem\n");
    return -1;
}

prcm_addr=mmap(NULL,0x2000,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x44df8000); //p142 0x44df8800
if(prcm_addr==NULL){
    printf("@E:prcm_addr null\n");
    return -1; 
}

*(volatile unsigned int *)(prcm_addr+0x800+0x258)=2;  // PRCM_CM_PER_QSPI_CLKCTRL ,  enable qspi module

val= *(volatile unsigned int *)(prcm_addr+0x800+0x258);  // It's curious that the val is 0x30000002, but not 0x2 . why ???


g_addr=mmap(NULL,0x1000,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x47900000); //qspi reg
if(!g_addr){
      printf("@E:g_addr null\n");
      return -1; 
}

val=*(volatile unsigned int *)(g_addr);   //panic here !!!!
printf("qspi id:0x%x\n");

val=*(volatile unsigned int *)(g_addr+0x40);
printf("qspi clock ctrl:0x%x\n");

close(fd);

The err output:

/////////////////////////////////////////////////////////////////////

root@dc-plc:/run/media/mmcblk0p1# ./test
[ 27.546739] Unhandled fault: external abort on non-linefetch (0x1018) at 0xb6f98000
[ 27.546750] pgd = d05ae09c
[ 27.546754] [b6f98000] *pgd=995e5831, *pte=47900303, *ppte=47900a33
[ 27.546836] omap_l3_noc 44000000.ocp: L3 application error: target 9 mod:1 (unclearable)
Bus error (core dumped)

How I can to access the QSPI regsters?  

Thanks!

  • Hi,

    I just did a quick experiment using our current AM437x Linux SDK v6.1 and an AM437x GP EVM. When I boot up Linux and try accessing the PRCM_CM_PER_QSPI_CLKCTRL register I get this:

    root@am437x-evm:~# devmem2 0x44DF8A58
    /dev/mem opened.
    Memory mapped at address 0xb6fc1000.
    Read at address  0x44DF8A58 (0xb6fc1a58): 0x00030000

    According to the TRM that means that "3h = Module is disabled and cannot be accessed". Sure enough, accessing the QSPI register range (QSPI_PID in this case) fails:

    root@am437x-evm:~# devmem2 0x47900000
    /dev/mem opened.[  142.421769] Unhandled fault: external abort on non-linefetch (0x1018) at 0xb6f15000
    [  142.430657] pgd = 244eb6ec
    [  142.433377] [b6f15000] *pgd=f3e26831
    [  142.437084] omap_l3_noc 44000000.ocp: L3 application error: target 9 mod:1 (unclearable)
    
    Memory mapped at address 0xb6f15000.
    Bus error (core dumped)

    But when I force this module to enabled state, I can then access its registers (QSPI_PID in this case) without issues:

    root@am437x-evm:~# devmem2 0x44DF8A58 l 2
    /dev/mem opened.
    Memory mapped at address 0xb6f1f000.
    Read at address  0x44DF8A58 (0xb6f1fa58): 0x0000000000030000
    Write at address 0x44DF8A58 (0xb6f1fa58): 0x0000000000000002, readback 0x0000000000000002
    root@am437x-evm:~# devmem2 0x47900000
    /dev/mem opened.
    Memory mapped at address 0xb6f75000.
    Read at address  0x47900000 (0xb6f75000): 0x4F400000

    And the value I read matches what the TRM says this register should have.

    Please try to re-create this using 'devmem2' and then see what the differences are with your setup. You might need to check the devmem2 source code (http://www.lartmaker.nl/lartware/port/devmem2.c) to see how memory is accessed.

    Regards, Andreas

  • Thank you for your help,  but I have still problem.

    I download devmem2.c  and compile it. Then I test it in my am437x system.

    root@dc-plc:/run/media/mmcblk0p1# devmem2 0x44df8a58 l 2                 //write 64 bit  data
    /dev/mem opened.
    Memory mapped at address 0xb6f93000.
    Read at address 0x44DF8A58 (0xb6f93a58): 0x0000000000030002
    Write at address 0x44DF8A58 (0xb6f93a58): 0x0000000000000002, readback 0x0000000000000002


    root@dc-plc:/run/media/mmcblk0p1# devmem2 0x47900000
    /dev/mem opened.
    Memory mapped at address 0xb6f4a000.
    Bus error (core dumped)


    root@dc-plc:/run/media/mmcblk0p1# devmem2 0x44df8a58 w 2               // write 32 bit data
    /dev/mem opened.
    Memory mapped at address 0xb6f39000.
    Read at address 0x44DF8A58 (0xb6f39a58): 0x00030002
    Write at address 0x44DF8A58 (0xb6f39a58): 0x00000002, readback 0x00000002


    root@dc-plc:/run/media/mmcblk0p1# devmem2 0x47900000
    /dev/mem opened.
    Memory mapped at address 0xb6fbc000.
    Bus error (core dumped)


    root@dc-plc:/run/media/mmcblk0p1# devmem2 0x44df8a58
    /dev/mem opened.
    Memory mapped at address 0xb6f81000.
    Read at address 0x44DF8A58 (0xb6f81a58): 0x00030002         //still  0x00030002, but not 0x00000002
    root@dc-plc:/run/media/mmcblk0p1#

    I hope your help!

    Thanks!

  • I think there is a bug in devmem2.c .

    .....

    *((unsigned long *) virt_addr) = writeval;            should change into --->  *((unsigned volatile long *) virt_addr) = writeval;  
    read_result = *((unsigned long *) virt_addr);       should change into ---> read_result = *((unsigned volatile long *) virt_addr);    

    ....

    I think the code lost keyword  volatile  that tells cpu to get value  from hardware register or flush value to register directly. 

    otherwise value maybe only save in  or fetch from cache but not really from  the register.

    So the read back seems OK, but not actual value in register, it's only a cache.

    Thanks! 

  • xujun zhang said:

    Thank you for your help,  but I have still problem.

    I download devmem2.c  and compile it. Then I test it in my am437x system.

    Can you make sure your QSPI device is disabled in the device tree (status = "disabled") to ensure there is no conflict.

    Then, you should try the official TI SDK. Maybe there is some different with the Kernel config (or something else) that triggers the issue in your system. If you can re-create it and see it working with the official TI SDK you have a starting point.

    You can also try the same from U-Boot prompt as another data point - check the 'mw' and 'md' commands.

    Regards, Andreas

  • I use ti-processor-sdk-linux-rt-am437x-evm-06.00.00.07 that download from TI web.

    And  I can read/write QSPI with such codes below, it works well. That's means the QSPI device is OK.

    But I want to  know the clock frequence of QSPI working,   so I need to access the registers of QSPI,  but it's sad I encounter such problem.

    It's astonishing.

    //////////////////////////////////////////////////////////////////////// 

    int QSPI_read (char *buf, int offset, int len)
    {
       int ret = len;

       lseek (qspi_fd, offset, SEEK_SET);
       ret = read (qspi_fd, buf, len);

       return ret;
    }

    int QSPI_write (char *buf, int offset, int len,int erase)
    {
       int ret;

       lseek (qspi_fd, offset, SEEK_SET);
       ret = write (qspi_fd, buf, len);

       return ret;
    }

    int QSPI_info (int display)
    {
       int ret = 0;

       struct mtd_info_user mtd;

       qspi_fd = open ("/dev/mtd0", O_SYNC | O_RDWR);  
       if (qspi_fd < 1) {
            printf ("Fail to open mtdblock0! :%d\n",qspi_fd);
            return 1;
       }

       if (ioctl (qspi_fd, MEMGETINFO, &mtd) < 0) {
           printf ("Fail to get mtd info!\n");
           return 2;
       }

       if (display) {
           printf ("---------- mtd0 info ---------\n");
           printf ("type:%d(0x%x)\n", mtd.type, mtd.type);
           printf ("flags:%d(0x%x)\n", mtd.flags, mtd.flags);
           printf ("size:%d(0x%x)\n", mtd.size, mtd.size);
           printf ("erasesize:%d(0x%x)\n", mtd.erasesize, mtd.erasesize);
           printf ("writesize:%d(0x%x)\n", mtd.writesize, mtd.writesize);
           printf ("oobsize:%d(0x%x)\n", mtd.oobsize, mtd.oobsize);
           printf ("\n");

          //QSPI_CLK();   // panic, and can't access QSPI register
    }

    //close(qspi_fd);

       return ret;
    }

  • Are you saying you can access the QSPI registers without issues? But in your custom code that once you do open("/dev/mtd0"...) you can no longer access the registers? Which specific register are you trying to access?

    Regards, Andreas

  • The function QSPI_read , QSPI_write, QSPI_info  works as user application,   and they call  apis  of QSPI driver in kernel.  And they works well.

    So the QSPI device is OK.  But I want to access QSPI registers by myself with such code, and will fail :

    int i,fd;
    unsigned int val;
    void *g_addr=NULL,*prcm_addr=NULL;

    fd=open("/dev/mem",O_RDWR|O_SYNC);
    if(fd==-1){
        printf("@E:open /dev/mem\n");
        return -1;
    }

    prcm_addr=mmap(NULL,0x2000,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x44df8000); //p142 0x44df8800
    if(prcm_addr==NULL){
        printf("@E:prcm_addr null\n");
        return -1; 
    }

    *(volatile unsigned int *)(prcm_addr+0x800+0x258)=2;  // PRCM_CM_PER_QSPI_CLKCTRL ,  enable qspi module

    val= *(volatile unsigned int *)(prcm_addr+0x800+0x258);  // It's curious that the val is 0x30000002, but not 0x2 . why ???

    g_addr=mmap(NULL,0x1000,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x47900000); //qspi reg
    if(!g_addr){
          printf("@E:g_addr null\n");
          return -1; 
    }

    val=*(volatile unsigned int *)(g_addr);   //panic here !!!!
    printf("qspi id:0x%x\n");

    val=*(volatile unsigned int *)(g_addr+0x40);
    printf("qspi clock ctrl:0x%x\n");

    close(fd);

    And I want to know the work frequency of QSPI working which saved in QSPI_CLOCK_CNTRL_REG. (offset: 0x40) 

  • I think I find the reason why cann't access the QSPI registers.  The clock domain of QSPI is PD_PER_L3S_GCLK, but it's not open.

    The value of  PRCM_CM_PER_L3S_CLKSTCTRL of my am437x system is 0x801, and  the bit 8 (CLKACTIVITY_ L3S_GCLK) is 0.  So fail to access the QSPI registers.

    But it's sad  I donn't know how to  enable PD_PER_L3S_GCLK although I have searched the whole manual book (AM437x Technical Reference Manual 2018) several times.

    Would you help me how to enable PD_PER_L3S_GCLK  please?  Thanks!

     

  • The problem still happens.

  • xujun zhang said:

    The value of  PRCM_CM_PER_L3S_CLKSTCTRL of my am437x system is 0x801, and  the bit 8 (CLKACTIVITY_ L3S_GCLK) is 0.  So fail to access the QSPI registers.

    But it's sad  I donn't know how to  enable PD_PER_L3S_GCLK although I have searched the whole manual book (AM437x Technical Reference Manual 2018) several times.

    Would you help me how to enable PD_PER_L3S_GCLK  please?  Thanks!

    The PD_PER_L3S_GCLK clock should get enabled implicitly when any of its consumers are requesting it (for example, in case of QSPI, when PRCM_CM_PER_QSPI_CLKCTRL is set to enable that module). How are you seeing 0x801 for that register?

    When I read this from my system I get 0x1102. This is on a standard AM437x EVM booted our SDK from SD card.

    root@am437x-evm:~# devmem2 0x44DF8A00   ;# Read PRCM_CM_PER_L3S_CLKSTCTRL
    /dev/mem opened.
    Memory mapped at address 0xb6f9e000.
    Read at address  0x44DF8A00 (0xb6f9ea00): 0x00001102
    root@am437x-evm:~# 

    Here you see bit 8 is turned on, meaning the L3S_GCLK clock is active. Actually sometimes I read 0x1902 from that register, which points to MMC activity which makes sense, and it shows we are looking at the right register.

    Also if you want to study the device clock system some more, there are two tools you can actually use. One is the clock tree tool, to visualize and understand how clocks are dependent on each other and how the hierarchy looks like. Then, there is omapconf, a command line tool already part of our SDKs. You can actually export the clock configuration from a live device (via omapconf export ctt) and then import it into the clock tree tool to visualize it. Have a look at the below links for more info...

    http://www.ti.com/tool/CLOCKTREETOOL

    https://github.com/omapconf/omapconf/wiki

    Regards, Andreas

  • Thanks for your help.

    I know the reason why can't access qspi registers.  If there are no devices in domain of L3S_GCLK used, the clock will shut and go to sleep. 

    So it must set PRCM_CM_PER_L3S_CLKSTCTRL before accessing qspi registers.