rk3288 基于qemu学习lcd驱动

qemu中的LCD相关的芯片手册

100ask修改了qemu的源码,实现了一个虚拟的LCD控制器,只有4个寄存器

地址 寄存器 说明
0x021C8000 fb_base_phys 用于设置Framebuffer的物理地址
0x021C8004 fb_xres 用于设置Framebuffer的X方向分辨率
0x021C8008 fb_yres 用于设置Framebuffer的Y方向分辨率
0x021C800C fb_bpp 用于设置Framebuffer中像素的位宽

使用qemu

#下载qemu机器
https://e.coding.net/weidongshan/ubuntu-18.04_imx6ul_qemu_system.git
#安装必要的软件
./install_sdl.sh
#执行qemu
./qemu-imx6ull-gui.sh // 启动后,登录名是root,无需密码

下载qemu内核源码并编译

#下载源码
git clone https://e.coding.net/codebug8/repo.git
mkdir -p 100ask_imx6ull-qemu && cd 100ask_imx6ull-qemu
../repo/repo init -u https://e.coding.net/weidongshan/manifests.git -b linux-sdk -m  imx6ull/100ask-imx6ull_qemu_release_v1.0.xml --no-repo-verify
../repo/repo sync -j4

#临时生效环境变量
#交叉编译器可以不用,因为与ubuntu1804的一样
export PATH=$PATH:/home/book/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

#编译内核
cd linux-4.9.88
make mrproper
make 100ask_imx6ull_qemu_defconfig
make zImage -jN //编译zImage内核镜像,其中N参数可以根据CPU个数,来加速编译系统。
make dtbs //编译设备树文件

#将编译出来的文件替换qemu的内核文件
#位置:arch/arm/boot/zImage // 内核
#位置:arch/arm/boot/dts/100ask_imx6ull_qemu.dtb // 设备树

#替换位置:/home/book/ubuntu-18.04_imx6ul_qemu_system/imx6ull-system-image

qemu退出模式是ctrl+alt+G

开始编译我们写好的代码替换qemu的lcd驱动

编译完成后替换zImage出现如下错误:

book@100ask:~/ubuntu-18.04_imx6ul_qemu_system$ ./qemu-imx6ull-gui.sh 
qemu-system-arm: warning: nic imx.enet.0 has no peer
qemu-system-arm: warning: nic imx.enet.1 has no peer
Uncompressing Linux... done, booting the kernel.

修改一些代码后测试成功,源码如下:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fb.h>
#include <linux/types.h>
#include <linux/dma-mapping.h>

static unsigned int pseudo_palette[16];

struct lcd_regs {
	volatile unsigned int fb_base_phys;
	volatile unsigned int fb_xres;
	volatile unsigned int fb_yres;
	volatile unsigned int fb_bpp;
};
static struct lcd_regs *mylcd_regs;

static struct fb_info *myfb_info;

static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
	chan &= 0xffff;
	chan >>= 16 - bf->length;
	return chan << bf->offset;
}

static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,
			     unsigned int green, unsigned int blue,
			     unsigned int transp, struct fb_info *info)
{
	unsigned int val;

	/* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n",
		   regno, red, green, blue); */
	switch (info->fix.visual) {
	case FB_VISUAL_TRUECOLOR:
		/* true-colour, use pseudo-palette */

		if (regno < 16) {
			u32 *pal = info->pseudo_palette;

			val  = chan_to_field(red,   &info->var.red);
			val |= chan_to_field(green, &info->var.green);
			val |= chan_to_field(blue,  &info->var.blue);

			pal[regno] = val;
		}
		break;

	default:
		return 1;	/* unknown type */
	}

	return 0;
}

static struct fb_ops myfb_ops = {
	.owner		= THIS_MODULE,
	.fb_setcolreg   = s3c_lcdfb_setcolreg,
	.fb_fillrect	= cfb_fillrect,
	.fb_copyarea	= cfb_copyarea,
	.fb_imageblit	= cfb_imageblit,
};

static int lcd_drv_init(void) 
{
	int ret;
	dma_addr_t phy_addr;	
	/* 1. crate */
	myfb_info = framebuffer_alloc(0, NULL);
	if(!myfb_info)
		return -ENOMEM;

	/* 2. set */
	/* 2.1 var resolution  color formate */
	myfb_info->var.xres = 500;
	myfb_info->var.yres = 300;
	myfb_info->var.bits_per_pixel = 16;		/* rgb565 */

	myfb_info->var.red.offset   = 11;
	myfb_info->var.red.length   = 5;
	myfb_info->var.green.offset = 5;
	myfb_info->var.green.length = 6;
	myfb_info->var.blue.offset  = 0;
	myfb_info->var.blue.length  = 5;
	myfb_info->var.xres_virtual = 500;
	myfb_info->var.yres_virtual = 300;

	/* 2.2 fix */
	strcmp(myfb_info->fix.id, "mylcd");
	myfb_info->fix.smem_len = myfb_info->var.xres * myfb_info->var.yres * myfb_info->var.bits_per_pixel / 8;
	if(myfb_info->var.bits_per_pixel == 24) {
		myfb_info->fix.smem_len = myfb_info->var.xres * myfb_info->var.yres * 4;
	}

	/* 2.3 fb virtual address */
	myfb_info->screen_base =  dma_alloc_writecombine(NULL, myfb_info->fix.smem_len,	
			&phy_addr, GFP_KERNEL);	 	/* virtual address */
	myfb_info->fix.smem_start = phy_addr;		/* physicsal address */
	myfb_info->fix.type = FB_TYPE_PACKED_PIXELS;
	myfb_info->fix.visual = FB_VISUAL_TRUECOLOR;

	myfb_info->fix.line_length = (myfb_info->var.xres_virtual * myfb_info->var.bits_per_pixel / 8);
	if(myfb_info->var.bits_per_pixel == 24) {
		myfb_info->fix.line_length = myfb_info->var.xres_virtual * 4;
	}

	/* 2.3 fops */
	myfb_info->fbops = &myfb_ops;
	myfb_info->pseudo_palette = pseudo_palette;

	/* 3. register */
	ret = register_framebuffer(myfb_info);

	/* 4. hardware opeation */
	mylcd_regs = ioremap(0x21c8000, sizeof(struct lcd_regs));
	mylcd_regs->fb_base_phys = phy_addr;
	mylcd_regs->fb_xres = 500;
	mylcd_regs->fb_yres = 300;
	mylcd_regs->fb_bpp = 16;

	return 0;
}

static void lcd_drv_exit(void)
{
	iounmap(mylcd_regs);

	unregister_framebuffer(myfb_info);

	dma_free_writecombine(NULL, PAGE_ALIGN(myfb_info->fix.smem_len),
			myfb_info->screen_base, myfb_info->fix.smem_start);

	framebuffer_release(myfb_info);
}

module_init(lcd_drv_init);
module_exit(lcd_drv_exit);

MODULE_AUTHOR("chen");
MODULE_DESCRIPTION("Framebuffer driver for the linux");
MODULE_LICENSE("GPL");

思路

遇到问题,先是屏蔽可能的错误,尽可能让内核先跑起来。
然后对比100ask_qemu_fb.c和s3c2410fb.c两个文件,补上一些漏掉的配置后,运行成功。

上一篇:如何为 FB Messenger 设置聊天机器人?


下一篇:Facebook统计事件接入及广告关联