linux设备树-LCD驱动程序
----------------------------------------------------------------------------------------------------------------------------
内核版本:linux 5.2.8
根文件系统:busybox 1.25.0
u-boot:2016.05
----------------------------------------------------------------------------------------------------------------------------
一、修改设备树
1.1 硬件接线
在Mini2440裸机开发之LCD基础我们已经介绍了LCD的硬件接线图。使用到的引脚如下:
GPIO | 功能 | GPIO | 功能 |
GPC8 | VD0 | GPD6 | VD14 |
GPC9 | VD1 | GPD7 | VD15 |
GPC10 | VD2 | GPD8 | VD16 |
GPC11 | VD3 | GPD9 | VD17 |
GPC12 | VD4 | GPD10 | VD18 |
GPC13 | VD5 | GPD11 | VD19 |
GPC14 | VD6 | GPD12 | VD20 |
GPC15 | VD7 | GPD13 | VD21 |
GPD0 | VD8 | GPD14 | VD22 |
GPD1 | VD9 | GPD15 | VD23 |
GPD2 | VD10 | GPC4 | VM:数据使能信号 |
GPD3 | VD11 | GPC3 | VFRAME:帧同步信号 |
GPD4 | VD12 | GPC2 | VLINE:行同步信号 |
GPD5 | VD13 | GPC1 | VCLK:像素时钟信号 |
GPG4 | LCD_PWR:LCD背光电源 | GPC0 | LEND:行结束信号 |
1.2 修改s3c2440-pinctrl.dtsi
既然我们知道了LCD使用到了哪些引脚,那就好好办了,修改内核arch/arm/boot/dts/s3c2440-pinctrl.dtsi文件,在pinctrl节点下添加两个引脚配置节点:
lcd_pinctrl: lcd_pinctrl { samsung,pins = "gpc-8", "gpc-9", "gpc-10", "gpc-11", "gpc-12", "gpc-13", "gpc-14", "gpc-15", "gpd-0", "gpd-1", "gpd-2", "gpd-3", "gpd-4", "gpd-5", "gpd-6", "gpd-7", "gpd-8", "gpd-9", "gpd-10", "gpd-11", "gpd-12", "gpd-13", "gpd-14", "gpd-15", "gpc-0", "gpc-1", "gpc-2", "gpc-3", "gpc-4"; samsung,pin-function = <EXYNOS_PIN_FUNC_2>; }; lcd_backlight: lcd_backlight { samsung,pins = "gpg-4"; samsung,pin-function = <3>; };
lcd_pinctrl:配置GPC8、GPC9、GPC10等引脚功能为LCD。
lcd_backlight:配置GPG4引脚功能为LCD电源,这个之所以单独拎出来,是因为其功能复用配置为LCD电源的值为3,比较特殊。
1.3 修改s3c2440-smdk2440.dts
1.3.1 内核LCD驱动回顾
linux 5.2.8内核实际上已经自带了s3c2440 LCD驱动,在linux驱动移植-LCD驱动基础文章中已经进行了很详细的介绍。
有关LCD硬件的配置参数、以及LCD控制器寄存器的配置参数都是存放在plaftrom设备s3c_device_lcd的platform_data字段中的,这个字段保存的是平台的私有数据,数据类型为s3c2410fb_mach_info。
static struct resource s3c_lcd_resource[] = { [0] = DEFINE_RES_MEM(S3C24XX_PA_LCD, S3C24XX_SZ_LCD), // 定义内存资源 起始地址0x4D000000(LCD相关寄存器基地址)、大小为1M [1] = DEFINE_RES_IRQ(IRQ_LCD), }; struct platform_device s3c_device_lcd = { // 定义platform设备 .name = "s3c2410-lcd", .id = -1, .num_resources = ARRAY_SIZE(s3c_lcd_resource), .resource = s3c_lcd_resource, .dev = { .dma_mask = &samsung_device_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), } };
s3c_device_lcd->dev.platform_data会被设置为&smdk2440_fb_info:
s3c_device_lcd->dev.platform_data=&smdk2440_fb_info
既然我们要采用设备树配置LCD的信息,那么我们就需要把smdk2440_fb_info中的配置信息抽离出来,放到设备树中:
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = { .lcdcon5 = S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_PWREN | S3C2410_LCDCON5_HWSWP, .type = S3C2410_LCDCON1_TFT, .width = LCD_WIDTH, .height = LCD_HEIGHT, .pixclock = 156250, /* 每个像素时长,10^12/VCLK */ .xres = LCD_WIDTH, .yres = LCD_HEIGHT, .bpp = 16, .left_margin = HFPD, // HFPD .right_margin = HBPD, // HBPD .hsync_len = HSPW, // HSPW .upper_margin = VBPD, // VBPD .lower_margin = VFPD, // VFPD .vsync_len = VSPW, // VSPW }; static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = { .displays = &smdk2440_lcd_cfg, .num_displays = 1, .default_display = 0, #if 1 /* currently setup by downloader */ .gpccon = 0xaaaaaaaa, .gpccon_mask = 0xffffffff, .gpcup = 0xffffffff, .gpcup_mask = 0xffffffff, .gpdcon = 0xaaaaaaaa, .gpdcon_mask = 0xffffffff, .gpdup = 0xffffffff, .gpdup_mask = 0xffffffff, #endif .lpcsel = ((0xCE6) & ~7) | 1<<1, // 第一位设置为1 选择输出分片率类型0:320 * 240 1:240*320 };
我们可以抽离出的信息包括:
- LCD相关寄存器基地址:0x4D000000;
- LCD中断IRQ_LCD,对应主中断源硬件中断号16;
- LCD所使用的时钟;
- 配置LCD相关的引脚复用为LCD功能,直接引用lcd_pinctrl、lcd_backlight节点即可,这样就不用了在LCD驱动中对这些引脚进行配置;
- lcdcon5寄存器:这个寄存器可以引脚极性,BPP,数据存放格式;设置为0xf09
- type:LCD的类型,设置为0x60;
- width;LCD面板的行宽,设置为240;
- heigh:LCD面板的列宽,设置为320;
- pixclock:每个像素时长,156250皮秒;
- xres:水平分辨率,设置为240;
- yres:垂直分辨率,设置为320
- bpp:每个像素点位数;
- left_margin:对应时序参数HFPD,水平后沿为有效数据的结束与HSYNC的上升沿之间的VCLK周期数,设置为9;
- right_margin:对应时序参数HBPD,描述水平后沿为HSYNC的下降沿与有效数据的开始之间的VCLK周期数,设置为19;
- hsync_len:对应时序参数HSPW,通过计算VCLK的数水平同步脉冲宽度决定HSYNC脉冲的高电平宽度,设置为9;
- upper_margin:对应时序参数VBPD,垂直同步周期后的无效行数,设置为1;
- lower_margin:对应时序参数VFPD,垂直同步周期前的的无效行数,设置为1;
- vsync_len:对应时序参数VSPW,通过计算无效行数垂直同步脉冲宽度决定VSYNC脉冲的高电平宽度,设置为1;
1.3.2 新增fb0设备节点
在内核arch/arm/boot/dts/s3c2440-smdk2440.dts文件中添加fb0设备节点,由于我使用的LCD型号为LCD-T35(TD035STEB4),所以设备节点的参数配置是适用于该型号的。
fb0: fb@4d000000{ compatible = "mylcd"; reg = <0x4D000000 0x60>; interrupts = <0 0 16 3>; clocks = <&clocks HCLK_LCD>; clock-names = "lcd"; pinctrl-names = "default"; pinctrl-0 = <&lcd_pinctrl &lcd_backlight>; status = "okay"; lcdcon5 = <0xf09>; type = <0x60>; width = /bits/ 16 <240>; height = /bits/ 16 <320>; pixclock = <156250>; xres = /bits/ 16 <240>; yres = /bits/ 16 <320>; bpp = /bits/ 16 <16>; left_margin = /bits/ 16 <9>; right_margin =/bits/ 16 <19>; hsync_len = /bits/ 16 <9>; upper_margin = /bits/ 16 <1>; lower_margin = /bits/ 16 <1>; vsync_len = /bits/ 16 <1>; };
当platform设备和驱动匹配,就会调用pinctrl_bind_pins函数,该函数通过调用pinctrl_lookup_state函数获取状态名为default和init的状态,并分别保存到default_state和init_state成员变量中。如果找不到init状态,则选择default状态作为设备引脚的状态。
二、修改驱动程序
2.1 修改platform_driver
为了让LCD驱动程序和我们定义的设备节点fb0匹配符上,我们需要修改s3c2410fb_driver变量添加设备树匹配项,该变量定义在drivers/video/fbdev/s3c2410fb.c:
static const struct of_device_id lcd_dt_match[] = { // 用于设备树匹配 { .compatible = "mylcd", .data = (void *)0 }, {}, }; static struct platform_driver s3c2410fb_driver = { .probe = s3c2410fb_probe, .remove = s3c2410fb_remove, .suspend = s3c2410fb_suspend, .resume = s3c2410fb_resume, .driver = { .name = "s3c2410-lcd", .of_match_table = of_match_ptr(lcd_dt_match), }, };
2.2 修改s3c24xxfb_probe
当platform设备和驱动匹配后,将会调用s3c2410fb_probe进行frambebuffer的注册:
static int s3c2410fb_probe(struct platform_device *pdev) { return s3c24xxfb_probe(pdev, DRV_S3C2410); }
最终调用的s3c24xxfb_probe函数,因此我们需要修改s3c24xxfb_probe的代码:
- 之前通过dev_get_platdata(&pdev->dev)函数获取platform设备的平台私有数据,需要修改为从设备树文件获取;
- 移除s3c2410fb_init_registers函数调用,该函数之前是用于配置LCD相关引脚为LCD功能的,这一步已经不需要了;
修改完之后代码如下:
static int s3c24xxfb_probe(struct platform_device *pdev, enum s3c_drv_type drv_type) { struct device_node *np; struct device *dev = &pdev->dev; struct s3c2410fb_info *info; struct s3c2410fb_display *display; struct fb_info *fbinfo; struct s3c2410fb_mach_info *mach_info; struct resource *res; int ret; int irq; int i; int size; u32 lcdcon1; np = dev->of_node; // 获取fb0设备节点 if (!np) { dev_err(dev, "could not find device info\n"); return -EINVAL; } display = devm_kzalloc(dev, sizeof(*display), GFP_KERNEL); // 动态分配struct s3c2410fb_display if (!display) { dev_err(dev, "no mem for display\n"); return -ENOMEM; } mach_info = devm_kzalloc(dev, sizeof(*mach_info), GFP_KERNEL); // 动态分配struct s3c2410fb_mach_info if (!mach_info) { dev_err(dev, "no mem for mach\n"); return -ENOMEM; }
dev->platform_data = mach_info; // 设置platform设备的平台私有数据 mach_info->displays = display; mach_info->num_displays = 1; mach_info->default_display = 0;
// 获取设备节点中的各个属性值,用来设置驱动参数 of_property_read_u32(np, "lcdcon5", (u32 *)(&display->lcdcon5)); of_property_read_u32(np, "type", &display->type); of_property_read_u16(np, "width", &display->width); of_property_read_u16(np, "height", &display->height); of_property_read_u32(np, "pixclock", &display->pixclock); of_property_read_u16(np, "xres", &display->xres); of_property_read_u16(np, "yres", &display->yres); of_property_read_u16(np, "bpp", &display->bpp); of_property_read_u16(np, "left_margin", &display->left_margin); of_property_read_u16(np, "right_margin", &display->right_margin); of_property_read_u16(np, "hsync_len", &display->hsync_len); of_property_read_u16(np, "upper_margin", &display->upper_margin); of_property_read_u16(np, "lower_margin", &display->lower_margin); of_property_read_u16(np, "vsync_len", &display->vsync_len); pr_debug("%s: lcdcon5: 0x%lx\n", __func__, display->lcdcon5); pr_debug("%s: type: 0x%x\n", __func__, display->type); pr_debug("%s: width: 0x%x\n", __func__, display->width); pr_debug("%s: height: 0x%x\n", __func__, display->height); pr_debug("%s: pixclock: 0x%x\n", __func__, display->pixclock); pr_debug("%s: xres: 0x%x\n", __func__, display->xres); pr_debug("%s: yres: 0x%x\n", __func__, display->yres); pr_debug("%s: bpp: 0x%x\n", __func__, display->bpp); pr_debug("%s: left_margin: 0x%x\n", __func__, display->left_margin); pr_debug("%s: right_margin: 0x%x\n", __func__, display->right_margin); pr_debug("%s: hsync_len: 0x%x\n", __func__, display->hsync_len); pr_debug("%s: upper_margin: 0x%x\n", __func__, display->upper_margin); pr_debug("%s: lower_margin: 0x%x\n", __func__, display->lower_margin); pr_debug("%s: vsync_len: 0x%x\n", __func__, display->vsync_len); irq = platform_get_irq(pdev, 0); // 获取第一个中断IRQ编号 if (irq < 0) { dev_err(&pdev->dev, "no irq for device\n"); return -ENOENT; } fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); // 分配一个fb_info结构体,额外分配s3c2410fb_info大小的内存,初始化fbinfo->device = &pdev->dev if (!fbinfo) return -ENOMEM; platform_set_drvdata(pdev, fbinfo); // 设置pdev->dev.driver_data = fbinfo info = fbinfo->par; // 获取成员par info->dev = &pdev->dev; // 初始化par成员 info->drv_type = drv_type; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 获取第一个内存资源,地址范围0x4D000000~(0x4D000000+0x60) if (res == NULL) { dev_err(&pdev->dev, "failed to get memory registers\n"); ret = -ENXIO; goto dealloc_fb; } size = resource_size(res); // 0x60 info->mem = request_mem_region(res->start, size, pdev->name); // 动态申请内存 if (info->mem == NULL) { // 内存已经被使用 dev_err(&pdev->dev, "failed to get memory region\n"); ret = -ENOENT; goto dealloc_fb; } info->io = ioremap(res->start, size); // 将LCD相关寄存器起始物理地址映射到虚拟地址,并返回虚拟地址 if (info->io == NULL) { dev_err(&pdev->dev, "ioremap() of registers failed\n"); ret = -ENXIO; goto release_mem; } if (drv_type == DRV_S3C2412) info->irq_base = info->io + S3C2412_LCDINTBASE; else info->irq_base = info->io + S3C2410_LCDINTBASE; dprintk("devinit\n"); strcpy(fbinfo->fix.id, driver_name); // 设置fb_info成员id为s3c2410fb /* Stop the video */ lcdcon1 = readl(info->io + S3C2410_LCDCON1); // S3C2410_LCDCON1=0,从而得到LCDCON1寄存器地址 读取寄存器值 writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); // 输出使能位设置为禁止
// 设置LCD不可变参数 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; fbinfo->fix.type_aux = 0; fbinfo->fix.xpanstep = 0; fbinfo->fix.ypanstep = 0; fbinfo->fix.ywrapstep = 0; fbinfo->fix.accel = FB_ACCEL_NONE;
// 设置LCD可变参数 fbinfo->var.nonstd = 0; fbinfo->var.activate = FB_ACTIVATE_NOW; fbinfo->var.accel_flags = 0; fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
// 设置LCD操作函数 fbinfo->fbops = &s3c2410fb_ops; fbinfo->flags = FBINFO_FLAG_DEFAULT; fbinfo->pseudo_palette = &info->pseudo_pal;
// 清空调色板数组 for (i = 0; i < 256; i++) info->palette_buffer[i] = PALETTE_BUFF_CLEAR; ret = devm_request_irq(dev, irq, s3c2410fb_irq, 0, pdev->name, info); // 申请中断 if (ret) { dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret); ret = -EBUSY; goto release_regs; }
// 时钟相关,获取lcd时钟 info->clk = clk_get(&pdev->dev, "lcd"); // 未修改前info->clk = clk_get(NULL, "lcd"); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed to get lcd clock source\n"); ret = PTR_ERR(info->clk); goto release_regs; } clk_prepare_enable(info->clk); // 时钟使能 dprintk("got and enabled clock\n"); usleep_range(1000, 1100); info->clk_rate = clk_get_rate(info->clk); // 获取时钟频率 /* find maximum required memory size for display */ for (i = 0; i < mach_info->num_displays; i++) { unsigned long smem_len = mach_info->displays[i].xres; smem_len *= mach_info->displays[i].yres; smem_len *= mach_info->displays[i].bpp; smem_len >>= 3; if (fbinfo->fix.smem_len < smem_len) fbinfo->fix.smem_len = smem_len; } /* Initialize video memory */ ret = s3c2410fb_map_video_memory(fbinfo); //为framgebuffer缓冲区动态申请内存空间,物理地址为fbinfo->fix.smem_start,虚拟地址为fbinfo->screen_base,大小为页对齐(fbinbfo->fix.smem_len) if (ret) { dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; goto release_clock; } dprintk("got video memory\n"); fbinfo->var.xres = display->xres; fbinfo->var.yres = display->yres; fbinfo->var.bits_per_pixel = display->bpp; // s3c2410fb_init_registers(fbinfo); // 设置GPIO,配置GPCUP、GPCCON、GPDUP、GPDCON为LCD功能 实际上就是给寄存器赋值,值来自smdk2440_fb_info中设置的值 s3c2410fb_check_var(&fbinfo->var, fbinfo); ret = s3c2410fb_cpufreq_register(info); // 根据LCD可变参数、lefrt_margin、right_margin、以及LCD控制器时钟频率(HCLK),计算LCD控制器时序参数,并设置相应控制寄存器值 s3c2410fb_calculate_tft_lcd_regs if (ret < 0) { dev_err(&pdev->dev, "Failed to register cpufreq\n"); goto free_video_memory; } ret = register_framebuffer(fbinfo); // 注册设备 if (ret < 0) { dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n", ret); goto free_cpufreq; } /* create device files */ ret = device_create_file(&pdev->dev, &dev_attr_debug); if (ret) dev_err(&pdev->dev, "failed to add debug attribute\n"); dev_info(&pdev->dev, "fb%d: %s frame buffer device\n", fbinfo->node, fbinfo->fix.id); return 0; free_cpufreq: s3c2410fb_cpufreq_deregister(info); free_video_memory: s3c2410fb_unmap_video_memory(fbinfo); release_clock: clk_disable_unprepare(info->clk); clk_put(info->clk); release_regs: iounmap(info->io); release_mem: release_mem_region(res->start, size); dealloc_fb: framebuffer_release(fbinfo); return ret; }
三、烧录开发板测试
3.1 配置启动logo
执行如下命令:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# make menuconfig
配置内核,显示启动logo:
Device Drivers ---> Graphics support ---> [*] Bootup logo ---> Frame buffer Devices ---> <*> Support for frame buffer devices ---> <*> S3C2410 LCD framebuffer support // 支持S3C2410、S3C2440
保存文件,输入文件名s3c2440_defconfig,在当前路径下生成s3c2440_defconfig:存档:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# mv s3c2440_defconfig ./arch/arm/configs/
3.2 编译内核
此时重新执行:
root@zhengyang:/work/sambashare/linux-5.2.8-dt#make distclean root@zhengyang:/work/sambashare/linux-5.2.8-dt#make s3c2440_defconfig root@zhengyang:/work/sambashare/linux-5.2.8-dt#make uImage V=1
将uImage复制到tftp服务器路径下:、
root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/uImage /work/tftpboot/
3.3 编译dts
在linux内核根目录执行如下命令:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# make dtbs DTC arch/arm/boot/dts/s3c2416-smdk2416.dtb DTC arch/arm/boot/dts/s3c2440-smdk2440.dtb
编译设备树文件,把前面配置过的arch/arm/boot/dts里的dts文件编译成dtb文件。
将s3c2440-smdk2440.dtb复制到tftp服务器路径下:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts/s3c2440-smdk2440.dtb /work/tftpboot/
3.4 启动内核
uboot启动后,将dtb下载到内存地址0x30001000中:
SMDK2440 # tftp 0x30001000 s3c2440-smdk2440.dtb
注意:我们可以修改uboot源码,扩展一个device_tree分区,然后将dtb文件存储在该分组取中。
然后将内核镜像加载到内存0x30008000地址,并烧录内核到Nand Flash:
SMDK2440 # tftp 30008000 uImage SMDK2440 # nand erase.part kernel SMDK2440 # nand write 30008000 kernel
然后可以使用如下命令启动内核:
SMDK2440 # bootm 0x30008000 - 0x30001000 // 无设备树时,直接bootm 0x30008000 //bootm uImage地址 ramdisk地址 设备树镜像地址
内核启动打印有关LCD信息如下:
... samsung-pinctrl 56000000.pinctrl: found group selector 44 for gpc-8 samsung-pinctrl 56000000.pinctrl: found group selector 45 for gpc-9 samsung-pinctrl 56000000.pinctrl: found group selector 46 for gpc-10 samsung-pinctrl 56000000.pinctrl: found group selector 47 for gpc-11 samsung-pinctrl 56000000.pinctrl: found group selector 48 for gpc-12 samsung-pinctrl 56000000.pinctrl: found group selector 49 for gpc-13 samsung-pinctrl 56000000.pinctrl: found group selector 50 for gpc-14 samsung-pinctrl 56000000.pinctrl: found group selector 51 for gpc-15 samsung-pinctrl 56000000.pinctrl: found group selector 52 for gpd-0 samsung-pinctrl 56000000.pinctrl: found group selector 53 for gpd-1 samsung-pinctrl 56000000.pinctrl: found group selector 54 for gpd-2 samsung-pinctrl 56000000.pinctrl: found group selector 55 for gpd-3 samsung-pinctrl 56000000.pinctrl: found group selector 56 for gpd-4 samsung-pinctrl 56000000.pinctrl: found group selector 57 for gpd-5 samsung-pinctrl 56000000.pinctrl: found group selector 58 for gpd-6 samsung-pinctrl 56000000.pinctrl: found group selector 59 for gpd-7 samsung-pinctrl 56000000.pinctrl: found group selector 60 for gpd-8 samsung-pinctrl 56000000.pinctrl: found group selector 61 for gpd-9 samsung-pinctrl 56000000.pinctrl: found group selector 62 for gpd-10 samsung-pinctrl 56000000.pinctrl: found group selector 63 for gpd-11 samsung-pinctrl 56000000.pinctrl: found group selector 64 for gpd-12 samsung-pinctrl 56000000.pinctrl: found group selector 65 for gpd-13 samsung-pinctrl 56000000.pinctrl: found group selector 66 for gpd-14 samsung-pinctrl 56000000.pinctrl: found group selector 67 for gpd-15 samsung-pinctrl 56000000.pinctrl: found group selector 36 for gpc-0 samsung-pinctrl 56000000.pinctrl: found group selector 37 for gpc-1 samsung-pinctrl 56000000.pinctrl: found group selector 38 for gpc-2 samsung-pinctrl 56000000.pinctrl: found group selector 39 for gpc-3 samsung-pinctrl 56000000.pinctrl: found group selector 40 for gpc-4 samsung-pinctrl 56000000.pinctrl: found group selector 96 for gpg-4 s3c2410-lcd 4d000000.fb: no init pinctrl state samsung-pinctrl 56000000.pinctrl: request pin 44 (gpc-8) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 45 (gpc-9) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 46 (gpc-10) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 47 (gpc-11) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 48 (gpc-12) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 49 (gpc-13) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 50 (gpc-14) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 51 (gpc-15) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 52 (gpd-0) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 53 (gpd-1) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 54 (gpd-2) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 55 (gpd-3) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 56 (gpd-4) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 57 (gpd-5) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 58 (gpd-6) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 59 (gpd-7) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 60 (gpd-8) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 61 (gpd-9) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 62 (gpd-10) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 63 (gpd-11) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 64 (gpd-12) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 65 (gpd-13) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 66 (gpd-14) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 67 (gpd-15) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 36 (gpc-0) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 37 (gpc-1) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 38 (gpc-2) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 39 (gpc-3) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 40 (gpc-4) for 4d000000.fb samsung-pinctrl 56000000.pinctrl: request pin 96 (gpg-4) for 4d000000.fb s3c2410-lcd 4d000000.fb: no sleep pinctrl state s3c2410-lcd 4d000000.fb: no idle pinctrl state OF: no dma-ranges found for node(/fb@4d000000) s3c2410-lcd 4d000000.fb: device is not dma coherent s3c2410-lcd 4d000000.fb: device is not behind an iommu OF: of_irq_parse_one: dev=/fb@4d000000, index=0 OF: parent=/interrupt-controller@4a000000, intsize=4 OF: intspec=0 of_irq_parse_raw: /interrupt-controller@4a000000:00000000,00000000,00000010,00000003 OF: of_irq_parse_raw: ipar=/interrupt-controller@4a000000, size=4 OF: -> addrsize=1 OF: -> got it ! clock-names lcd in index 0 // 时钟名称"lcd"在clock-names属性中索引 PM: Adding info for No Bus:fb0 PM: Adding info for No Bus:vtcon1 Console: switching to colour frame buffer device 30x40 s3c2410-lcd 4d000000.fb: fb0: s3c2410fb frame buffer device ....
内核启动完成后会在显示屏上看到启动logo:
3.5 演示
运行如下命令:
[root@zy:/]# echo hello > /dev/tty1
此时在LCD可以看到有hello显示出来。
此外我们可以重定位控制台到LCD设备,重新启动开发板,在uboot运行过程中按下任意键,然后设定启动参数:
set bootargs "noinitrd console=tty1 console=ttySAC0,115200 root=/dev/nfs rw nfsroot=192.168.0.200:/work/nfs_root/rootfs ip=192.168.0.105:192.168.0.200:192.168.0.1:255.255.255.0::eth0:off" save
重启开发板,此时启动输出信息就会输出到LCD显示屏上:
参考文章
[6]tq2440_dt/drivers/video/fbdev/s3c2410fb.c
[7] tq2440_dt/arch/arm/boot/dts/s3c2440-tq2440-dt.dts