【转载】帧缓冲驱动程序分析及其在BSP上的添加
原文地址:(四)帧缓冲驱动程序分析及其在BSP上的添加 作者:gfvvz

点击(此处)折叠或打开
- /* 修改内容1:LCD接口类型及模式设置
- * BSP中位于 static void __init jason6410_map_io(void){} 函数内。
- */
- /* set the LCD type */
- tmp = __raw_readl(S3C64XX_SPCON);//读取当前SPCON寄存器值
- tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;//清零LCD_SEL[1:0]
- tmp |= S3C64XX_SPCON_LCD_SEL_RGB;//置位最后一位,LCD_SEL[1:0] = 01
- __raw_writel(tmp, S3C64XX_SPCON);//写入LCD_SEL[1:0] = 01的值到SPCON寄存器,“RGB I/F style”
- /* remove the lcd bypass */
- tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);//读取当前MOFPCON寄存器值
- tmp &= ~MIFPCON_LCD_BYPASS;//清零SEL_BYPASS[3]
- __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);//写入SEL_BYPASS[3]已清零的值到MOFPCON寄存器,"normal mode"
点击(此处)折叠或打开
- /* 使用到的宏定义 */
- #define S3C64XX_SPCON_LCD_SEL_MASK (0x3 << 0)
- #define S3C64XX_SPCON_LCD_SEL_RGB (0x1 << 0)
- #define MIFPCON_LCD_BYPASS(1 << 3)
点击(此处)折叠或打开
- /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
- static struct s3c_fb_platdata jason6410_lcd_pdata __initdata = {
- .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,//配置数据信号线GPIO
- .win[0] = &jason6410_fb_win0,//LCD屏参数
- .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,//配置VIDCON0寄存器
- .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,//配置VIDCON1寄存器
- };
- //配置LCD数据信号线GPIO
- extern void s3c64xx_fb_gpio_setup_24bpp(void)
- {
- s3c_gpio_cfgrange_nopull(S3C64XX_GPI(0), 16, S3C_GPIO_SFN(2));//GPI
- s3c_gpio_cfgrange_nopull(S3C64XX_GPJ(0), 12, S3C_GPIO_SFN(2));//GPJ
- }
点击(此处)折叠或打开
- /* 使用到的宏定义 */
- #define VIDCON0_VIDOUT_RGB (0x0 << 26) //见下图2
- #define VIDCON0_PNRMODE_RGB(0x0 << 17)//见下图3
- #define VIDCON1_INV_HSYNC(1 << 6)//见下图4
- #define VIDCON1_INV_VSYNC(1 << 5)//见下图4





点击(此处)折叠或打开
- static struct s3c_fb_pd_win jason6410_fb_win0 = {
- /* this is to ensure we use win0 */
- .win_mode = {
- #if 0
- .pixclock = 115440,//pixel clock in ps (pico seconds)
- #endif
- .left_margin = 0x03,//time from sync to picture
- .right_margin = 0x02,//time from picture to sync
- .upper_margin = 0x01,//time from sync to picture
- .lower_margin = 0x01,//time from picture to sync
- .hsync_len = 0x28,//length of horizontal sync
- .vsync_len = 0x01,//length of vertical sync
- .xres = 480,
- .yres = 272,
- },
- .max_bpp = 32,
- .default_bpp = 16,
- };
- 附:下图摘自内核里的Documentation/fb/framebuffer.txt
- Video Mode Timings
- +----------+---------------------------------------------+----------+-------+
- | | ↑ | | |
- | | |upper_margin | | |
- | | ↓ | | |
- +----------###############################################----------+-------+
- | # ↑ # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | left # | # right | hsync |
- | margin # | xres # margin | len |
- |<-------->#<---------------+--------------------------->#<-------->|<----->|
- | # | # | |
- | # | # | |
- | # | # | |
- | # |yres # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # | # | |
- | # ↓ # | |
- +----------###############################################----------+-------+
- | | ↑ | | |
- | | |lower_margin | | |
- | | ↓ | | |
- +----------+---------------------------------------------+----------+-------+
- | | ↑ | | |
- | | |vsync_len | | |
- | | ↓ | | |
- +----------+---------------------------------------------+----------+-------+
点击(此处)折叠或打开
- static struct s3c_fb_pd_win jason6410_fb_win0 = {
- /* this is to ensure we use win0 */
- .win_mode = {
- #if 0
- .pixclock = 115440,
- #endif
- .left_margin = 0x03,
- .right_margin = 0x02,
- .upper_margin = 0x01,
- .lower_margin = 0x01,
- .hsync_len = 0x28,
- .vsync_len = 0x01,
- .xres = 480,
- .yres = 272,
- },
- .max_bpp = 32,
- .default_bpp = 16,
- };
- /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
- static struct s3c_fb_platdata jason6410_lcd_pdata __initdata = {
- .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
- .win[0] = &jason6410_fb_win0,
- .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
- .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
- };
- //static void __init jason6410_machine_init(void)函数中:
- s3c_fb_set_platdata(&jason6410_lcd_pdata);
参看arch/arm/plat-samsung/devs.c中FB部分,如下代码。
点击(此处)折叠或打开
- /* FB */
- #ifdef CONFIG_S3C_DEV_FB
- static struct resource s3c_fb_resource[] = {
- [0] = DEFINE_RES_MEM(S3C_PA_FB, SZ_16K),
- [1] = DEFINE_RES_IRQ(IRQ_LCD_VSYNC),
- [2] = DEFINE_RES_IRQ(IRQ_LCD_FIFO),
- [3] = DEFINE_RES_IRQ(IRQ_LCD_SYSTEM),
- };
- struct platform_device s3c_device_fb = {
- .name = "s3c-fb",
- .id = -1,
- .num_resources = ARRAY_SIZE(s3c_fb_resource),
- .resource = s3c_fb_resource,
- .dev = {
- .dma_mask = &samsung_device_dma_mask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- };
- void __init s3c_fb_set_platdata(struct s3c_fb_platdata *pd)
- {
- s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),
- &s3c_device_fb);
- }
- #endif /* CONFIG_S3C_DEV_FB */
最终,设置完s3c_device_fb平台设备结构体,结构体之间的关系如下:
点击(此处)折叠或打开
- //1. s3c_device_fb平台设备结构体
- struct platform_device s3c_device_fb = {
- .name = "s3c-fb",
- .id = -1,
- .num_resources = ARRAY_SIZE(s3c_fb_resource),
- .resource = s3c_fb_resource,
- .dev = {
- .dma_mask = &samsung_device_dma_mask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- };
- //2. s3c_device_fb平台设备结构体中的resource结构体
- static struct resource s3c_fb_resource[] = {
- [0] = DEFINE_RES_MEM(S3C_PA_FB, SZ_16K),
- [1] = DEFINE_RES_IRQ(IRQ_LCD_VSYNC),
- [2] = DEFINE_RES_IRQ(IRQ_LCD_FIFO),
- [3] = DEFINE_RES_IRQ(IRQ_LCD_SYSTEM),
- };
- //3. s3c_device_fb平台设备结构体中的dev结构体里私有数据指针所指向的平台私有数据
- static struct s3c_fb_platdata jason6410_lcd_pdata __initdata = {
- .setup_gpio= s3c64xx_fb_gpio_setup_24bpp,
- .win[0]= &jason6410_fb_win0,
- .vidcon0= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
- .vidcon1= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
- };
- //4. 平台私有数据jason6410_lcd_pdata结构体里的window_settings结构体
- static struct s3c_fb_pd_win jason6410_fb_win0 = {
- /* this is to ensure we use win0 */
- .win_mode= {
- #if 0
- .pixclock= 115440,
- #endif
- .left_margin= 0x03,
- .right_margin= 0x02,
- .upper_margin= 0x01,
- .lower_margin= 0x01,
- .hsync_len= 0x28,
- .vsync_len= 0x01,
- .xres= 480,
- .yres= 272,
- },
- .max_bpp= 32,
- .default_bpp= 16,
- };
- /*
- * 实际上,相当于有如下三个红色标注的结构体
- * 1. 在jason6410_machine_init函数里的platform_add_devices函数注册s3c_device_fb平台设备结构体;
- * 2. 通过私有数据指针找到jason6410_lcd_pdata结构体;
- * 3. 通过s3c_fb_pd_win结构体指针,找到
jason6410_fb_win0结构体; - */
- struct platform_device s3c_device_fb = {
- .name= "s3c-fb",
- .id= -1,
- .num_resources= ARRAY_SIZE(s3c_fb_resource),
- .resource= {
- [0] = DEFINE_RES_MEM(S3C_PA_FB, SZ_16K),
- [1] = DEFINE_RES_IRQ(IRQ_LCD_VSYNC),
- [2] = DEFINE_RES_IRQ(IRQ_LCD_FIFO),
- [3] = DEFINE_RES_IRQ(IRQ_LCD_SYSTEM),
- }
- .dev= {
- .platform_data= &jason6410_lcd_pdata,
- .dma_mask= &samsung_device_dma_mask,
- .coherent_dma_mask= DMA_BIT_MASK(32),
- },
- };
- static struct s3c_fb_platdata jason6410_lcd_pdata __initdata = {
- .setup_gpio= s3c64xx_fb_gpio_setup_24bpp,
- .win[0]= &jason6410_fb_win0,
- .vidcon0= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
- .vidcon1= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
- };
- static struct s3c_fb_pd_win jason6410_fb_win0 = {
- /* this is to ensure we use win0 */
- .win_mode= {
- #if 0
- .pixclock= 115440,
- #endif
- .left_margin= 0x03,
- .right_margin= 0x02,
- .upper_margin= 0x01,
- .lower_margin= 0x01,
- .hsync_len= 0x28,
- .vsync_len= 0x01,
- .xres= 480,
- .yres= 272,
- },
- .max_bpp= 32,
- .default_bpp= 16,
- };
点击(此处)折叠或打开
- /* linux/arch/arm/mach-s3c64xx/mach-jason6410.c
- *
- * Copyright 2012 Jason Lu <gfvvz@yahoo.com.cn>
- * http://jason2012.blog.chinaunix.net
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/fb.h>
- #include <linux/gpio.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
- #include <linux/dm9000.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
- #include <linux/serial_core.h>
- #include <linux/types.h>
- #include <asm/mach-types.h>
- #include <asm/mach/arch.h>
- #include <asm/mach/map.h>
- #include <mach/map.h>
- #include <mach/regs-gpio.h>
- #include <mach/regs-modem.h>
- #include <mach/regs-srom.h>
- #include <plat/s3c6410.h>
- #include <plat/adc.h>
- #include <plat/cpu.h>
- #include <plat/devs.h>
- #include <plat/fb.h>
- #include <plat/nand.h>
- #include <plat/regs-serial.h>
- #include <plat/ts.h>
- #include <plat/regs-fb-v4.h>
- #include <plat/iic.h>
- #include <video/platform_lcd.h>
- #define UCON S3C2410_UCON_DEFAULT
- #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
- #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
- static struct s3c2410_uartcfg jason6410_uartcfgs[] __initdata = {
- [0] = {
- .hwport= 0,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
- },
- [1] = {
- .hwport = 1,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
- },
- [2] = {
- .hwport = 2,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
- },
- [3] = {
- .hwport = 3,
- .flags = 0,
- .ucon = UCON,
- .ulcon = ULCON,
- .ufcon = UFCON,
- },
- };
- /* Framebuffer. */
- static struct s3c_fb_pd_win jason6410_fb_win0 = {
- /* this is to ensure we use win0 */
- .win_mode = {
- #if 0
- .pixclock = 115440,
- #endif
- .left_margin = 0x03,
- .right_margin= 0x02,
- .upper_margin= 0x01,
- .lower_margin= 0x01,
- .hsync_len = 0x28,
- .vsync_len = 0x01,
- .xres = 480,
- .yres = 272,
- },
- .max_bpp = 32,
- .default_bpp = 16,
- };
- /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
- static struct s3c_fb_platdata jason6410_lcd_pdata __initdata = {
- .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
- .win[0] = &jason6410_fb_win0,
- .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
- .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
- };
- /* Nand flash */
- static struct mtd_partition jason6410_nand_part[] = {
- {
- .name = "u-boot-2011.06",
- .offset = 0,
- .size = (4 * 128 *SZ_1K),
- .mask_flags = MTD_CAP_NANDFLASH,
- },
- {
- .name = "Linux Kernel 3.2.8",
- .offset = MTDPART_OFS_APPEND,
- .size = (5*SZ_1M) ,
- .mask_flags = MTD_CAP_NANDFLASH,
- },
- {
- .name = "UBI File System",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- }
- };
- static struct s3c2410_nand_set jason6410_nand_sets[] = {
- [0] = {
- .name = "nand",
- .nr_chips = 1,
- .nr_partitions = ARRAY_SIZE(jason6410_nand_part),
- .partitions = jason6410_nand_part,
- },
- };
- static struct s3c2410_platform_nand jason6410_nand_info = {
- .tacls= 25,
- .twrph0 = 55,
- .twrph1 = 40,
- .nr_sets = ARRAY_SIZE(jason6410_nand_sets),
- .sets = jason6410_nand_sets,
- };
- static struct platform_device *jason6410_devices[] __initdata = {
- &s3c_device_nand,
- &s3c_device_i2c0,
- &s3c_device_fb,
- };
- static struct i2c_board_info i2c_devs0[] __initdata = {
- { I2C_BOARD_INFO("24c08", 0x50), },
- };
- static struct i2c_board_info i2c_devs1[] __initdata = {
- /* Add your i2c device here */
- };
- static void __init jason6410_map_io(void)
- {
- u32 tmp;
- s3c64xx_init_io(NULL, 0);
- s3c24xx_init_clocks(12000000);
- s3c24xx_init_uarts(jason6410_uartcfgs, ARRAY_SIZE(jason6410_uartcfgs));
- /* set the LCD type */
- tmp = __raw_readl(S3C64XX_SPCON);
- tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
- tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
- __raw_writel(tmp, S3C64XX_SPCON);
- /* remove the lcd bypass */
- tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
- tmp &= ~MIFPCON_LCD_BYPASS;
- __raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
- }
- static void __init jason6410_machine_init(void)
- {
- s3c_device_nand.name = "s3c6410-nand";
- s3c_nand_set_platdata(&jason6410_nand_info);
- s3c_i2c0_set_platdata(NULL);
- s3c_fb_set_platdata(&jason6410_lcd_pdata);
- if (ARRAY_SIZE(i2c_devs0)) {
- i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
- }
- if (ARRAY_SIZE(i2c_devs1)) {
- i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
- }
- platform_add_devices(jason6410_devices, ARRAY_SIZE(jason6410_devices));
- }
- MACHINE_START(JASON6410, "JASON6410")
- /* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
- .atag_offset = 0x100,
- .init_irq= s3c6410_init_irq,
- .map_io = jason6410_map_io,
- .init_machine = jason6410_machine_init,
- .timer = &s3c24xx_timer,
- MACHINE_END
4、帧缓冲平台驱动
点击(此处)折叠或打开
- //平台设备设备与驱动匹配函数
- static int platform_match(struct device *dev, struct device_driver *drv)
- {
- struct platform_device *pdev = to_platform_device(dev);
- struct platform_driver *pdrv = to_platform_driver(drv);
- /* Attempt an OF style match first */
- if (of_driver_match_device(dev, drv))
- return 1;
- /* Then try to match against the id table */
- if (pdrv->id_table)
- return platform_match_id(pdrv->id_table, pdev) != NULL;
- /* fall-back to driver name match */
- return (strcmp(pdev->name, drv->name) == 0);
- }
- //platform_match_id函数
- static const struct platform_device_id *platform_match_id(
- const struct platform_device_id *id,
- struct platform_device *pdev)
- {
- while (id->name[0]) {
- if (strcmp(pdev->name, id->name) == 0) {
- pdev->id_entry = id;
- return id;
- }
- id++;
- }
- return NULL;
- }
点击(此处)折叠或打开
- //@driver/video/s3c-fb.c
- //s3c_fb_driver平台驱动结构体
- static struct platform_driver s3c_fb_driver = {
- .probe = s3c_fb_probe,
- .remove = __devexit_p(s3c_fb_remove),
- .id_table = s3c_fb_driver_ids,
- .driver = {
- .name = "s3c-fb",
- .owner= THIS_MODULE,
- .pm = &s3cfb_pm_ops,
- },
- };
- //s3c_fb_driver平台驱动结构体注册
- static int __init s3c_fb_init(void)
- {
- return platform_driver_register(&s3c_fb_driver);
- }
- //s3c_fb_driver平台驱动结构体id_table
- static struct platform_device_id s3c_fb_driver_ids[] = {
- {
- .name= "s3c-fb",//匹配平台设备名的名字
- .driver_data= (unsigned long)&s3c_fb_data_64xx,
- }, {
- .name= "s5pc100-fb",
- .driver_data= (unsigned long)&s3c_fb_data_s5pc100,
- }, {
- .name= "s5pv210-fb",
- .driver_data= (unsigned long)&s3c_fb_data_s5pv210,
- }, {
- .name= "exynos4-fb",
- .driver_data= (unsigned long)&s3c_fb_data_exynos4,
- }, {
- .name= "s3c2443-fb",
- .driver_data= (unsigned long)&s3c_fb_data_s3c2443,
- }, {
- .name= "s5p64x0-fb",
- .driver_data= (unsigned long)&s3c_fb_data_s5p64x0,
- },
- {},
- };
- //平台设备ID结构体中的驱动数据
- static struct s3c_fb_driverdata s3c_fb_data_64xx = {
- .variant = {
- .nr_windows= 5,
- .vidtcon= VIDTCON0,
- .wincon= WINCON(0),
- .winmap= WINxMAP(0),
- .keycon= WKEYCON,
- .osd= VIDOSD_BASE,
- .osd_stride= 16,
- .buf_start= VIDW_BUF_START(0),
- .buf_size= VIDW_BUF_SIZE(0),
- .buf_end= VIDW_BUF_END(0),
- .palette = {
- [0] = 0x400,
- [1] = 0x800,
- [2] = 0x300,
- [3] = 0x320,
- [4] = 0x340,
- },
- .has_prtcon= 1,
- .has_clksel= 1,
- },
- .win[0]= &s3c_fb_data_64xx_wins[0],
- .win[1]= &s3c_fb_data_64xx_wins[1],
- .win[2]= &s3c_fb_data_64xx_wins[2],
- .win[3]= &s3c_fb_data_64xx_wins[3],
- .win[4]= &s3c_fb_data_64xx_wins[4],
- };
点击(此处)折叠或打开
- static int __devinit s3c_fb_probe(struct platform_device *pdev)
- {
- const struct platform_device_id *platid;
- struct s3c_fb_driverdata *fbdrv;
- struct device *dev = &pdev->dev;
- struct s3c_fb_platdata *pd;
- struct s3c_fb *sfb;
- struct resource *res;
- int win;
- int ret = 0;
- //platid指向平台设备结构体里的id_entry成员,即
platid = pdev->id_entry; - platid = platform_get_device_id(pdev);
- //fbdrv指向平台设备结构体id_entry项的driver_data成员
- fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
- //判断是否超出最大硬件支持的最大窗口数
- if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
- dev_err(dev, "too many windows, cannot attach\n");
- return -EINVAL;
- }
- //指向平台设备的平台数据
- pd = pdev->dev.platform_data;
- if (!pd) {
- dev_err(dev, "no platform data specified\n");
- return -EINVAL;
- }
- //1. 给s3c_fb结构体分配内存
- sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
- if (!sfb) {
- dev_err(dev, "no memory for framebuffers\n");
- return -ENOMEM;
- }
- dev_dbg(dev, "allocate new framebuffer %p\n", sfb);
- //2. 设置s3c_fb结构体
- sfb->dev = dev; //指向设备
- sfb->pdata = pd; //指向平台设备的平台数据
- sfb->variant = fbdrv->variant; //s3c_fb_variant结构体拷贝(结构体完全一样可直接拷贝)
- spin_lock_init(&sfb->slock); //初始化自旋锁
- //3. 获取并使能模块总时钟
- sfb->bus_clk = clk_get(dev, "lcd");//找到对应的bus clock,模块总时钟
- if (IS_ERR(sfb->bus_clk)) {
- dev_err(dev, "failed to get bus clock\n");
- ret = PTR_ERR(sfb->bus_clk);
- goto err_sfb;
- }
- clk_enable(sfb->bus_clk);//使能模块总时钟
- if (!sfb->variant.has_clksel) {//判断driver_data里是否已定义源时钟
- sfb->lcd_clk = clk_get(dev, "sclk_fimd");//未定义,用“sclk_fimd”去clock文件里找
- if (IS_ERR(sfb->lcd_clk)) {
- dev_err(dev, "failed to get lcd clock\n");
- ret = PTR_ERR(sfb->lcd_clk);
- goto err_bus_clk;
- }
- clk_enable(sfb->lcd_clk); //使能clock文件里找到的时钟源
- }
- pm_runtime_enable(sfb->dev); //使能设备运行时电源管理
- //4. 获取平台设备数据
- //获取资源起始地址、结束地址,是显示控制器寄存器组地址
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "failed to find registers\n");
- ret = -ENOENT;
- goto err_lcd_clk;
- }
- //为显示控制器寄存器组分配内存
- sfb->regs_res = request_mem_region(res->start, resource_size(res),
- dev_name(dev));
- if (!sfb->regs_res) {
- dev_err(dev, "failed to claim register region\n");
- ret = -ENOENT;
- goto err_lcd_clk;
- }
- //把寄存器组地址映射到内存
- //注:这里使用ioremap,所以,BSP中不需要编写针对LCD的I/O内存静态映射;
- // 即static struct map_desc jason6410_iodesc[]{};里面这部分。
- sfb->regs = ioremap(res->start, resource_size(res));
- if (!sfb->regs) {
- dev_err(dev, "failed to map registers\n");
- ret = -ENXIO;
- goto err_req_region;
- }
- //获取资源中的中断部分
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(dev, "failed to acquire irq resource\n");
- ret = -ENOENT;
- goto err_ioremap;
- }
- sfb->irq_no = res->start;
- ret = request_irq(sfb->irq_no, s3c_fb_irq,//注册中断处理函数
- 0, "s3c_fb", sfb);
- if (ret) {
- dev_err(dev, "irq request failed\n");
- goto err_ioremap;
- }
- dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
- //pdev->dev->p->driver_data = sfb
- platform_set_drvdata(pdev, sfb);
- //运行时恢复操作的入口
- pm_runtime_get_sync(sfb->dev);
- /* setup gpio and output polarity controls */
- //5. 设置寄存器组
- pd->setup_gpio(); //设置数据线的GPIO,pd见23行,即s3c64xx_fb_gpio_setup_24bpp,见BSP
- writel(pd->vidcon1, sfb->regs + VIDCON1); //写VIDCON1寄存器
- /* zero all windows before we do anything */
- for (win = 0; win < fbdrv->variant.nr_windows; win++) //复位所有窗口寄存器
- s3c_fb_clear_win(sfb, win);
- /* initialise colour key controls */ //初始化
- for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
- void __iomem *regs = sfb->regs + sfb->variant.keycon;
- regs += (win * 8);//GNU下空指针可以算数运算,并且算法操作与char *一致
- writel(0xffffff, regs + WKEYCON0); //详见S3C6410X.pdf 516页
- writel(0xffffff, regs + WKEYCON1);
- }
- /* we have the register setup, start allocating framebuffers */
- //6. 设置完寄存器,开始分配帧缓冲
- for (win = 0; win < fbdrv->variant.nr_windows; win++) {
- if (!pd->win[win])
- continue;
- if (!pd->win[win]->win_mode.pixclock) //如果未定义像素时钟,在此计算
- s3c_fb_missing_pixclock(&pd->win[win]->win_mode); //计算像素时钟
- //注册硬件窗口,下面展开细说
- ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
- &sfb->windows[win]);
- if (ret < 0) {
- dev_err(dev, "failed to create window %d\n", win);
- for (; win >= 0; win--)
- s3c_fb_release_win(sfb, sfb->windows[win]);
- goto err_irq;
- }
- }
- //再一次,同line 112/114
- platform_set_drvdata(pdev, sfb);
- pm_runtime_put_sync(sfb->dev);
- return 0;
- err_irq:
- free_irq(sfb->irq_no, sfb);
- err_ioremap:
- iounmap(sfb->regs);
- err_req_region:
- release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
- err_lcd_clk:
- if (!sfb->variant.has_clksel) {
- clk_disable(sfb->lcd_clk);
- clk_put(sfb->lcd_clk);
- }
- err_bus_clk:
- clk_disable(sfb->bus_clk);
- clk_put(sfb->bus_clk);
- err_sfb:
- kfree(sfb);
- return ret;
- }
4.3 s3c_fb_probe_win函数分析(注册硬件窗口)
点击(此处)折叠或打开
- /**
- * s3c_fb_probe_win() - register an hardware window
- * @sfb: The base resources for the hardware
- * @variant: The variant information for this window.
- * @res: Pointer to where to place the resultant window.
- *
- * Allocate and do the basic initialisation for one of the hardware's graphics
- * windows.
- */
- static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
- struct s3c_fb_win_variant *variant,
- struct s3c_fb_win **res)
- {
- struct fb_var_screeninfo *var;
- struct fb_videomode *initmode;
- struct s3c_fb_pd_win *windata;
- struct s3c_fb_win *win;
- struct fb_info *fbinfo;
- int palette_size;
- int ret;
- dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
- init_waitqueue_head(&sfb->vsync_info.wait); //初始化等待队列头
- palette_size = variant->palette_sz * 4; //设置调色板大小
- //1.创建fb_info结构体,并分配驱动私有数据
- fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
- palette_size * sizeof(u32), sfb->dev);
- if (!fbinfo) {
- dev_err(sfb->dev, "failed to allocate framebuffer\n");
- return -ENOENT;
- }
- //windata指向平台设备驱动私有数据里的win[win_no]成员,这里是BSP中的jason6410_fb_win0结构体
- //initmode指向jason6410_fb_win结构体里的win_mode成员
点击(此处)折叠或打开
- static struct s3c_fb_pd_win jason6410_fb_win0 = {
- /* this is to ensure we use win0 */
- .win_mode = {
- #if 0
- .pixclock = 115440,
- #endif
- .left_margin = 0x03,
- .right_margin = 0x02,
- .upper_margin = 0x01,
- .lower_margin = 0x01,
- .hsync_len = 0x28,
- .vsync_len = 0x01,
- .xres = 480,
- .yres = 272,
- },
- .max_bpp = 32,
- .default_bpp = 16,
- };
- windata = sfb->pdata->win[win_no];
- initmode = &windata->win_mode;
- WARN_ON(windata->max_bpp == 0);//调用dump_stack,打印堆栈信息
- WARN_ON(windata->win_mode.xres == 0);
- WARN_ON(windata->win_mode.yres == 0);
- //2. 帧缓冲每个窗口的s3c_fb_win结构体设置
- win = fbinfo->par; //见代码30行分配fb_info结构体部分,在那fbinfo->par已指向驱动私有数据
- *res = win;//*res指向win
- var = &fbinfo->var; //var指向fb_var_screeninfo结构体
- win->variant = *variant;//结构体复制(同一类型结构体可以复制)
- win->fbinfo = fbinfo;//fbinfo指向fb_info结构体
- win->parent = sfb;//parent指向s3c_fb结构体
- win->windata = windata; //windata指向s3c_fb_pd_win结构体
- win->index = win_no;//编号
- win->palette_buffer = (u32 *)(win + 1); //指向调色板缓冲区
- //3. 为帧缓冲的窗口分配显示内存
- ret = s3c_fb_alloc_memory(sfb, win);
- if (ret) {
- dev_err(sfb->dev, "failed to allocate display memory\n");
- return ret;
- }
- /* setup the r/b/g positions for the window's palette */
- //4. 为窗口调色板设置r/g/b的位置,这里的palette_16bpp为初始化值1,程序中未对其赋值
点击(此处)折叠或打开
- //该结构体位于4.1节
- struct s3c_fb_win_variant {
- unsigned int has_osd_c:1;
- unsigned int has_osd_d:1;
- unsigned int has_osd_alpha:1;
- unsigned int palette_16bpp:;
- unsigned short osd_size_off;
- unsigned short palette_sz;
- u32 valid_bpp;
- };
- if (win->variant.palette_16bpp) {
- /* Set RGB 5:6:5 as default */
- win->palette.r.offset = 11;
- win->palette.r.length = 5;
- win->palette.g.offset = 5;
- win->palette.g.length = 6;
- win->palette.b.offset = 0;
- win->palette.b.length = 5;
- } else {
- /* Set 8bpp or 8bpp and 1bit alpha */
- win->palette.r.offset = 16;
- win->palette.r.length = 8;
- win->palette.g.offset = 8;
- win->palette.g.length = 8;
- win->palette.b.offset = 0;
- win->palette.b.length = 8;
- }
- /* setup the initial video mode from the window */
- //5. 设置初始视频模式,填充结构体fbinfo
- //将fb_videomode结构体中成员赋值给fb_var_screeninfo结构体对应成员
- fb_videomode_to_var(&fbinfo->var, initmode);
- fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
- fbinfo->fix.accel = FB_ACCEL_NONE;
- fbinfo->var.activate = FB_ACTIVATE_NOW;
- fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
- fbinfo->var.bits_per_pixel = windata->default_bpp;
- fbinfo->fbops = &s3c_fb_ops;
- fbinfo->flags = FBINFO_FLAG_DEFAULT;
- fbinfo->pseudo_palette = &win->pseudo_palette;
- /* prepare to actually start the framebuffer */
- //6. 检查可变参数,帧缓冲层核实信息,并根据硬件能力更新几种信息。
- ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
- if (ret < 0) {
- dev_err(sfb->dev, "check_var failed on initial video params\n");
- return ret;
- }
- /* create initial colour map */
- //7. 分配和设置fb_cmap结构体,该结构体记录设备无关的颜色表信息
- ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
- if (ret == 0)
- fb_set_cmap(&fbinfo->cmap, fbinfo);
- else
- dev_err(sfb->dev, "failed to allocate fb cmap\n");
- //8. 设置帧缓冲模式
- s3c_fb_set_par(fbinfo);
- dev_dbg(sfb->dev, "about to register framebuffer\n");
- /* run the check_var and set_par on our configuration. */
- //9. 注册一个帧缓冲设备
- ret = register_framebuffer(fbinfo);
- if (ret < 0) {
- dev_err(sfb->dev, "failed to register framebuffer\n");
- return ret;
- }
- dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
- return 0;
- }
点击(此处)折叠或打开
- /*
- * S3C6410 framebuffer test programs
- */
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <linux/fb.h>
- #include <sys/mman.h>
- int main()
- {
- int fbfd = 0;
- struct fb_var_screeninfo vinfo;
- unsigned long screensize = 0;
- char *fbp = 0;
- int x = 0, y = 0;
- int i = 0;
- // Open the file for reading and writing
- fbfd = open("/dev/fb0", O_RDWR);
- if (!fbfd) {
- printf("Error: cannot open framebuffer device.\n");
- exit(1);
- }
- printf("The framebuffer device was opened successfully.\n");
- // Get variable screen information
- if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
- printf("Error reading variable information.\n");
- exit(1);
- }
- printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
- if (vinfo.bits_per_pixel != 16) {
- printf("Error: not supported bits_per_pixel, it only supports 16 bit color\n");
- exit(1);
- }
- // Figure out the size of the screen in bytes
- screensize = vinfo.xres * vinfo.yres * 2;
- // Map the device to memory
- fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
- fbfd, 0);
- if ((int)fbp == -1) {
- printf("Error: failed to map framebuffer device to memory.\n");
- exit(4);
- }
- printf("The framebuffer device was mapped to memory successfully.\n");
- // Draw 3 rect with graduated RED/GREEN/BLUE
- for (i = 0; i < 3; i++) {
- for (y = i * (vinfo.yres / 3); y < (i + 1) * (vinfo.yres / 3); y++) {
- for (x = 0; x < vinfo.xres; x++) {
- long location = x * 2 + y * vinfo.xres * 2;
- int r = 0, g = 0, b = 0;
- unsigned short rgb;
- if (i == 0)
- r = ((x * 1.0) / vinfo.xres) * 32;
- if (i == 1)
- g = ((x * 1.0) / vinfo.xres) * 64;
- if (i == 2)
- b = ((x * 1.0) / vinfo.xres) * 32;
- rgb = (r << 11) | (g << 5) | b;
- *((unsigned short*)(fbp + location)) = rgb;
- }
- }
- }
- munmap(fbp, screensize);
- close(fbfd);
- return 0;
- }



点击(此处)折叠或打开
- gedit arch/arm/plat-samsung/include/plat/map-base.h
- line 39 add:
- #define S3C_VA_LCD S3C_ADDR(0x01100000) /* LCD */
在BSP中添加:
点击(此处)折叠或打开
- static struct map_desc jason6410_iodesc[] = {
- {
- /* LCD support */
- .virtual = (unsigned long)S3C_VA_LCD,//虚拟地址
- .pfn = __phys_to_pfn(S3C_PA_FB),//物理地址
- .length = SZ_16K,
- .type = MT_DEVICE,
- },
- };
- static void __init jason6410_map_io(void)
- {
- s3c64xx_init_io(jason6410_iodesc, ARRAY_SIZE(jason6410_iodesc)); //初始化
- ......
- }
点击(此处)折叠或打开
- Device Drivers --->
- Graphics support --->
- <*> Support for frame buffer devices --->
- <*> Samsung S3C framebuffer support
- Device Drivers --->
- Graphics support --->
- [ ] Backlight & LCD device support --->
- Device Drivers --->
- Graphics support --->
- Console display driver support --->
- <*> Framebuffer Console support
- Device Drivers --->
- Graphics support --->
- [*] Bootup logo --->




点击(此处)折叠或打开
- # bmptoppm logo.bmp > logo.ppm
- # ppmquant 224 logo.ppm > logo_224.ppm
- # pnmnoraw logo_224.ppm > logo_linux_clut224.ppm
5. 将上一步骤中生成的logo_linux_clut224.ppm拷贝到内核目录:drivers/video/logo/覆盖原有图片。
点击(此处)折叠或打开
- # rm drivers/video/logo/.l*
点击(此处)折叠或打开
- make uImage -j4
点击(此处)折叠或打开
- cat logo_cat.bmp > /dev/fb0
注意:在内核里必须勾选如下选项,不选择,是显示不了启动图片的。
点击(此处)折叠或打开
- Device Drivers --->
- Graphics support --->
- Console display driver support --->
- <*> Framebuffer Console support
附录1:启动界面


善自带的文件系统里有三个界面程序,我试着打开qt4(“/bin/qt4 &”
命令)那个界面时,有错误提示了,先是socket相关错误,就照着友善2.6.38内核的配置,配置了Networking
support下的内核选项。接着报信号量错误,就照着友善的配置在Gernel Setup下配置内核选项。现在能启动界面了。
有一个问题是,友善文件系统里自带的rcS有输出信息输出到显示屏上,不好看。就在文件系统里的etc/init.d/rcS里,把所有 ">
/dev/tty1"都注释掉,这样这些打印信息只会在串口终端里显示,不会影响界面显示了。用如下命令生成新的ubi文件系统。
点击(此处)折叠或打开
- # mkubimage-slc rootfs_qtopia_qt4 rootfs_qtopia_qt4-slc.ubi
【转载】帧缓冲驱动程序分析及其在BSP上的添加的更多相关文章
- OpenGL核心技术之帧缓冲
笔者介绍:姜雪伟.IT公司技术合伙人,IT高级讲师.CSDN社区专家.特邀编辑.畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...
- RT-Thread下的串口驱动程序分析【转载】
编写本文稿的目的,在于通过分析stm32平台上的串口中断源码,学习 RTT中如何编写中断处理程序 如何编写RTT设备驱动接口代码 了解串行设备的常见处理机制 先以RTT官方源码中的STM32 BSP包 ...
- [国嵌攻略][143][LCD驱动程序分析]
LCD驱动程序分析 LCD驱动程序代码在/drivers/video/s3c2410fb.c文件中,在该驱动的s3c2410fb_init中注册了平台驱动,该驱动的初始化代码在s3c24xxfc_pr ...
- android 电容屏(三):驱动调试之驱动程序分析篇
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
- 【转】android 电容屏(三):驱动调试之驱动程序分析篇
关键词:android 电容屏 tp 工作队列 中断 坐点计算 电容屏主要参数平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV310( ...
- Microsoft宣布为Power BI提供AI模型构建器,关键驱动程序分析和Azure机器学习集成
微软的Power BI现在是一种正在大量结合人工智能(AI)的商业分析服务,它使用户无需编码经验或深厚的技术专长就能够创建报告,仪表板等.近日西雅图公司宣布推出几款新的AI功能,包括图像识别和文本分析 ...
- linux PWM蜂鸣器移植以及驱动程序分析【转】
本文转载自:https://blog.csdn.net/lxllinux/article/details/80885331 一.关于PWM: PWM(Pulse Width Modula ...
- c# GDI画图 双缓冲画图分析
双缓冲绘图分析 1.Windows 绘图原理 我们在 Windows 环境下看到各种元素,如菜单.按钮.窗口.图像,从根本上说,都是“画”出来的.这时的屏幕,就相当于一块黑板,而 Windows ...
- Linux中LCD设备驱动-framebuffer(帧缓冲)【】
转自:https://blog.csdn.net/linux_devices_driver/article/details/7079442 1.framebuffer 帧缓冲 帧缓冲(fram ...
随机推荐
- C#中用鼠标移动页面功能的实现(代码控制滚动条)
项目中需要实现以下功能: 打印预览控件中,可以用鼠标拖动页面,以查看超出显示范围之外的部分内容. 该功能本来可以通过拉动水平和垂直滚动条来实现,但实际使用中,用户更趋向于直接用鼠标拖动页面来实现,很多 ...
- Java内存区域与模拟内存区域异常
我把Java的内存区域画了一张思维导图,以及各区域的主要功能. 模拟Java堆溢出 Java堆用于存储对象实例.仅仅要不断地创建对象而且保证GC ROOTS到对象之间有可达路径避免被回收机制清除.就能 ...
- 从头认识java-14.2 进一步了解数组
这一章节我们来全面了解一下数组. 1.数组在初始化之前.我们不能使用他的引用来做不论什么事情. package com.ray.ch14; public class Test { public sta ...
- dede程序打开install安装时出现dir
刚在网上找了个开源的dede程序,打开install安装时出现dir.解决方法例如以下: 1.删除install下的index.html和install_lock.txt(有的是要删除install. ...
- 《C陷阱与缺陷》学习笔记(一)
前言和导读 "得心应手的工具在初学时的困难程度往往超过那些easy上手的工具."比較认同这句话. 我至今认为自己事实上还是个刚入了门的刚開始学习的人. 第一章 "词法&q ...
- iOS 自己定义页面的切换动画与交互动画 By Swift
在iOS7之前,开发人员为了寻求自己定义Navigation Controller的Push/Pop动画,仅仅能受限于子类化一个UINavigationController,或是用自己定义的动画去覆盖 ...
- git 操作分支
1. git 查看本地分支:git branch 2. git 查看所有分支:git branch -a 3. git 新建本地分支:git branch branchName 4. git 新建分支 ...
- mybatis的两种分页方式:RowBounds和PageHelper
原理:拦截器. 使用方法: RowBounds:在mapper.java中的方法中传入RowBounds对象. RowBounds rowBounds = new RowBounds(offset, ...
- jdk并发工具包之锁
1.cynchronized扩展:可重锁入ReentrantLock ReentrantLock是通过cas算法实现的 RenntrantLock lock=new ReentrantLock(); ...
- emacs 简记
简介 Emacs作为神的编辑器,不用介绍了吧,说点感受. 用了一段时间了,总体感觉其实Emacs是很简单的,甚至比vim还简单,因为在X环境下,打开后可以就像记事本一样使用.但是,使用Emacs的人一 ...