OpenRisc-11-编写ipcore 的linux driver,然后run helloworld

引言

我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线interface的ip,可以实现plug & work。

所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。

本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。

 

11.1 编写wishbone为interface的ip core(ip_mkg)

1》这一步请参考:

http://blog.csdn.net/rill_zhen/article/details/8659788

2》将其中的my_slave_module链接到ORPSoC的wishbone上。

 

11.2 编写linux下的driver module

代码及makefile如下:

1》ip_mkg.c

 

/*
*
* rill mkg driver
*
*/
#include <linux/vmalloc.h>
#include <linux/slab.h>

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* get_user and put_user */
//#include <linux/clk.h>
//#include <linux/ioport.h>
#include <asm/io.h> /*ioremap*/
#include <linux/platform_device.h> /*cleanup_module*/

#include "ip_mkg.h"


void	__iomem 	*g_mkg_mem_base = NULL;

static int device_open(struct inode *inode, struct file *file)
{
	g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
	if(NULL == g_mkg_mem_base)
	{
		printk(KERN_ERR "mkg open ioremap error!\n");
		return -1;
	}
	else
	{
		printk("mkg ioremap addr:%d!\n",(int)g_mkg_mem_base);
	}

	return 0;
}

static int device_release(struct inode *inode, struct file *file)
{
	return 0;
}


static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
	return 0;
}

static ssize_t device_write(struct file *filp, const char *buffer, size_t count, loff_t *offset)
{
   return 0;
}

long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
   int ret_val = 0;
   unsigned int ret = 0;
   struct reg_data *new_regs;

   switch(ioctl_num)
   {
      case IOCTL_REG_SET:
	  {
		 new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);
		 if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0) 
		 	{
			    kfree(new_regs);
			    printk(KERN_ERR " error copy line_datafrom user.\n");
				return -1;
		 	}

			iowrite16(new_regs->value,g_mkg_mem_base+new_regs->addr);
		 kfree(new_regs);
     }
	 break;

	case IOCTL_REG_GET:
	{
	 new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);
	 if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0) 
	 	{
		    kfree(new_regs);
		    printk(KERN_ERR " error copy line_datafrom user.\n");
			return -1;
	 	}

		ret = ioread16(g_mkg_mem_base+new_regs->addr);
	 	kfree(new_regs);
		return ret;
	}
	break;
      
   }


  return -1;
}

struct file_operations our_file_ops = {
  .unlocked_ioctl = device_ioctl,
  .read = device_read,
  .write = device_write,
  .open = device_open,
  .release = device_release,
  .owner = THIS_MODULE,
};

int init_module()
{
	int ret_val;
	int ret;
	void __iomem *ret_from_request;
	

	//=== Allocate character device 
	ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &our_file_ops);
	if (ret_val < 0)
	{
		printk(KERN_ALERT " device %s failed(%d)\n", DEVICE_NAME, ret_val);
		return ret_val;
	}

	ret = check_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);
	if (ret < 0) 
	{
		printk(KERN_ERR "mkg check_mem_region bussy error!\n");
		return -1;
	}

	ret_from_request = request_mem_region(MKG_MEM_BASE, MKG_MEM_LEN, "ip_mkg");

	//===ioremap mkg registers

	g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
	if(NULL == g_mkg_mem_base)
	{
		printk(KERN_ERR "mkg ioremap error!\n");
		return -1;
	}
	else
	{
		;//printk("mkg ioremap addr:%d!\n",g_mkg_mem_base);
	}

	printk("mkg module init done!\n");

	return 0;
}

void cleanup_module()
{
	release_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);

	unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rill zhen:[email protected]");


 

 

2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。

 

#ifndef __IP_MKG_H__
#define __IP_MKG_H__

#define MAJOR_NUM	102
#define DEVICE_NAME	"ip_mkg"
#define MKG_MEM_BASE 0x10000001
#define MKG_MEM_LEN	32

#define IOCTL_REG_SET 0
#define IOCTL_REG_GET 1



struct reg_data 
{
	unsigned short addr;
	int value;
};

#endif


 

 

3》Makefile

 

# To build modules outside of the kernel tree, we run "make"
# in the kernel source tree; the Makefile these then includes this
# Makefile once again.
# This conditional selects whether we are being included from the
# kernel Makefile or not.
ifeq ($(KERNELRELEASE),)

    # Assume the source tree is where the running kernel was built
    # You should set KERNELDIR in the environment if it's elsewhere
    KERNELDIR ?= /home/openrisc/soc-design/linux
    # The current directory is passed to sub-makes as argument
    PWD := $(shell pwd)

modules:
	make -C $(KERNELDIR) M=$(PWD) modules ARCH=openrisc CROSS_COMPILE=or32-linux-

modules_install:
	make -C $(KERNELDIR) M=$(PWD) modules_install ARCH=openrisc CROSS_COMPILE=or32-linux-

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers

.PHONY: modules modules_install clean

else
    # called from kernel build system: just declare what our modules are
    obj-m := ip_mkg.o
endif


 

 

11.3 遇到的问题

1》当在执行make时会遇到如下警告:__ioremap undefined。

OpenRisc-11-编写ipcore 的linux driver,然后run helloworld_第1张图片

2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。

 

OpenRisc-11-编写ipcore 的linux driver,然后run helloworld_第2张图片

11.4 解决方法

在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。

 

#include <linux/module.h>

EXPORT_SYMBOL(__ioremap);


 

 

 

 

 

11.5 小结

实验步骤

 

0》virtualbox虚拟机unbuntu上安装nfs服务

0.0>确保virtualbox能上网

0.1> apt-get install nfs-kernel-server

0.2>创建nfs共享目录:mkdir /home/openrisc/nfs

0.3>vim /etc/exports,添加如下内容

/home/openrisc/nfs  *(rw,sync)

0.4>重启nfs服务

sudo /etc/init.d/nfs-kernel-server restart

 

1》修改arch/openrisc/mm/ioremap.c

2》cd /home/openrisc/soc-design/linux

3》make ARCH=openrisc defconfig;make生成vmlinux

4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件

5》参考如下链接,在FPGA板子上运行linux(刚刚生成的vmlinux文件)

http://blog.csdn.net/rill_zhen/article/details/8535317

6》配置virtualbox的ip

sudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255

7》配置PC机的ip为192.168.1.102

8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。

9》板子上执行mkdir nfs,创建本地nfs共享目录

10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs

11》在virtualbox里将ip_mkg.ko copy到nfs共享目录

12》板子上cd nfs

13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下

14》创建设备节点:mknod /dev/ip_mkg c 102 0

15》测试:cat /dev/ip_mkg,看到如下结果:

16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下

soc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS

\soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。 

OpenRisc-11-编写ipcore 的linux driver,然后run helloworld_第3张图片

 

 

16》运行helloworld

16.1>编写hello.c

#include <stdio.h>

void main()
{
printf("rill helloworld!\n");
}


16.2>编译: or2-linux-gcc hello.c -o hello

16.3>copy到板子上:cp hello /home/openrisc/nfs

16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:

 

OpenRisc-11-编写ipcore 的linux driver,然后run helloworld_第4张图片

 

 

17》最后放一首歌,庆祝一下:

OpenRisc-11-编写ipcore 的linux driver,然后run helloworld_第5张图片

梦醒时分
词曲:李宗盛
演唱:陈淑桦

你说你爱了不该爱的人
你的心中满是伤痕
你说你犯了不该犯的错
心中满是悔恨
你说你尝尽了生活的苦
找不到可以相信的人
你说你感到万分沮丧
甚至开始怀疑人生

早知道伤心总是难免的
你又何苦一往情深
因为爱情总是难舍难分
何必在意那一点点温存
要知道伤心总是难免的
在每一个梦醒时分
有些事情你现在不必问
有些人你永远不必等

你说你爱了不该爱的人
你的心中满是伤痕
你说你犯了不该犯的错
心中满是悔恨
你说你尝尽了生活的苦
找不到可以相信的人
你说你感到万分沮丧
甚至开始怀疑人生

早知道伤心总是难免的
你又何苦一往情深
因为爱情总是难舍难分
何必在意那一点点温存
要知道伤心总是难免的
在每一个梦醒时分
有些事情你现在不必问
有些人你永远不必等

早知道伤心总是难免的
你又何苦一往情深
因为爱情总是难舍难分
何必在意那一点点温存
要知道伤心总是难免的
在每一个梦醒时分
有些事情你现在不必问
有些人你永远不必等 

你可能感兴趣的:(OpenRisc-11-编写ipcore 的linux driver,然后run helloworld)