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.

AM57xx GPMC access issue

Other Parts Discussed in Thread: SYSCONFIG

Hello,

I have connected FPGA on GPMC interface using multiplexed IO mode. I have modifiled pin mux in u-boot as per attached mux_data.h file. Also I have done modification in gpmc_init function of u-boot as below:

#else
        const u32  gpmc_regs[GPMC_MAX_REG] = {  0x1A00,                         //GPMC Config 1
                                                M_NAND_GPMC_CONFIG2,
                                                M_NAND_GPMC_CONFIG3,
                                                M_NAND_GPMC_CONFIG4,
                                                M_NAND_GPMC_CONFIG5,
                                                M_NAND_GPMC_CONFIG6,
                                                0
                                                };
//        u32 base = CONFIG_SYS_NAND_BASE;
        u32 base = 0x18000000;

        u32 size = GPMC_SIZE_16M;
#if 0
        const u32 gpmc_regs[GPMC_MAX_REG] = { 0, 0, 0, 0, 0, 0, 0 };
        u32 size = 0;
        u32 base = 0;
#endif
#endif

Below is the device tree modification

&gpmc{

status = "okay";

};

After this much of modification I am trying to access FPGA registers, but I am not able to read any register. When I have probed GPMC signals I have found that there is no any transactions on signals. Even I can not see the clock also.

Here I have attached my fpga driver. Please note that I am using CS3 to access FPGA.


Could anyone please suggest me if I am missing anything?8171.mux_data.h

/*
 * copyright (c)2016 eInfochips - All rights reserved.
 *
 * This software is authored by eInfochips and is eInfochips'
 * intelletual property,including the copyrights in all countries in the world.
 * This software is provided under a license to use only with all other rights,
 * including ownership rights, being retained by eInfochips.
 *
 * This file may not be distributed, copied or reproduced in any manner,
 * electronic or otherwise, without the written consent of eInfochips.
 */

#include <linux/module.h>
#include <linux/slab.h> /* for kmalloc() and kfree() */
#include <linux/major.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/gpio.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>      /* For put_user and get_user */
#include <linux/moduleparam.h>	/* for module parameter */
#include <linux/omap-gpmc.h>
#include <misc/zeiss_fpga.h>
#if 0
#define ZEISS_FPGA_MAJOR	(233)
#define ZEISS_FPGA_MINOR	(0)

//#define FPGA_INITIAL_REG_SKIP	(256)
#define FPGA_INITIAL_REG_SKIP	(0)
#define REG_BIT(x)		(0x1 << x)

#define FPGA_IOC_MAGIC 		('r')		/*  define all ioctls */
#define FPGA_IOC_MAXNR 		(28)

#define FPGA_RW_CTRL 		_IOWR(FPGA_IOC_MAGIC, 1, fpga_ctrl_t)

typedef enum _fpga_reg_t {
	VIC_FPGA_INFO = 0,
	FPGA_CONFIG_REG_COUNT=0x016F,
} fpga_reg_t;

typedef struct _fpga_ctrl_t {
	char rw; /* 0 = write else read */
	unsigned char reg;
	unsigned short val;
} fpga_ctrl_t;
#endif

static unsigned long fpga_base;
static struct class *fw_class;
static int fpga_device_open = 0;
static void __iomem *base_reg;

void __iomem *fpga_reg[FPGA_CONFIG_REG_COUNT];
EXPORT_SYMBOL(fpga_reg);

int zeiss_fpga_fw_open (struct inode *inode,struct file *file)
{
	if (fpga_device_open){
		return -EBUSY;
	}

	fpga_device_open++;
	return 0;
}

int zeiss_fpga_fw_close (struct inode *inode,struct file *file)
{
	fpga_device_open--;
	return 0;
}

static void zeiss_fpga_reg_write(unsigned short val, void __iomem *reg_addr)
{
	__raw_writew(val, reg_addr);
}

static unsigned short zeiss_fpga_reg_read(void __iomem *reg_addr)
{
	return(__raw_readw(reg_addr));
}

long zeiss_fpga_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int err = 0;
	fpga_ctrl_t fpga;

	if (_IOC_TYPE(cmd) != FPGA_IOC_MAGIC){
		printk("error in ioctl magic no, FPGA_IOC_MAGIC should"
			" be \'%c\'\n", _IOC_TYPE(cmd));
		return -EINVAL;
	}
	if (_IOC_NR(cmd) > FPGA_IOC_MAXNR){
		printk("error in FPGA_IOC_MAXNR \n");
		return -ENOTTY;
	}
	if (_IOC_DIR(cmd) & _IOC_READ)
		err = !access_ok(VERIFY_WRITE,  (void __user *)arg,
				_IOC_SIZE(cmd));
	else if (_IOC_DIR(cmd) & _IOC_WRITE)
		err =  !access_ok(VERIFY_READ,  (void __user *)arg,
				_IOC_SIZE(cmd));
	if (err){
		printk("error in _IOC_READ or _IOC_WRITE \n");
		return -EFAULT;
	}

	/* Get data from user space */
	if (copy_from_user(&fpga, (fpga_ctrl_t *) arg,
				sizeof(fpga_ctrl_t))) {
		err = -EFAULT;
		return err;	
	}
	
	if(cmd == FPGA_RW_CTRL) {
		if(true == fpga.rw) {
			fpga.val = zeiss_fpga_reg_read(fpga_reg[fpga.reg]);
		}
		else {
			zeiss_fpga_reg_write(fpga.val, fpga_reg[fpga.reg]);
		}

		/* Set data from user space */
		if(copy_to_user((fpga_ctrl_t *)arg, &fpga,  sizeof(fpga_ctrl_t)))
			err = -EFAULT;
	}
	else 
		err = -EINVAL;
	return err;
}

static const struct file_operations zeiss_fpga_fops = {
	.owner          = THIS_MODULE,
	.unlocked_ioctl	= zeiss_fpga_fw_ioctl,
	.open           = zeiss_fpga_fw_open,
	.release	= zeiss_fpga_fw_close
};

static int zeiss_fpga_gpmc_mem_map(void)
{
	int count;

	/* Map FPGA registers into driver memory to access it later on */
	/* Increment FPGA_CONFIG_REG_COUNT by 1 if you add configuration reg. */
	for(count = 0; count < FPGA_CONFIG_REG_COUNT; count++)
	{
		fpga_reg[count] = ioremap((fpga_base + FPGA_INITIAL_REG_SKIP + count*2), 0x2);
	}
	return 0;
}

static int zeiss_fpga_gpmc_mem_unmap(void)
{
	int count;

	/* Un-mapped FPGA registers */
	for(count = 0; count < FPGA_CONFIG_REG_COUNT; count++)
		iounmap((void *)fpga_reg[count]);

	return 0;
}

static int zeiss_fpga_gpmc_init(void)
{
	int err;

	err = gpmc_cs_request(3, SZ_16M - 1,(unsigned long*)&fpga_base);
	printk("\n$$$$$$$$$ fpga_base = %x $$$$$$$$$$\n", fpga_base);
	return err;
}

static void zeiss_fpga_gpmc_clean(void)
{
	gpmc_cs_free(1);
}

static int __init zeiss_fpga_init(void)
{
	int err = 0;

	printk("\n$$$$$$$$$ zeiss_fpga_init $$$$$$$$$$\n");

	 /* Register the driver */
	if(register_chrdev(ZEISS_FPGA_MAJOR, "zeiss_fpga_fw", &zeiss_fpga_fops)) {
		printk("zeiss_fpga driver: Unable to register driver\n");
		return (-ENODEV);
	}

	/* Create device class */
	fw_class = class_create(THIS_MODULE, "zeiss_fpga_fw");
	if (IS_ERR(fw_class)) {
		err = PTR_ERR(fw_class);
		goto out_chrdev;
	}

	/* Initilize GPMCMap FPGA configuration register memory to GPMC CS1 memory */
	if(zeiss_fpga_gpmc_init() < 0) {
		printk("zeiss_fpga driver: unable to initialize gpmc\n");
		err = -1;
	}

	/* Map FPGA configuration register memory to GPMC CS1 progrramed memory */
        zeiss_fpga_gpmc_mem_map();

	/* Create the device entry of the driver */
	device_create(fw_class, NULL, MKDEV(ZEISS_FPGA_MAJOR, ZEISS_FPGA_MINOR), NULL,
			"zeiss_fpga_fw");

	return err;
out_chrdev:
	/* Unregister the driver */
	unregister_chrdev(ZEISS_FPGA_MAJOR, "zeiss_fpga_fw");
	return err;
}

static void __exit zeiss_fpga_exit(void)
{

	/* Remove the device entry of the driver */                                 	
	device_destroy(fw_class, MKDEV(ZEISS_FPGA_MAJOR, ZEISS_FPGA_MINOR));
	class_destroy(fw_class);

	zeiss_fpga_gpmc_mem_unmap();
	zeiss_fpga_gpmc_clean();

	/* Unregister the driver */
	unregister_chrdev(ZEISS_FPGA_MAJOR, "zeiss_fpga_fw");
        

}

module_init(zeiss_fpga_init);
module_exit(zeiss_fpga_exit);

MODULE_AUTHOR("eInfochips");
MODULE_DESCRIPTION("FPGA register access driver");
MODULE_LICENSE("GPL");

  • I will ask the software team to look at this. First thing I notice is that you are configuring the wrong registers. These listed on your post are used for NAND access only.
  • Hi,

    Which SDK is this? Or which kernel version, if you are using non-ti kernel?
    Have you added gpmc pinmux configurations in dts? Also you need more settings than just changing gpmc status="okay", have a look at Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt

    Best Regards,
    Yordan
  • Hello Yordan,

    I am using SDK v2.0.0.

    Have you added gpmc pinmux configurations in dts?
    I have tried to add pin muxing in dts file, but after adding pin mux, I was not able to boot the kernel, so I have kept it in u-boot only. After kernel boot, if I read registers, then register values are ok.
    Below are the pin mux settings I have tried to implement:
    fpga_pin_ctrl: fpga_pin_ctrl {
    pinctrl-single,pins = <
    0x00 (PIN_INPUT | MUX_MODE0) /*GPMC_AD0, MODE0*/
    0x04 (PIN_INPUT | MUX_MODE0) /*GPMC_AD1, MODE0*/
    0x08 (PIN_INPUT | MUX_MODE0) /*GPMC_AD2, MODE0*/
    0x0C (PIN_INPUT | MUX_MODE0) /*GPMC_AD3, MODE0*/
    0x10 (PIN_INPUT | MUX_MODE0) /*GPMC_AD4, MODE0*/
    0x14 (PIN_INPUT | MUX_MODE0) /*GPMC_AD5, MODE0*/
    0x18 (PIN_INPUT | MUX_MODE0) /*GPMC_AD6, MODE0*/
    0x1C (PIN_INPUT | MUX_MODE0) /*GPMC_AD7, MODE0*/
    0x20 (PIN_INPUT | MUX_MODE0) /*GPMC_AD8, MODE0*/
    0x24 (PIN_INPUT | MUX_MODE0) /*GPMC_AD9, MODE0*/
    0x28 (PIN_INPUT | MUX_MODE0) /*GPMC_AD10, MODE0*/
    0x2C (PIN_INPUT | MUX_MODE0) /*GPMC_AD11, MODE0*/
    0x30 (PIN_INPUT | MUX_MODE0) /*GPMC_AD12, MODE0*/
    0x34 (PIN_INPUT | MUX_MODE0) /*GPMC_AD13, MODE0*/
    0x38 (PIN_INPUT | MUX_MODE0) /*GPMC_AD14, MODE0*/
    0x3c (PIN_INPUT | MUX_MODE0) /* gpmc_ad15 */
    0xd8 (PIN_INPUT_PULLUP | MUX_MODE0)
    0xcc (PIN_OUTPUT | MUX_MODE0)
    0xC0 (PIN_OUTPUT | MUX_MODE0)
    0xc4 (PIN_OUTPUT | MUX_MODE0)
    0xc8 (PIN_OUTPUT | MUX_MODE0)
    0xd0 (PIN_OUTPUT | MUX_MODE0)
    >;
    };

    Also you need more settings than just changing gpmc status="okay", have a look at Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
    I am trying to register char driver on GPMC. Below portion for GPMC is already available in dts file
    gpmc: gpmc@50000000 {
    compatible = "ti,am3352-gpmc";
    ti,hwmods = "gpmc";
    reg = <0x50000000 0x37c>; /* device IO registers */
    interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
    gpmc,num-cs = <8>;
    gpmc,num-waitpins = <2>;
    #address-cells = <2>;
    #size-cells = <1>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;
    #interrupt-cells = <2>;
    status = "disabled";
    };
    So I have just changed it's status.

    Please note that After kernel boot, the value of GPMC_SYSCONFIG reg is 0x11, which means GPMC is still in reset. I believe that once I change the status = "okay" then atlease GPMC should get enable.
  • Hi Rakesh,

    Rakesh Modi said:
    Also you need more settings than just changing gpmc status="okay", have a look at Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt
    I am trying to register char driver on GPMC. Below portion for GPMC is already available in dts file
    gpmc: gpmc@50000000 {
    compatible = "ti,am3352-gpmc";
    ti,hwmods = "gpmc";
    reg = <0x50000000 0x37c>; /* device IO registers */
    interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
    gpmc,num-cs = <8>;
    gpmc,num-waitpins = <2>;
    #address-cells = <2>;
    #size-cells = <1>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;
    #interrupt-cells = <2>;
    status = "disabled";
    };
    So I have just changed it's status.

    This is NOT enough.  When you connect a nor-like, nand-like, or ethernet or etc.. device, you need to add a child nodes in the DTS file. The code referenced from you is located in the DTSI file. 

    So if your fpga is configured as nand-like device you need to add something like: 

     

    &gpmc {
          status = "okay";
          pinctrl-names = "default", "sleep";
          pinctrl-0 = <&nandflash_pins_default>;
          pinctrl-1 = <&nandflash_pins_sleep>;
          ranges = <0 0 0x08000000 0x1000000>; /* CS0: 16MB for NAND */
          nand@0,0 {
                 compatible = "ti,omap2-nand";
                 reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
                 interrupt-parent = <&intc>;
                 interrupts = <100>;
                 ready-gpio = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */
                 ti,nand-ecc-opt = "bch8";
                 ti,elm-id = <&elm>;
                 nand-bus-width = <8>;
                 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,bus-turnaround-ns = <0>;
                 gpmc,cycle2cycle-delay-ns = <0>;
                 gpmc,clk-activation-ns = <0>;
                 gpmc,wr-access-ns = <40>;
                 gpmc,wr-data-mux-bus-ns = <0>;
    /* MTD partition table */
    /* All SPL-* partitions are sized to minimal length
    * which can be independently programmable. For
    * NAND flash this is equal to size of erase-block */
                 #address-cells = <1>;
                 #size-cells = <1>;
                 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>;
            };
       };
    };

    Rakesh Modi said:
    I have tried to add pin muxing in dts file, but after adding pin mux, I was not able to boot the kernel, so I have kept it in u-boot only. After kernel boot, if I read registers, then register values are ok.

     

    This also NOT correct. Without specifying nandflash_pins_default/sleep pinmux nodes & 
          pinctrl-names = "default", "sleep";
          pinctrl-0 = <&nandflash_pins_default>;
          pinctrl-1 = <&nandflash_pins_sleep>;

    in gpmc device tree node, kernel DOES NOT associate the pins with the GPMC controller.  I suggest you check your design to see which pins are not used for some other function and can be muxed as gpmc & add gpmc pinmux settings and &gpmc node in your DTS file. 

    Best Regards, 
    Yordan

  • Hi Yordan,
    I have also tried to add child node. I have seen code for other GPMC devices and tries the same as you have suggested, but in that case, if I add child node, then during FPGA init, cs_request fails.
    I have seen other drivers also like nand and ethernet, in both cases during init function cs_request is already there.
    I have two questions:
    1) If adding child node does not allow me to do cs_request, then how does it works for other driver?
    2) If I can not do cs_request, then how can I get the memory region in FPGA driver?


    I have implemented GPMC settings in init function, as shown below:

    static int zeiss_fpga_gpmc_init(void)
    {
            int err;
            struct gpmc_settings s;
            struct gpmc_timings gpmc_t;

            err = gpmc_cs_request(FPGA_CS, SZ_16M,(unsigned long*)&fpga_base);
            if (err < 0) {
                    pr_err("omap2-gpmc: Cannot request GPMC CS %d, error %d\n",
                           FPGA_CS, err);
                    return err;
            }

            memset(&s, 0, sizeof(struct gpmc_settings));
            s.wait_on_write = true;
            s.device_width = GPMC_DEVWIDTH_16BIT;
            s.mux_add_data = GPMC_MUX_AD;

            memset(&gpmc_t, 0, sizeof(struct gpmc_timings));
            gpmc_t.sync_clk = 0;
            gpmc_t.cs_on = 0;
            gpmc_t.cs_rd_off = 100;
            gpmc_t.cs_wr_off = 100;
            gpmc_t.we_on = 54;
            gpmc_t.oe_on = 54;
            gpmc_t.adv_on = 12;
            gpmc_t.adv_rd_off = 48;
            gpmc_t.adv_wr_off = 48;
            gpmc_t.we_off = 90;
            gpmc_t.oe_off = 90;
            gpmc_t.access = 80;
            gpmc_t.rd_cycle = 100;
            gpmc_t.wr_cycle = 100;
            gpmc_t.wr_access = 100;
            gpmc_t.wr_data_mux_bus = 50;
            gpmc_t.page_burst_access = 6;
            gpmc_t.bus_turnaround = 12;

            err = gpmc_cs_set_timings(FPGA_CS, &gpmc_t, &s);
            if (err < 0) {
                    pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n",
                            err);
                    return err;
            }

            err = gpmc_cs_program_settings(FPGA_CS, &s);
            if (err < 0)
                    zeiss_fpga_gpmc_clean();
                                                                                                                                                                
    }

    I have also added below pinmux and its node in dts file.

    fpga_pin_ctrl: fpga_pin_ctrl {
                    pinctrl-single,pins = <
                            0x00 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD0, MODE0*/     
                            0x04 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD1, MODE0*/
                            0x08 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD2, MODE0*/
                            0x0C (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD3, MODE0*/
                            0x10 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD4, MODE0*/
                            0x14 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD5, MODE0*/
                            0x18 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD6, MODE0*/
                            0x1C (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD7, MODE0*/
                            0x20 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD8, MODE0*/
                            0x24 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD9, MODE0*/
                            0x28 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD10, MODE0*/
                            0x2C (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD11, MODE0*/
                            0x30 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD12, MODE0*/
                            0x34 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD13, MODE0*/
                            0x38 (PIN_INPUT  | MUX_MODE0)        /*GPMC_AD14, MODE0*/
                            0x3c (PIN_INPUT  | MUX_MODE0)        /* gpmc_ad15       */
                          0xd8 (PIN_INPUT_PULLUP  | MUX_MODE0)    
                          0xcc (PIN_OUTPUT | MUX_MODE0)   
                            0xb4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
                            0xC0 (PIN_OUTPUT | MUX_MODE0)   
                            0xc4 (PIN_OUTPUT | MUX_MODE0)   
                            0xc8 (PIN_OUTPUT | MUX_MODE0)   
                            0xd0 (PIN_OUTPUT | MUX_MODE0)    
                    >;
            };
    &gpmc{
            status = "okay";
            ti,no-idle-on-init;
            pinctrl-names = "default";
            pinctrl-0 = <&fpga_pin_ctrl>;
            ranges = <0 0 0x1000000 0x01000000>;

    fpga@3,0 {
                    compatible = "zeiss,fpga_fw";
                    reg = <3 0 4>;          
                  
                    bank-width = <2>;
            
                    interrupt-parent = <&gpmc>;
                    interrupts = <0>;

                    gpmc,mux-add-data;
                    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-off-ns = <40>;
                    gpmc,oe-off-ns = <54>;
                    gpmc,access-ns = <64>;
                    gpmc,rd-cycle-ns = <82>;
                    gpmc,wr-cycle-ns = <82>;
                    gpmc,wr-access-ns = <40>;
                    gpmc,wr-data-mux-bus-ns = <0>;

                    #address-cells = <1>;
                    #size-cells = <1>;
                    
            };
    };

    In this case kernel gives below error and GPMC can not probe:

    [    0.342177] irq: no irq domain found for /ocp/l4@4a000000/scm@2000/pinmux@1400 !
    [    0.357787] omap-gpmc 50000000.gpmc: could not find pctldev for node /ocp/l4@4a000000/scm@2000/pinmux@1400/fpga_pin_ctrl, deferring probe

  • Hello,
    Is there any update on this thread?

  • Hi,

    Are you able to boot to console? Can you verify with devmem2, that pinctrl settings are NOT implemented?

    As for your dts configurations:
    1. Why do you set CS0 in &gpmc node:
    ranges = <0 0 0x1000000 0x01000000>;
    and then use CS3 in the child node:
    reg = <3 0 4>; ?

    2. Can you try using:
    interrupt-parent = <&intc>;
    interrupts = <corresponding gpmc interrupt>

    Best Regards,
    Yordan
  • Thanks for your support Yordan,
    I have make GPMC lines working on my way due to below reasons:

    1) If I add pin muxing in dts file, I was getting error to probe GPMC driver as I have mentioned earlier
    2) If I add child node, then I was not aware how to access cs requested memory, during probing of child node.

    Due to this issues, I have removed pin muxing and child node from dts file. I know its not the proper way to add driver, but if I could get solution for above two issues then I can initialize everything in dts only.

    Still I am not able to read data from FPGA, but it may be the issue with timing or anything else. Please let me know if I am doing anything wrongly.

    Below is my initialization function:

    static int zeiss_fpga_gpmc_init(void)
    {
    int err = 0;
    struct gpmc_settings s;
    struct gpmc_timings gpmc_t;

    err = gpmc_cs_request(FPGA_CS, 4,(unsigned long*)&fpga_base);
    if (err < 0) {
    printk("omap2-gpmc: Cannot request GPMC CS %d, error %d\n",
    FPGA_CS, err);
    return err;
    }
    gpmc_cs_disable_mem(FPGA_CS);
    memset(&s, 0, sizeof(struct gpmc_settings));
    s.device_width = GPMC_DEVWIDTH_16BIT;
    s.mux_add_data = GPMC_MUX_AD;
    s.sync_read = 1;
    s.sync_write = 1;

    memset(&gpmc_t, 0, sizeof(struct gpmc_timings));

    gpmc_t.sync_clk = 0;
    gpmc_t.cs_on = 0;
    gpmc_t.cs_rd_off = 44;
    gpmc_t.cs_wr_off = 44;
    gpmc_t.we_on = 54;
    gpmc_t.oe_on = 54;
    gpmc_t.adv_on = 6;
    gpmc_t.adv_rd_off = 34;
    gpmc_t.adv_wr_off = 44;
    gpmc_t.we_off = 40;
    gpmc_t.oe_off = 54;
    gpmc_t.access = 64;
    gpmc_t.rd_cycle = 82;
    gpmc_t.wr_cycle = 82;
    gpmc_t.wr_access = 40;
    gpmc_t.wr_data_mux_bus = 0;
    gpmc_t.page_burst_access = 6;
    gpmc_t.bus_turnaround = 12;

    err = gpmc_cs_program_settings(FPGA_CS, &s);
    if (err < 0)
    zeiss_fpga_gpmc_clean();

    err = gpmc_cs_set_timings(FPGA_CS, &gpmc_t, &s);
    if (err < 0) {
    pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n",
    err);
    return err;
    gpmc_cs_enable_mem(FPGA_CS);
    return err;
    }

    Thank you once again for all your support.
  • Hi,

    "1) If I add pin muxing in dts file, I was getting error to probe GPMC driver as I have mentioned earlier"

    With the latest SDK, I've sometimes seen such probe errors, but regardless, when I check pinmux registers with devmem2, I can verify that the correct pinmux  settings were eventually applied by the kernel (this is probably some timing in calling driver apis, haven't investigated it).  That is why I requested to verify register values with devmem2, if you are able to boot to linux console.

    "2) If I add child node, then I was not aware how to access cs requested memory, during probing of child node."  

    Please have a look at the following user space driver: 

    /*
    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) ;
    }
    

    In the main function you can see how the mem attached to gpmc cs2 is mapped to kernel virtual memory & then a consecutive write and read operations are performed. 

    The difference in kernel space is the remapping of the physical address to the kernel virtual memory space: instead of mmap(), you should use ioremap(), here is an example on how to use access physical memory space using ioremap():


    static void __iomem *gpmc_rev_base; 
    gpmc_rev_base = ioremap(0x50000000, 32); 
    unsigned long int temp = __raw_readl(gpmc_rev_base);
    printk("\n========GPMC REV is %x================\n", temp);  

    Another difference is how you read/write to that memory location: 

    in user space you use:
       instead of:       

    *p32 = 0xdeadbeef;      //write
    uint32_t val = *p32;
    *p32 = 0xcafebabe;      //write
    uint32_t val2 = *p32;
    printf("val=%#x\n", val);   //read
    printf("val=%#x\n", val2);  //read

    you should use __raw_readl() & __raw_writel(). 

    Hope this helps. 

    Best Regards, 
    Yordan

  • Hello Yordan,

    I am right now trying to read FPGA register. My configuration is 16-bit, nor like device, Synchronous read/write.

    I can see on fpga side that fpga revives proper address, and sends data out, but AM57xx does not read it. It gives always 0. So could you please let me know if I am missing anything?

    My timing configurations are as below:

            gpmc_t.sync_clk = 8001;

           gpmc_t.cs_on = 0;

           gpmc_t.cs_rd_off = 186*2;

           gpmc_t.cs_wr_off = 186*2;

           gpmc_t.we_on = 54*2;   //54

           gpmc_t.oe_on = 54*2;   //54

           gpmc_t.adv_on = 12*2;

           gpmc_t.adv_rd_off = 48*2;

           gpmc_t.adv_wr_off = 48*2;

           gpmc_t.we_off = 168*2;

           gpmc_t.oe_off = 168*2;

           gpmc_t.access = 114*2;

           gpmc_t.rd_cycle = 186*2;

           gpmc_t.wr_cycle = 186*2;

           gpmc_t.wr_access = 186*2;

           gpmc_t.wr_data_mux_bus = 90*2; //90

           gpmc_t.page_burst_access = 6*2;

           gpmc_t.bus_turnaround = 12*2;

           gpmc_t.cycle2cycle_delay = 18;

           gpmc_t.bool_timings.cycle2cyclesamecsen = 1;

    Also please see the attached timing diagram, I am trying to read register 0x0016.