brintos

brintos / linux-shallow public Read only

0
0
Text · 58.5 KiB · 6da5ae7 Raw
2150 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.4 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.5 6 */7 8#include <linux/compiler.h>9#include <linux/module.h>10#include <linux/seq_file.h>11#include <linux/slab.h>12#include <linux/stat.h>13#include <linux/via-core.h>14#include <linux/via_i2c.h>15 16#define _MASTER_FILE17#include "global.h"18 19static char *viafb_name = "Via";20static u32 pseudo_pal[17];21 22/* video mode */23static char *viafb_mode;24static char *viafb_mode1;25static int viafb_bpp = 32;26static int viafb_bpp1 = 32;27 28static unsigned int viafb_second_offset;29static int viafb_second_size;30 31static int viafb_accel = 1;32 33/* Added for specifying active devices.*/34static char *viafb_active_dev;35 36/*Added for specify lcd output port*/37static char *viafb_lcd_port = "";38static char *viafb_dvi_port = "";39 40static void retrieve_device_setting(struct viafb_ioctl_setting41	*setting_info);42static int viafb_pan_display(struct fb_var_screeninfo *var,43	struct fb_info *info);44 45static struct fb_ops viafb_ops;46 47/* supported output devices on each IGP48 * only CX700, VX800, VX855, VX900 were documented49 * VIA_CRT should be everywhere50 * VIA_6C can be onle pre-CX700 (probably only on CLE266) as 6C is used for PLL51 * source selection on CX700 and later52 * K400 seems to support VIA_96, VIA_DVP1, VIA_LVDS{1,2} as in viamode.c53 */54static const u32 supported_odev_map[] = {55	[UNICHROME_CLE266]	= VIA_CRT | VIA_LDVP0 | VIA_LDVP1,56	[UNICHROME_K400]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS157				| VIA_LVDS2,58	[UNICHROME_K800]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS159				| VIA_LVDS2,60	[UNICHROME_PM800]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS161				| VIA_LVDS2,62	[UNICHROME_CN700]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS163				| VIA_LVDS2,64	[UNICHROME_CX700]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,65	[UNICHROME_CN750]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,66	[UNICHROME_K8M890]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,67	[UNICHROME_P4M890]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,68	[UNICHROME_P4M900]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,69	[UNICHROME_VX800]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,70	[UNICHROME_VX855]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,71	[UNICHROME_VX900]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,72};73 74static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth)75{76	var->grayscale = 0;77	var->red.msb_right = 0;78	var->green.msb_right = 0;79	var->blue.msb_right = 0;80	var->transp.offset = 0;81	var->transp.length = 0;82	var->transp.msb_right = 0;83	var->nonstd = 0;84	switch (depth) {85	case 8:86		var->bits_per_pixel = 8;87		var->red.offset = 0;88		var->green.offset = 0;89		var->blue.offset = 0;90		var->red.length = 8;91		var->green.length = 8;92		var->blue.length = 8;93		break;94	case 15:95		var->bits_per_pixel = 16;96		var->red.offset = 10;97		var->green.offset = 5;98		var->blue.offset = 0;99		var->red.length = 5;100		var->green.length = 5;101		var->blue.length = 5;102		break;103	case 16:104		var->bits_per_pixel = 16;105		var->red.offset = 11;106		var->green.offset = 5;107		var->blue.offset = 0;108		var->red.length = 5;109		var->green.length = 6;110		var->blue.length = 5;111		break;112	case 24:113		var->bits_per_pixel = 32;114		var->red.offset = 16;115		var->green.offset = 8;116		var->blue.offset = 0;117		var->red.length = 8;118		var->green.length = 8;119		var->blue.length = 8;120		break;121	case 30:122		var->bits_per_pixel = 32;123		var->red.offset = 20;124		var->green.offset = 10;125		var->blue.offset = 0;126		var->red.length = 10;127		var->green.length = 10;128		var->blue.length = 10;129		break;130	}131}132 133static void viafb_update_fix(struct fb_info *info)134{135	u32 bpp = info->var.bits_per_pixel;136 137	info->fix.visual =138		bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;139	info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,140		VIA_PITCH_SIZE);141}142 143static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,144	struct viafb_par *viaparinfo)145{146	memset(fix, 0, sizeof(struct fb_fix_screeninfo));147	strcpy(fix->id, viafb_name);148 149	fix->smem_start = viaparinfo->fbmem;150	fix->smem_len = viaparinfo->fbmem_free;151 152	fix->type = FB_TYPE_PACKED_PIXELS;153	fix->type_aux = 0;154	fix->visual = FB_VISUAL_TRUECOLOR;155 156	fix->xpanstep = fix->ywrapstep = 0;157	fix->ypanstep = 1;158 159	/* Just tell the accel name */160	viafbinfo->fix.accel = FB_ACCEL_VIA_UNICHROME;161}162static int viafb_open(struct fb_info *info, int user)163{164	DEBUG_MSG(KERN_INFO "viafb_open!\n");165	return 0;166}167 168static int viafb_release(struct fb_info *info, int user)169{170	DEBUG_MSG(KERN_INFO "viafb_release!\n");171	return 0;172}173 174static inline int get_var_refresh(struct fb_var_screeninfo *var)175{176	u32 htotal, vtotal;177 178	htotal = var->left_margin + var->xres + var->right_margin179		+ var->hsync_len;180	vtotal = var->upper_margin + var->yres + var->lower_margin181		+ var->vsync_len;182	return PICOS2KHZ(var->pixclock) * 1000 / (htotal * vtotal);183}184 185static int viafb_check_var(struct fb_var_screeninfo *var,186	struct fb_info *info)187{188	int depth, refresh;189	struct viafb_par *ppar = info->par;190	u32 line;191 192	DEBUG_MSG(KERN_INFO "viafb_check_var!\n");193	/* Sanity check */194	/* HW neither support interlacte nor double-scaned mode */195	if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)196		return -EINVAL;197 198	/* the refresh rate is not important here, as we only want to know199	 * whether the resolution exists200	 */201	if (!viafb_get_best_mode(var->xres, var->yres, 60)) {202		DEBUG_MSG(KERN_INFO203			  "viafb: Mode %dx%dx%d not supported!!\n",204			  var->xres, var->yres, var->bits_per_pixel);205		return -EINVAL;206	}207 208	depth = fb_get_color_depth(var, &info->fix);209	if (!depth)210		depth = var->bits_per_pixel;211 212	if (depth < 0 || depth > 32)213		return -EINVAL;214	else if (!depth)215		depth = 24;216	else if (depth == 15 && viafb_dual_fb && ppar->iga_path == IGA1)217		depth = 15;218	else if (depth == 30)219		depth = 30;220	else if (depth <= 8)221		depth = 8;222	else if (depth <= 16)223		depth = 16;224	else225		depth = 24;226 227	viafb_fill_var_color_info(var, depth);228	if (var->xres_virtual < var->xres)229		var->xres_virtual = var->xres;230 231	line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,232		VIA_PITCH_SIZE);233	if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)234		return -EINVAL;235 236	/* Based on var passed in to calculate the refresh,237	 * because our driver use some modes special.238	 */239	refresh = viafb_get_refresh(var->xres, var->yres,240		get_var_refresh(var));241 242	/* Adjust var according to our driver's own table */243	viafb_fill_var_timing_info(var,244		viafb_get_best_mode(var->xres, var->yres, refresh));245	if (var->accel_flags & FB_ACCELF_TEXT &&246		!ppar->shared->vdev->engine_mmio)247		var->accel_flags = 0;248 249	return 0;250}251 252static int viafb_set_par(struct fb_info *info)253{254	struct viafb_par *viapar = info->par;255	int refresh;256	DEBUG_MSG(KERN_INFO "viafb_set_par!\n");257 258	viafb_update_fix(info);259	viapar->depth = fb_get_color_depth(&info->var, &info->fix);260	viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres,261		viafbinfo->var.bits_per_pixel, 0);262 263	if (viafb_dual_fb) {264		viafb_update_device_setting(viafbinfo1->var.xres,265			viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel,266			1);267	} else if (viafb_SAMM_ON == 1) {268		DEBUG_MSG(KERN_INFO269		"viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",270			  viafb_second_xres, viafb_second_yres, viafb_bpp1);271 272		viafb_update_device_setting(viafb_second_xres,273			viafb_second_yres, viafb_bpp1, 1);274	}275 276	refresh = get_var_refresh(&info->var);277	if (viafb_dual_fb && viapar->iga_path == IGA2) {278		viafb_bpp1 = info->var.bits_per_pixel;279		viafb_refresh1 = refresh;280	} else {281		viafb_bpp = info->var.bits_per_pixel;282		viafb_refresh = refresh;283	}284 285	if (info->var.accel_flags & FB_ACCELF_TEXT)286		info->flags &= ~FBINFO_HWACCEL_DISABLED;287	else288		info->flags |= FBINFO_HWACCEL_DISABLED;289	viafb_setmode();290	viafb_pan_display(&info->var, info);291 292	return 0;293}294 295/* Set one color register */296static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green,297unsigned blue, unsigned transp, struct fb_info *info)298{299	struct viafb_par *viapar = info->par;300	u32 r, g, b;301 302	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {303		if (regno > 255)304			return -EINVAL;305 306		if (!viafb_dual_fb || viapar->iga_path == IGA1)307			viafb_set_primary_color_register(regno, red >> 8,308				green >> 8, blue >> 8);309 310		if (!viafb_dual_fb || viapar->iga_path == IGA2)311			viafb_set_secondary_color_register(regno, red >> 8,312				green >> 8, blue >> 8);313	} else {314		if (regno > 15)315			return -EINVAL;316 317		r = (red >> (16 - info->var.red.length))318			<< info->var.red.offset;319		b = (blue >> (16 - info->var.blue.length))320			<< info->var.blue.offset;321		g = (green >> (16 - info->var.green.length))322			<< info->var.green.offset;323		((u32 *) info->pseudo_palette)[regno] = r | g | b;324	}325 326	return 0;327}328 329static int viafb_pan_display(struct fb_var_screeninfo *var,330	struct fb_info *info)331{332	struct viafb_par *viapar = info->par;333	u32 vram_addr = viapar->vram_addr334		+ var->yoffset * info->fix.line_length335		+ var->xoffset * info->var.bits_per_pixel / 8;336 337	DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);338	if (!viafb_dual_fb) {339		via_set_primary_address(vram_addr);340		via_set_secondary_address(vram_addr);341	} else if (viapar->iga_path == IGA1)342		via_set_primary_address(vram_addr);343	else344		via_set_secondary_address(vram_addr);345 346	return 0;347}348 349static int viafb_blank(int blank_mode, struct fb_info *info)350{351	DEBUG_MSG(KERN_INFO "viafb_blank!\n");352	/* clear DPMS setting */353 354	switch (blank_mode) {355	case FB_BLANK_UNBLANK:356		/* Screen: On, HSync: On, VSync: On */357		/* control CRT monitor power management */358		via_set_state(VIA_CRT, VIA_STATE_ON);359		break;360	case FB_BLANK_HSYNC_SUSPEND:361		/* Screen: Off, HSync: Off, VSync: On */362		/* control CRT monitor power management */363		via_set_state(VIA_CRT, VIA_STATE_STANDBY);364		break;365	case FB_BLANK_VSYNC_SUSPEND:366		/* Screen: Off, HSync: On, VSync: Off */367		/* control CRT monitor power management */368		via_set_state(VIA_CRT, VIA_STATE_SUSPEND);369		break;370	case FB_BLANK_POWERDOWN:371		/* Screen: Off, HSync: Off, VSync: Off */372		/* control CRT monitor power management */373		via_set_state(VIA_CRT, VIA_STATE_OFF);374		break;375	}376 377	return 0;378}379 380static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)381{382	union {383		struct viafb_ioctl_mode viamode;384		struct viafb_ioctl_samm viasamm;385		struct viafb_driver_version driver_version;386		struct fb_var_screeninfo sec_var;387		struct _panel_size_pos_info panel_pos_size_para;388		struct viafb_ioctl_setting viafb_setting;389		struct device_t active_dev;390	} u;391	u32 state_info = 0;392	u32 *viafb_gamma_table;393	char driver_name[] = "viafb";394 395	u32 __user *argp = (u32 __user *) arg;396	u32 gpu32;397 398	DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd);399	printk(KERN_WARNING "viafb_ioctl: Please avoid this interface as it is unstable and might change or vanish at any time!\n");400	memset(&u, 0, sizeof(u));401 402	switch (cmd) {403	case VIAFB_GET_CHIP_INFO:404		if (copy_to_user(argp, viaparinfo->chip_info,405				sizeof(struct chip_information)))406			return -EFAULT;407		break;408	case VIAFB_GET_INFO_SIZE:409		return put_user((u32)sizeof(struct viafb_ioctl_info), argp);410	case VIAFB_GET_INFO:411		return viafb_ioctl_get_viafb_info(arg);412	case VIAFB_HOTPLUG:413		return put_user(viafb_ioctl_hotplug(info->var.xres,414					      info->var.yres,415					      info->var.bits_per_pixel), argp);416	case VIAFB_SET_HOTPLUG_FLAG:417		if (copy_from_user(&gpu32, argp, sizeof(gpu32)))418			return -EFAULT;419		viafb_hotplug = (gpu32) ? 1 : 0;420		break;421	case VIAFB_GET_RESOLUTION:422		u.viamode.xres = (u32) viafb_hotplug_Xres;423		u.viamode.yres = (u32) viafb_hotplug_Yres;424		u.viamode.refresh = (u32) viafb_hotplug_refresh;425		u.viamode.bpp = (u32) viafb_hotplug_bpp;426		if (viafb_SAMM_ON == 1) {427			u.viamode.xres_sec = viafb_second_xres;428			u.viamode.yres_sec = viafb_second_yres;429			u.viamode.virtual_xres_sec = viafb_dual_fb ? viafbinfo1->var.xres_virtual : viafbinfo->var.xres_virtual;430			u.viamode.virtual_yres_sec = viafb_dual_fb ? viafbinfo1->var.yres_virtual : viafbinfo->var.yres_virtual;431			u.viamode.refresh_sec = viafb_refresh1;432			u.viamode.bpp_sec = viafb_bpp1;433		} else {434			u.viamode.xres_sec = 0;435			u.viamode.yres_sec = 0;436			u.viamode.virtual_xres_sec = 0;437			u.viamode.virtual_yres_sec = 0;438			u.viamode.refresh_sec = 0;439			u.viamode.bpp_sec = 0;440		}441		if (copy_to_user(argp, &u.viamode, sizeof(u.viamode)))442			return -EFAULT;443		break;444	case VIAFB_GET_SAMM_INFO:445		u.viasamm.samm_status = viafb_SAMM_ON;446 447		if (viafb_SAMM_ON == 1) {448			if (viafb_dual_fb) {449				u.viasamm.size_prim = viaparinfo->fbmem_free;450				u.viasamm.size_sec = viaparinfo1->fbmem_free;451			} else {452				if (viafb_second_size) {453					u.viasamm.size_prim =454					    viaparinfo->fbmem_free -455					    viafb_second_size * 1024 * 1024;456					u.viasamm.size_sec =457					    viafb_second_size * 1024 * 1024;458				} else {459					u.viasamm.size_prim =460					    viaparinfo->fbmem_free >> 1;461					u.viasamm.size_sec =462					    (viaparinfo->fbmem_free >> 1);463				}464			}465			u.viasamm.mem_base = viaparinfo->fbmem;466			u.viasamm.offset_sec = viafb_second_offset;467		} else {468			u.viasamm.size_prim =469			    viaparinfo->memsize - viaparinfo->fbmem_used;470			u.viasamm.size_sec = 0;471			u.viasamm.mem_base = viaparinfo->fbmem;472			u.viasamm.offset_sec = 0;473		}474 475		if (copy_to_user(argp, &u.viasamm, sizeof(u.viasamm)))476			return -EFAULT;477 478		break;479	case VIAFB_TURN_ON_OUTPUT_DEVICE:480		if (copy_from_user(&gpu32, argp, sizeof(gpu32)))481			return -EFAULT;482		if (gpu32 & CRT_Device)483			via_set_state(VIA_CRT, VIA_STATE_ON);484		if (gpu32 & DVI_Device)485			viafb_dvi_enable();486		if (gpu32 & LCD_Device)487			viafb_lcd_enable();488		break;489	case VIAFB_TURN_OFF_OUTPUT_DEVICE:490		if (copy_from_user(&gpu32, argp, sizeof(gpu32)))491			return -EFAULT;492		if (gpu32 & CRT_Device)493			via_set_state(VIA_CRT, VIA_STATE_OFF);494		if (gpu32 & DVI_Device)495			viafb_dvi_disable();496		if (gpu32 & LCD_Device)497			viafb_lcd_disable();498		break;499	case VIAFB_GET_DEVICE:500		u.active_dev.crt = viafb_CRT_ON;501		u.active_dev.dvi = viafb_DVI_ON;502		u.active_dev.lcd = viafb_LCD_ON;503		u.active_dev.samm = viafb_SAMM_ON;504		u.active_dev.primary_dev = viafb_primary_dev;505 506		u.active_dev.lcd_dsp_cent = viafb_lcd_dsp_method;507		u.active_dev.lcd_panel_id = viafb_lcd_panel_id;508		u.active_dev.lcd_mode = viafb_lcd_mode;509 510		u.active_dev.xres = viafb_hotplug_Xres;511		u.active_dev.yres = viafb_hotplug_Yres;512 513		u.active_dev.xres1 = viafb_second_xres;514		u.active_dev.yres1 = viafb_second_yres;515 516		u.active_dev.bpp = viafb_bpp;517		u.active_dev.bpp1 = viafb_bpp1;518		u.active_dev.refresh = viafb_refresh;519		u.active_dev.refresh1 = viafb_refresh1;520 521		u.active_dev.epia_dvi = viafb_platform_epia_dvi;522		u.active_dev.lcd_dual_edge = viafb_device_lcd_dualedge;523		u.active_dev.bus_width = viafb_bus_width;524 525		if (copy_to_user(argp, &u.active_dev, sizeof(u.active_dev)))526			return -EFAULT;527		break;528 529	case VIAFB_GET_DRIVER_VERSION:530		u.driver_version.iMajorNum = VERSION_MAJOR;531		u.driver_version.iKernelNum = VERSION_KERNEL;532		u.driver_version.iOSNum = VERSION_OS;533		u.driver_version.iMinorNum = VERSION_MINOR;534 535		if (copy_to_user(argp, &u.driver_version,536			sizeof(u.driver_version)))537			return -EFAULT;538 539		break;540 541	case VIAFB_GET_DEVICE_INFO:542 543		retrieve_device_setting(&u.viafb_setting);544 545		if (copy_to_user(argp, &u.viafb_setting,546				 sizeof(u.viafb_setting)))547			return -EFAULT;548 549		break;550 551	case VIAFB_GET_DEVICE_SUPPORT:552		viafb_get_device_support_state(&state_info);553		if (put_user(state_info, argp))554			return -EFAULT;555		break;556 557	case VIAFB_GET_DEVICE_CONNECT:558		viafb_get_device_connect_state(&state_info);559		if (put_user(state_info, argp))560			return -EFAULT;561		break;562 563	case VIAFB_GET_PANEL_SUPPORT_EXPAND:564		state_info =565		    viafb_lcd_get_support_expand_state(info->var.xres,566						 info->var.yres);567		if (put_user(state_info, argp))568			return -EFAULT;569		break;570 571	case VIAFB_GET_DRIVER_NAME:572		if (copy_to_user(argp, driver_name, sizeof(driver_name)))573			return -EFAULT;574		break;575 576	case VIAFB_SET_GAMMA_LUT:577		viafb_gamma_table = memdup_array_user(argp, 256, sizeof(u32));578		if (IS_ERR(viafb_gamma_table))579			return PTR_ERR(viafb_gamma_table);580		viafb_set_gamma_table(viafb_bpp, viafb_gamma_table);581		kfree(viafb_gamma_table);582		break;583 584	case VIAFB_GET_GAMMA_LUT:585		viafb_gamma_table = kmalloc_array(256, sizeof(u32),586						  GFP_KERNEL);587		if (!viafb_gamma_table)588			return -ENOMEM;589		viafb_get_gamma_table(viafb_gamma_table);590		if (copy_to_user(argp, viafb_gamma_table,591			256 * sizeof(u32))) {592			kfree(viafb_gamma_table);593			return -EFAULT;594		}595		kfree(viafb_gamma_table);596		break;597 598	case VIAFB_GET_GAMMA_SUPPORT_STATE:599		viafb_get_gamma_support_state(viafb_bpp, &state_info);600		if (put_user(state_info, argp))601			return -EFAULT;602		break;603	case VIAFB_SYNC_SURFACE:604		DEBUG_MSG(KERN_INFO "lobo VIAFB_SYNC_SURFACE\n");605		break;606	case VIAFB_GET_DRIVER_CAPS:607		break;608 609	case VIAFB_GET_PANEL_MAX_SIZE:610		if (copy_from_user(&u.panel_pos_size_para, argp,611				   sizeof(u.panel_pos_size_para)))612			return -EFAULT;613		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;614		if (copy_to_user(argp, &u.panel_pos_size_para,615		     sizeof(u.panel_pos_size_para)))616			return -EFAULT;617		break;618	case VIAFB_GET_PANEL_MAX_POSITION:619		if (copy_from_user(&u.panel_pos_size_para, argp,620				   sizeof(u.panel_pos_size_para)))621			return -EFAULT;622		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;623		if (copy_to_user(argp, &u.panel_pos_size_para,624				 sizeof(u.panel_pos_size_para)))625			return -EFAULT;626		break;627 628	case VIAFB_GET_PANEL_POSITION:629		if (copy_from_user(&u.panel_pos_size_para, argp,630				   sizeof(u.panel_pos_size_para)))631			return -EFAULT;632		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;633		if (copy_to_user(argp, &u.panel_pos_size_para,634				 sizeof(u.panel_pos_size_para)))635			return -EFAULT;636		break;637	case VIAFB_GET_PANEL_SIZE:638		if (copy_from_user(&u.panel_pos_size_para, argp,639				   sizeof(u.panel_pos_size_para)))640			return -EFAULT;641		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;642		if (copy_to_user(argp, &u.panel_pos_size_para,643				 sizeof(u.panel_pos_size_para)))644			return -EFAULT;645		break;646 647	case VIAFB_SET_PANEL_POSITION:648		if (copy_from_user(&u.panel_pos_size_para, argp,649				   sizeof(u.panel_pos_size_para)))650			return -EFAULT;651		break;652	case VIAFB_SET_PANEL_SIZE:653		if (copy_from_user(&u.panel_pos_size_para, argp,654				   sizeof(u.panel_pos_size_para)))655			return -EFAULT;656		break;657 658	default:659		return -EINVAL;660	}661 662	return 0;663}664 665static void viafb_fillrect(struct fb_info *info,666	const struct fb_fillrect *rect)667{668	struct viafb_par *viapar = info->par;669	struct viafb_shared *shared = viapar->shared;670	u32 fg_color;671	u8 rop;672 673	if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt) {674		cfb_fillrect(info, rect);675		return;676	}677 678	if (!rect->width || !rect->height)679		return;680 681	if (info->fix.visual == FB_VISUAL_TRUECOLOR)682		fg_color = ((u32 *)info->pseudo_palette)[rect->color];683	else684		fg_color = rect->color;685 686	if (rect->rop == ROP_XOR)687		rop = 0x5A;688	else689		rop = 0xF0;690 691	DEBUG_MSG(KERN_DEBUG "viafb 2D engine: fillrect\n");692	if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_FILL,693		rect->width, rect->height, info->var.bits_per_pixel,694		viapar->vram_addr, info->fix.line_length, rect->dx, rect->dy,695		NULL, 0, 0, 0, 0, fg_color, 0, rop))696		cfb_fillrect(info, rect);697}698 699static void viafb_copyarea(struct fb_info *info,700	const struct fb_copyarea *area)701{702	struct viafb_par *viapar = info->par;703	struct viafb_shared *shared = viapar->shared;704 705	if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt) {706		cfb_copyarea(info, area);707		return;708	}709 710	if (!area->width || !area->height)711		return;712 713	DEBUG_MSG(KERN_DEBUG "viafb 2D engine: copyarea\n");714	if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_COLOR,715		area->width, area->height, info->var.bits_per_pixel,716		viapar->vram_addr, info->fix.line_length, area->dx, area->dy,717		NULL, viapar->vram_addr, info->fix.line_length,718		area->sx, area->sy, 0, 0, 0))719		cfb_copyarea(info, area);720}721 722static void viafb_imageblit(struct fb_info *info,723	const struct fb_image *image)724{725	struct viafb_par *viapar = info->par;726	struct viafb_shared *shared = viapar->shared;727	u32 fg_color = 0, bg_color = 0;728	u8 op;729 730	if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt ||731		(image->depth != 1 && image->depth != viapar->depth)) {732		cfb_imageblit(info, image);733		return;734	}735 736	if (image->depth == 1) {737		op = VIA_BITBLT_MONO;738		if (info->fix.visual == FB_VISUAL_TRUECOLOR) {739			fg_color =740				((u32 *)info->pseudo_palette)[image->fg_color];741			bg_color =742				((u32 *)info->pseudo_palette)[image->bg_color];743		} else {744			fg_color = image->fg_color;745			bg_color = image->bg_color;746		}747	} else748		op = VIA_BITBLT_COLOR;749 750	DEBUG_MSG(KERN_DEBUG "viafb 2D engine: imageblit\n");751	if (shared->hw_bitblt(shared->vdev->engine_mmio, op,752		image->width, image->height, info->var.bits_per_pixel,753		viapar->vram_addr, info->fix.line_length, image->dx, image->dy,754		(u32 *)image->data, 0, 0, 0, 0, fg_color, bg_color, 0))755		cfb_imageblit(info, image);756}757 758static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)759{760	struct viafb_par *viapar = info->par;761	void __iomem *engine = viapar->shared->vdev->engine_mmio;762	u32 temp, xx, yy, bg_color = 0, fg_color = 0,763		chip_name = viapar->shared->chip_info.gfx_chip_name;764	int i, j = 0, cur_size = 64;765 766	if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo)767		return -ENODEV;768 769	/* LCD ouput does not support hw cursors (at least on VN896) */770	if ((chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) ||771		viafb_LCD_ON)772		return -ENODEV;773 774	viafb_show_hw_cursor(info, HW_Cursor_OFF);775 776	if (cursor->set & FB_CUR_SETHOT) {777		temp = (cursor->hot.x << 16) + cursor->hot.y;778		writel(temp, engine + VIA_REG_CURSOR_ORG);779	}780 781	if (cursor->set & FB_CUR_SETPOS) {782		yy = cursor->image.dy - info->var.yoffset;783		xx = cursor->image.dx - info->var.xoffset;784		temp = yy & 0xFFFF;785		temp |= (xx << 16);786		writel(temp, engine + VIA_REG_CURSOR_POS);787	}788 789	if (cursor->image.width <= 32 && cursor->image.height <= 32)790		cur_size = 32;791	else if (cursor->image.width <= 64 && cursor->image.height <= 64)792		cur_size = 64;793	else {794		printk(KERN_WARNING "viafb_cursor: The cursor is too large "795			"%dx%d", cursor->image.width, cursor->image.height);796		return -ENXIO;797	}798 799	if (cursor->set & FB_CUR_SETSIZE) {800		temp = readl(engine + VIA_REG_CURSOR_MODE);801		if (cur_size == 32)802			temp |= 0x2;803		else804			temp &= ~0x2;805 806		writel(temp, engine + VIA_REG_CURSOR_MODE);807	}808 809	if (cursor->set & FB_CUR_SETCMAP) {810		fg_color = cursor->image.fg_color;811		bg_color = cursor->image.bg_color;812		if (chip_name == UNICHROME_CX700 ||813			chip_name == UNICHROME_VX800 ||814			chip_name == UNICHROME_VX855 ||815			chip_name == UNICHROME_VX900) {816			fg_color =817				((info->cmap.red[fg_color] & 0xFFC0) << 14) |818				((info->cmap.green[fg_color] & 0xFFC0) << 4) |819				((info->cmap.blue[fg_color] & 0xFFC0) >> 6);820			bg_color =821				((info->cmap.red[bg_color] & 0xFFC0) << 14) |822				((info->cmap.green[bg_color] & 0xFFC0) << 4) |823				((info->cmap.blue[bg_color] & 0xFFC0) >> 6);824		} else {825			fg_color =826				((info->cmap.red[fg_color] & 0xFF00) << 8) |827				(info->cmap.green[fg_color] & 0xFF00) |828				((info->cmap.blue[fg_color] & 0xFF00) >> 8);829			bg_color =830				((info->cmap.red[bg_color] & 0xFF00) << 8) |831				(info->cmap.green[bg_color] & 0xFF00) |832				((info->cmap.blue[bg_color] & 0xFF00) >> 8);833		}834 835		writel(bg_color, engine + VIA_REG_CURSOR_BG);836		writel(fg_color, engine + VIA_REG_CURSOR_FG);837	}838 839	if (cursor->set & FB_CUR_SETSHAPE) {840		struct {841			u8 data[CURSOR_SIZE];842			u32 bak[CURSOR_SIZE / 4];843		} *cr_data = kzalloc(sizeof(*cr_data), GFP_ATOMIC);844		int size = ((cursor->image.width + 7) >> 3) *845			cursor->image.height;846 847		if (!cr_data)848			return -ENOMEM;849 850		if (cur_size == 32) {851			for (i = 0; i < (CURSOR_SIZE / 4); i++) {852				cr_data->bak[i] = 0x0;853				cr_data->bak[i + 1] = 0xFFFFFFFF;854				i += 1;855			}856		} else {857			for (i = 0; i < (CURSOR_SIZE / 4); i++) {858				cr_data->bak[i] = 0x0;859				cr_data->bak[i + 1] = 0x0;860				cr_data->bak[i + 2] = 0xFFFFFFFF;861				cr_data->bak[i + 3] = 0xFFFFFFFF;862				i += 3;863			}864		}865 866		switch (cursor->rop) {867		case ROP_XOR:868			for (i = 0; i < size; i++)869				cr_data->data[i] = cursor->mask[i];870			break;871		case ROP_COPY:872 873			for (i = 0; i < size; i++)874				cr_data->data[i] = cursor->mask[i];875			break;876		default:877			break;878		}879 880		if (cur_size == 32) {881			for (i = 0; i < size; i++) {882				cr_data->bak[j] = (u32) cr_data->data[i];883				cr_data->bak[j + 1] = ~cr_data->bak[j];884				j += 2;885			}886		} else {887			for (i = 0; i < size; i++) {888				cr_data->bak[j] = (u32) cr_data->data[i];889				cr_data->bak[j + 1] = 0x0;890				cr_data->bak[j + 2] = ~cr_data->bak[j];891				cr_data->bak[j + 3] = ~cr_data->bak[j + 1];892				j += 4;893			}894		}895 896		memcpy_toio(viafbinfo->screen_base + viapar->shared->897			cursor_vram_addr, cr_data->bak, CURSOR_SIZE);898		kfree(cr_data);899	}900 901	if (cursor->enable)902		viafb_show_hw_cursor(info, HW_Cursor_ON);903 904	return 0;905}906 907static int viafb_sync(struct fb_info *info)908{909	if (!(info->flags & FBINFO_HWACCEL_DISABLED))910		viafb_wait_engine_idle(info);911	return 0;912}913 914static int get_primary_device(void)915{916	int primary_device = 0;917	/* Rule: device on iga1 path are the primary device. */918	if (viafb_SAMM_ON) {919		if (viafb_CRT_ON) {920			if (viaparinfo->shared->iga1_devices & VIA_CRT) {921				DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n", IGA1);922				primary_device = CRT_Device;923			}924		}925		if (viafb_DVI_ON) {926			if (viaparinfo->tmds_setting_info->iga_path == IGA1) {927				DEBUG_MSG(KERN_INFO "DVI IGA Path:%d\n",928					viaparinfo->929					tmds_setting_info->iga_path);930				primary_device = DVI_Device;931			}932		}933		if (viafb_LCD_ON) {934			if (viaparinfo->lvds_setting_info->iga_path == IGA1) {935				DEBUG_MSG(KERN_INFO "LCD IGA Path:%d\n",936					viaparinfo->937					lvds_setting_info->iga_path);938				primary_device = LCD_Device;939			}940		}941		if (viafb_LCD2_ON) {942			if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {943				DEBUG_MSG(KERN_INFO "LCD2 IGA Path:%d\n",944					viaparinfo->945					lvds_setting_info2->iga_path);946				primary_device = LCD2_Device;947			}948		}949	}950	return primary_device;951}952 953static void retrieve_device_setting(struct viafb_ioctl_setting954	*setting_info)955{956 957	/* get device status */958	if (viafb_CRT_ON == 1)959		setting_info->device_status = CRT_Device;960	if (viafb_DVI_ON == 1)961		setting_info->device_status |= DVI_Device;962	if (viafb_LCD_ON == 1)963		setting_info->device_status |= LCD_Device;964	if (viafb_LCD2_ON == 1)965		setting_info->device_status |= LCD2_Device;966 967	setting_info->samm_status = viafb_SAMM_ON;968	setting_info->primary_device = get_primary_device();969 970	setting_info->first_dev_bpp = viafb_bpp;971	setting_info->second_dev_bpp = viafb_bpp1;972 973	setting_info->first_dev_refresh = viafb_refresh;974	setting_info->second_dev_refresh = viafb_refresh1;975 976	setting_info->first_dev_hor_res = viafb_hotplug_Xres;977	setting_info->first_dev_ver_res = viafb_hotplug_Yres;978	setting_info->second_dev_hor_res = viafb_second_xres;979	setting_info->second_dev_ver_res = viafb_second_yres;980 981	/* Get lcd attributes */982	setting_info->lcd_attributes.display_center = viafb_lcd_dsp_method;983	setting_info->lcd_attributes.panel_id = viafb_lcd_panel_id;984	setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode;985}986 987static int __init parse_active_dev(void)988{989	viafb_CRT_ON = STATE_OFF;990	viafb_DVI_ON = STATE_OFF;991	viafb_LCD_ON = STATE_OFF;992	viafb_LCD2_ON = STATE_OFF;993	/* 1. Modify the active status of devices. */994	/* 2. Keep the order of devices, so we can set corresponding995	   IGA path to devices in SAMM case. */996	/*    Note: The previous of active_dev is primary device,997	   and the following is secondary device. */998	if (!viafb_active_dev) {999		if (machine_is_olpc()) { /* LCD only */1000			viafb_LCD_ON = STATE_ON;1001			viafb_SAMM_ON = STATE_OFF;1002		} else {1003			viafb_CRT_ON = STATE_ON;1004			viafb_SAMM_ON = STATE_OFF;1005		}1006	} else if (!strcmp(viafb_active_dev, "CRT+DVI")) {1007		/* CRT+DVI */1008		viafb_CRT_ON = STATE_ON;1009		viafb_DVI_ON = STATE_ON;1010		viafb_primary_dev = CRT_Device;1011	} else if (!strcmp(viafb_active_dev, "DVI+CRT")) {1012		/* DVI+CRT */1013		viafb_CRT_ON = STATE_ON;1014		viafb_DVI_ON = STATE_ON;1015		viafb_primary_dev = DVI_Device;1016	} else if (!strcmp(viafb_active_dev, "CRT+LCD")) {1017		/* CRT+LCD */1018		viafb_CRT_ON = STATE_ON;1019		viafb_LCD_ON = STATE_ON;1020		viafb_primary_dev = CRT_Device;1021	} else if (!strcmp(viafb_active_dev, "LCD+CRT")) {1022		/* LCD+CRT */1023		viafb_CRT_ON = STATE_ON;1024		viafb_LCD_ON = STATE_ON;1025		viafb_primary_dev = LCD_Device;1026	} else if (!strcmp(viafb_active_dev, "DVI+LCD")) {1027		/* DVI+LCD */1028		viafb_DVI_ON = STATE_ON;1029		viafb_LCD_ON = STATE_ON;1030		viafb_primary_dev = DVI_Device;1031	} else if (!strcmp(viafb_active_dev, "LCD+DVI")) {1032		/* LCD+DVI */1033		viafb_DVI_ON = STATE_ON;1034		viafb_LCD_ON = STATE_ON;1035		viafb_primary_dev = LCD_Device;1036	} else if (!strcmp(viafb_active_dev, "LCD+LCD2")) {1037		viafb_LCD_ON = STATE_ON;1038		viafb_LCD2_ON = STATE_ON;1039		viafb_primary_dev = LCD_Device;1040	} else if (!strcmp(viafb_active_dev, "LCD2+LCD")) {1041		viafb_LCD_ON = STATE_ON;1042		viafb_LCD2_ON = STATE_ON;1043		viafb_primary_dev = LCD2_Device;1044	} else if (!strcmp(viafb_active_dev, "CRT")) {1045		/* CRT only */1046		viafb_CRT_ON = STATE_ON;1047		viafb_SAMM_ON = STATE_OFF;1048	} else if (!strcmp(viafb_active_dev, "DVI")) {1049		/* DVI only */1050		viafb_DVI_ON = STATE_ON;1051		viafb_SAMM_ON = STATE_OFF;1052	} else if (!strcmp(viafb_active_dev, "LCD")) {1053		/* LCD only */1054		viafb_LCD_ON = STATE_ON;1055		viafb_SAMM_ON = STATE_OFF;1056	} else1057		return -EINVAL;1058 1059	return 0;1060}1061 1062static int parse_port(char *opt_str, int *output_interface)1063{1064	if (!strncmp(opt_str, "DVP0", 4))1065		*output_interface = INTERFACE_DVP0;1066	else if (!strncmp(opt_str, "DVP1", 4))1067		*output_interface = INTERFACE_DVP1;1068	else if (!strncmp(opt_str, "DFP_HIGHLOW", 11))1069		*output_interface = INTERFACE_DFP;1070	else if (!strncmp(opt_str, "DFP_HIGH", 8))1071		*output_interface = INTERFACE_DFP_HIGH;1072	else if (!strncmp(opt_str, "DFP_LOW", 7))1073		*output_interface = INTERFACE_DFP_LOW;1074	else1075		*output_interface = INTERFACE_NONE;1076	return 0;1077}1078 1079static void parse_lcd_port(void)1080{1081	parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info.1082		output_interface);1083	/*Initialize to avoid unexpected behavior */1084	viaparinfo->chip_info->lvds_chip_info2.output_interface =1085	INTERFACE_NONE;1086 1087	DEBUG_MSG(KERN_INFO "parse_lcd_port: viafb_lcd_port:%s,interface:%d\n",1088		  viafb_lcd_port, viaparinfo->chip_info->lvds_chip_info.1089		  output_interface);1090}1091 1092static void parse_dvi_port(void)1093{1094	parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info.1095		output_interface);1096 1097	DEBUG_MSG(KERN_INFO "parse_dvi_port: viafb_dvi_port:%s,interface:%d\n",1098		  viafb_dvi_port, viaparinfo->chip_info->tmds_chip_info.1099		  output_interface);1100}1101 1102#ifdef CONFIG_FB_VIA_DIRECT_PROCFS1103 1104/*1105 * The proc filesystem read/write function, a simple proc implement to1106 * get/set the value of DPA  DVP0,   DVP0DataDriving,  DVP0ClockDriving, DVP1,1107 * DVP1Driving, DFPHigh, DFPLow CR96,   SR2A[5], SR1B[1], SR2A[4], SR1E[2],1108 * CR9B,    SR65,    CR97,    CR991109 */1110static int viafb_dvp0_proc_show(struct seq_file *m, void *v)1111{1112	u8 dvp0_data_dri = 0, dvp0_clk_dri = 0, dvp0 = 0;1113	dvp0_data_dri =1114	    (viafb_read_reg(VIASR, SR2A) & BIT5) >> 4 |1115	    (viafb_read_reg(VIASR, SR1B) & BIT1) >> 1;1116	dvp0_clk_dri =1117	    (viafb_read_reg(VIASR, SR2A) & BIT4) >> 3 |1118	    (viafb_read_reg(VIASR, SR1E) & BIT2) >> 2;1119	dvp0 = viafb_read_reg(VIACR, CR96) & 0x0f;1120	seq_printf(m, "%x %x %x\n", dvp0, dvp0_data_dri, dvp0_clk_dri);1121	return 0;1122}1123 1124static int viafb_dvp0_proc_open(struct inode *inode, struct file *file)1125{1126	return single_open(file, viafb_dvp0_proc_show, NULL);1127}1128 1129static ssize_t viafb_dvp0_proc_write(struct file *file,1130	const char __user *buffer, size_t count, loff_t *pos)1131{1132	char buf[20], *value, *pbuf;1133	u8 reg_val = 0;1134	unsigned long length, i;1135	if (count < 1)1136		return -EINVAL;1137	length = count > 20 ? 20 : count;1138	if (copy_from_user(&buf[0], buffer, length))1139		return -EFAULT;1140	buf[length - 1] = '\0';	/*Ensure end string */1141	pbuf = &buf[0];1142	for (i = 0; i < 3; i++) {1143		value = strsep(&pbuf, " ");1144		if (value != NULL) {1145			if (kstrtou8(value, 0, &reg_val) < 0)1146				return -EINVAL;1147			DEBUG_MSG(KERN_INFO "DVP0:reg_val[%lu]=:%x\n", i,1148				  reg_val);1149			switch (i) {1150			case 0:1151				viafb_write_reg_mask(CR96, VIACR,1152					reg_val, 0x0f);1153				break;1154			case 1:1155				viafb_write_reg_mask(SR2A, VIASR,1156					reg_val << 4, BIT5);1157				viafb_write_reg_mask(SR1B, VIASR,1158					reg_val << 1, BIT1);1159				break;1160			case 2:1161				viafb_write_reg_mask(SR2A, VIASR,1162					reg_val << 3, BIT4);1163				viafb_write_reg_mask(SR1E, VIASR,1164					reg_val << 2, BIT2);1165				break;1166			default:1167				break;1168			}1169		} else {1170			break;1171		}1172	}1173	return count;1174}1175 1176static const struct proc_ops viafb_dvp0_proc_ops = {1177	.proc_open	= viafb_dvp0_proc_open,1178	.proc_read	= seq_read,1179	.proc_lseek	= seq_lseek,1180	.proc_release	= single_release,1181	.proc_write	= viafb_dvp0_proc_write,1182};1183 1184static int viafb_dvp1_proc_show(struct seq_file *m, void *v)1185{1186	u8 dvp1 = 0, dvp1_data_dri = 0, dvp1_clk_dri = 0;1187	dvp1 = viafb_read_reg(VIACR, CR9B) & 0x0f;1188	dvp1_data_dri = (viafb_read_reg(VIASR, SR65) & 0x0c) >> 2;1189	dvp1_clk_dri = viafb_read_reg(VIASR, SR65) & 0x03;1190	seq_printf(m, "%x %x %x\n", dvp1, dvp1_data_dri, dvp1_clk_dri);1191	return 0;1192}1193 1194static int viafb_dvp1_proc_open(struct inode *inode, struct file *file)1195{1196	return single_open(file, viafb_dvp1_proc_show, NULL);1197}1198 1199static ssize_t viafb_dvp1_proc_write(struct file *file,1200	const char __user *buffer, size_t count, loff_t *pos)1201{1202	char buf[20], *value, *pbuf;1203	u8 reg_val = 0;1204	unsigned long length, i;1205	if (count < 1)1206		return -EINVAL;1207	length = count > 20 ? 20 : count;1208	if (copy_from_user(&buf[0], buffer, length))1209		return -EFAULT;1210	buf[length - 1] = '\0';	/*Ensure end string */1211	pbuf = &buf[0];1212	for (i = 0; i < 3; i++) {1213		value = strsep(&pbuf, " ");1214		if (value != NULL) {1215			if (kstrtou8(value, 0, &reg_val) < 0)1216				return -EINVAL;1217			switch (i) {1218			case 0:1219				viafb_write_reg_mask(CR9B, VIACR,1220					reg_val, 0x0f);1221				break;1222			case 1:1223				viafb_write_reg_mask(SR65, VIASR,1224					reg_val << 2, 0x0c);1225				break;1226			case 2:1227				viafb_write_reg_mask(SR65, VIASR,1228					reg_val, 0x03);1229				break;1230			default:1231				break;1232			}1233		} else {1234			break;1235		}1236	}1237	return count;1238}1239 1240static const struct proc_ops viafb_dvp1_proc_ops = {1241	.proc_open	= viafb_dvp1_proc_open,1242	.proc_read	= seq_read,1243	.proc_lseek	= seq_lseek,1244	.proc_release	= single_release,1245	.proc_write	= viafb_dvp1_proc_write,1246};1247 1248static int viafb_dfph_proc_show(struct seq_file *m, void *v)1249{1250	u8 dfp_high = 0;1251	dfp_high = viafb_read_reg(VIACR, CR97) & 0x0f;1252	seq_printf(m, "%x\n", dfp_high);1253	return 0;1254}1255 1256static int viafb_dfph_proc_open(struct inode *inode, struct file *file)1257{1258	return single_open(file, viafb_dfph_proc_show, NULL);1259}1260 1261static ssize_t viafb_dfph_proc_write(struct file *file,1262	const char __user *buffer, size_t count, loff_t *pos)1263{1264	int err;1265	u8 reg_val;1266	err = kstrtou8_from_user(buffer, count, 0, &reg_val);1267	if (err)1268		return err;1269 1270	viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f);1271	return count;1272}1273 1274static const struct proc_ops viafb_dfph_proc_ops = {1275	.proc_open	= viafb_dfph_proc_open,1276	.proc_read	= seq_read,1277	.proc_lseek	= seq_lseek,1278	.proc_release	= single_release,1279	.proc_write	= viafb_dfph_proc_write,1280};1281 1282static int viafb_dfpl_proc_show(struct seq_file *m, void *v)1283{1284	u8 dfp_low = 0;1285	dfp_low = viafb_read_reg(VIACR, CR99) & 0x0f;1286	seq_printf(m, "%x\n", dfp_low);1287	return 0;1288}1289 1290static int viafb_dfpl_proc_open(struct inode *inode, struct file *file)1291{1292	return single_open(file, viafb_dfpl_proc_show, NULL);1293}1294 1295static ssize_t viafb_dfpl_proc_write(struct file *file,1296	const char __user *buffer, size_t count, loff_t *pos)1297{1298	int err;1299	u8 reg_val;1300	err = kstrtou8_from_user(buffer, count, 0, &reg_val);1301	if (err)1302		return err;1303 1304	viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f);1305	return count;1306}1307 1308static const struct proc_ops viafb_dfpl_proc_ops = {1309	.proc_open	= viafb_dfpl_proc_open,1310	.proc_read	= seq_read,1311	.proc_lseek	= seq_lseek,1312	.proc_release	= single_release,1313	.proc_write	= viafb_dfpl_proc_write,1314};1315 1316static int viafb_vt1636_proc_show(struct seq_file *m, void *v)1317{1318	u8 vt1636_08 = 0, vt1636_09 = 0;1319	switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {1320	case VT1636_LVDS:1321		vt1636_08 =1322		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,1323		    &viaparinfo->chip_info->lvds_chip_info, 0x08) & 0x0f;1324		vt1636_09 =1325		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,1326		    &viaparinfo->chip_info->lvds_chip_info, 0x09) & 0x1f;1327		seq_printf(m, "%x %x\n", vt1636_08, vt1636_09);1328		break;1329	default:1330		break;1331	}1332	switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {1333	case VT1636_LVDS:1334		vt1636_08 =1335		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,1336			&viaparinfo->chip_info->lvds_chip_info2, 0x08) & 0x0f;1337		vt1636_09 =1338		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,1339			&viaparinfo->chip_info->lvds_chip_info2, 0x09) & 0x1f;1340		seq_printf(m, " %x %x\n", vt1636_08, vt1636_09);1341		break;1342	default:1343		break;1344	}1345	return 0;1346}1347 1348static int viafb_vt1636_proc_open(struct inode *inode, struct file *file)1349{1350	return single_open(file, viafb_vt1636_proc_show, NULL);1351}1352 1353static ssize_t viafb_vt1636_proc_write(struct file *file,1354	const char __user *buffer, size_t count, loff_t *pos)1355{1356	char buf[30], *value, *pbuf;1357	struct IODATA reg_val;1358	unsigned long length, i;1359	if (count < 1)1360		return -EINVAL;1361	length = count > 30 ? 30 : count;1362	if (copy_from_user(&buf[0], buffer, length))1363		return -EFAULT;1364	buf[length - 1] = '\0';	/*Ensure end string */1365	pbuf = &buf[0];1366	switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {1367	case VT1636_LVDS:1368		for (i = 0; i < 2; i++) {1369			value = strsep(&pbuf, " ");1370			if (value != NULL) {1371				if (kstrtou8(value, 0, &reg_val.Data) < 0)1372					return -EINVAL;1373				switch (i) {1374				case 0:1375					reg_val.Index = 0x08;1376					reg_val.Mask = 0x0f;1377					viafb_gpio_i2c_write_mask_lvds1378					    (viaparinfo->lvds_setting_info,1379					    &viaparinfo->1380					    chip_info->lvds_chip_info,1381					     reg_val);1382					break;1383				case 1:1384					reg_val.Index = 0x09;1385					reg_val.Mask = 0x1f;1386					viafb_gpio_i2c_write_mask_lvds1387					    (viaparinfo->lvds_setting_info,1388					    &viaparinfo->1389					    chip_info->lvds_chip_info,1390					     reg_val);1391					break;1392				default:1393					break;1394				}1395			} else {1396				break;1397			}1398		}1399		break;1400	default:1401		break;1402	}1403	switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {1404	case VT1636_LVDS:1405		for (i = 0; i < 2; i++) {1406			value = strsep(&pbuf, " ");1407			if (value != NULL) {1408				if (kstrtou8(value, 0, &reg_val.Data) < 0)1409					return -EINVAL;1410				switch (i) {1411				case 0:1412					reg_val.Index = 0x08;1413					reg_val.Mask = 0x0f;1414					viafb_gpio_i2c_write_mask_lvds1415					    (viaparinfo->lvds_setting_info2,1416					    &viaparinfo->1417					    chip_info->lvds_chip_info2,1418					     reg_val);1419					break;1420				case 1:1421					reg_val.Index = 0x09;1422					reg_val.Mask = 0x1f;1423					viafb_gpio_i2c_write_mask_lvds1424					    (viaparinfo->lvds_setting_info2,1425					    &viaparinfo->1426					    chip_info->lvds_chip_info2,1427					     reg_val);1428					break;1429				default:1430					break;1431				}1432			} else {1433				break;1434			}1435		}1436		break;1437	default:1438		break;1439	}1440	return count;1441}1442 1443static const struct proc_ops viafb_vt1636_proc_ops = {1444	.proc_open	= viafb_vt1636_proc_open,1445	.proc_read	= seq_read,1446	.proc_lseek	= seq_lseek,1447	.proc_release	= single_release,1448	.proc_write	= viafb_vt1636_proc_write,1449};1450 1451#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */1452 1453static int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v)1454{1455	via_odev_to_seq(m, supported_odev_map[1456		viaparinfo->shared->chip_info.gfx_chip_name]);1457	return 0;1458}1459 1460static ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev)1461{1462	char buf[64], *ptr = buf;1463	u32 devices;1464	bool add, sub;1465 1466	if (count < 1 || count > 63)1467		return -EINVAL;1468	if (copy_from_user(&buf[0], buffer, count))1469		return -EFAULT;1470	buf[count] = '\0';1471	add = buf[0] == '+';1472	sub = buf[0] == '-';1473	if (add || sub)1474		ptr++;1475	devices = via_parse_odev(ptr, &ptr);1476	if (*ptr == '\n')1477		ptr++;1478	if (*ptr != 0)1479		return -EINVAL;1480	if (add)1481		*odev |= devices;1482	else if (sub)1483		*odev &= ~devices;1484	else1485		*odev = devices;1486	return count;1487}1488 1489static int viafb_iga1_odev_proc_show(struct seq_file *m, void *v)1490{1491	via_odev_to_seq(m, viaparinfo->shared->iga1_devices);1492	return 0;1493}1494 1495static int viafb_iga1_odev_proc_open(struct inode *inode, struct file *file)1496{1497	return single_open(file, viafb_iga1_odev_proc_show, NULL);1498}1499 1500static ssize_t viafb_iga1_odev_proc_write(struct file *file,1501	const char __user *buffer, size_t count, loff_t *pos)1502{1503	u32 dev_on, dev_off, dev_old, dev_new;1504	ssize_t res;1505 1506	dev_old = dev_new = viaparinfo->shared->iga1_devices;1507	res = odev_update(buffer, count, &dev_new);1508	if (res != count)1509		return res;1510	dev_off = dev_old & ~dev_new;1511	dev_on = dev_new & ~dev_old;1512	viaparinfo->shared->iga1_devices = dev_new;1513	viaparinfo->shared->iga2_devices &= ~dev_new;1514	via_set_state(dev_off, VIA_STATE_OFF);1515	via_set_source(dev_new, IGA1);1516	via_set_state(dev_on, VIA_STATE_ON);1517	return res;1518}1519 1520static const struct proc_ops viafb_iga1_odev_proc_ops = {1521	.proc_open	= viafb_iga1_odev_proc_open,1522	.proc_read	= seq_read,1523	.proc_lseek	= seq_lseek,1524	.proc_release	= single_release,1525	.proc_write	= viafb_iga1_odev_proc_write,1526};1527 1528static int viafb_iga2_odev_proc_show(struct seq_file *m, void *v)1529{1530	via_odev_to_seq(m, viaparinfo->shared->iga2_devices);1531	return 0;1532}1533 1534static int viafb_iga2_odev_proc_open(struct inode *inode, struct file *file)1535{1536	return single_open(file, viafb_iga2_odev_proc_show, NULL);1537}1538 1539static ssize_t viafb_iga2_odev_proc_write(struct file *file,1540	const char __user *buffer, size_t count, loff_t *pos)1541{1542	u32 dev_on, dev_off, dev_old, dev_new;1543	ssize_t res;1544 1545	dev_old = dev_new = viaparinfo->shared->iga2_devices;1546	res = odev_update(buffer, count, &dev_new);1547	if (res != count)1548		return res;1549	dev_off = dev_old & ~dev_new;1550	dev_on = dev_new & ~dev_old;1551	viaparinfo->shared->iga2_devices = dev_new;1552	viaparinfo->shared->iga1_devices &= ~dev_new;1553	via_set_state(dev_off, VIA_STATE_OFF);1554	via_set_source(dev_new, IGA2);1555	via_set_state(dev_on, VIA_STATE_ON);1556	return res;1557}1558 1559static const struct proc_ops viafb_iga2_odev_proc_ops = {1560	.proc_open	= viafb_iga2_odev_proc_open,1561	.proc_read	= seq_read,1562	.proc_lseek	= seq_lseek,1563	.proc_release	= single_release,1564	.proc_write	= viafb_iga2_odev_proc_write,1565};1566 1567#define IS_VT1636(lvds_chip)	((lvds_chip).lvds_chip_name == VT1636_LVDS)1568static void viafb_init_proc(struct viafb_shared *shared)1569{1570	struct proc_dir_entry *iga1_entry, *iga2_entry,1571		*viafb_entry = proc_mkdir("viafb", NULL);1572 1573	shared->proc_entry = viafb_entry;1574	if (viafb_entry) {1575#ifdef CONFIG_FB_VIA_DIRECT_PROCFS1576		proc_create("dvp0", 0, viafb_entry, &viafb_dvp0_proc_ops);1577		proc_create("dvp1", 0, viafb_entry, &viafb_dvp1_proc_ops);1578		proc_create("dfph", 0, viafb_entry, &viafb_dfph_proc_ops);1579		proc_create("dfpl", 0, viafb_entry, &viafb_dfpl_proc_ops);1580		if (IS_VT1636(shared->chip_info.lvds_chip_info)1581			|| IS_VT1636(shared->chip_info.lvds_chip_info2))1582			proc_create("vt1636", 0, viafb_entry,1583				    &viafb_vt1636_proc_ops);1584#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */1585 1586		proc_create_single("supported_output_devices", 0, viafb_entry,1587			viafb_sup_odev_proc_show);1588		iga1_entry = proc_mkdir("iga1", viafb_entry);1589		shared->iga1_proc_entry = iga1_entry;1590		proc_create("output_devices", 0, iga1_entry,1591			    &viafb_iga1_odev_proc_ops);1592		iga2_entry = proc_mkdir("iga2", viafb_entry);1593		shared->iga2_proc_entry = iga2_entry;1594		proc_create("output_devices", 0, iga2_entry,1595			    &viafb_iga2_odev_proc_ops);1596	}1597}1598static void viafb_remove_proc(struct viafb_shared *shared)1599{1600	struct proc_dir_entry *viafb_entry = shared->proc_entry;1601 1602	if (!viafb_entry)1603		return;1604 1605	remove_proc_entry("output_devices", shared->iga2_proc_entry);1606	remove_proc_entry("iga2", viafb_entry);1607	remove_proc_entry("output_devices", shared->iga1_proc_entry);1608	remove_proc_entry("iga1", viafb_entry);1609	remove_proc_entry("supported_output_devices", viafb_entry);1610 1611#ifdef CONFIG_FB_VIA_DIRECT_PROCFS1612	remove_proc_entry("dvp0", viafb_entry);/* parent dir */1613	remove_proc_entry("dvp1", viafb_entry);1614	remove_proc_entry("dfph", viafb_entry);1615	remove_proc_entry("dfpl", viafb_entry);1616	if (IS_VT1636(shared->chip_info.lvds_chip_info)1617		|| IS_VT1636(shared->chip_info.lvds_chip_info2))1618		remove_proc_entry("vt1636", viafb_entry);1619#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */1620 1621	remove_proc_entry("viafb", NULL);1622}1623#undef IS_VT16361624 1625static int parse_mode(const char *str, u32 devices, u32 *xres, u32 *yres)1626{1627	const struct fb_videomode *mode = NULL;1628	char *ptr;1629 1630	if (!str) {1631		if (devices == VIA_CRT)1632			mode = via_aux_get_preferred_mode(1633				viaparinfo->shared->i2c_26);1634		else if (devices == VIA_DVP1)1635			mode = via_aux_get_preferred_mode(1636				viaparinfo->shared->i2c_31);1637 1638		if (mode) {1639			*xres = mode->xres;1640			*yres = mode->yres;1641		} else if (machine_is_olpc()) {1642			*xres = 1200;1643			*yres = 900;1644		} else {1645			*xres = 640;1646			*yres = 480;1647		}1648		return 0;1649	}1650 1651	*xres = simple_strtoul(str, &ptr, 10);1652	if (ptr[0] != 'x')1653		return -EINVAL;1654 1655	*yres = simple_strtoul(&ptr[1], &ptr, 10);1656	if (ptr[0])1657		return -EINVAL;1658 1659	return 0;1660}1661 1662 1663#ifdef CONFIG_PM1664static int viafb_suspend(void *unused)1665{1666	console_lock();1667	fb_set_suspend(viafbinfo, 1);1668	viafb_sync(viafbinfo);1669	console_unlock();1670 1671	return 0;1672}1673 1674static int viafb_resume(void *unused)1675{1676	console_lock();1677	if (viaparinfo->shared->vdev->engine_mmio)1678		viafb_reset_engine(viaparinfo);1679	viafb_set_par(viafbinfo);1680	if (viafb_dual_fb)1681		viafb_set_par(viafbinfo1);1682	fb_set_suspend(viafbinfo, 0);1683 1684	console_unlock();1685	return 0;1686}1687 1688static struct viafb_pm_hooks viafb_fb_pm_hooks = {1689	.suspend = viafb_suspend,1690	.resume = viafb_resume1691};1692 1693#endif1694 1695static void i2c_bus_probe(struct viafb_shared *shared)1696{1697	/* should be always CRT */1698	printk(KERN_INFO "viafb: Probing I2C bus 0x26\n");1699	shared->i2c_26 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_26));1700 1701	/* seems to be usually DVP1 */1702	printk(KERN_INFO "viafb: Probing I2C bus 0x31\n");1703	shared->i2c_31 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_31));1704 1705	/* FIXME: what is this? */1706	if (!machine_is_olpc()) {1707		printk(KERN_INFO "viafb: Probing I2C bus 0x2C\n");1708		shared->i2c_2C = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_2C));1709	}1710 1711	printk(KERN_INFO "viafb: Finished I2C bus probing");1712}1713 1714static void i2c_bus_free(struct viafb_shared *shared)1715{1716	via_aux_free(shared->i2c_26);1717	via_aux_free(shared->i2c_31);1718	via_aux_free(shared->i2c_2C);1719}1720 1721int via_fb_pci_probe(struct viafb_dev *vdev)1722{1723	u32 default_xres, default_yres;1724	struct fb_var_screeninfo default_var;1725	int rc;1726	u32 viafb_par_length;1727 1728	DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");1729	memset(&default_var, 0, sizeof(default_var));1730	viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8);1731 1732	/* Allocate fb_info and ***_par here, also including some other needed1733	 * variables1734	*/1735	viafbinfo = framebuffer_alloc(viafb_par_length +1736		ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8),1737		&vdev->pdev->dev);1738	if (!viafbinfo)1739		return -ENOMEM;1740 1741	viaparinfo = (struct viafb_par *)viafbinfo->par;1742	viaparinfo->shared = viafbinfo->par + viafb_par_length;1743	viaparinfo->shared->vdev = vdev;1744	viaparinfo->vram_addr = 0;1745	viaparinfo->tmds_setting_info = &viaparinfo->shared->tmds_setting_info;1746	viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info;1747	viaparinfo->lvds_setting_info2 =1748		&viaparinfo->shared->lvds_setting_info2;1749	viaparinfo->chip_info = &viaparinfo->shared->chip_info;1750 1751	i2c_bus_probe(viaparinfo->shared);1752	if (viafb_dual_fb)1753		viafb_SAMM_ON = 1;1754	parse_lcd_port();1755	parse_dvi_port();1756 1757	viafb_init_chip_info(vdev->chip_type);1758	/*1759	 * The framebuffer will have been successfully mapped by1760	 * the core (or we'd not be here), but we still need to1761	 * set up our own accounting.1762	 */1763	viaparinfo->fbmem = vdev->fbmem_start;1764	viaparinfo->memsize = vdev->fbmem_len;1765	viaparinfo->fbmem_free = viaparinfo->memsize;1766	viaparinfo->fbmem_used = 0;1767	viafbinfo->screen_base = vdev->fbmem;1768 1769	viafbinfo->fix.mmio_start = vdev->engine_start;1770	viafbinfo->fix.mmio_len = vdev->engine_len;1771	viafbinfo->node = 0;1772	viafbinfo->fbops = &viafb_ops;1773	viafbinfo->flags = FBINFO_HWACCEL_YPAN;1774 1775	viafbinfo->pseudo_palette = pseudo_pal;1776	if (viafb_accel && !viafb_setup_engine(viafbinfo)) {1777		viafbinfo->flags |= FBINFO_HWACCEL_COPYAREA |1778			FBINFO_HWACCEL_FILLRECT |  FBINFO_HWACCEL_IMAGEBLIT;1779		default_var.accel_flags = FB_ACCELF_TEXT;1780	} else {1781		viafbinfo->flags |= FBINFO_HWACCEL_DISABLED;1782		default_var.accel_flags = 0;1783	}1784 1785	if (viafb_second_size && (viafb_second_size < 8)) {1786		viafb_second_offset = viaparinfo->fbmem_free -1787			viafb_second_size * 1024 * 1024;1788	} else {1789		viafb_second_size = 8;1790		viafb_second_offset = viaparinfo->fbmem_free -1791			viafb_second_size * 1024 * 1024;1792	}1793 1794	parse_mode(viafb_mode, viaparinfo->shared->iga1_devices,1795		&default_xres, &default_yres);1796	if (viafb_SAMM_ON == 1)1797		parse_mode(viafb_mode1, viaparinfo->shared->iga2_devices,1798			&viafb_second_xres, &viafb_second_yres);1799 1800	default_var.xres = default_xres;1801	default_var.yres = default_yres;1802	default_var.xres_virtual = default_xres;1803	default_var.yres_virtual = default_yres;1804	default_var.bits_per_pixel = viafb_bpp;1805	viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(1806		default_var.xres, default_var.yres, viafb_refresh));1807	viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);1808	viafbinfo->var = default_var;1809 1810	if (viafb_dual_fb) {1811		viafbinfo1 = framebuffer_alloc(viafb_par_length,1812				&vdev->pdev->dev);1813		if (!viafbinfo1) {1814			rc = -ENOMEM;1815			goto out_fb_release;1816		}1817		viaparinfo1 = viafbinfo1->par;1818		memcpy(viaparinfo1, viaparinfo, viafb_par_length);1819		viaparinfo1->vram_addr = viafb_second_offset;1820		viaparinfo1->memsize = viaparinfo->memsize -1821			viafb_second_offset;1822		viaparinfo->memsize = viafb_second_offset;1823		viaparinfo1->fbmem = viaparinfo->fbmem + viafb_second_offset;1824 1825		viaparinfo1->fbmem_used = viaparinfo->fbmem_used;1826		viaparinfo1->fbmem_free = viaparinfo1->memsize -1827			viaparinfo1->fbmem_used;1828		viaparinfo->fbmem_free = viaparinfo->memsize;1829		viaparinfo->fbmem_used = 0;1830 1831		viaparinfo->iga_path = IGA1;1832		viaparinfo1->iga_path = IGA2;1833		memcpy(viafbinfo1, viafbinfo, sizeof(struct fb_info));1834		viafbinfo1->par = viaparinfo1;1835		viafbinfo1->screen_base = viafbinfo->screen_base +1836			viafb_second_offset;1837 1838		default_var.xres = viafb_second_xres;1839		default_var.yres = viafb_second_yres;1840		default_var.xres_virtual = viafb_second_xres;1841		default_var.yres_virtual = viafb_second_yres;1842		default_var.bits_per_pixel = viafb_bpp1;1843		viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(1844			default_var.xres, default_var.yres, viafb_refresh1));1845 1846		viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1);1847		viafb_check_var(&default_var, viafbinfo1);1848		viafbinfo1->var = default_var;1849		viafb_update_fix(viafbinfo1);1850		viaparinfo1->depth = fb_get_color_depth(&viafbinfo1->var,1851			&viafbinfo1->fix);1852	}1853 1854	viafb_check_var(&viafbinfo->var, viafbinfo);1855	viafb_update_fix(viafbinfo);1856	viaparinfo->depth = fb_get_color_depth(&viafbinfo->var,1857		&viafbinfo->fix);1858	default_var.activate = FB_ACTIVATE_NOW;1859	rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0);1860	if (rc)1861		goto out_fb1_release;1862 1863	if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)1864	    && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) {1865		rc = register_framebuffer(viafbinfo1);1866		if (rc)1867			goto out_dealloc_cmap;1868	}1869	rc = register_framebuffer(viafbinfo);1870	if (rc)1871		goto out_fb1_unreg_lcd_cle266;1872 1873	if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device)1874			|| (viaparinfo->chip_info->gfx_chip_name !=1875			UNICHROME_CLE266))) {1876		rc = register_framebuffer(viafbinfo1);1877		if (rc)1878			goto out_fb_unreg;1879	}1880	DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n",1881		  viafbinfo->node, viafbinfo->fix.id, default_var.xres,1882		  default_var.yres, default_var.bits_per_pixel);1883 1884	viafb_init_proc(viaparinfo->shared);1885	viafb_init_dac(IGA2);1886 1887#ifdef CONFIG_PM1888	viafb_pm_register(&viafb_fb_pm_hooks);1889#endif1890	return 0;1891 1892out_fb_unreg:1893	unregister_framebuffer(viafbinfo);1894out_fb1_unreg_lcd_cle266:1895	if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)1896	    && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266))1897		unregister_framebuffer(viafbinfo1);1898out_dealloc_cmap:1899	fb_dealloc_cmap(&viafbinfo->cmap);1900out_fb1_release:1901	framebuffer_release(viafbinfo1);1902out_fb_release:1903	i2c_bus_free(viaparinfo->shared);1904	framebuffer_release(viafbinfo);1905	return rc;1906}1907 1908void via_fb_pci_remove(struct pci_dev *pdev)1909{1910	DEBUG_MSG(KERN_INFO "via_pci_remove!\n");1911	fb_dealloc_cmap(&viafbinfo->cmap);1912	unregister_framebuffer(viafbinfo);1913	if (viafb_dual_fb)1914		unregister_framebuffer(viafbinfo1);1915	viafb_remove_proc(viaparinfo->shared);1916	i2c_bus_free(viaparinfo->shared);1917	framebuffer_release(viafbinfo);1918	if (viafb_dual_fb)1919		framebuffer_release(viafbinfo1);1920}1921 1922#ifndef MODULE1923static int __init viafb_setup(void)1924{1925	char *this_opt;1926	char *options;1927 1928	DEBUG_MSG(KERN_INFO "viafb_setup!\n");1929 1930	if (fb_get_options("viafb", &options))1931		return -ENODEV;1932 1933	if (!options || !*options)1934		return 0;1935 1936	while ((this_opt = strsep(&options, ",")) != NULL) {1937		if (!*this_opt)1938			continue;1939 1940		if (!strncmp(this_opt, "viafb_mode1=", 12)) {1941			viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL);1942			if (!viafb_mode1)1943				return -ENOMEM;1944		} else if (!strncmp(this_opt, "viafb_mode=", 11)) {1945			viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL);1946			if (!viafb_mode)1947				return -ENOMEM;1948		} else if (!strncmp(this_opt, "viafb_bpp1=", 11)) {1949			if (kstrtouint(this_opt + 11, 0, &viafb_bpp1) < 0)1950				return -EINVAL;1951		} else if (!strncmp(this_opt, "viafb_bpp=", 10)) {1952			if (kstrtouint(this_opt + 10, 0, &viafb_bpp) < 0)1953				return -EINVAL;1954		} else if (!strncmp(this_opt, "viafb_refresh1=", 15)) {1955			if (kstrtoint(this_opt + 15, 0, &viafb_refresh1) < 0)1956				return -EINVAL;1957		} else if (!strncmp(this_opt, "viafb_refresh=", 14)) {1958			if (kstrtoint(this_opt + 14, 0, &viafb_refresh) < 0)1959				return -EINVAL;1960		} else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21)) {1961			if (kstrtoint(this_opt + 21, 0,1962				      &viafb_lcd_dsp_method) < 0)1963				return -EINVAL;1964		} else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19)) {1965			if (kstrtoint(this_opt + 19, 0,1966				      &viafb_lcd_panel_id) < 0)1967				return -EINVAL;1968		} else if (!strncmp(this_opt, "viafb_accel=", 12)) {1969			if (kstrtoint(this_opt + 12, 0, &viafb_accel) < 0)1970				return -EINVAL;1971		} else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14)) {1972			if (kstrtoint(this_opt + 14, 0, &viafb_SAMM_ON) < 0)1973				return -EINVAL;1974		} else if (!strncmp(this_opt, "viafb_active_dev=", 17)) {1975			viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL);1976			if (!viafb_active_dev)1977				return -ENOMEM;1978		} else if (!strncmp(this_opt,1979			"viafb_display_hardware_layout=", 30)) {1980			if (kstrtoint(this_opt + 30, 0,1981				      &viafb_display_hardware_layout) < 0)1982				return -EINVAL;1983		} else if (!strncmp(this_opt, "viafb_second_size=", 18)) {1984			if (kstrtoint(this_opt + 18, 0, &viafb_second_size) < 0)1985				return -EINVAL;1986		} else if (!strncmp(this_opt,1987			"viafb_platform_epia_dvi=", 24)) {1988			if (kstrtoint(this_opt + 24, 0,1989				      &viafb_platform_epia_dvi) < 0)1990				return -EINVAL;1991		} else if (!strncmp(this_opt,1992			"viafb_device_lcd_dualedge=", 26)) {1993			if (kstrtoint(this_opt + 26, 0,1994				      &viafb_device_lcd_dualedge) < 0)1995				return -EINVAL;1996		} else if (!strncmp(this_opt, "viafb_bus_width=", 16)) {1997			if (kstrtoint(this_opt + 16, 0, &viafb_bus_width) < 0)1998				return -EINVAL;1999		} else if (!strncmp(this_opt, "viafb_lcd_mode=", 15)) {2000			if (kstrtoint(this_opt + 15, 0, &viafb_lcd_mode) < 0)2001				return -EINVAL;2002		} else if (!strncmp(this_opt, "viafb_lcd_port=", 15)) {2003			viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL);2004			if (!viafb_lcd_port)2005				return -ENOMEM;2006		} else if (!strncmp(this_opt, "viafb_dvi_port=", 15)) {2007			viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL);2008			if (!viafb_dvi_port)2009				return -ENOMEM;2010		}2011	}2012	return 0;2013}2014#endif2015 2016/*2017 * These are called out of via-core for now.2018 */2019int __init viafb_init(void)2020{2021	u32 dummy_x, dummy_y;2022	int r = 0;2023 2024	if (machine_is_olpc())2025		/* Apply XO-1.5-specific configuration. */2026		viafb_lcd_panel_id = 23;2027 2028#ifndef MODULE2029	r = viafb_setup();2030	if (r < 0)2031		return r;2032#endif2033	if (parse_mode(viafb_mode, 0, &dummy_x, &dummy_y)2034		|| !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh)2035		|| parse_mode(viafb_mode1, 0, &dummy_x, &dummy_y)2036		|| !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1)2037		|| viafb_bpp < 0 || viafb_bpp > 322038		|| viafb_bpp1 < 0 || viafb_bpp1 > 322039		|| parse_active_dev())2040		return -EINVAL;2041 2042	printk(KERN_INFO2043       "VIA Graphics Integration Chipset framebuffer %d.%d initializing\n",2044	       VERSION_MAJOR, VERSION_MINOR);2045	return r;2046}2047 2048void __exit viafb_exit(void)2049{2050	DEBUG_MSG(KERN_INFO "viafb_exit!\n");2051}2052 2053static struct fb_ops viafb_ops = {2054	.owner = THIS_MODULE,2055	.fb_open = viafb_open,2056	.fb_release = viafb_release,2057	__FB_DEFAULT_IOMEM_OPS_RDWR,2058	.fb_check_var = viafb_check_var,2059	.fb_set_par = viafb_set_par,2060	.fb_setcolreg = viafb_setcolreg,2061	.fb_pan_display = viafb_pan_display,2062	.fb_blank = viafb_blank,2063	.fb_fillrect = viafb_fillrect,2064	.fb_copyarea = viafb_copyarea,2065	.fb_imageblit = viafb_imageblit,2066	.fb_cursor = viafb_cursor,2067	.fb_ioctl = viafb_ioctl,2068	.fb_sync = viafb_sync,2069	__FB_DEFAULT_IOMEM_OPS_MMAP,2070};2071 2072 2073#ifdef MODULE2074module_param(viafb_mode, charp, S_IRUSR);2075MODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)");2076 2077module_param(viafb_mode1, charp, S_IRUSR);2078MODULE_PARM_DESC(viafb_mode1, "Set resolution (default=640x480)");2079 2080module_param(viafb_bpp, int, S_IRUSR);2081MODULE_PARM_DESC(viafb_bpp, "Set color depth (default=32bpp)");2082 2083module_param(viafb_bpp1, int, S_IRUSR);2084MODULE_PARM_DESC(viafb_bpp1, "Set color depth (default=32bpp)");2085 2086module_param(viafb_refresh, int, S_IRUSR);2087MODULE_PARM_DESC(viafb_refresh,2088	"Set CRT viafb_refresh rate (default = 60)");2089 2090module_param(viafb_refresh1, int, S_IRUSR);2091MODULE_PARM_DESC(viafb_refresh1,2092	"Set CRT refresh rate (default = 60)");2093 2094module_param(viafb_lcd_panel_id, int, S_IRUSR);2095MODULE_PARM_DESC(viafb_lcd_panel_id,2096	"Set Flat Panel type(Default=1024x768)");2097 2098module_param(viafb_lcd_dsp_method, int, S_IRUSR);2099MODULE_PARM_DESC(viafb_lcd_dsp_method,2100	"Set Flat Panel display scaling method.(Default=Expansion)");2101 2102module_param(viafb_SAMM_ON, int, S_IRUSR);2103MODULE_PARM_DESC(viafb_SAMM_ON,2104	"Turn on/off flag of SAMM(Default=OFF)");2105 2106module_param(viafb_accel, int, S_IRUSR);2107MODULE_PARM_DESC(viafb_accel,2108	"Set 2D Hardware Acceleration: 0 = OFF, 1 = ON (default)");2109 2110module_param(viafb_active_dev, charp, S_IRUSR);2111MODULE_PARM_DESC(viafb_active_dev, "Specify active devices.");2112 2113module_param(viafb_display_hardware_layout, int, S_IRUSR);2114MODULE_PARM_DESC(viafb_display_hardware_layout,2115	"Display Hardware Layout (LCD Only, DVI Only...,etc)");2116 2117module_param(viafb_second_size, int, S_IRUSR);2118MODULE_PARM_DESC(viafb_second_size,2119	"Set secondary device memory size");2120 2121module_param(viafb_dual_fb, int, S_IRUSR);2122MODULE_PARM_DESC(viafb_dual_fb,2123	"Turn on/off flag of dual framebuffer devices.(Default = OFF)");2124 2125module_param(viafb_platform_epia_dvi, int, S_IRUSR);2126MODULE_PARM_DESC(viafb_platform_epia_dvi,2127	"Turn on/off flag of DVI devices on EPIA board.(Default = OFF)");2128 2129module_param(viafb_device_lcd_dualedge, int, S_IRUSR);2130MODULE_PARM_DESC(viafb_device_lcd_dualedge,2131	"Turn on/off flag of dual edge panel.(Default = OFF)");2132 2133module_param(viafb_bus_width, int, S_IRUSR);2134MODULE_PARM_DESC(viafb_bus_width,2135	"Set bus width of panel.(Default = 12)");2136 2137module_param(viafb_lcd_mode, int, S_IRUSR);2138MODULE_PARM_DESC(viafb_lcd_mode,2139	"Set Flat Panel mode(Default=OPENLDI)");2140 2141module_param(viafb_lcd_port, charp, S_IRUSR);2142MODULE_PARM_DESC(viafb_lcd_port, "Specify LCD output port.");2143 2144module_param(viafb_dvi_port, charp, S_IRUSR);2145MODULE_PARM_DESC(viafb_dvi_port, "Specify DVI output port.");2146 2147MODULE_DESCRIPTION("VIA UniChrome (Pro) and Chrome9 display driver");2148MODULE_LICENSE("GPL");2149#endif2150