📄 jzlcd.c
字号:
static int jzfb_set_par(struct fb_info *info){ print_dbg("jzfb_set_par"); return 0;}/* * (Un)Blank the display. * Fix me: should we use VESA value? */static int jzfb_blank(int blank_mode, struct fb_info *info){ dprintk("fb_blank %d %p", blank_mode, info); switch (blank_mode) { case FB_BLANK_UNBLANK: //case FB_BLANK_NORMAL: /* Turn on panel */ __lcd_set_ena(); __lcd_display_on(); break; case FB_BLANK_NORMAL: case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN:#if 0 /* Turn off panel */ __lcd_set_dis(); __lcd_display_off();#endif break; default: break; } return 0;}/* * pan display */static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; int dy; if (!var || !cfb) { return -EINVAL; } if (var->xoffset - cfb->fb.var.xoffset) { /* No support for X panning for now! */ return -EINVAL; } dy = var->yoffset - cfb->fb.var.yoffset; print_dbg("var.yoffset: %d", dy); if (dy) { print_dbg("Panning screen of %d lines", dy); lcd_frame_desc0->databuf += (cfb->fb.fix.line_length * dy); /* TODO: Wait for current frame to finished */ } return 0;}/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */static struct fb_ops jzfb_ops = { .owner = THIS_MODULE, .fb_setcolreg = jzfb_setcolreg, .fb_check_var = jzfb_check_var, .fb_set_par = jzfb_set_par, .fb_blank = jzfb_blank, .fb_pan_display = jzfb_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_mmap = jzfb_mmap, .fb_ioctl = jzfb_ioctl,#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) .fb_rotate = jzfb_fb_rotate,#endif};static int jzfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; int chgvar = 0; var->height = jzfb.h ; var->width = jzfb.w ; var->bits_per_pixel = jzfb.bpp; var->vmode = FB_VMODE_NONINTERLACED; var->activate = cfb->fb.var.activate; var->xres = var->width; var->yres = var->height; var->xres_virtual = var->width; var->yres_virtual = var->height; var->xoffset = 0; var->yoffset = 0; var->pixclock = 0; var->left_margin = 0; var->right_margin = 0; var->upper_margin = 0; var->lower_margin = 0; var->hsync_len = 0; var->vsync_len = 0; var->sync = 0; var->activate &= ~FB_ACTIVATE_TEST; /* * CONUPDATE and SMOOTH_XPAN are equal. However, * SMOOTH_XPAN is only used internally by fbcon. */ if (var->vmode & FB_VMODE_CONUPDATE) { var->vmode |= FB_VMODE_YWRAP; var->xoffset = cfb->fb.var.xoffset; var->yoffset = cfb->fb.var.yoffset; } if (var->activate & FB_ACTIVATE_TEST) return 0; if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) return -EINVAL; if (cfb->fb.var.xres != var->xres) chgvar = 1; if (cfb->fb.var.yres != var->yres) chgvar = 1; if (cfb->fb.var.xres_virtual != var->xres_virtual) chgvar = 1; if (cfb->fb.var.yres_virtual != var->yres_virtual) chgvar = 1; if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) chgvar = 1; var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; switch(var->bits_per_pixel){ case 1: /* Mono */ cfb->fb.fix.visual = FB_VISUAL_MONO01; cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; break; case 2: /* Mono */ var->red.offset = 0; var->red.length = 2; var->green.offset = 0; var->green.length = 2; var->blue.offset = 0; var->blue.length = 2; cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; break; case 4: /* PSEUDOCOLOUR*/ var->red.offset = 0; var->red.length = 4; var->green.offset = 0; var->green.length = 4; var->blue.offset = 0; var->blue.length = 4; cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; cfb->fb.fix.line_length = var->xres / 2; break; case 8: /* PSEUDOCOLOUR, 256 */ var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; cfb->fb.fix.line_length = var->xres ; break; case 15: /* DIRECTCOLOUR, 32k */ var->bits_per_pixel = 15; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; cfb->fb.fix.line_length = var->xres_virtual * 2; break; case 16: /* DIRECTCOLOUR, 64k */ var->bits_per_pixel = 16; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; cfb->fb.fix.line_length = var->xres_virtual * 2; break; case 18: case 24: case 32: /* DIRECTCOLOUR, 16M */ var->bits_per_pixel = 32; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; cfb->fb.fix.line_length = var->xres_virtual * 4; break; default: /* in theory this should never happen */ printk(KERN_WARNING "%s: don't support for %dbpp\n", cfb->fb.fix.id, var->bits_per_pixel); break; } cfb->fb.var = *var; cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; /* * Update the old var. The fbcon drivers still use this. * Once they are using cfb->fb.var, this can be dropped. * --rmk */ //display->var = cfb->fb.var; /* * If we are setting all the virtual consoles, also set the * defaults used to create new consoles. */ fb_set_cmap(&cfb->fb.cmap, &cfb->fb); dprintk("jzfb_set_var: after fb_set_cmap...\n"); return 0;}static struct lcd_cfb_info * jzfb_alloc_fb_info(void){ struct lcd_cfb_info *cfb; cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL); if (!cfb) return NULL; jzlcd_info = cfb; memset(cfb, 0, sizeof(struct lcd_cfb_info) ); cfb->currcon = -1; strcpy(cfb->fb.fix.id, "jz-lcd"); cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; cfb->fb.fix.type_aux = 0; cfb->fb.fix.xpanstep = 1; cfb->fb.fix.ypanstep = 1; cfb->fb.fix.ywrapstep = 0; cfb->fb.fix.accel = FB_ACCEL_NONE; cfb->fb.var.nonstd = 0; cfb->fb.var.activate = FB_ACTIVATE_NOW; cfb->fb.var.height = -1; cfb->fb.var.width = -1; cfb->fb.var.accel_flags = FB_ACCELF_TEXT; cfb->fb.fbops = &jzfb_ops; cfb->fb.flags = FBINFO_FLAG_DEFAULT; cfb->fb.pseudo_palette = (void *)(cfb + 1); switch (jzfb.bpp) { case 1: fb_alloc_cmap(&cfb->fb.cmap, 4, 0); break; case 2: fb_alloc_cmap(&cfb->fb.cmap, 8, 0); break; case 4: fb_alloc_cmap(&cfb->fb.cmap, 32, 0); break; case 8: default: fb_alloc_cmap(&cfb->fb.cmap, 256, 0); break; } dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len); return cfb;}/* * Map screen memory */static int jzfb_map_smem(struct lcd_cfb_info *cfb){ struct page * map = NULL; unsigned char *tmp; unsigned int page_shift, needroom, t;#if defined(CONFIG_SOC_JZ4740) if (jzfb.bpp == 18 || jzfb.bpp == 24) t = 32; else t = jzfb.bpp;#else if (jzfb.bpp == 15) t = 16; else t = jzfb.bpp;#endif needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; for (page_shift = 0; page_shift < 12; page_shift++) if ((PAGE_SIZE << page_shift) >= needroom) break; /* lcd_palette room total 4KB: * 0 -- 512: lcd palette * 1024 -- [1024+16*3]: lcd descripters * [1024+16*3] -- 4096: reserved */ lcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); if ((!lcd_palette)) return -ENOMEM; memset((void *)lcd_palette, 0, PAGE_SIZE); map = virt_to_page(lcd_palette); set_bit(PG_reserved, &map->flags); lcd_desc_base = (struct lcd_desc *)(lcd_palette + 1024); jz_lcd_buffer_addrs.fb_num = CONFIG_JZLCD_FRAMEBUFFER_MAX; printk("jzlcd use %d framebuffer:\n", CONFIG_JZLCD_FRAMEBUFFER_MAX); /* alloc frame buffer space */ for ( t = 0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) { lcd_frame[t] = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); if ((!lcd_frame[t])) { printk("no mem for fb[%d]\n", t); return -ENOMEM; }// memset((void *)lcd_frame[t], 0, PAGE_SIZE << page_shift); for (tmp=(unsigned char *)lcd_frame[t]; tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); tmp += PAGE_SIZE) { map = virt_to_page(tmp); set_bit(PG_reserved, &map->flags); } jz_lcd_buffer_addrs.fb_phys_addr[t] = virt_to_phys((void *)lcd_frame[t]); printk("jzlcd fb[%d] phys addr =0x%08x\n", t, jz_lcd_buffer_addrs.fb_phys_addr[t]); }#if !defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame[0]); cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); cfb->fb.screen_base = (unsigned char *)(((unsigned int)lcd_frame[0] & 0x1fffffff) | 0xa0000000);#else /* Framebuffer rotate */ lcd_frame_user_fb = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); if ((!lcd_frame_user_fb)) { printk("no mem for fb[%d]\n", t); return -ENOMEM; } memset((void *)lcd_frame_user_fb, 0, PAGE_SIZE << page_shift); for (tmp=(unsigned char *)lcd_frame_user_fb; tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); tmp += PAGE_SIZE) { map = virt_to_page(tmp); set_bit(PG_reserved, &map->flags); } printk("Rotate userfb phys addr =0x%08x\n", (unsigned int)virt_to_phys((void *)lcd_frame_user_fb)); cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame_user_fb); cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); cfb->fb.screen_base = (unsigned char *)(((unsigned int)lcd_frame_user_fb & 0x1fffffff) | 0xa0000000);#endif /* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */ if (!cfb->fb.screen_base) { printk("%s: unable to map screen memory\n", cfb->fb.fix.id); return -ENOMEM; } return 0;}static void jzfb_free_fb_info(struct lcd_cfb_info *cfb){ if (cfb) { fb_alloc_cmap(&cfb->fb.cmap, 0, 0); kfree(cfb); }}static void jzfb_unmap_smem(struct lcd_cfb_info *cfb){ struct page * map = NULL; unsigned char *tmp; unsigned int page_shift, needroom, t;#if defined(CONFIG_SOC_JZ4740) if (jzfb.bpp == 18 || jzfb.bpp == 24) t = 32; else t = jzfb.bpp;#else if (jzfb.bpp == 15) t = 16; else t = jzfb.bpp;#endif needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; for (page_shift = 0; page_shift < 12; page_shift++) if ((PAGE_SIZE << page_shift) >= needroom) break; if (cfb && cfb->fb.screen_base) { iounmap(cfb->fb.screen_base); cfb->fb.screen_base = NULL; release_mem_region(cfb->fb.fix.smem_start, cfb->fb.fix.smem_len); } if (lcd_palette) { map = virt_to_page(lcd_palette); clear_bit(PG_reserved, &map->flags); free_pages((int)lcd_palette, 0); } for ( t=0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) { if (lcd_frame[t]) { for (tmp=(unsigned char *)lcd_frame[t]; tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); tmp += PAGE_SIZE) { map = virt_to_page(tmp); clear_bit(PG_reserved, &map->flags); } free_pages((int)lcd_frame[t], page_shift); } }#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) if (lcd_frame_user_fb) { for (tmp=(unsigned char *)lcd_frame_user_fb; tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); tmp += PAGE_SIZE) { map = virt_to_page(tmp); clear_bit(PG_reserved, &map->flags); } free_pages((int)lcd_frame_user_fb, page_shift); } #endif}static void lcd_descriptor_init(void){ int i; unsigned int pal_size; unsigned int frm_size, ln_size; unsigned char dual_panel = 0; i = jzfb.bpp;#if defined(CONFIG_SOC_JZ4740) if (i == 18 || i == 24) i = 32;#else if (i == 15) i = 16;#endif frm_size = (jzfb.w*jzfb.h*i)>>3; ln_size = (jzfb.w*i)>>3; if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) { dual_panel = 1; frm_size >>= 1; } frm_size = frm_size / 4; ln_size = ln_size / 4; switch (jzfb.bpp) { case 1: pal_size = 4; break; case 2: pal_size = 8; break; case 4: pal_size = 32; break; case 8: default: pal_size = 512; } pal_size /= 4; lcd_frame_desc0 = lcd_desc_base + 0; lcd_frame_desc1 = lcd_desc_base + 1; lcd_palette_desc = lcd_desc_base + 2; jz_lcd_buffer_addrs.lcd_desc_phys_addr = (unsigned int)virt_to_phys(lcd_frame_desc0); /* Palette Descriptor */ lcd_palette_desc->next_desc = (int)virt_to_phys(lcd_frame_desc0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -