程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

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显示屏上:

参考文章

[1]linux驱动移植-LCD驱动基础

[2]linux驱动移植-LCD设备驱动

[3]linux驱动移植-LCD触摸屏设备驱动

[4]第六课:在LCD驱动中使用设备树

[5]基于设备树的TQ2440触摸屏驱动移植

[6]tq2440_dt/drivers/video/fbdev/s3c2410fb.c

[7] tq2440_dt/arch/arm/boot/dts/s3c2440-tq2440-dt.dts

[8]tq2440_dt/arch/arm/boot/dts/s3c2440-pinctrl.dtsi

[9]Mini2440裸机开发之LCD基础

[10]Mini2440裸机开发之LCD编程(GB2312、ASCII字库制作)

posted @ 2023-05-05 00:47  大奥特曼打小怪兽  阅读(307)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步