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.

Using AM335x gpmc-nand interface (cs1) to connect a FPGA / Linux 3.12

Due to limited pins i want to connect a FPGA (with internal peripherals) to the nand bus (8bit) and select with cs1.

The idea is, to use the raw-flash interface or an simple driver which can read and write some data in a low level manner througt the nand-bus to and from the FPGA (Command, Address, Status, Data)

I have configured in the dts the gpio1_30 for cs1, and a second (dummy) flash device:

 nandflash_pins: pinmux_nandflash {
   pinctrl-single,pins = <

......
     0x7c (PIN_OUTPUT | MUX_MODE0)           /* gpmc_csn0.gpmc_csn0 */
    0x80 (PIN_OUTPUT | MUX_MODE0)           /* gpmc_csn1.gpmc_cs1 */

 ........

&gpmc {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&nandflash_pins>;
        ranges = <0 0 0x08000000 0x1000000   /* CS0: NAND */
                  1 0 0x09000000 0x1000000>;  /* CS1: NAND */
        nandflash: nand@0,0 {
                reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
                nand-bus-width = <8>;
                ti,nand-ecc-opt = "bch8";
                gpmc,device-nand = "true";
                gpmc,device-width = <1>;
............

      };

       nandx: nand@1,0 {
                reg = <1 0 4>; /* CS1, offset 0, IO size 4 */
                nand-bus-width = <8>;
                ti,nand-ecc-opt = "bch8";
                gpmc,device-nand = "true";
                gpmc,device-width = <1>;
.......

     };

If there is no 2. device on the bus, I expect an error (dmesg) that the device will not found, but there an a lot of errors:

"kobject try to init an initialized object, something is seriouly wrong"

and than backtrace data.

Linux works normal.

My questions:

Is it possible to use the nand-flash bus for low level communication to a FPGA (with appropriate logic)?

Which functions should be implemented in the FPGA that the a low level nand-driver accept the FPGA as a NAND-Flash?

What is wrong with the device tree?

Thank you for help

  • Hi,

    One of the things that may be causing problems is the NAND hardware ECC module that's part of the GPMC. See processors.wiki.ti.com/.../Linux_Core_NAND_User's_Guide for details of the Linux SDK NAND driver.
  • Hi Biser,
    thank you for this hint. If I can use very low level driver it looks like the ECC data can be ignored (hopefully).

    The lot of errrors with the backtrace data propably comes from the gpmc-nand driver. In kernel 3.12 it is not possible to use two nand flash devices. See e2e.ti.com/.../343017 but this is for Kernel 3.15.

    Do you know if there is a workaround for Kernel 3.12? gpmc-nand.c is very different in 3.12.
    Best regards
    Siegmar
  • Hi Siegmar,

    Is it possible to use the nand-flash bus for low level communication to a FPGA (with appropriate logic)?

    Yes, if FPGA is configured appropriately this should be possible. Unfortunately I'm not experienced in programming FPGAs, so I cannot help with instructions for this. However, I'm sure you could configure the FPGA as a NAND FLASH CONTROLLER, but you'll have to double check if it can be a NAND FLASH device, I am not certain of this. 

    Your dts settings (at least the part you've shared) seems correct. Maybe try to include the ti,elm-id = <&elm>; part (see am335x-evm.dts for reference).

    The lot of errrors with the backtrace data propably comes from the gpmc-nand driver. In kernel 3.12 it is not possible to use two nand flash devices.

    It should be possible to use two memory devices connected to different chip selects on the GPMC.
    As for the errors can you share the dmesg output, maybe it will provide some hints for debugging your problem?

    Best Regards,
    Yordan

  • Hi Yordan,

    because the error said that there is a try to initialize a already initialzed device and due to the fact that there is patch for 3.15 which will enable the use of more than one nand device I am quiete shure that this will not work on 3.12.
    Because of this and many more problems I am thinking about to use this bus as 8bit non-multiplex bus (like an 8bit sram) with cs1 wo address lines but with one or two gpio lines and a special protocol to transfer data from and to the FPGA.

    I have changed the devicetree pinmux:
    nandflash_pins: pinmux_nandflash {
    pinctrl-single,pins = <
    0x1c ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (T9) gpmc_ad7.gpmc_ad7 */
    0x18 ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (R9) gpmc_ad6.gpmc_ad6 */
    0x14 ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (V8) gpmc_ad5.gpmc_ad5 */
    0x10 ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (U8) gpmc_ad4.gpmc_ad4 */
    0xc ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (T8) gpmc_ad3.gpmc_ad3 */
    0x8 ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (R8) gpmc_ad2.gpmc_ad2 */
    0x4 ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (V7) gpmc_ad1.gpmc_ad1 */
    0x0 ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (U7) gpmc_ad0.gpmc_ad0 */
    0x70 ( PIN_INPUT_PULLUP | MUX_MODE0 ) /* (T17) gpmc_wait0.gpmc_wait0 */
    0x7c ( PIN_OUTPUT_PULLUP | MUX_MODE0 ) /* (V6) gpmc_csn0.gpmc_csn0 */
    0x80 ( PIN_OUTPUT_PULLUP | MUX_MODE0 ) /* (U9) gpmc_csn1.gpmc_csn1 */
    0x90 ( PIN_OUTPUT_PULLUP | MUX_MODE0 ) /* (R7) gpmc_advn_ale.gpmc_advn_ale */
    0x94 ( PIN_OUTPUT_PULLUP | MUX_MODE0 ) /* (T7) gpmc_oen_ren.gpmc_oen_ren */
    0x98 ( PIN_OUTPUT_PULLUP | MUX_MODE0 ) /* (U6) gpmc_wen.gpmc_wen */
    0x9c ( PIN_OUTPUT_PULLUP | MUX_MODE0 ) /* (T6) gpmc_be0n_cle.gpmc_be0n_cle */
    >;
    and adjusted the device definition for nand and sram:
    &gpmc {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&nandflash_pins>;
    ranges = <0 0 0x08000000 0x1000000 /* CS0: NAND */
    1 0 0x09000000 0x0001000>; /* CS1: NOR */
    nandflash: nand@0,0 {
    reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
    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>;
    .......
    elm_id = <&elm>;
    #address-cells = <1>;
    #size-cells = <1>;
    /* Partitions will be overwritten by bootloader! */
    partition@0 {
    label = "xload";
    ..........
    };
    nor: sram {
    reg = <1 0 0x1000>; /* CS1, offset 0, size=*/
    gpmc,device-width = <1>;
    gpmc,sync-clk-ps = <0>;
    gpmc,cs-on-ns = <50>;
    gpmc,cs-rd-off-ns = <30>;
    gpmc,cs-wr-off-ns = <30>;
    gpmc,adv-on-ns = <0>;
    gpmc,adv-rd-off-ns = <30>;
    gpmc,adv-wr-off-ns = <30>;
    gpmc,we-on-ns = <20>;
    gpmc,we-off-ns = <20>;
    gpmc,oe-on-ns = <20>;
    gpmc,oe-off-ns = <30>;
    gpmc,access-ns = <60>;
    gpmc,rd-cycle-ns = <100>;
    gpmc,wr-cycle-ns = <100>;
    gpmc,wait-on-read = "true";
    gpmc,wait-on-write = "true";
    gpmc,bus-turnaround-ns = <0>;
    gpmc,cycle2cycle-delay-ns = <50>;
    gpmc,cycle2cycle-diffcsen;
    gpmc,clk-activation-ns = <0>;
    gpmc,wait-monitoring-ns = <0>;
    gpmc,wr-access-ns = <30>;
    #address-cells = <2>;
    #size-cells = <1>;
    };


    I have tested the read/write access to the sram addr:

    const __CHAR32_TYPE__ memaddr = 0x09000000;
    const __CHAR32_TYPE__ memsize = 0x00001000;
    __CHAR32_TYPE__ alloc_memsize, page_size, page_mask;
    void *mem_ptr;
    unsigned char *phyaddr;

    main() {
    ....
    if ((fd = open("/dev/mem", O_RDWR, O_SYNC) ) < 0) {
    printf("can't open /dev/mem \n");
    exit (-1);
    }
    page_size = sysconf(_SC_PAGESIZE);
    alloc_memsize = (memsize/page_size + 1)*page_size;
    page_mask = page_size-1;
    mem_ptr = (unsigned char *) mmap(NULL, alloc_memsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, memaddr & ~page_mask);
    if ((long)mem_ptr == -1) {
    printf("mmap error1 \n");
    exit (-1);
    }
    phyaddr = (unsigned char*)mem_ptr;
    *phyaddr = 0x55; <<<--- bus error and abort


    The prg will abort with an bus error (line is marked).

    There is something wrong with the devicetree (or the testprg), because the nand is working as before, but the sram addr are not available for accessing it.

    Can you please have a look and tell me what is going wrong?
    Thank you in advance
    Siegmar
  • Hi Yordan,

    additional to my last reply:
    "dmesg" does not show any meg for "sram" (if I use "nor" insread of "sram" than there a an error msg saying probing child, nor failed)
    cat /proc/iomem have no entry for "sram"
    omap2.nand0 has an entry 0x01000000 - 0x01000003 <<<---- why not 0x08000000 as range in dts?

    Best regards
    Siegmar
  • Hi Yordan,
    I have erroneous marked the last two replies as "suggest as answer".
    There are similar other threads in this forum, but none of them is "solved".
    Best regards
  • Hi Yordan,

    I am now quiete shure that this is a software problem of mapping the gpmc cs area to userland memory ptr.
    There is no error msg in the dmesg, but also no entry in /proc/iomem.

    Therefore I have put some printk(KERN_INFO,...) in the gpmc.c / gpmc_probe_generic_child() and I can see that the gpmc_cs1 is mapped to 0x2000000, with the length specified in the reg() line inside the dts.

    In userland I have tried to map as you can see in post Aug 25,2016 10:50 AM (but with memaddr=0x2000000, but this will end with "bus_error".
    Than I habe try out the following:
    .......
    page_size = sysconf(_SC_PAGESIZE);
    if ((fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
    printf("can't open /dev/mem \n");
    exit (-1);
    }
    // get pointer to gpmc cs1 area
    if ((mem_ptr = malloc(memsize + (page_size-1))) == NULL) {
    printf("allocation error \n");
    exit (-1);
    }

    if ((unsigned long)mem_ptr % page_size)
    mem_ptr += page_size - ((unsigned long)mem_ptr % page_size);
    mem_ptr = (unsigned char *) mmap((caddr_t)mem_ptr, memsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

    if ((long)mem_ptr == -1) {
    printf("mmap error1 \n");
    exit (-1);
    }
    else {
    phyaddr = (unsigned char*) mem_ptr;
    printf("mmap gpmc_cs1: %lx\n", (unsigned long) phyaddr);
    }
    ret = 0;
    *phyaddr = 0x55;
    ----
    ended also with bus error wen writing to the mapped addr.

    Can you please have a look and tell me what is wrong?
    Thank you
    Siegmar
  • Hi Siegmar,

    You've defined CS0 & CS1, as:

    ranges = <0 0 0x08000000 0x1000000 /* CS0: NAND */

                        1 0 0x09000000 0x0001000>; /* CS1: NOR */

    Then you define the nand @CS0:

      nandflash: nand@0,0 {

    And after that you do not associate the NOR-like device with any CS:

       nor: sram {

    Can you try the following definitions:

       nand@0,0 {

              reg = <0 0 4>;

              <nand configs go here>

        };

        nor@1,0 {  

               reg = <1 0 0x1000>;

               <rest of the nor settings go here>

       };

    This should get your gpmc to /proc/iomem

    Also when you access any of the CS address spaces from user space, you need to mmap() its base address & the mem size you want to access first. Lets say you  need to access the NAND@CS0 (starting from 0x0), I've done the following to access gpmc cs0 (this is an example, you should adapt to match your use case):

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

       volatile uint8_t *extmem;

       extmem = (uint8_t *) mmap(NULL,0x10000000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x10000000);

    Then you can access the address space of CS0. 

    Best Regards, 
    Yordan

  • Hi Yordan,

    sorry I have forgotten to tell you that I had changed from "sram" to "nor@1,0" because I have seen, that only "nor" and "ethernet" will be accepted as generic devices on the gpmc bus inside gpmc.c (Kernel 3.12).
    I have also disabled the wait signals for read and write.
    With the mapping you suggested it works and I can see the access (cs1, ale, db0..7,wren).

    I can now use the available gpmc pins from the nand-bus as 8bit async bus to connect the FPGA. Thank you.

    Only two remarks:
    1) the addresses in the range (dts) are actual not the address in the system (3.12), it seems that thy will be remaped to continously addr started at 0x01000000, so the nor device in my case is at 0x02000000 and not at 0x09000000.
    2) even if the access will work as expected, the nor ist NOT seen in /proc/iomem! Ihave found the addr with add. printk in the gpmc.c code.

    Best regards
    Siegmar