📄 mq200fb.c
字号:
/* * linux/drivers/video/mq200fb.c -- MQ-200 for a frame buffer device * based on linux/driver/video/pm2fb.c * * Copyright (C) 2000 Lineo, Japan * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/malloc.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/selection.h>#include <linux/console.h>#include <linux/init.h>#include <linux/timer.h>#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <asm/io.h>#include "mq200fb.h"#if 0#define PRINTK(args...) printk(args)#else#define PRINTK(args...)#endif#define WITH_NONE 0#define WITH_HSYNC (1 << 0)#define WITH_VSYNC (1 << 1)/**************************************************************** * type definitions *//**** * PLL parameters */struct pll_par { u16 m_par; /* M parameter */ u16 n_par; /* N parameter */ u16 p_par; /* P parameter */};/**** * display control values */struct disp_par { u16 hdt; /* horizontal display total; * hdt >= hse + 4; val = hdt - 2 */ u16 hde; /* horizontal display end */ u16 vdt; /* vertical display total; * vdt >= vse + 2; val = vdt - 1 */ u16 vde; /* vertical display end; val = vde - 1 */ u16 hss; /* horizontal sync start; hss >= hde + 4 */ u16 hse; /* horizontal sync end; hse >= hss + 4 */ u16 vss; /* vertical sync start; vss >= vde + 1 */ u16 vse; /* vertical sync end; vse >= vss + 1 */};/**** * window control values */struct win_par { u16 hws; /* horizontal window start */ u16 hww; /* horizontal window width; * hww >= 8; val = hww - 1 */ u16 wald; /* window additional line data */ u16 vws; /* vertical window start */ u16 vwh; /* vertical window height; * vwh >= 1; val = vwh - 1 */ s16 wst; /* window stride; do NOT use a negative number */ unsigned long wsa; /* window start address */};/**** * The hardware specific data in this structure uniquely defines a video * mode. * * If your hardware supports only one video mode, you can leave it empty. */struct mq200fb_par { struct pll_par pll[3]; /* PLL 1, 2 and 3 */ struct { struct disp_par disp; /* display control */ struct win_par win; /* window control */ struct win_par awin; /* alternate window control */ u16 gcd; /* graphics color depth */ u16 agcd; /* alternate graphics color depth */ u16 v_height; /* virtual height for main window */ u16 v_aheight; /* virtual height for alternate window */ u16 fd; /* pixclock = source_clock / fd / sd */ u16 sd; } gc[2]; /* graphics controller 1 and 2 */};struct mq200fb_cursor_info { struct { u16 x, y; } size; int enable; struct timer_list timer;};struct mq200fb_info { struct fb_info_gen gen; struct mq200fb_par current_par; int current_par_valid; u16 vendor_id; /* MQ-200 vendor ID */ u16 device_id; /* MQ-200 device ID */ struct { u32 fb_size; /* framebuffer size */ unsigned long rg_base; /* physical register memory base */ unsigned long p_fb; /* physical address of frame buffer */ unsigned long v_fb; /* virtual address of frame buffer */ unsigned long p_regs; /* physical address of rg_base */ unsigned long v_regs; /* virtual address of rg_base */ } regions; unsigned long pmu_base; /* power management unit */ unsigned long cpu_base; /* CPU interface */ unsigned long miu_base; /* memory interface unit */ unsigned long in_base; /* interrupt controller */ unsigned long gc_base; /* graphics controller 1&2 */ unsigned long ge_base; /* graphics engine */ unsigned long fpi_base; /* flat panel interface */ unsigned long cp1_base; /* color palette 1 */ unsigned long dc_base; /* device configuration */ unsigned long pci_base; /* PCI configuration */ unsigned long psf_base; /* ??? */ struct display disp; struct mq200fb_cursor_info cursor_info; spinlock_t lock;};/**************************************************************** * function prototype declarations */static int mq200fb_open(struct fb_info*, int);static int mq200fb_release(struct fb_info*, int);static void mq200fb_detect(void);static int mq200fb_encode_fix(struct fb_fix_screeninfo*, const void*, struct fb_info_gen*);static int mq200fb_decode_var(const struct fb_var_screeninfo*, void*, struct fb_info_gen*);static int mq200fb_encode_var(struct fb_var_screeninfo*, const void*, struct fb_info_gen*);static void mq200fb_get_par(void*, struct fb_info_gen*);static void mq200fb_set_par(const void*, struct fb_info_gen*);static int mq200fb_getcolreg(unsigned, unsigned*, unsigned*, unsigned*, unsigned*, struct fb_info*);static int mq200fb_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info*);static int mq200fb_pan_display(const struct fb_var_screeninfo*, struct fb_info_gen*);static int mq200fb_blank(int, struct fb_info_gen*);static void mq200fb_set_disp(const void*, struct display*, struct fb_info_gen*);#ifdef FBCON_HAS_CFB8static void mq200fb_cursor(struct display*, int, int, int);static int mq200fb_set_font(struct display*, int, int);static void mq200fb_clear(struct vc_data*, struct display*, int, int, int, int);static void mq200fb_clear_margins(struct vc_data*, struct display*, int);static void mq200fb_putc(struct vc_data*, struct display*, int, int, int);static void mq200fb_putcs(struct vc_data*, struct display*, const unsigned short*, int, int, int);#endifstatic int is_color_palette_enabled(const struct mq200fb_par*);static u32 get_line_length(const struct mq200fb_par*);static u32 get_width(const struct mq200fb_par*);#if 0static void set_v_width(struct mq200fb_par*, int);#endifstatic u32 get_v_height(const struct mq200fb_par*);static u32 get_height(const struct mq200fb_par*);#if 0static void set_v_height(struct mq200fb_par*, int);#endifstatic int get_bits_per_pixel(const struct mq200fb_par*);#if 0static void set_bits_per_pixel(struct mq200fb_par*, int);#endifstatic u32 get_right_margin(const struct mq200fb_par*);static u32 get_left_margin(const struct mq200fb_par*);static u32 get_lower_margin(const struct mq200fb_par*);static u32 get_upper_margin(const struct mq200fb_par*);static u32 get_hsync_len(const struct mq200fb_par*);static u32 get_vsync_len(const struct mq200fb_par*);static u32 get_xoffset(const struct mq200fb_par*);static u32 get_yoffset(const struct mq200fb_par*);static u32 get_pixclock(const struct mq200fb_par*);static double get_pll_freq(const struct pll_par*);static double get_fd_val(const struct mq200fb_par*);static double get_sd_val(const struct mq200fb_par*);static void power_state_transition(const struct mq200fb_info*, int);#if 0static void vsync(void);static void mq200_interrupt(int, void*, struct pt_regs*);static void mq200_enable_irq(const struct mq200fb_info*);#endifstatic int mq200fb_conf(struct mq200fb_info*);static int mq200_probe(struct mq200fb_info*);static void mq200_reset(const struct mq200fb_info*);static void dc_reset(const struct mq200fb_info*);static void miu_reset(const struct mq200fb_info*);static void pmu_reset(const struct mq200fb_info*);static void gc1_reset(const struct mq200fb_info*);static void ge_reset(const struct mq200fb_info*);static void cp1_reset(const struct mq200fb_info*);static void set_screen(const struct mq200fb_info*, const struct mq200fb_par*);static void set_cursor_shape(const struct mq200fb_info*);static void enable_cursor(struct mq200fb_info*);static void disable_cursor(struct mq200fb_info*);static int set_cursor_pos(const struct mq200fb_info*, unsigned, unsigned);static void cursor_timer_handler(unsigned long);static void get_color_palette(const struct mq200fb_info*, unsigned, unsigned*, unsigned*, unsigned*);static void set_color_palette(const struct mq200fb_info*, unsigned, unsigned, unsigned, unsigned);static void enable_dac(const struct mq200fb_info*);static void disable_dac(const struct mq200fb_info*, unsigned);static int __inline__ is_enough_cmd_fifo(const struct mq200fb_info*, int);static int __inline__ is_enough_src_fifo(const struct mq200fb_info*, int);static void wait_cmd_fifo(const struct mq200fb_info*, int);static void wait_src_fifo(const struct mq200fb_info*, int);static void ge_rect_fill(const struct mq200fb_info*, int, int, int, int, u32);static void ge_bitblt_char(const struct mq200fb_info*, int, int, u8*, int, int, u32, u32);static void add_cursor_timer(struct mq200fb_cursor_info*);/**************************************************************** * static variables definitions *//**** * In most cases the `generic' routines (fbgen_*) should be satisfactory. * However, you're free to fill in your own replacements. */static struct fb_ops mq200fb_ops = {#if LINUX_VERSION_CODE >= 0x020400 owner: THIS_MODULE,#else fb_open: mq200fb_open, fb_release: mq200fb_release,#endif fb_get_fix: fbgen_get_fix, fb_get_var: fbgen_get_var, fb_set_var: fbgen_set_var, fb_get_cmap: fbgen_get_cmap, fb_set_cmap: fbgen_set_cmap, fb_pan_display: fbgen_pan_display,};static struct mq200fb_info mq200fb_info;static struct { char font[40]; struct mq200fb_par par;} mq200fb_options = { font: "", { { { 219, 16, 2 }, /* PLL1 = 12.288MHz * 220 / 17 / 4 = 39.76 */ { 242, 16, 2 }, /* PLL2 = 12.288MHz * 243 / 17 / 4 = 43.91 */ { 242, 22, 2 }, /* PLL3 = 12.288MHz * 243 / 23 / 4 = 32.46 */ }, { { /* graphics controller 1 */ { 1047, 800, 624, 599, 832, 976, 601, 604 }, /* display */ { 0, 800, 0, 0, 600, 800, 0 }, /* window */ { }, /* alternate window */ 3, /* gcd = 8-bpp */ 3, /* agcd = 8-bpp */ 600, /* virtual height for main window */ 0, /* virtual height for alternate window */ 0, /* fd = 1 */ 1 /* sd = 1 */ }, { /* graphics controller 2 */ } }, }};/**** * Interfaces to hardware functions */static struct fbgen_hwswitch mq200_switch = { detect: mq200fb_detect, encode_fix: mq200fb_encode_fix, decode_var: mq200fb_decode_var, encode_var: mq200fb_encode_var, get_par: mq200fb_get_par, set_par: mq200fb_set_par, getcolreg: mq200fb_getcolreg, setcolreg: mq200fb_setcolreg, pan_display: mq200fb_pan_display, blank: mq200fb_blank, set_disp: mq200fb_set_disp};#ifdef FBCON_HAS_CFB8static void mq200fb_ds_setup(struct display* disp){ fbcon_cfb8_setup(disp);}/**** * fbcon switch for the low level operations. */static struct display_switch mq200_cfb8 = { setup: mq200fb_ds_setup, bmove: fbcon_cfb8_bmove, clear: mq200fb_clear, putc: mq200fb_putc, putcs: mq200fb_putcs, cursor: mq200fb_cursor, set_font: mq200fb_set_font, clear_margins: mq200fb_clear_margins, fontwidthmask: FONTWIDTH(8) | FONTWIDTH(16)};#endif/**************************************************************** * functions for struct fb_ops member */#if LINUX_VERSION_CODE < 0x020400static intmq200fb_open(struct fb_info* info, int user){ MOD_INC_USE_COUNT; return 0;}#endif#if LINUX_VERSION_CODE < 0x020400static intmq200fb_release(struct fb_info* info, int user){ MOD_DEC_USE_COUNT; return 0;}#endif/**************************************************************** * functions for struct fbgen_hwswitch member *//**** * This function should detect the current video mode settings and store * it as the default video mode */static voidmq200fb_detect(void){}/**** * This function should fill in the 'fix' structure based on the values * in the `par' structure. */static intmq200fb_encode_fix(struct fb_fix_screeninfo* fix, const void* par, struct fb_info_gen* info){ const struct mq200fb_par* mq200fb_par = par; struct mq200fb_info* fb_info = (struct mq200fb_info*)info; strcpy(fix->id, CHIPNAME);#if LINUX_VERSION_CODE >= 0x020400 fix->smem_start = fb_info->regions.p_fb; fix->mmio_start = fb_info->regions.p_regs;#else fix->smem_start = (char*)fb_info->regions.p_fb; fix->mmio_start = (char*)fb_info->regions.p_regs;#endif fix->smem_len = fb_info->regions.fb_size; fix->mmio_len = MQ200_REGS_SIZE; fix->accel = FB_ACCEL_MEDIAQ_MQ200; fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = is_color_palette_enabled(mq200fb_par) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; if (fb_info->current_par_valid) fix->line_length = get_line_length(mq200fb_par); else fix->line_length = 0; fix->xpanstep = 0; /* $H$j$"$($: */ fix->ypanstep = 1; /* $H$j$"$($: */ fix->ywrapstep = 0; return 0;}/**** * Get the video params out of 'var'. If a value doesn't fit, round it up, * if it's too big, return -EINVAL. * * Suggestion: Round up in the following order: bits_per_pixel, xres, * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, * bitfields, horizontal timing, vertical timing. */static intmq200fb_decode_var(const struct fb_var_screeninfo *var, void* par, struct fb_info_gen *info){ struct mq200fb_info* fb_info = (struct mq200fb_info*)info; struct mq200fb_par* fb_par = (struct mq200fb_par*)par; *fb_par = fb_info->current_par; return 0;}/**** * Fill the 'var' structure based on the values in 'par' and maybe other * values read out of the hardware. */static intmq200fb_encode_var(struct fb_var_screeninfo* var, const void* par, struct fb_info_gen* info){ const struct mq200fb_par* mq200fb_par = par; struct fb_var_screeninfo new_var; memset(&new_var, 0, sizeof new_var); new_var.xres_virtual = get_line_length(mq200fb_par) * 8; new_var.yres_virtual = get_v_height(mq200fb_par); new_var.xres = get_width(mq200fb_par); new_var.yres = get_height(mq200fb_par); new_var.right_margin = get_right_margin(mq200fb_par); new_var.hsync_len = get_hsync_len(mq200fb_par); new_var.left_margin = get_left_margin(mq200fb_par); new_var.lower_margin = get_lower_margin(mq200fb_par); new_var.vsync_len = get_vsync_len(mq200fb_par); new_var.upper_margin = get_upper_margin(mq200fb_par); new_var.bits_per_pixel = get_bits_per_pixel(mq200fb_par); switch (get_bits_per_pixel(mq200fb_par)) { case 1: case 2: case 4: case 16: case 24: case 32: PRINTK(CHIPNAME ": %d bpp is not supported depth.\n", get_bits_per_pixel(mq200fb_par)); break; case 8: new_var.red.length = new_var.green.length = new_var.blue.length = 8; break; } new_var.xoffset = get_xoffset(mq200fb_par); new_var.yoffset = get_yoffset(mq200fb_par); new_var.height = new_var.width = -1; new_var.pixclock = get_pixclock(mq200fb_par); new_var.sync = 0; new_var.vmode = FB_VMODE_NONINTERLACED; new_var.activate = FB_ACTIVATE_NOW; *var = new_var; return 0;}/**** * Fill the hardware's 'par' structure. */static void mq200fb_get_par(void* par, struct fb_info_gen *info){ struct mq200fb_info* fb_info = (struct mq200fb_info*)info; if (! fb_info->current_par_valid) {// mq200_reset(fb_info); set_screen(fb_info, &fb_info->current_par); fb_info->current_par_valid = 1; } *((struct mq200fb_par*)par) = fb_info->current_par;}/**** * Set the hardware according to 'par'. */static void mq200fb_set_par(const void* par, struct fb_info_gen *info){ struct mq200fb_info* fb_info = (struct mq200fb_info*)info; struct mq200fb_par* fb_par = (struct mq200fb_par*)par; set_screen(fb_info, fb_par); fb_info->current_par = *fb_par; fb_info->current_par_valid = 1;}/**** * Read a single color register and split it into colors/transparent. * The return values must have a 16 bit magnitude. * Return != 0 for invalid regno. */static int mq200fb_getcolreg(unsigned regno, unsigned* red, unsigned* green, unsigned* blue, unsigned* transp, struct fb_info* info){ struct mq200fb_info* fb_info = (struct mq200fb_info*)info;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -