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.

AM335x GPMC read/write data to nand from application

I want to write/read data to nand through gpmc from my application in ccs studio (or in QT Creator). What should I do for it? Thank you for your answers.

  • Hi,

    Are you using Linux? What version?
  • Yes, I'm using Linux kernel 3.12 from TI SDK.
  • Hi,

    First of all you need to configure your kernel accordingly. Add the gpmc device tree node in your dts file (see am335x-evm.dts for example), so that the kernel can initializa the GPMC controller & set its pins accordingly.

    After that you need to configure your GPMC_CONFIGx registers from user space.
    Have in mind that from user space you need to remap the physical addresses of the registers to the appropriate linux virtual memory map.
    You also have to mmap() (man7.org/.../mmap.2.html) the GPMC CS address space, in order to read/write from the nand memory, i.e.:
    volatile uint16_t *extmem;
    /*mmaping the memory space*/
    extmem = (uint16_t *) mmap(NULL,0x08000000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x08000000);
    volatile uint32_t * p32 = (uint32_t *) &extmem[0x100020];
    /*actual write to the memory location*/
    *p32 = 0xdeadbeef;

    Best Regards,
    Yordan
  • Yordan, thank you for your answer. I had done all that you recommended, but now I receive a message

    "Unhandled fault: external abort on non-linefetch (0x1818) at 0xaf151040"

    in the terminal and

    "Bus error "

    in QT Creator. Here is my code:

    int fp=open("/dev/mem",O_RDWR|O_SYNC);

    if (fp<0)

    {

        cout <<"Cannot open /dev/mem!"<<endl;

        return EXIT_FAILURE;

    }

    volatile uint16_t *gpmc1;

    gpmc1=(uint16_t*)mmap(NULL,0x08000000,PROT_READ|PROT_WRITE,MAP_SHARED,fp,0x08000000);

    volatile uint32_t * p32 = (uint32_t *) &gpmc1[0x100020];

    *p32 = 0x1;

    What do you think about it? My gpmc configuration is the following:

    gpmc: gpmc@50000000{
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&nandflash_pins_s0>;
    ranges = <0 0 0x08000000 0x10000000>; /* CS0: NAND */
    nand@0,0 {
    reg = <0 0 0>; /* CS0, offset 0 */
    nand-bus-width = <8>;
    ti,nand-ecc-opt = "bch8";
    gpmc,device-nand = "true";
    gpmc,device-width = <1>;
    gpmc,sync-clk-ps = <0>;
    gpmc,cs-on-ns = <0>;
    gpmc,cs-rd-off-ns = <44>;
    gpmc,cs-wr-off-ns = <44>;
    gpmc,adv-on-ns = <6>;
    gpmc,adv-rd-off-ns = <34>;
    gpmc,adv-wr-off-ns = <44>;
    gpmc,we-on-ns = <0>;
    gpmc,we-off-ns = <40>;
    gpmc,oe-on-ns = <0>;
    gpmc,oe-off-ns = <54>;
    gpmc,access-ns = <64>;
    gpmc,rd-cycle-ns = <82>;
    gpmc,wr-cycle-ns = <82>;
    gpmc,wait-on-read = "true";
    gpmc,wait-on-write = "true";
    gpmc,bus-turnaround-ns = <0>;
    gpmc,cycle2cycle-delay-ns = <0>;
    gpmc,clk-activation-ns = <0>;
    gpmc,wait-monitoring-ns = <0>;
    gpmc,wr-access-ns = <40>;
    gpmc,wr-data-mux-bus-ns = <0>;

    #address-cells = <1>;
    #size-cells = <1>;
    elm_id = <&elm>;
    partition@0 {
    label = "NAND.SPL";
    reg = <0x00000000 0x000020000>;
    };
    partition@1 {
    label = "NAND.SPL.backup1";
    reg = <0x00020000 0x00020000>;
    };
    partition@2 {
    label = "NAND.SPL.backup2";
    reg = <0x00040000 0x00020000>;
    };
    partition@3 {
    label = "NAND.SPL.backup3";
    reg = <0x00060000 0x00020000>;
    };
    partition@4 {
    label = "NAND.u-boot-spl-os";
    reg = <0x00080000 0x00040000>;
    };
    partition@5 {
    label = "NAND.u-boot";
    reg = <0x000C0000 0x00100000>;
    };
    partition@6 {
    label = "NAND.u-boot-env";
    reg = <0x001C0000 0x00020000>;
    };
    partition@7 {
    label = "NAND.u-boot-env.backup1";
    reg = <0x001E0000 0x00020000>;
    };
    partition@8 {
    label = "NAND.kernel";
    reg = <0x00200000 0x00800000>;
    };
    partition@9 {
    label = "NAND.file-system";
    reg = <0x00A00000 0x0F600000>;
    };
    };
    };

  • Hi,

    The unhandled fault message means that you're trying to write to a memory that was not mapped or you haven't enabled GPMC clocks from PRCM.  

    Probably the gpmc cs address space is differs from the mmapped address space.  

    To test if your GPMC clocks are enabled you can run devmem2 command on some of the gpmc registers from your console (NOT from your QT application). If you get buss error, then you need to do the GPMC initialization in the QT application.

    I am attaching an example use space driver, that I've used some time ago. Have in mind that this setting configures GPMC_CONFIGx registers for NOR like device, you need to modify the settings to match your use case (nand device attached to GPMC):

    /*
    Test file for talking to external memory using GPMC pins in GPMC mode.
    */
    
    #include <stdio.h>
    #include <time.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include "hw_gpmc.h" // SYS-BIOS
    #include "hw_cm_per.h" // SYS-BIOS
    #include "soc_AM335x.h" // SYS-BIOS
    
    #define MMAP_OFFSET 0x44c00000
    
    // redefine HWREG macro to use MMAP result
    #define HWREG(x) __mmapl[(x-MMAP_OFFSET)/4]
    #define GPMCREG(x) __mmapl[(x-MMAP_OFFSET + SOC_GPMC_0_REGS )/4]
    
    #define CSC_FPGA
    
    volatile uint32_t *__mmapl;
    
    void gpmc_init_cs(int csNum, int burst_en, int base)
    {
        uint16_t clk_divider = 4; 
        uint16_t extra_delay = 0;
    
        //cycle 0 is for synchronous reset
        uint16_t cs_on        = 0;
        uint16_t aad_oe_on    = cs_on;
        uint16_t aad_oe_off   = aad_oe_on + 1;
        
        //adv is just one low pulse
        uint16_t aad_adv_on   = 0;
        uint16_t aad_adv_off  = aad_oe_off;
        uint16_t adv_on       = aad_adv_off;
        uint16_t adv_off      = adv_on + 1; 
     
        //write begin
        uint16_t we_assert    = adv_off;
        uint16_t data_bus    = we_assert; 
        uint16_t access_time  = 1; //cycles to access each data
        uint16_t write_access = data_bus +  access_time + 1;  //when slave reads the data
        //write end
        uint16_t write_csoff  = write_access + 1; //Rule 7
        uint16_t we_deassert  = write_csoff; 
        uint16_t write_cycles = write_csoff; 
    
        //read begin
        uint16_t oe_assert    = adv_off;
        uint16_t read_access  = oe_assert + 2;  //When Sitara reads the data
    
        //read end
        uint16_t read_csoff   = read_access + 1; //Rule 7
        uint16_t oe_deassert  = read_csoff;
        uint16_t read_cycles  = read_csoff + 1; //allow OE on RFIC to switch back to address mode 
    
        uint16_t wait_monitor_delay = 0; // 1 extra clock wait before read
    
        uint16_t transaction_delay = 0;
    
       uint16_t granularity = 1; 
    #if 0
        if (clk_divider == 4) {
          //granularity doubles RD/WRCYCLETIME, RD/WRACCESSTIME, PAGEBURSTACCESSTIME, CSONTIME, CSRD/WROFFTIME,
          //ADVONTIME, ADVRD/WROFFTIME, OEONTIME, OEOFFTIME, WEONTIME, WEOFFTIME,
          //CYCLE2CYCLEDELAY, BUSTURNAROUND, TIMEOUTSTARTVALUE
          granularity = 2;
        }
    #endif
    
        //configure for NOR 
        // CONFIG 1 .. 16 bits multiplexed
        HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG1(csNum)) = (0x0 |
            ((clk_divider -1) <<  GPMC_CONFIG1_0_GPMCFCLKDIVIDER_SHIFT) |
            ((granularity -1) <<  GPMC_CONFIG1_0_TIMEPARAGRANULARITY_SHIFT) |
            (0x1 << GPMC_CONFIG1_0_MUXADDDATA_SHIFT ) |
            (GPMC_CONFIG1_0_DEVICESIZE_SIXTEENBITS <<  GPMC_CONFIG1_0_DEVICESIZE_SHIFT ) |
            (0 << GPMC_CONFIG1_0_CLKACTIVATIONTIME_SHIFT) |
            (wait_monitor_delay << GPMC_CONFIG1_0_WAITMONITORINGTIME_SHIFT) |
            (0x1 << GPMC_CONFIG1_0_WAITWRITEMONITORING_SHIFT) |
            (0x1 << GPMC_CONFIG1_0_WAITREADMONITORING_SHIFT) |
            (0x0 << GPMC_CONFIG1_0_DEVICETYPE_SHIFT) |
            (2 << GPMC_CONFIG1_0_ATTACHEDDEVICEPAGELENGTH_SHIFT ) |
            (1 << GPMC_CONFIG1_0_WRITETYPE_SHIFT) |
            (1 << GPMC_CONFIG1_0_READTYPE_SHIFT) |
            (burst_en << GPMC_CONFIG1_0_READMULTIPLE_SHIFT) |
            (burst_en << GPMC_CONFIG1_0_WRITEMULTIPLE_SHIFT) |
            0);	
    
    
    
       
        uint16_t  mult = (clk_divider / (granularity));
    
        // config 2 .. chip select assert/deassert times
        HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG2(csNum)) = (0x0 |
            ((cs_on * mult) << GPMC_CONFIG2_0_CSONTIME_SHIFT) |	// CS_ON_TIME 
            (extra_delay << GPMC_CONFIG2_0_CSEXTRADELAY_SHIFT) |
            ((read_csoff * mult) << GPMC_CONFIG2_0_CSRDOFFTIME_SHIFT) |	// CS_DEASSERT_RD
            ((write_csoff * mult) << GPMC_CONFIG2_0_CSWROFFTIME_SHIFT));	//CS_DEASSERT_WR
    
        // config 3 .. latch enable assert and de-assert
        HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG3(csNum)) = (0x0 |
            ((adv_on * mult) << GPMC_CONFIG3_0_ADVONTIME_SHIFT) | //ADV_ASSERT
            (extra_delay << GPMC_CONFIG3_0_ADVEXTRADELAY_SHIFT) |
            ((adv_off * mult) << GPMC_CONFIG3_0_ADVRDOFFTIME_SHIFT) | //ADV_DEASSERT_RD
            ((adv_off * mult) << GPMC_CONFIG3_0_ADVWROFFTIME_SHIFT) | //ADV_DEASSERT_WR
            ((aad_adv_on * mult) << GPMC_CONFIG3_0_ADVAADMUXONTIME_SHIFT) |
            ((aad_adv_off * mult) << GPMC_CONFIG3_0_ADVAADMUXRDOFFTIME_SHIFT) |
            ((aad_adv_off * mult) << GPMC_CONFIG3_0_ADVAADMUXWROFFTIME_SHIFT) |
    	0); 
    
        // config 4 .. output enable / read write enable assert and de-assert
        HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG4(csNum)) = (0x0 |
            (extra_delay << GPMC_CONFIG4_0_OEEXTRADELAY_SHIFT) |
            (extra_delay << GPMC_CONFIG4_0_WEEXTRADELAY_SHIFT) |
            ((oe_assert * mult) << GPMC_CONFIG4_0_OEONTIME_SHIFT) |	//OE_ASSERT
            ((oe_deassert * mult) << GPMC_CONFIG4_0_OEOFFTIME_SHIFT) |	//OE_DEASSERT
            ((we_assert * mult) << GPMC_CONFIG4_0_WEONTIME_SHIFT)| //WE_ASSERT
            ((we_deassert * mult) << GPMC_CONFIG4_0_WEOFFTIME_SHIFT) | //WE_DEASSERT
    	((aad_oe_off * mult) << GPMC_CONFIG4_0_OEAADMUXOFFTIME_SHIFT) |
    	((aad_oe_on * mult) << GPMC_CONFIG4_0_OEAADMUXONTIME_SHIFT)
    	); 
        // Config 5 - read and write cycle time
        HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG5(csNum)) = (0x0 |
            ((read_cycles * mult) << GPMC_CONFIG5_0_RDCYCLETIME_SHIFT)|	//CFG_5_RD_CYCLE_TIM XXX
            ((write_cycles * mult) << GPMC_CONFIG5_0_WRCYCLETIME_SHIFT)|	//CFG_5_WR_CYCLE_TIM 
            ((read_access * mult) << GPMC_CONFIG5_0_RDACCESSTIME_SHIFT)|          // CFG_5_RD_ACCESS_TIM XXX
            ((access_time * mult)  << GPMC_CONFIG5_0_PAGEBURSTACCESSTIME_SHIFT));  
    
        //force write data on rising edge 
        int fix = 1;
        if (clk_divider == 1) {
          fix = 0;
        }
    
    
        // Config 6 .. bus turnaround delay, etc
        HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG6(csNum)) = (0x0 |
            (((transaction_delay) ? 1 : 0) << GPMC_CONFIG6_0_CYCLE2CYCLESAMECSEN_SHIFT) |
            ((transaction_delay * mult) << GPMC_CONFIG6_0_CYCLE2CYCLEDELAY_SHIFT) |
            ((data_bus * mult) << GPMC_CONFIG6_0_WRDATAONADMUXBUS_SHIFT)| //WR_DATA_ON_ADMUX 
            ((write_access * mult - fix ) << GPMC_CONFIG6_0_WRACCESSTIME_SHIFT));  //CFG_6_WR_ACCESS_TIM
    
        // config 7 .. base address of the chip select and address space.
        HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG7(csNum)) =
            ( base << 4 << GPMC_CONFIG7_0_BASEADDRESS_SHIFT) | //base address mask
            (0x1 << GPMC_CONFIG7_0_CSVALID_SHIFT) | //enable
            (0x0 << GPMC_CONFIG7_0_MASKADDRESS_SHIFT);  //256Mb
    
    
    }
    
    void gpmc_init()
    {
    
    
        //enable clock to GPMC module
        HWREG(SOC_PRCM_REGS + CM_PER_GPMC_CLKCTRL ) |=
                    CM_PER_GPMC_CLKCTRL_MODULEMODE_ENABLE;
        //check to see if enabled
        while((HWREG(SOC_PRCM_REGS + CM_PER_GPMC_CLKCTRL) & CM_PER_GPMC_CLKCTRL_IDLEST) !=
                    (CM_PER_GPMC_CLKCTRL_IDLEST_FUNC << CM_PER_GPMC_CLKCTRL_IDLEST_SHIFT));
    
    
        //reset the GPMC module
        HWREG(SOC_GPMC_0_REGS + GPMC_SYSCONFIG ) |= GPMC_SYSCONFIG_SOFTRESET;
        while((HWREG(SOC_GPMC_0_REGS + GPMC_SYSSTATUS) & GPMC_SYSSTATUS_RESETDONE) ==
                    GPMC_SYSSTATUS_RESETDONE_RSTONGOING);
    
    
        //disable all CSn
        for (int i = 0; i < 8; i++) {
          HWREG(SOC_GPMC_0_REGS + GPMC_CONFIG7(i)) = 0;
        }
    
        HWREG(SOC_GPMC_0_REGS + GPMC_SYSCONFIG) = 0x11;
        HWREG(SOC_GPMC_0_REGS + GPMC_IRQENABLE) = 0x0;
        HWREG(SOC_GPMC_0_REGS + GPMC_TIMEOUT_CONTROL) = GPMC_TIMEOUT_CONTROL_TIMEOUTSTARTVALUE;
    #ifndef CSC_FPGA
        HWREG(SOC_GPMC_0_REGS + GPMC_TIMEOUT_CONTROL) = GPMC_TIMEOUT_CONTROL_TIMEOUTSTARTVALUE | 1; //enable timeout
    #endif
    
        gpmc_init_cs(1, 0, 1); //single @ 0x10000000 (256Mb)
        gpmc_init_cs(2, 1, 0); //burst @ 0x0 
        //The first 1MB of address space 0x0-0xFFFFF is inaccessible externally.
    }
    
    uint16_t mymem[0x10000];
    
    void gpmc_dump(int cs)
    {
    
      printf("GPMC_SYSCONFIG=0x%08x\n",GPMCREG(GPMC_SYSCONFIG));
      printf("GPMC_TIMEOUT_CONTROL=0x%08x\n",GPMCREG(GPMC_TIMEOUT_CONTROL));
      printf("GPMC_IRQENABLE=0x%08x\n",GPMCREG(GPMC_IRQENABLE));
      printf("GPMC_CONFIG=0x%08x\n",GPMCREG(GPMC_CONFIG));
    
      printf("CSn=%d....\n", cs);
      printf("GPMC_CONFIG1_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG1(cs)));
      printf("GPMC_CONFIG2_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG2(cs)));
      printf("GPMC_CONFIG3_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG3(cs)));
      printf("GPMC_CONFIG4_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG4(cs)));
      printf("GPMC_CONFIG5_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG5(cs)));
      printf("GPMC_CONFIG6_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG6(cs)));
      printf("GPMC_CONFIG7_CSn=0x%08x\n", GPMCREG(GPMC_CONFIG7(cs)));
    }
    
    int main(int argc, char** argv)
    {
        int fd = open("/dev/mem", O_RDWR|O_SYNC); //O_SYNC makes the memory uncacheable
    #if 1
        __mmapl = (uint32_t*) mmap(NULL, 0x20000000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, MMAP_OFFSET);
    
        //gpmc_dump(6);
        gpmc_init();
        gpmc_dump(2);
    #endif
    
    
    #if 1
        volatile uint8_t *extmem;
        extmem = (uint8_t *) mmap(NULL,0x10000000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x10000000);
        volatile uint32_t * p32 = (uint32_t *) &extmem[0x100020];
        *p32 = 0xdeadbeef;
        uint32_t val = *p32;
        *p32 = 0xcafebabe;
        uint32_t val2 = *p32;
    		printf("val=%#x\n", val);
    		printf("val=%#x\n", val2);
     
        //printf("size=%d\n", sizeof(buffer));
        //memcpy(extmem, buffer, sizeof(buffer)-1);
    
    #endif
        return(0) ;
    }
    

    Also revise your pinmux settings.

    Hope this helps.

    Best Regards, 

    Yordan

  • Yordan, could you attach .dts file or gpmc configuration for nor like device? I want to test gpmc with the nor device at first and then go to the nand. Thank you very much for you help.
  • Hi Alex,

    You can see an example of nor configuration in: Documentation/devicetree/bindings/mtd/gpmc-nor.txt

    But have in mind that the user app will overwrite the timings specified in the dts.

    Another example is: 

    	gpmc_pins: pinmux_gpmc_pins {
    		pinctrl-single,pins = <
    			0x000 0x30	/* gpmc_ad0.gpmc_ad0 MODE0 | INPUT | PULLUP */
    			0x004 0x30	/* gpmc_ad1.gpmc_ad1 MODE0 | INPUT | PULLUP */
    			0x008 0x30	/* gpmc_ad2.gpmc_ad2 MODE0 | INPUT | PULLUP */
    			0x00C 0x30	/* gpmc_ad3.gpmc_ad3 MODE0 | INPUT | PULLUP */
    			0x010 0x30	/* gpmc_ad4.gpmc_ad4 MODE0 | INPUT | PULLUP */
    			0x014 0x30	/* gpmc_ad5.gpmc_ad5 MODE0 | INPUT | PULLUP */
    			0x018 0x30	/* gpmc_ad6.gpmc_ad6 MODE0 | INPUT | PULLUP */
    			0x01C 0x30	/* gpmc_ad7.gpmc_ad7 MODE0 | INPUT | PULLUP */
    			0x020 0x30	/* gpmc_ad8.gpmc_ad8 MODE0 | INPUT | PULLUP */
    			0x024 0x30	/* gpmc_ad9.gpmc_ad9 MODE0 | INPUT | PULLUP */
    			0x028 0x30	/* gpmc_ad10.gpmc_ad10 MODE0 | INPUT | PULLUP */
    			0x02C 0x30	/* gpmc_ad11.gpmc_ad11 MODE0 | INPUT | PULLUP */
    			0x030 0x30	/* gpmc_ad12.gpmc_ad12 MODE0 | INPUT | PULLUP */
    			0x034 0x30	/* gpmc_ad13.gpmc_ad13 MODE0 | INPUT | PULLUP */
    			0x038 0x30	/* gpmc_ad14.gpmc_ad14 MODE0 | INPUT | PULLUP */
    			0x03C 0x30	/* gpmc_ad15.gpmc_ad15 MODE0 | INPUT | PULLUP */
    			0x080 0x08	/* gpmc_cscn1.gpmc_cscn1 MODE0 | OUTPUT */
    			0x084 0x08	/* gpmc_cscn2.gpmc_cscn2 MODE0 | OUTPUT */
    			0x08C 0x28	/* gpmc_clk.gpmc_clk MODE0 | OUTPUT */
    			0x090 0x08	/* gpmc_advn_ale.gpmc_advn_ale MODE0 | OUTPUT */
    			0x094 0x08	/* gpmc_oen_ren.gpmc_oen_ren MODE0 | OUTPUT */
    			0x098 0x08	/* gpmc_wen.gpmc_wen MODE0 | OUTPUT */
    
    			0x070 0x30	/* gpmc_wait0.gpmc_wait0 MODE0 | INPUT | PULLUP */
    
    		>;
    	};
    
    
    &gpmc {
    			status = "okay";
    			pinctrl-names = "default";
    			pinctrl-0 = <&gpmc_pins>;
    
    			#address-cells = <2>;
    			#size-cells = <1>;
    
    			/* chip select ranges */
    			ranges = <1 0 0x01000000 0x1000000>;
    
    			ethernet{
    						reg = <1 0 0x01000000>;	/*CSn1*/
    				
    				bank-width = <2>;		/* GPMC_CONFIG1_DEVICESIZE(1) */
    
    				/*gpmc,burst-write;*/
    				/*gpmc,burst-read;*/
    				/*gpmc,burst-wrap;*/
    				gpmc,sync-read;		/* GPMC_CONFIG1_READTYPE_ASYNC */
    				gpmc,sync-write;		/* GPMC_CONFIG1_WRITETYPE_ASYNC */
    				gpmc,clk-activation-ns = <0>;	/* GPMC_CONFIG1_CLKACTIVATIONTIME(2) */
    				gpmc,burst-length = <16>;	/* GPMC_CONFIG1_PAGE_LEN(2) */
    				gpmc,mux-add-data = <2>;	/* GPMC_CONFIG1_MUXTYPE(2) */
    
    				gpmc,sync-clk-ps = <20000>;	/* CONFIG2 */
    
    				gpmc,cs-on-ns = <0>;
    				gpmc,cs-rd-off-ns = <100>;
    				gpmc,cs-wr-off-ns = <40>;
    
    				gpmc,adv-on-ns = <0>;		/* CONFIG3 */
    				gpmc,adv-rd-off-ns = <20>;
    				gpmc,adv-wr-off-ns = <20>;
    
    				gpmc,we-on-ns = <20>;		/* CONFIG4 */
    				gpmc,we-off-ns = <40>;
    				gpmc,oe-on-ns = <20>;
    				gpmc,oe-off-ns = <100>;
    
    				gpmc,page-burst-access-ns = <20>;	/* CONFIG 5 */
    				gpmc,access-ns = <80>;
    				gpmc,rd-cycle-ns = <120>;
    				gpmc,wr-cycle-ns = <60>;
    				gpmc,wr-access-ns = <40>;		/* CONFIG 6 */
    				gpmc,wr-data-mux-bus-ns = <20>;
    
    				/*gpmc,bus-turnaround-ns = <40>;*/		/* CONFIG6:3:0 = 4 */
    				gpmc,cycle2cycle-samecsen;		/* CONFIG6:7 = 1 */
    				gpmc,cycle2cycle-delay-ns = <20>;	/* CONFIG6:11:8 = 4 */
    
    				/* not using dma engine yet, but we can get the channel number here */
    				dmas = <&edma 1>;
    				dma-names = "cscdma";
    
    		};
    };
    
    

    Best Regards,

    Yordan

  • Also, after you do the dts modifications & boot your board, before executing the user space driver, try:
    1. see if gpmc is present in /proc/iomem
    2. use devmem2 on some of the GPMC registers, to make sure that module is properly initialized.

    Best Regards,
    Yordan
  • Hi Yordan,

    I've understood how to work with gpmc using your application, thank you. And now I need to use dma to free the processor. Do you have any example of using dma to read/write data through gpmc?
  • Hi Alex,

    The AM335x GEL files are a good example on this. I don't have user space api for this.

    Best Regards,
    Yordan