samsung s3c - fb. c 분석
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/fb.h>
#include <linux/io.h>
#include <mach/map.h>
#include <mach/regs-fb.h>
#include <plat/fb.h>
struct s3c_fb;
struct s3c_fb_win {
struct s3c_fb_pd_win *windata;
struct s3c_fb *parent;
struct fb_info *fbinfo;
struct s3c_fb_palette palette;
u32 *palette_buffer;
u32 pseudo_palette[16];
unsigned int index;
};
struct s3c_fb {
struct device *dev;
struct resource *regs_res;
struct clk *bus_clk;
void __iomem *regs;
unsigned char enabled;
struct s3c_fb_platdata *pdata;
struct s3c_fb_win *windows[S3C_FB_MAX_WIN];
};
static int s3c_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
/* always ensure these are zero, for drop through cases below */
var->transp.offset = 0;
var->transp.length = 0;
/* 16 bpp, 565 format */
var->red.offset = 11;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
return 0;
}
static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
{
unsigned long clk = clk_get_rate(sfb->bus_clk);
unsigned long long tmp;
unsigned int result;
tmp = (unsigned long long)clk;
tmp *= pixclk;
do_div(tmp, 1000000000UL);
result = (unsigned int)tmp / 1000;
dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)
",
pixclk, clk, result, clk / result);
return result;
}
static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
{
int pix_per_word;
if (bpp > 16)
return pix;
pix_per_word = (8 * 32) / bpp;
return ALIGN(pix, pix_per_word);
}
static int s3c_fb_set_par(struct fb_info *info)
{
struct fb_var_screeninfo *var = &info->var;
struct s3c_fb_win *win = info->par;
struct s3c_fb *sfb = win->parent;
void __iomem *regs = sfb->regs;
int win_no = win->index;
u32 osdc_data = 0;
u32 data;
u32 pagewidth;
int clkdiv;
info->fix.visual = FB_VISUAL_TRUECOLOR;//true color
info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
/* disable the window whilst we update it */
writel(0, regs + WINCON(win_no));
if (win_no == 0) {
clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
data = sfb->pdata->vidcon0;
data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
if (clkdiv > 1)
data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
else
data &= ~VIDCON0_CLKDIR; /* 1:1 clock */
/* write the timing data to the panel */
data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
writel(data, regs + VIDCON0);
data = VIDTCON0_VBPD(var->upper_margin - 1) |
VIDTCON0_VFPD(var->lower_margin - 1) |
VIDTCON0_VSPW(var->vsync_len - 1);
writel(data, regs + VIDTCON0);
data = VIDTCON1_HBPD(var->left_margin - 1) |
VIDTCON1_HFPD(var->right_margin - 1) |
VIDTCON1_HSPW(var->hsync_len - 1);
writel(data, regs + VIDTCON1);
data = VIDTCON2_LINEVAL(var->yres - 1) |
VIDTCON2_HOZVAL(var->xres - 1);
writel(data, regs + VIDTCON2);
}
/* write the buffer address */
writel(info->fix.smem_start, regs + VIDW_BUF_START(win_no));
data = info->fix.smem_start + info->fix.line_length * var->yres;
writel(data, regs + VIDW_BUF_END(win_no));
pagewidth = (var->xres * var->bits_per_pixel) >> 3;
data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
writel(data, regs + VIDW_BUF_SIZE(win_no));
/* write 'OSD' registers to control position of framebuffer */
data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
writel(data, regs + VIDOSD_A(win_no));
data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
var->xres - 1)) |
VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
writel(data, regs + VIDOSD_B(win_no));
data = var->xres * var->yres;
osdc_data = VIDISD14C_ALPHA1_R(0xf) |
VIDISD14C_ALPHA1_G(0xf) |
VIDISD14C_ALPHA1_B(0xf);
if (s3c_fb_has_osd_d(win_no)) {
writel(data, regs + VIDOSD_D(win_no));
writel(osdc_data, regs + VIDOSD_C(win_no));
} else
writel(data, regs + VIDOSD_C(win_no));
data = WINCONx_ENWIN;
data |= WINCON0_BPPMODE_16BPP_565;
data |= WINCONx_HAWSWP;
data |= WINCONx_BURSTLEN_16WORD;
writel(data, regs + WINCON(win_no));
writel(0x0, regs + WINxMAP(win_no));
return 0;
}
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_fb_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
struct s3c_fb_win *win = info->par;
struct s3c_fb *sfb = win->parent;
unsigned int val;
//regno 2-255
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
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;
}
return 0;
}
static int s3c_fb_blank(int blank_mode, struct fb_info *info)
{
return 0;
}
static struct fb_ops s3c_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = s3c_fb_check_var,// , */
.fb_set_par = s3c_fb_set_par,// info->var video */
.fb_blank = s3c_fb_blank,// */
.fb_setcolreg = s3c_fb_setcolreg,// color */
.fb_fillrect = cfb_fillrect,// drivers/video/cfblillrect.c , FB_CIRRUS */
.fb_copyarea = cfb_copyarea,// drivers/video/cfbcopyarea.c*/
.fb_imageblit = cfb_imageblit,// drivers/video/cfbimgblt.c*/
};
static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
struct s3c_fb_win *win)
{
struct s3c_fb_pd_win *windata = win->windata;
dma_addr_t map_dma;// */
unsigned int real_size, virt_size, size;
struct fb_info *fbi = win->fbinfo;
real_size = windata->win_mode.xres * windata->win_mode.yres * windata->default_bpp;
virt_size = windata->virtual_x * windata->virtual_y * windata->default_bpp;
size = real_size / 4;
fbi->fix.smem_len = size;
printk("the size is %d, fbi->fix.smem_len = %d
", size, windata->win_mode.xres * windata->win_mode.yres * windata->max_bpp);
//the size is 522240, fbi->fix.smem_len = 4177920*/
//PAGE_ALIGN()1k */
size = PAGE_ALIGN(size);
/** dma_alloc_writecombine() cache */
fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
&map_dma, GFP_KERNEL);
printk( "mapped %x to %p
", (unsigned int)map_dma, fbi->screen_base);
memset(fbi->screen_base, 0x0, size);
//smem_start: */
fbi->fix.smem_start = map_dma;
return 0;
}
/**
*s3c_fb_probe_win(): ,
*@sfb:
*@res:
*
*/
static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
struct s3c_fb_win **res)
{
struct fb_var_screeninfo *var;// */
struct fb_videomode *initmode;//include/linux/fb.h */
struct s3c_fb_pd_win *windata;// bsp */
struct s3c_fb_win *win;// fb_info*/
struct fb_info *fbinfo;//fb_info, */
int palette_size;
int ret;
palette_size = 256;// */
/** fb_info */
fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
palette_size * sizeof(u32), sfb->dev);
// bsp .win[0] = &smdk6410_fb_win0,
windata = sfb->pdata->win[win_no];
initmode = &windata->win_mode;
win = fbinfo->par;
var = &fbinfo->var;
win->fbinfo = fbinfo;
win->parent = sfb;
win->windata = windata;
win->index = win_no;
win->palette_buffer = (u32 *)(win + 1);
/** , DMA */
ret = s3c_fb_alloc_memory(sfb, win);
// plat-samsung/include/plat/regs-fb-v4.h
/* setup the r/b/g positions for the window's palette */
s3c_fb_init_palette(win_no, &win->palette);
/* setup the initial video mode from the window */
fb_videomode_to_var(&fbinfo->var, initmode);
/* FBI */
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;/* Packed Pixels */
fbinfo->fix.accel = FB_ACCEL_NONE;/* no hardware accelerator */
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->var.bits_per_pixel = windata->default_bpp;// BPP
fbinfo->fbops = &s3c_fb_ops;//
fbinfo->flags = FBINFO_FLAG_DEFAULT;//linux/fb.h 0x0001 Low-level driver is a module */
fbinfo->pseudo_palette = &win->pseudo_palette;
/* prepare to actually start the framebuffer */
ret = s3c_fb_check_var(&fbinfo->var, fbinfo);// framebuffer
/* create initial colour map */
ret = fb_alloc_cmap(&fbinfo->cmap, s3c_fb_win_pal_size(win_no), 1);
fb_set_cmap(&fbinfo->cmap, fbinfo);// drivers/video/fbcmap.c
s3c_fb_set_par(fbinfo);//framebuffer request to set new framebuffer state.
//
ret = register_framebuffer(fbinfo);
*res = win;
return 0;
}
static int s3c_fb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct s3c_fb_platdata *pd;//plat-samsung/include/plat/fb.h
struct s3c_fb *sfb;/*s3c_fb ,
* , 。
* */
struct resource *res;
int win;
int ret = 0;
pd = pdev->dev.platform_data;//get bsp's platform_data
sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);// fb_info
sfb->dev = dev;
sfb->pdata = pd;// sfb dev,pd
// lcd
sfb->bus_clk = clk_get(dev, "lcd");
clk_enable(sfb->bus_clk);
/** LCD IO */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/** IO */
sfb->regs_res = request_mem_region(res->start, resource_size(res), pdev->name);
/** IO */
sfb->regs = ioremap(res->start, resource_size(res));
// gpio ,
//arch/arm/mach-s3c64xx/setup-fb-24bpp.c
pd->setup_gpio();
// , .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
// VIDCON1 0x7710_0004, HSYNC VSYNC 1,
writel(pd->vidcon1, sfb->regs + VIDCON1);
for (win = 0; win < S3C_FB_MAX_WIN; win++) {
if (!pd->win[win])
continue;//win=0
// framebuffer s3c_fb_probe_win
ret = s3c_fb_probe_win(sfb, win, &sfb->windows[win]);
}
// sfb ,
//platform_get_drvdata()
platform_set_drvdata(pdev, sfb);
return 0;
}
static int s3c_fb_remove(struct platform_device *pdev)
{
return 0;
}
#define s3c_fb_suspend NULL
#define s3c_fb_resume NULL
static struct platform_driver s3c_fb_driver = {
.probe = s3c_fb_probe,
.remove = s3c_fb_remove,
.suspend = s3c_fb_suspend,
.resume = s3c_fb_resume,
.driver = {
.name = "s3c-fb",
.owner = THIS_MODULE,
},
};
static int __init s3c_fb_init(void)
{
return platform_driver_register(&s3c_fb_driver);
}
static void __exit s3c_fb_cleanup(void)
{
platform_driver_unregister(&s3c_fb_driver);
}
module_init(s3c_fb_init);
module_exit(s3c_fb_cleanup);
MODULE_AUTHOR("Ben Dooks <[email protected]>");
MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:s3c-fb");
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Docker를 사용한 React 및 .NET Core 6.0 샘플 프로젝트 - 1부이 기사에서는 Entity Framework Core Code First 접근 방식을 사용하는 ASP.NET Core 6.0 WEP API의 CRUD(만들기, 읽기, 업데이트 및 삭제) 작업에 대해 설명합니다. 웹 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.