📄 w100fb.c
字号:
/* * linux/drivers/video/w100fb.c * * Frame Buffer Device for ATI Imageon w100 (Wallaby) * * Copyright (C) 2002, ATI Corp. * Copyright (C) 2004-2006 Richard Purdie * Copyright (c) 2005 Ian Molton * Copyright (c) 2006 Alberto Mardegan * * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net> * * Generic platform support by Ian Molton <spyro@f2s.com> * and Richard Purdie <rpurdie@rpsys.net> * * w32xx support by Ian Molton * * Hardware acceleration support by Alberto Mardegan * <mardy@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/platform_device.h>#include <linux/string.h>#include <linux/vmalloc.h>#include <asm/io.h>#include <asm/uaccess.h>#include <video/w100fb.h>#include "w100fb.h"/* * Prototypes */static void w100_suspend(u32 mode);static void w100_vsync(void);static void w100_hw_init(struct w100fb_par*);static void w100_pwm_setup(struct w100fb_par*);static void w100_init_clocks(struct w100fb_par*);static void w100_setup_memory(struct w100fb_par*);static void w100_init_lcd(struct w100fb_par*);static void w100_set_dispregs(struct w100fb_par*);static void w100_update_enable(void);static void w100_update_disable(void);static void calc_hsync(struct w100fb_par *par);static void w100_init_graphic_engine(struct w100fb_par *par);struct w100_pll_info *w100_get_xtal_table(unsigned int freq);/* Pseudo palette size */#define MAX_PALETTES 16#define W100_SUSPEND_EXTMEM 0#define W100_SUSPEND_ALL 1#define BITS_PER_PIXEL 16/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */static void *remapped_base;static void *remapped_regs;static void *remapped_fbuf;#define REMAPPED_FB_LEN 0x15ffff/* This is the offset in the w100's address space we map the current framebuffer memory to. We use the position of external memory as we can remap internal memory to there if external isn't present. */#define W100_FB_BASE MEM_EXT_BASE_VALUE/* * Sysfs functions */static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf){ struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; return sprintf(buf, "%d\n",par->flip);}static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ unsigned int flip; struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; flip = simple_strtoul(buf, NULL, 10); if (flip > 0) par->flip = 1; else par->flip = 0; w100_update_disable(); w100_set_dispregs(par); w100_update_enable(); calc_hsync(par); return count;}static DEVICE_ATTR(flip, 0644, flip_show, flip_store);static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ unsigned long regs, param; regs = simple_strtoul(buf, NULL, 16); param = readl(remapped_regs + regs); printk("Read Register 0x%08lX: 0x%08lX\n", regs, param); return count;}static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ unsigned long regs, param; sscanf(buf, "%lx %lx", ®s, ¶m); if (regs <= 0x2000) { printk("Write Register 0x%08lX: 0x%08lX\n", regs, param); writel(param, remapped_regs + regs); } return count;}static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf){ struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; return sprintf(buf, "%d\n",par->fastpll_mode);}static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; if (simple_strtoul(buf, NULL, 10) > 0) { par->fastpll_mode=1; printk("w100fb: Using fast system clock (if possible)\n"); } else { par->fastpll_mode=0; printk("w100fb: Using normal system clock\n"); } w100_init_clocks(par); calc_hsync(par); return count;}static DEVICE_ATTR(fastpllclk, 0644, fastpllclk_show, fastpllclk_store);/* * Some touchscreens need hsync information from the video driver to * function correctly. We export it here. */unsigned long w100fb_get_hsynclen(struct device *dev){ struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; /* If display is blanked/suspended, hsync isn't active */ if (par->blanked) return 0; else return par->hsync_len;}EXPORT_SYMBOL(w100fb_get_hsynclen);static void w100fb_clear_screen(struct w100fb_par *par){ memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));}/* * Set a palette value from rgb components */static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ unsigned int val; int ret = 1; /* * If greyscale is true, then we convert the RGB value * to greyscale no matter what visual we are using. */ if (info->var.grayscale) red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; /* * 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information. */ if (regno < MAX_PALETTES) { u32 *pal = info->pseudo_palette; val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); pal[regno] = val; ret = 0; } return ret;}/* * Blank the display based on value in blank_mode */static int w100fb_blank(int blank_mode, struct fb_info *info){ struct w100fb_par *par = info->par; struct w100_tg_info *tg = par->mach->tg; switch(blank_mode) { case FB_BLANK_NORMAL: /* Normal blanking */ case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ case FB_BLANK_POWERDOWN: /* Poweroff */ if (par->blanked == 0) { if(tg && tg->suspend) tg->suspend(par); par->blanked = 1; } break; case FB_BLANK_UNBLANK: /* Unblanking */ if (par->blanked != 0) { if(tg && tg->resume) tg->resume(par); par->blanked = 0; } break; } return 0;}static void w100_fifo_wait(int entries){ union rbbm_status_u status; int i; for (i = 0; i < 2000000; i++) { status.val = readl(remapped_regs + mmRBBM_STATUS); if (status.f.cmdfifo_avail >= entries) return; udelay(1); } printk(KERN_ERR "w100fb: FIFO Timeout!\n");}static int w100fb_sync(struct fb_info *info){ union rbbm_status_u status; int i; for (i = 0; i < 2000000; i++) { status.val = readl(remapped_regs + mmRBBM_STATUS); if (!status.f.gui_active) return 0; udelay(1); } printk(KERN_ERR "w100fb: Graphic engine timeout!\n"); return -EBUSY;}static void w100_init_graphic_engine(struct w100fb_par *par){ union dp_gui_master_cntl_u gmc; union dp_mix_u dp_mix; union dp_datatype_u dp_datatype; union dp_cntl_u dp_cntl; w100_fifo_wait(4); writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET); writel(par->xres, remapped_regs + mmDST_PITCH); writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET); writel(par->xres, remapped_regs + mmSRC_PITCH); w100_fifo_wait(3); writel(0, remapped_regs + mmSC_TOP_LEFT); writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT); writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT); w100_fifo_wait(4); dp_cntl.val = 0; dp_cntl.f.dst_x_dir = 1; dp_cntl.f.dst_y_dir = 1; dp_cntl.f.src_x_dir = 1; dp_cntl.f.src_y_dir = 1; dp_cntl.f.dst_major_x = 1; dp_cntl.f.src_major_x = 1; writel(dp_cntl.val, remapped_regs + mmDP_CNTL); gmc.val = 0; gmc.f.gmc_src_pitch_offset_cntl = 1; gmc.f.gmc_dst_pitch_offset_cntl = 1; gmc.f.gmc_src_clipping = 1; gmc.f.gmc_dst_clipping = 1; gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE; gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */ gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST; gmc.f.gmc_byte_pix_order = 1; gmc.f.gmc_default_sel = 0; gmc.f.gmc_rop3 = ROP3_SRCCOPY; gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR; gmc.f.gmc_clr_cmp_fcn_dis = 1; gmc.f.gmc_wr_msk_dis = 1; gmc.f.gmc_dp_op = DP_OP_ROP; writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL); dp_datatype.val = dp_mix.val = 0; dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype; dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype; dp_datatype.f.dp_src2_type = 0; dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype; dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype; dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order; writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE); dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source; dp_mix.f.dp_src2_source = 1; dp_mix.f.dp_rop3 = gmc.f.gmc_rop3; dp_mix.f.dp_op = gmc.f.gmc_dp_op; writel(dp_mix.val, remapped_regs + mmDP_MIX);}static void w100fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect){ union dp_gui_master_cntl_u gmc; if (info->state != FBINFO_STATE_RUNNING) return; if (info->flags & FBINFO_HWACCEL_DISABLED) { cfb_fillrect(info, rect); return; } gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL); gmc.f.gmc_rop3 = ROP3_PATCOPY; gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR; w100_fifo_wait(2); writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL); writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR); w100_fifo_wait(2); writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X); writel((rect->width << 16) | (rect->height & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);}static void w100fb_copyarea(struct fb_info *info, const struct fb_copyarea *area){ u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; u32 h = area->height, w = area->width; union dp_gui_master_cntl_u gmc; if (info->state != FBINFO_STATE_RUNNING) return; if (info->flags & FBINFO_HWACCEL_DISABLED) { cfb_copyarea(info, area); return; } gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL); gmc.f.gmc_rop3 = ROP3_SRCCOPY; gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE; w100_fifo_wait(1); writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL); w100_fifo_wait(3); writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X); writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X); writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);}/* * Change the resolution by calling the appropriate hardware functions */static void w100fb_activate_var(struct w100fb_par *par){ struct w100_tg_info *tg = par->mach->tg; w100_pwm_setup(par);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -