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两个文件,补上一些漏掉的配置后,运行成功。