📄 arkfb.c
字号:
return 0;}static const struct svga_pll ics5342_pll = {3, 129, 3, 33, 0, 3, 60000, 250000, 14318};/* pd4 - allow only posdivider 4 (r=2) */static const struct svga_pll ics5342_pll_pd4 = {3, 129, 3, 33, 2, 2, 60000, 335000, 14318};/* 270 MHz should be upper bound for VCO clock according to specs, but that is too restrictive in pd4 case */static int ics5342_set_freq(struct dac_info *info, int channel, u32 freq){ u16 m, n, r; /* only postdivider 4 (r=2) is valid in mode DAC_PSEUDO8_16 */ int rv = svga_compute_pll((DAC_PAR(info)->mode == DAC_PSEUDO8_16) ? &ics5342_pll_pd4 : &ics5342_pll, freq, &m, &n, &r, 0); if (rv < 0) { return -EINVAL; } else { u8 code[6] = {4, 3, 5, m-2, 5, (n-2) | (r << 5)}; dac_write_regs(info, code, 3); return 0; }}static void ics5342_release(struct dac_info *info){ ics5342_set_mode(info, DAC_PSEUDO8_8); kfree(info);}static struct dac_ops ics5342_ops = { .dac_set_mode = ics5342_set_mode, .dac_set_freq = ics5342_set_freq, .dac_release = ics5342_release};static struct dac_info * ics5342_init(dac_read_regs_t drr, dac_write_regs_t dwr, void *data){ struct dac_info *info = kzalloc(sizeof(struct ics5342_info), GFP_KERNEL); if (! info) return NULL; info->dacops = &ics5342_ops; info->dac_read_regs = drr; info->dac_write_regs = dwr; info->data = data; DAC_PAR(info)->mode = DAC_PSEUDO8_8; /* estimation */ return info;}/* ------------------------------------------------------------------------- */static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};static void ark_dac_read_regs(void *data, u8 *code, int count){ u8 regval = vga_rseq(NULL, 0x1C); while (count != 0) { vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0); code[1] = vga_r(NULL, dac_regs[code[0] & 3]); count--; code += 2; } vga_wseq(NULL, 0x1C, regval);}static void ark_dac_write_regs(void *data, u8 *code, int count){ u8 regval = vga_rseq(NULL, 0x1C); while (count != 0) { vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0); vga_w(NULL, dac_regs[code[0] & 3], code[1]); count--; code += 2; } vga_wseq(NULL, 0x1C, regval);}static void ark_set_pixclock(struct fb_info *info, u32 pixclock){ struct arkfb_info *par = info->par; u8 regval; int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock); if (rv < 0) { printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node); return; } /* Set VGA misc register */ regval = vga_r(NULL, VGA_MIS_R); vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);}/* Open framebuffer */static int arkfb_open(struct fb_info *info, int user){ struct arkfb_info *par = info->par; mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { memset(&(par->state), 0, sizeof(struct vgastate)); par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; par->state.num_crtc = 0x60; par->state.num_seq = 0x30; save_vga(&(par->state)); } par->ref_count++; mutex_unlock(&(par->open_lock)); return 0;}/* Close framebuffer */static int arkfb_release(struct fb_info *info, int user){ struct arkfb_info *par = info->par; mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { mutex_unlock(&(par->open_lock)); return -EINVAL; } if (par->ref_count == 1) { restore_vga(&(par->state)); dac_set_mode(par->dac, DAC_PSEUDO8_8); } par->ref_count--; mutex_unlock(&(par->open_lock)); return 0;}/* Validate passed in var */static int arkfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ int rv, mem, step; /* Find appropriate format */ rv = svga_match_format (arkfb_formats, var, NULL); if (rv < 0) { printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); return rv; } /* Do not allow to have real resoulution larger than virtual */ if (var->xres > var->xres_virtual) var->xres_virtual = var->xres; if (var->yres > var->yres_virtual) var->yres_virtual = var->yres; /* Round up xres_virtual to have proper alignment of lines */ step = arkfb_formats[rv].xresstep - 1; var->xres_virtual = (var->xres_virtual+step) & ~step; /* Check whether have enough memory */ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; if (mem > info->screen_size) { printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); return -EINVAL; } rv = svga_check_timings (&ark_timing_regs, var, info->node); if (rv < 0) { printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); return rv; } /* Interlaced mode is broken */ if (var->vmode & FB_VMODE_INTERLACED) return -EINVAL; return 0;}/* Set video mode from par */static int arkfb_set_par(struct fb_info *info){ struct arkfb_info *par = info->par; u32 value, mode, hmul, hdiv, offset_value, screen_size; u32 bpp = info->var.bits_per_pixel; u8 regval; if (bpp != 0) { info->fix.ypanstep = 1; info->fix.line_length = (info->var.xres_virtual * bpp) / 8; info->flags &= ~FBINFO_MISC_TILEBLITTING; info->tileops = NULL; /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0); info->pixmap.blit_y = ~(u32)0; offset_value = (info->var.xres_virtual * bpp) / 64; screen_size = info->var.yres_virtual * info->fix.line_length; } else { info->fix.ypanstep = 16; info->fix.line_length = 0; info->flags |= FBINFO_MISC_TILEBLITTING; info->tileops = &arkfb_tile_ops; /* supports 8x16 tiles only */ info->pixmap.blit_x = 1 << (8 - 1); info->pixmap.blit_y = 1 << (16 - 1); offset_value = info->var.xres_virtual / 16; screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64; } info->var.xoffset = 0; info->var.yoffset = 0; info->var.activate = FB_ACTIVATE_NOW; /* Unlock registers */ svga_wcrt_mask(0x11, 0x00, 0x80); /* Blank screen and turn off sync */ svga_wseq_mask(0x01, 0x20, 0x20); svga_wcrt_mask(0x17, 0x00, 0x80); /* Set default values */ svga_set_default_gfx_regs(); svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(ark_start_address_regs, 0); /* ARK specific initialization */ svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */ svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */ vga_wseq(NULL, 0x13, info->fix.smem_start >> 16); vga_wseq(NULL, 0x14, info->fix.smem_start >> 24); vga_wseq(NULL, 0x15, 0); vga_wseq(NULL, 0x16, 0); /* Set the FIFO threshold register */ /* It is fascinating way to store 5-bit value in 8-bit register */ regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1; vga_wseq(NULL, 0x18, regval); /* Set the offset register */ pr_debug("fb%d: offset register : %d\n", info->node, offset_value); svga_wcrt_multi(ark_offset_regs, offset_value); /* fix for hi-res textmode */ svga_wcrt_mask(0x40, 0x08, 0x08); if (info->var.vmode & FB_VMODE_DOUBLE) svga_wcrt_mask(0x09, 0x80, 0x80); else svga_wcrt_mask(0x09, 0x00, 0x80); if (info->var.vmode & FB_VMODE_INTERLACED) svga_wcrt_mask(0x44, 0x04, 0x04); else svga_wcrt_mask(0x44, 0x00, 0x04); hmul = 1; hdiv = 1; mode = svga_match_format(arkfb_formats, &(info->var), &(info->fix)); /* Set mode-specific register values */ switch (mode) { case 0: pr_debug("fb%d: text mode\n", info->node); svga_set_textmode_vga_regs(); vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); vga_wgfx(NULL, VGA_GFX_MODE, 0x40); vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */ if (info->var.pixclock > 20000) { pr_debug("fb%d: not using multiplex\n", info->node); svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); } else { pr_debug("fb%d: using multiplex\n", info->node); svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_16); hdiv = 2; } break; case 4: pr_debug("fb%d: 5/5/5 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB1555_16); break; case 5: pr_debug("fb%d: 5/6/5 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB0565_16); break; case 6: pr_debug("fb%d: 8/8/8 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB0888_16); hmul = 3; hdiv = 2; break; case 7: pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB8888_16); hmul = 2; break; default: printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node); return -EINVAL; } ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul); svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv, (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1, hmul, info->node); /* Set interlaced mode start/end register */ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; value = ((value * hmul / hdiv) / 8) - 5; vga_wcrt(NULL, 0x42, (value + 1) / 2); memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ svga_wcrt_mask(0x17, 0x80, 0x80); svga_wseq_mask(0x01, 0x00, 0x20); return 0;}/* Set a colour register */static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *fb){ switch (fb->var.bits_per_pixel) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -