编写frame buffer驱动(待续)

开发板:tiny4412(1611) 
内核:linux4.4 

编译器: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320)

参考linux3.5版本的驱动,显示功能一般都是平台设备。

tiny4412-lcds.c  中配置了屏幕的一些参数。mach-tiny4412.c文件中的smdk4x12_machine_init 函数,通过里面的tiny4412_fb_init_pdata(&smdk4x12_lcd0_pdata); 和s5p_fimd0_set_platdata(&smdk4x12_lcd0_pdata); 填充到平台设备s5p_device_fimd0 ;再通过 platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices)); 注册,在exynos4_map_io()函数中通过s5p_fb_setname(0, "exynos4-fb")  把s5p_device_fimd0 设备名称改为exynos4-fb  。
 对应的驱动即是driver/video/s3c-fb.c 。 

static struct resource s5p_fimd0_resource[] = {
        [0] = DEFINE_RES_MEM(S5P_PA_FIMD0, SZ_32K),
        [1] = DEFINE_RES_IRQ(IRQ_FIMD0_VSYNC),
        [2] = DEFINE_RES_IRQ(IRQ_FIMD0_FIFO),
        [3] = DEFINE_RES_IRQ(IRQ_FIMD0_SYSTEM),
};

struct platform_device s5p_device_fimd0 = {
        .name           = "s5p-fb",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(s5p_fimd0_resource),
        .resource       = s5p_fimd0_resource,
        .dev            = {
                .dma_mask               = &samsung_device_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
};

驱动待调试。。。。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <asm/uaccess.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/fb.h>
#include <linux/dma-mapping.h>

#include <video/samsung_fimd.h>

static struct fb_info *fbi=NULL;
//void __iomem   *fb_base;
static volatile void __iomem *regs1=NULL;
static volatile void __iomem *regs2=NULL;
struct clk *sclk=NULL;
struct clk *clk_parent=NULL;

static int s3d_setcolreg(unsigned regno,
                         unsigned red, unsigned green, unsigned blue,
                         unsigned transp, struct fb_info *info)
{
	
       	return 0;
}


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

static int fb_probe(struct platform_device *pdev) {  
	
    	struct device *dev = &pdev->dev;  
    	int ret;
	u32 reg;

    	printk("%s enter.\n", __func__);

        sclk = devm_clk_get(dev,"sclk_fimd");
	if (IS_ERR(sclk)) {
                pr_err("Unable to get clock\n");
                return PTR_ERR(sclk);
        }
	
	clk_parent=devm_clk_get(dev,"mout_mpll_user");
	if (IS_ERR(clk_parent)) {
                pr_err("Unable to get parent clock\n");
                return PTR_ERR(clk_parent);
        }
	
/*	error

	ret=clk_set_parent(sclk, clk_parent);
	if (ret) {
		printk("%d",ret);
                pr_err("Unable to set parent clock \n");
                return PTR_ERR(sclk);
        }
	
	if (clk_set_rate(sclk, 800000000)) {
		pr_err("rate change failed\n");
		return PTR_ERR(sclk);
        }
*/
	clk_prepare(sclk);
    	ret=clk_enable(sclk);

	clk_prepare(clk_parent);
    	ret=clk_enable(clk_parent);

	printk("%ld\n",clk_get_rate(clk_parent));
/*
	res=platform_get_resource(pdev,IORESOURCE_MEM,0);
        if(!res){
                dev_err(dev, "failed to get timer base mem resource\n");
            return -ENOMEM;
        }

        fb_reg=devm_ioremap_resource(dev,res);
        if(fb_reg<0){
                dev_err(dev, "failed to get timer base mem\n");
            return -ENOMEM;
        }
*/

	regs1=ioremap(0x11C00000,0x8000);
	printk("map: %p\n",regs1);
	regs2=ioremap(0x10030000,0xd000);
	printk("map: %p\n",regs2);
	/* output polarity controls */
	
	printk("test\n");
	reg = 0xe0|(1 << 9);
        writel( reg, regs1 + VIDCON1);
	printk("ok\n");
	
	/* set video clock running at under-run */
      
	reg = readl( regs1 + VIDCON1);
	reg &= ~VIDCON1_VCLK_MASK;
	reg |= VIDCON1_VCLK_RUN;
	writel(reg, regs1 + VIDCON1);

	/* zero all windows before we do anything */
	/* initialise colour key controls */
	/* fb set rgb timing */

	/* 1. selcet SCLKMPLL_USER_T 0110 : 800M*/
#define CLK_SRC_LCD0 0xC234
	reg = readl( regs2 + CLK_SRC_LCD0);		//0x1003_0000
    	reg &= ~0x0f;
    	reg |= 0x06;
    	writel( reg, regs2 + CLK_SRC_LCD0);	
	/* 2. set SCLK_FIMD0 divider ratio 1:1 */
#define	CLK_DIV_LCD  0xC534
	reg = readl( regs2 + CLK_DIV_LCD);		//0x1003_0000
        reg &= ~0x0f;
        writel( reg, regs2 + CLK_DIV_LCD);   
	/* 3. set VCLK divider ratio 24:1 =33.3M*/	//Is there others should to set?
	reg = readl( regs1 + VIDCON0);            
        reg &= ~(0xf<<6);
        reg |= 0x17<<6;
        writel( reg, regs1 + VIDCON0);
	/* 4. set horizontal and vertical lcd rgb interface timing */

	//set VBPD VFPD VSFW - 12 21 9	
	reg = readl( regs1 + VIDTCON0);
        reg &= ~(0xfff);
        reg |= (12<<16) | (21<<8) | 9;
        writel( reg, regs1 + VIDTCON0);

	//set HBPD HFPD HSPW - 35 209 9
	reg = readl( regs1 + VIDTCON1);
        reg &= ~(0xfff);
        reg |= (35<<16) | (209<<8) | 9;
        writel( reg, regs1 + VIDTCON1);

	//set LINEVAL HOZVAL - 479 799
        writel( (479<<11) | 799, regs1 + VIDTCON2);
	//VIDTCON3 config the FrameINT ,which is used for double buffer

	/* set data format */

	// 24bpp [5:2]:1011 enable signal [0]:1	
	reg = readl( regs1 + WINCON(0));
        reg &= ~( ( 0b1111 <<2 ) | 1 );
        reg |= ( 0b1011 <<2 ) |1 ;
        writel( reg, regs1 + WINCON(0));

	// enable chanel 0 [0]:1
	reg = readl( regs1 + SHADOWCON);
        reg &= ~ 1 ;
        reg |= 1 ;
        writel( reg, regs1 + SHADOWCON);

	// select chanel [18:16]:1 [2:0]:1
#define WINCHMAP2 0x003C
	reg = readl( regs1 + WINCHMAP2);
        reg &= ~ ( ( 0b111<<16 ) | 0b111);
        reg |=  (1<<16) | 1;
        writel( reg, regs1 + WINCHMAP2);
	
	// set coordinate
	//left top
#define VIDOSD0A 0x0040
        writel( 0, regs1 + VIDOSD0A);

	// right bottom [21:11]:800 [10:0]:480
#define VIDOSD0B 0x0044
	writel( ( 799<<11 ) | 479, regs1 + VIDOSD0B);

	// size
#define VIDOSD0C 0x0048
	writel(  480*800, regs1 + VIDOSD0C);

	/* we have the register setup, start allocating framebuffers */
	fbi = framebuffer_alloc(0, NULL);

	fbi->flags = FBINFO_DEFAULT;
        fbi->fbops = &fb_ops;
        //fbi->screen_base = fb_base;				need to be set
        fbi->screen_size = 800*480*4;

	// fill fix common fields
	strlcpy(fbi->fix.id, "win9_fb", sizeof(fbi->fix.id));
        //fbi->fix.smem_start = sp->fb_base_phys;		need to be set
        fbi->fix.smem_len = 800*480*4;
        fbi->fix.type = FB_TYPE_PLANES;
       	fbi->fix.visual = FB_VISUAL_TRUECOLOR;

	fbi->var.xres = 800;
        fbi->var.yres = 480;
        fbi->var.xres_virtual = 800;
        fbi->var.yres_virtual = 480;
        fbi->var.bits_per_pixel = 32;	//32 or 24 ??

	fbi->var.red.offset = 16;
        fbi->var.red.length = 8;
        fbi->var.green.offset = 8;
        fbi->var.green.length = 8;
        fbi->var.blue.offset = 0;
        fbi->var.blue.length = 8;

	// allocate mem
	fbi->screen_base = dma_alloc_writecombine(dev, fbi->fix.smem_len, (dma_addr_t *)&fbi->fix.smem_start, GFP_KERNEL);

	// start adress of video buffer(win0-0)
#define VIDW00ADD0B0 0x00A0
	writel( fbi->fix.smem_start, regs1 + VIDW00ADD0B0);	//phys_address

	// end address of video buffer(win0-0)
#define VIDW00ADD1B0 0x00D0
        writel( fbi->fix.smem_start + fbi->fix.smem_len , regs1 + VIDW00ADD1B0);   
	
	// pagewidth [12:0] 800*4
#define VIDW00ADD2    0x0100
	writel(  800*4 , regs1 + VIDW00ADD2);
	
	// start output signal
	reg = readl( regs1 + VIDCON0);
    	writel(reg | 0x01, regs1 + VIDCON0);

	ret = register_framebuffer(fbi);
    	return ret;
}

static int fb_remove(struct platform_device *pdev) {  
    	return 0;   
}

static const struct of_device_id dt_ids[] = {  
        { .compatible = "tiny4412,lcd_win9", },  
        {},  
};  

MODULE_DEVICE_TABLE(of, dt_ids);  

static struct platform_driver fb_driver = {  
    .driver        = {  
         .name    = "fb",  
         .of_match_table    = of_match_ptr(dt_ids),  
    },  
     .probe         = fb_probe,  
     .remove        = fb_remove,  
};  

static int fb_init(void){
	return  platform_driver_register(&fb_driver);  
}

static void fb_exit(void){
	 platform_driver_unregister(&fb_driver);  
}

module_init(fb_init);
module_exit(fb_exit);
MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值