Menu Close

Writing the Device Tree Driver and Adding the FPGA register

This article talks about how to write a device tree driver as well as adding the FPGA register.

For related subjects, please refer to the SOC Table of Contents.

 

We will first create a folder titled “work” in our home folder and go into its directory from the terminal.

We will next execute the following two commands to create a new PetaLinux project in the directory.

sptl
petalinux-create -t project --template zynq -n fii-module

Note that we named the project fii-module to match the development board we will be using.

We will then copy the FPGA SDK directory FII_7030.sdk to the work folder we just created and edit fii_module. Use the following command to enter the fii_module project directory:

cd fii-module

Next, we will execute the sptl command, and configure the project by using the following command:

petalinux-config --get-hw-description ~/work/FII_7030.sdk/

This will bring up the settings page.

We don’t need to make any changes, and we can simply choose < Save > and < Exit >.

Next, we will insert and create the fpga device tree driver by using the following command:

petalinux-create -t modules --name fii-dt-driver

We can now go on to edit the driver by going into the ~/work/fii-module/project-spec/meta-user/recipes-modules/fii-dt-driver/files directory and editing the fii-dt-driver.c file.

Code download: Device Tree Driver

Once the file is open, we will modify it as such:

/*  fii-dt-driver.c - The simplest kernel module.
* Copyright (C) 2013 - 2016 Xilinx, Inc
*
*   This program is free software; you can redistribute it and/or modify
*   it unde r the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License along
*   with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>  /* for put_user */
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>

/* Standard module information, edit as appropriate */

MODULE_LICENSE("GPL");

MODULE_AUTHOR
    ("FII inc.");

MODULE_DESCRIPTION
    ("fii-dt-driver - loadable module template generated by petalinux-create -t modules");

#define DRIVER_NAME "fii-dt-driver"

static const struct of_device_id  of_match_fii_dt_driver[] = {
//    {.compatible = "fii,fii-dt-driver", .data = NULL},
    {.compatible = "fii,fii-dt-driver", },
    {/*sentinel*/},
};

//platform driver

static struct class  *fii_dt_driver_class;
static unsigned int major;
static unsigned int * gpio_base;
static unsigned int * gpio_data;
static unsigned int * gpio_dir;

static int fii_dt_driver_init(void);

static int fii_dt_driver_open(struct inode* node,struct file* filp){
    gpio_data = ioremap(gpio_base, 8);

    if(gpio_data){
        printk("kernel: ioremap(0x%08x)=0x%08x \n", gpio_base, gpio_data);
    }

    else{
        return -EINVAL;
    }

    gpio_dir = gpio_data + 1;

    return 0;
}

static int fii_dt_driver_release(struct platform_device * dev)
{
    iounmap(gpio_data);

    unregister_chrdev(major, "fii-dt-driver");
    device_destroy(fii_dt_driver_class,MKDEV(major,0));
    class_destroy(fii_dt_driver_class);   

    return 0;
}

/*
    0x43c0_0000 + 4 = value
    0x43c0_0000 + 8 = direction
*/

static ssize_t fii_dt_driver_read(struct file *filp, char *buf, size_t size, loff_t *offset)
{
    unsigned char val[32];
    unsigned int temp;
    unsigned int *addr_p;
    int i,cnt;
    printk("kernel: fii-dt-driver read start.... size = %d\n", size);
//  cnt = size - 1;
    cnt = size;

    addr_p = gpio_data;
    temp = *addr_p ;

    for(i = 0; i < cnt/4; i++ )
    {
        val[i*4 + 3] = temp & 0xff;
        val[i*4 + 2] = (temp >> 8) & 0xff;
        val[i*4 + 1] = (temp >> 16) & 0xff;
        val[i*4 + 0] = (temp >> 24) & 0xff;
        addr_p ++;

        temp = *addr_p;
    }

    if(i % 4 == 1)
    {
        val[i*4 + 0] = temp & 0xff;
    }

    if(i % 4 == 2)
    {
        val[i*4 + 1] = temp & 0xff;
        val[i*4 + 0] = (temp >> 8) & 0xff;
    }

    if(i % 4 == 3)
    {
        val[i*4 + 2] = temp & 0xff;
        val[i*4 + 1] = (temp >> 8) & 0xff;
        val[i*4 + 0] = (temp >> 16) & 0xff;
    }

    copy_to_user(buf, val, cnt);

    return cnt;
}

static ssize_t fii_dt_driver_write(struct file * filp, const char __user *buf, size_t size, loff_t * offset) {

    unsigned char val[32];
    unsigned int temp = 0;
    unsigned int * addr_p;

    int i,cnt;

    memset(val,0,32);
    addr_p = gpio_data;

    printk("kernel: fii-dt-driver write start.... size = %d\n", size);

    copy_from_user(&val, buf, size);

    cnt = size - 1;

    printk("kernel: val[0] = 0x%08x \n", val[0]);

    if(val[0] == 'w')
    {
        temp = val[2];
        temp = temp << 8 | val[3];
        temp = temp << 8 | val[4];
        temp = temp << 8 | val[5];

        *addr_p = temp;

        printk("kernel: gpio_data = 0x%08x \n", temp);
    }

    else if(val[0] == 'd')
    {
        addr_p ++;
        temp = val[2];
        temp = temp << 8 | val[3];
        temp = temp << 8 | val[4];
        temp = temp << 8 | val[5];

        *addr_p = temp;
        printk("kernel: gpio_dir = 0x%08x \n", temp);
    }

    else
    {
        printk("kernel: invalid parameter \n");
    }

    return size;
}

static struct file_operations fii_dt_driver_oprs = {
    .owner      = THIS_MODULE,
    .open       = fii_dt_driver_open,
    .write      = fii_dt_driver_write,
    .read       = fii_dt_driver_read,
};

static int fii_dt_driver_probe(struct platform_device *pdev)
{
    struct resource *res;
    printk ("kernel: enter fii_dt_driver probe ...... \n");
    printk ("kernel: enter fii_dt_driver probe ...... \n");
    printk ("kernel: enter fii_dt_driver probe ...... \n");
    printk ("kernel: enter fii_dt_driver probe ...... \n");
    printk ("kernel: enter fii_dt_driver probe ...... \n");
    printk ("kernel: enter fii_dt_driver probe ...... \n");

    res = platform_get_resource(pdev, IORESOURCE_MEM,0);

    if(res){
        gpio_base = res->start;
    }

    major=register_chrdev(0, "fii-dt-driver", &fii_dt_driver_oprs);

    if (major < 0) {
        printk ("Registering the character device failed with %d\n", major);

        return major;
    }

    fii_dt_driver_class = class_create(THIS_MODULE, "fii-dt-driver_class");
    device_create(fii_dt_driver_class,NULL,MKDEV(major,0),NULL,"fii-dt-driver");

    return 0;
}

MODULE_DEVICE_TABLE(of, of_match_fii_dt_driver);

static struct platform_driver fii_dt_driver_drv = {
    .driver     = {
        .name   = "fii-dt-driver",
        .owner  = THIS_MODULE,
        .of_match_table = of_match_fii_dt_driver,
    },
    .probe      = fii_dt_driver_probe,
    .remove     = fii_dt_driver_release,
};

static int fii_dt_driver_init(void){       /* register device  */

    return platform_driver_register(&fii_dt_driver_drv);
}

static void fii_dt_driver_exit(void){
    platform_driver_unregister(&fii_dt_driver_drv);

    return;
};

module_init(fii_dt_driver_init);
module_exit(fii_dt_driver_exit);

MODULE_ALIAS("platform:fii-dt-driver");

When you finish writing the code, please execute the following command to edit the PetaLinux driver settings.

petalinux-config -c rootfs

Once the graphical interface opens, go into modules and include fii-dt-driver by pressing [Y]. Make sure you save and exit when you are finished.

We will now edit the user’s device tree system-user.dtsi located in ~/work/fii-module/project-spec/meta-user/recipes-bsp/device-tree/files/.

Please edit it as follows:

/include/ “system-conf.dtsi”

/ {
            fii-dt-driver {
                        #address-cells = <1>;
                        #size-cells = <1>;
                        compatible = “fii,fii-dt-driver”;
                        reg = <0x43c00000 8>;
            };

};

Make sure the compatible portion of the code matches with that in the previous file we edited, or else the system will not be able to find the driver. Note that because it is a string, you cannot have excess spaces.

We will then proceed to compile the kernel by using the following command:

petalinux-build -c kernel

Next, we will use the following command to compile the driver:

petalinux-build -c fii-dt-driver

Now we can go ahead and compile the entire project by using the following command:

petalinux-build

We will now create the project files by executing the following command:

petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga --u-boot --force

We will now copy the BOOT.BIN file and the image.ub file from ~/work/fii-module/images/linux/ to partition 1 of the SD card, which should be the boot partition; and extract rootfs.cpio to the other partition, which should be titled rootfs.

When finished, please plug the SD card into the fii_7030 development board and boot it up. Make sure you are connected to the board via PuTTY. Recall that both the username and the password is root.

Posted in Textbook and Training Project

Related Articles

Leave a Reply

Your email address will not be published.

Leave the field below empty!