162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
462306a36Sopenharmony_ci * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/compiler.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/seq_file.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/stat.h>
1362306a36Sopenharmony_ci#include <linux/via-core.h>
1462306a36Sopenharmony_ci#include <linux/via_i2c.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define _MASTER_FILE
1762306a36Sopenharmony_ci#include "global.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic char *viafb_name = "Via";
2062306a36Sopenharmony_cistatic u32 pseudo_pal[17];
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* video mode */
2362306a36Sopenharmony_cistatic char *viafb_mode;
2462306a36Sopenharmony_cistatic char *viafb_mode1;
2562306a36Sopenharmony_cistatic int viafb_bpp = 32;
2662306a36Sopenharmony_cistatic int viafb_bpp1 = 32;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic unsigned int viafb_second_offset;
2962306a36Sopenharmony_cistatic int viafb_second_size;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int viafb_accel = 1;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Added for specifying active devices.*/
3462306a36Sopenharmony_cistatic char *viafb_active_dev;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*Added for specify lcd output port*/
3762306a36Sopenharmony_cistatic char *viafb_lcd_port = "";
3862306a36Sopenharmony_cistatic char *viafb_dvi_port = "";
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic void retrieve_device_setting(struct viafb_ioctl_setting
4162306a36Sopenharmony_ci	*setting_info);
4262306a36Sopenharmony_cistatic int viafb_pan_display(struct fb_var_screeninfo *var,
4362306a36Sopenharmony_ci	struct fb_info *info);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic struct fb_ops viafb_ops;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* supported output devices on each IGP
4862306a36Sopenharmony_ci * only CX700, VX800, VX855, VX900 were documented
4962306a36Sopenharmony_ci * VIA_CRT should be everywhere
5062306a36Sopenharmony_ci * VIA_6C can be onle pre-CX700 (probably only on CLE266) as 6C is used for PLL
5162306a36Sopenharmony_ci * source selection on CX700 and later
5262306a36Sopenharmony_ci * K400 seems to support VIA_96, VIA_DVP1, VIA_LVDS{1,2} as in viamode.c
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_cistatic const u32 supported_odev_map[] = {
5562306a36Sopenharmony_ci	[UNICHROME_CLE266]	= VIA_CRT | VIA_LDVP0 | VIA_LDVP1,
5662306a36Sopenharmony_ci	[UNICHROME_K400]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
5762306a36Sopenharmony_ci				| VIA_LVDS2,
5862306a36Sopenharmony_ci	[UNICHROME_K800]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
5962306a36Sopenharmony_ci				| VIA_LVDS2,
6062306a36Sopenharmony_ci	[UNICHROME_PM800]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
6162306a36Sopenharmony_ci				| VIA_LVDS2,
6262306a36Sopenharmony_ci	[UNICHROME_CN700]	= VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
6362306a36Sopenharmony_ci				| VIA_LVDS2,
6462306a36Sopenharmony_ci	[UNICHROME_CX700]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
6562306a36Sopenharmony_ci	[UNICHROME_CN750]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
6662306a36Sopenharmony_ci	[UNICHROME_K8M890]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
6762306a36Sopenharmony_ci	[UNICHROME_P4M890]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
6862306a36Sopenharmony_ci	[UNICHROME_P4M900]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
6962306a36Sopenharmony_ci	[UNICHROME_VX800]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
7062306a36Sopenharmony_ci	[UNICHROME_VX855]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
7162306a36Sopenharmony_ci	[UNICHROME_VX900]	= VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	var->grayscale = 0;
7762306a36Sopenharmony_ci	var->red.msb_right = 0;
7862306a36Sopenharmony_ci	var->green.msb_right = 0;
7962306a36Sopenharmony_ci	var->blue.msb_right = 0;
8062306a36Sopenharmony_ci	var->transp.offset = 0;
8162306a36Sopenharmony_ci	var->transp.length = 0;
8262306a36Sopenharmony_ci	var->transp.msb_right = 0;
8362306a36Sopenharmony_ci	var->nonstd = 0;
8462306a36Sopenharmony_ci	switch (depth) {
8562306a36Sopenharmony_ci	case 8:
8662306a36Sopenharmony_ci		var->bits_per_pixel = 8;
8762306a36Sopenharmony_ci		var->red.offset = 0;
8862306a36Sopenharmony_ci		var->green.offset = 0;
8962306a36Sopenharmony_ci		var->blue.offset = 0;
9062306a36Sopenharmony_ci		var->red.length = 8;
9162306a36Sopenharmony_ci		var->green.length = 8;
9262306a36Sopenharmony_ci		var->blue.length = 8;
9362306a36Sopenharmony_ci		break;
9462306a36Sopenharmony_ci	case 15:
9562306a36Sopenharmony_ci		var->bits_per_pixel = 16;
9662306a36Sopenharmony_ci		var->red.offset = 10;
9762306a36Sopenharmony_ci		var->green.offset = 5;
9862306a36Sopenharmony_ci		var->blue.offset = 0;
9962306a36Sopenharmony_ci		var->red.length = 5;
10062306a36Sopenharmony_ci		var->green.length = 5;
10162306a36Sopenharmony_ci		var->blue.length = 5;
10262306a36Sopenharmony_ci		break;
10362306a36Sopenharmony_ci	case 16:
10462306a36Sopenharmony_ci		var->bits_per_pixel = 16;
10562306a36Sopenharmony_ci		var->red.offset = 11;
10662306a36Sopenharmony_ci		var->green.offset = 5;
10762306a36Sopenharmony_ci		var->blue.offset = 0;
10862306a36Sopenharmony_ci		var->red.length = 5;
10962306a36Sopenharmony_ci		var->green.length = 6;
11062306a36Sopenharmony_ci		var->blue.length = 5;
11162306a36Sopenharmony_ci		break;
11262306a36Sopenharmony_ci	case 24:
11362306a36Sopenharmony_ci		var->bits_per_pixel = 32;
11462306a36Sopenharmony_ci		var->red.offset = 16;
11562306a36Sopenharmony_ci		var->green.offset = 8;
11662306a36Sopenharmony_ci		var->blue.offset = 0;
11762306a36Sopenharmony_ci		var->red.length = 8;
11862306a36Sopenharmony_ci		var->green.length = 8;
11962306a36Sopenharmony_ci		var->blue.length = 8;
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	case 30:
12262306a36Sopenharmony_ci		var->bits_per_pixel = 32;
12362306a36Sopenharmony_ci		var->red.offset = 20;
12462306a36Sopenharmony_ci		var->green.offset = 10;
12562306a36Sopenharmony_ci		var->blue.offset = 0;
12662306a36Sopenharmony_ci		var->red.length = 10;
12762306a36Sopenharmony_ci		var->green.length = 10;
12862306a36Sopenharmony_ci		var->blue.length = 10;
12962306a36Sopenharmony_ci		break;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void viafb_update_fix(struct fb_info *info)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	u32 bpp = info->var.bits_per_pixel;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	info->fix.visual =
13862306a36Sopenharmony_ci		bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
13962306a36Sopenharmony_ci	info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
14062306a36Sopenharmony_ci		VIA_PITCH_SIZE);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
14462306a36Sopenharmony_ci	struct viafb_par *viaparinfo)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
14762306a36Sopenharmony_ci	strcpy(fix->id, viafb_name);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	fix->smem_start = viaparinfo->fbmem;
15062306a36Sopenharmony_ci	fix->smem_len = viaparinfo->fbmem_free;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	fix->type = FB_TYPE_PACKED_PIXELS;
15362306a36Sopenharmony_ci	fix->type_aux = 0;
15462306a36Sopenharmony_ci	fix->visual = FB_VISUAL_TRUECOLOR;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	fix->xpanstep = fix->ywrapstep = 0;
15762306a36Sopenharmony_ci	fix->ypanstep = 1;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* Just tell the accel name */
16062306a36Sopenharmony_ci	viafbinfo->fix.accel = FB_ACCEL_VIA_UNICHROME;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_cistatic int viafb_open(struct fb_info *info, int user)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_open!\n");
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int viafb_release(struct fb_info *info, int user)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_release!\n");
17162306a36Sopenharmony_ci	return 0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic inline int get_var_refresh(struct fb_var_screeninfo *var)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	u32 htotal, vtotal;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	htotal = var->left_margin + var->xres + var->right_margin
17962306a36Sopenharmony_ci		+ var->hsync_len;
18062306a36Sopenharmony_ci	vtotal = var->upper_margin + var->yres + var->lower_margin
18162306a36Sopenharmony_ci		+ var->vsync_len;
18262306a36Sopenharmony_ci	return PICOS2KHZ(var->pixclock) * 1000 / (htotal * vtotal);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic int viafb_check_var(struct fb_var_screeninfo *var,
18662306a36Sopenharmony_ci	struct fb_info *info)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	int depth, refresh;
18962306a36Sopenharmony_ci	struct viafb_par *ppar = info->par;
19062306a36Sopenharmony_ci	u32 line;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_check_var!\n");
19362306a36Sopenharmony_ci	/* Sanity check */
19462306a36Sopenharmony_ci	/* HW neither support interlacte nor double-scaned mode */
19562306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
19662306a36Sopenharmony_ci		return -EINVAL;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* the refresh rate is not important here, as we only want to know
19962306a36Sopenharmony_ci	 * whether the resolution exists
20062306a36Sopenharmony_ci	 */
20162306a36Sopenharmony_ci	if (!viafb_get_best_mode(var->xres, var->yres, 60)) {
20262306a36Sopenharmony_ci		DEBUG_MSG(KERN_INFO
20362306a36Sopenharmony_ci			  "viafb: Mode %dx%dx%d not supported!!\n",
20462306a36Sopenharmony_ci			  var->xres, var->yres, var->bits_per_pixel);
20562306a36Sopenharmony_ci		return -EINVAL;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	depth = fb_get_color_depth(var, &info->fix);
20962306a36Sopenharmony_ci	if (!depth)
21062306a36Sopenharmony_ci		depth = var->bits_per_pixel;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (depth < 0 || depth > 32)
21362306a36Sopenharmony_ci		return -EINVAL;
21462306a36Sopenharmony_ci	else if (!depth)
21562306a36Sopenharmony_ci		depth = 24;
21662306a36Sopenharmony_ci	else if (depth == 15 && viafb_dual_fb && ppar->iga_path == IGA1)
21762306a36Sopenharmony_ci		depth = 15;
21862306a36Sopenharmony_ci	else if (depth == 30)
21962306a36Sopenharmony_ci		depth = 30;
22062306a36Sopenharmony_ci	else if (depth <= 8)
22162306a36Sopenharmony_ci		depth = 8;
22262306a36Sopenharmony_ci	else if (depth <= 16)
22362306a36Sopenharmony_ci		depth = 16;
22462306a36Sopenharmony_ci	else
22562306a36Sopenharmony_ci		depth = 24;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	viafb_fill_var_color_info(var, depth);
22862306a36Sopenharmony_ci	if (var->xres_virtual < var->xres)
22962306a36Sopenharmony_ci		var->xres_virtual = var->xres;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
23262306a36Sopenharmony_ci		VIA_PITCH_SIZE);
23362306a36Sopenharmony_ci	if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
23462306a36Sopenharmony_ci		return -EINVAL;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* Based on var passed in to calculate the refresh,
23762306a36Sopenharmony_ci	 * because our driver use some modes special.
23862306a36Sopenharmony_ci	 */
23962306a36Sopenharmony_ci	refresh = viafb_get_refresh(var->xres, var->yres,
24062306a36Sopenharmony_ci		get_var_refresh(var));
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* Adjust var according to our driver's own table */
24362306a36Sopenharmony_ci	viafb_fill_var_timing_info(var,
24462306a36Sopenharmony_ci		viafb_get_best_mode(var->xres, var->yres, refresh));
24562306a36Sopenharmony_ci	if (var->accel_flags & FB_ACCELF_TEXT &&
24662306a36Sopenharmony_ci		!ppar->shared->vdev->engine_mmio)
24762306a36Sopenharmony_ci		var->accel_flags = 0;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int viafb_set_par(struct fb_info *info)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
25562306a36Sopenharmony_ci	int refresh;
25662306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	viafb_update_fix(info);
25962306a36Sopenharmony_ci	viapar->depth = fb_get_color_depth(&info->var, &info->fix);
26062306a36Sopenharmony_ci	viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres,
26162306a36Sopenharmony_ci		viafbinfo->var.bits_per_pixel, 0);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (viafb_dual_fb) {
26462306a36Sopenharmony_ci		viafb_update_device_setting(viafbinfo1->var.xres,
26562306a36Sopenharmony_ci			viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel,
26662306a36Sopenharmony_ci			1);
26762306a36Sopenharmony_ci	} else if (viafb_SAMM_ON == 1) {
26862306a36Sopenharmony_ci		DEBUG_MSG(KERN_INFO
26962306a36Sopenharmony_ci		"viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",
27062306a36Sopenharmony_ci			  viafb_second_xres, viafb_second_yres, viafb_bpp1);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		viafb_update_device_setting(viafb_second_xres,
27362306a36Sopenharmony_ci			viafb_second_yres, viafb_bpp1, 1);
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	refresh = get_var_refresh(&info->var);
27762306a36Sopenharmony_ci	if (viafb_dual_fb && viapar->iga_path == IGA2) {
27862306a36Sopenharmony_ci		viafb_bpp1 = info->var.bits_per_pixel;
27962306a36Sopenharmony_ci		viafb_refresh1 = refresh;
28062306a36Sopenharmony_ci	} else {
28162306a36Sopenharmony_ci		viafb_bpp = info->var.bits_per_pixel;
28262306a36Sopenharmony_ci		viafb_refresh = refresh;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (info->var.accel_flags & FB_ACCELF_TEXT)
28662306a36Sopenharmony_ci		info->flags &= ~FBINFO_HWACCEL_DISABLED;
28762306a36Sopenharmony_ci	else
28862306a36Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_DISABLED;
28962306a36Sopenharmony_ci	viafb_setmode();
29062306a36Sopenharmony_ci	viafb_pan_display(&info->var, info);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/* Set one color register */
29662306a36Sopenharmony_cistatic int viafb_setcolreg(unsigned regno, unsigned red, unsigned green,
29762306a36Sopenharmony_ciunsigned blue, unsigned transp, struct fb_info *info)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
30062306a36Sopenharmony_ci	u32 r, g, b;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
30362306a36Sopenharmony_ci		if (regno > 255)
30462306a36Sopenharmony_ci			return -EINVAL;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		if (!viafb_dual_fb || viapar->iga_path == IGA1)
30762306a36Sopenharmony_ci			viafb_set_primary_color_register(regno, red >> 8,
30862306a36Sopenharmony_ci				green >> 8, blue >> 8);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		if (!viafb_dual_fb || viapar->iga_path == IGA2)
31162306a36Sopenharmony_ci			viafb_set_secondary_color_register(regno, red >> 8,
31262306a36Sopenharmony_ci				green >> 8, blue >> 8);
31362306a36Sopenharmony_ci	} else {
31462306a36Sopenharmony_ci		if (regno > 15)
31562306a36Sopenharmony_ci			return -EINVAL;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		r = (red >> (16 - info->var.red.length))
31862306a36Sopenharmony_ci			<< info->var.red.offset;
31962306a36Sopenharmony_ci		b = (blue >> (16 - info->var.blue.length))
32062306a36Sopenharmony_ci			<< info->var.blue.offset;
32162306a36Sopenharmony_ci		g = (green >> (16 - info->var.green.length))
32262306a36Sopenharmony_ci			<< info->var.green.offset;
32362306a36Sopenharmony_ci		((u32 *) info->pseudo_palette)[regno] = r | g | b;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return 0;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic int viafb_pan_display(struct fb_var_screeninfo *var,
33062306a36Sopenharmony_ci	struct fb_info *info)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
33362306a36Sopenharmony_ci	u32 vram_addr = viapar->vram_addr
33462306a36Sopenharmony_ci		+ var->yoffset * info->fix.line_length
33562306a36Sopenharmony_ci		+ var->xoffset * info->var.bits_per_pixel / 8;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
33862306a36Sopenharmony_ci	if (!viafb_dual_fb) {
33962306a36Sopenharmony_ci		via_set_primary_address(vram_addr);
34062306a36Sopenharmony_ci		via_set_secondary_address(vram_addr);
34162306a36Sopenharmony_ci	} else if (viapar->iga_path == IGA1)
34262306a36Sopenharmony_ci		via_set_primary_address(vram_addr);
34362306a36Sopenharmony_ci	else
34462306a36Sopenharmony_ci		via_set_secondary_address(vram_addr);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int viafb_blank(int blank_mode, struct fb_info *info)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_blank!\n");
35262306a36Sopenharmony_ci	/* clear DPMS setting */
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	switch (blank_mode) {
35562306a36Sopenharmony_ci	case FB_BLANK_UNBLANK:
35662306a36Sopenharmony_ci		/* Screen: On, HSync: On, VSync: On */
35762306a36Sopenharmony_ci		/* control CRT monitor power management */
35862306a36Sopenharmony_ci		via_set_state(VIA_CRT, VIA_STATE_ON);
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:
36162306a36Sopenharmony_ci		/* Screen: Off, HSync: Off, VSync: On */
36262306a36Sopenharmony_ci		/* control CRT monitor power management */
36362306a36Sopenharmony_ci		via_set_state(VIA_CRT, VIA_STATE_STANDBY);
36462306a36Sopenharmony_ci		break;
36562306a36Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:
36662306a36Sopenharmony_ci		/* Screen: Off, HSync: On, VSync: Off */
36762306a36Sopenharmony_ci		/* control CRT monitor power management */
36862306a36Sopenharmony_ci		via_set_state(VIA_CRT, VIA_STATE_SUSPEND);
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci	case FB_BLANK_POWERDOWN:
37162306a36Sopenharmony_ci		/* Screen: Off, HSync: Off, VSync: Off */
37262306a36Sopenharmony_ci		/* control CRT monitor power management */
37362306a36Sopenharmony_ci		via_set_state(VIA_CRT, VIA_STATE_OFF);
37462306a36Sopenharmony_ci		break;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	union {
38362306a36Sopenharmony_ci		struct viafb_ioctl_mode viamode;
38462306a36Sopenharmony_ci		struct viafb_ioctl_samm viasamm;
38562306a36Sopenharmony_ci		struct viafb_driver_version driver_version;
38662306a36Sopenharmony_ci		struct fb_var_screeninfo sec_var;
38762306a36Sopenharmony_ci		struct _panel_size_pos_info panel_pos_size_para;
38862306a36Sopenharmony_ci		struct viafb_ioctl_setting viafb_setting;
38962306a36Sopenharmony_ci		struct device_t active_dev;
39062306a36Sopenharmony_ci	} u;
39162306a36Sopenharmony_ci	u32 state_info = 0;
39262306a36Sopenharmony_ci	u32 *viafb_gamma_table;
39362306a36Sopenharmony_ci	char driver_name[] = "viafb";
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	u32 __user *argp = (u32 __user *) arg;
39662306a36Sopenharmony_ci	u32 gpu32;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd);
39962306a36Sopenharmony_ci	printk(KERN_WARNING "viafb_ioctl: Please avoid this interface as it is unstable and might change or vanish at any time!\n");
40062306a36Sopenharmony_ci	memset(&u, 0, sizeof(u));
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	switch (cmd) {
40362306a36Sopenharmony_ci	case VIAFB_GET_CHIP_INFO:
40462306a36Sopenharmony_ci		if (copy_to_user(argp, viaparinfo->chip_info,
40562306a36Sopenharmony_ci				sizeof(struct chip_information)))
40662306a36Sopenharmony_ci			return -EFAULT;
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci	case VIAFB_GET_INFO_SIZE:
40962306a36Sopenharmony_ci		return put_user((u32)sizeof(struct viafb_ioctl_info), argp);
41062306a36Sopenharmony_ci	case VIAFB_GET_INFO:
41162306a36Sopenharmony_ci		return viafb_ioctl_get_viafb_info(arg);
41262306a36Sopenharmony_ci	case VIAFB_HOTPLUG:
41362306a36Sopenharmony_ci		return put_user(viafb_ioctl_hotplug(info->var.xres,
41462306a36Sopenharmony_ci					      info->var.yres,
41562306a36Sopenharmony_ci					      info->var.bits_per_pixel), argp);
41662306a36Sopenharmony_ci	case VIAFB_SET_HOTPLUG_FLAG:
41762306a36Sopenharmony_ci		if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
41862306a36Sopenharmony_ci			return -EFAULT;
41962306a36Sopenharmony_ci		viafb_hotplug = (gpu32) ? 1 : 0;
42062306a36Sopenharmony_ci		break;
42162306a36Sopenharmony_ci	case VIAFB_GET_RESOLUTION:
42262306a36Sopenharmony_ci		u.viamode.xres = (u32) viafb_hotplug_Xres;
42362306a36Sopenharmony_ci		u.viamode.yres = (u32) viafb_hotplug_Yres;
42462306a36Sopenharmony_ci		u.viamode.refresh = (u32) viafb_hotplug_refresh;
42562306a36Sopenharmony_ci		u.viamode.bpp = (u32) viafb_hotplug_bpp;
42662306a36Sopenharmony_ci		if (viafb_SAMM_ON == 1) {
42762306a36Sopenharmony_ci			u.viamode.xres_sec = viafb_second_xres;
42862306a36Sopenharmony_ci			u.viamode.yres_sec = viafb_second_yres;
42962306a36Sopenharmony_ci			u.viamode.virtual_xres_sec = viafb_dual_fb ? viafbinfo1->var.xres_virtual : viafbinfo->var.xres_virtual;
43062306a36Sopenharmony_ci			u.viamode.virtual_yres_sec = viafb_dual_fb ? viafbinfo1->var.yres_virtual : viafbinfo->var.yres_virtual;
43162306a36Sopenharmony_ci			u.viamode.refresh_sec = viafb_refresh1;
43262306a36Sopenharmony_ci			u.viamode.bpp_sec = viafb_bpp1;
43362306a36Sopenharmony_ci		} else {
43462306a36Sopenharmony_ci			u.viamode.xres_sec = 0;
43562306a36Sopenharmony_ci			u.viamode.yres_sec = 0;
43662306a36Sopenharmony_ci			u.viamode.virtual_xres_sec = 0;
43762306a36Sopenharmony_ci			u.viamode.virtual_yres_sec = 0;
43862306a36Sopenharmony_ci			u.viamode.refresh_sec = 0;
43962306a36Sopenharmony_ci			u.viamode.bpp_sec = 0;
44062306a36Sopenharmony_ci		}
44162306a36Sopenharmony_ci		if (copy_to_user(argp, &u.viamode, sizeof(u.viamode)))
44262306a36Sopenharmony_ci			return -EFAULT;
44362306a36Sopenharmony_ci		break;
44462306a36Sopenharmony_ci	case VIAFB_GET_SAMM_INFO:
44562306a36Sopenharmony_ci		u.viasamm.samm_status = viafb_SAMM_ON;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci		if (viafb_SAMM_ON == 1) {
44862306a36Sopenharmony_ci			if (viafb_dual_fb) {
44962306a36Sopenharmony_ci				u.viasamm.size_prim = viaparinfo->fbmem_free;
45062306a36Sopenharmony_ci				u.viasamm.size_sec = viaparinfo1->fbmem_free;
45162306a36Sopenharmony_ci			} else {
45262306a36Sopenharmony_ci				if (viafb_second_size) {
45362306a36Sopenharmony_ci					u.viasamm.size_prim =
45462306a36Sopenharmony_ci					    viaparinfo->fbmem_free -
45562306a36Sopenharmony_ci					    viafb_second_size * 1024 * 1024;
45662306a36Sopenharmony_ci					u.viasamm.size_sec =
45762306a36Sopenharmony_ci					    viafb_second_size * 1024 * 1024;
45862306a36Sopenharmony_ci				} else {
45962306a36Sopenharmony_ci					u.viasamm.size_prim =
46062306a36Sopenharmony_ci					    viaparinfo->fbmem_free >> 1;
46162306a36Sopenharmony_ci					u.viasamm.size_sec =
46262306a36Sopenharmony_ci					    (viaparinfo->fbmem_free >> 1);
46362306a36Sopenharmony_ci				}
46462306a36Sopenharmony_ci			}
46562306a36Sopenharmony_ci			u.viasamm.mem_base = viaparinfo->fbmem;
46662306a36Sopenharmony_ci			u.viasamm.offset_sec = viafb_second_offset;
46762306a36Sopenharmony_ci		} else {
46862306a36Sopenharmony_ci			u.viasamm.size_prim =
46962306a36Sopenharmony_ci			    viaparinfo->memsize - viaparinfo->fbmem_used;
47062306a36Sopenharmony_ci			u.viasamm.size_sec = 0;
47162306a36Sopenharmony_ci			u.viasamm.mem_base = viaparinfo->fbmem;
47262306a36Sopenharmony_ci			u.viasamm.offset_sec = 0;
47362306a36Sopenharmony_ci		}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		if (copy_to_user(argp, &u.viasamm, sizeof(u.viasamm)))
47662306a36Sopenharmony_ci			return -EFAULT;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		break;
47962306a36Sopenharmony_ci	case VIAFB_TURN_ON_OUTPUT_DEVICE:
48062306a36Sopenharmony_ci		if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
48162306a36Sopenharmony_ci			return -EFAULT;
48262306a36Sopenharmony_ci		if (gpu32 & CRT_Device)
48362306a36Sopenharmony_ci			via_set_state(VIA_CRT, VIA_STATE_ON);
48462306a36Sopenharmony_ci		if (gpu32 & DVI_Device)
48562306a36Sopenharmony_ci			viafb_dvi_enable();
48662306a36Sopenharmony_ci		if (gpu32 & LCD_Device)
48762306a36Sopenharmony_ci			viafb_lcd_enable();
48862306a36Sopenharmony_ci		break;
48962306a36Sopenharmony_ci	case VIAFB_TURN_OFF_OUTPUT_DEVICE:
49062306a36Sopenharmony_ci		if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
49162306a36Sopenharmony_ci			return -EFAULT;
49262306a36Sopenharmony_ci		if (gpu32 & CRT_Device)
49362306a36Sopenharmony_ci			via_set_state(VIA_CRT, VIA_STATE_OFF);
49462306a36Sopenharmony_ci		if (gpu32 & DVI_Device)
49562306a36Sopenharmony_ci			viafb_dvi_disable();
49662306a36Sopenharmony_ci		if (gpu32 & LCD_Device)
49762306a36Sopenharmony_ci			viafb_lcd_disable();
49862306a36Sopenharmony_ci		break;
49962306a36Sopenharmony_ci	case VIAFB_GET_DEVICE:
50062306a36Sopenharmony_ci		u.active_dev.crt = viafb_CRT_ON;
50162306a36Sopenharmony_ci		u.active_dev.dvi = viafb_DVI_ON;
50262306a36Sopenharmony_ci		u.active_dev.lcd = viafb_LCD_ON;
50362306a36Sopenharmony_ci		u.active_dev.samm = viafb_SAMM_ON;
50462306a36Sopenharmony_ci		u.active_dev.primary_dev = viafb_primary_dev;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		u.active_dev.lcd_dsp_cent = viafb_lcd_dsp_method;
50762306a36Sopenharmony_ci		u.active_dev.lcd_panel_id = viafb_lcd_panel_id;
50862306a36Sopenharmony_ci		u.active_dev.lcd_mode = viafb_lcd_mode;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		u.active_dev.xres = viafb_hotplug_Xres;
51162306a36Sopenharmony_ci		u.active_dev.yres = viafb_hotplug_Yres;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		u.active_dev.xres1 = viafb_second_xres;
51462306a36Sopenharmony_ci		u.active_dev.yres1 = viafb_second_yres;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		u.active_dev.bpp = viafb_bpp;
51762306a36Sopenharmony_ci		u.active_dev.bpp1 = viafb_bpp1;
51862306a36Sopenharmony_ci		u.active_dev.refresh = viafb_refresh;
51962306a36Sopenharmony_ci		u.active_dev.refresh1 = viafb_refresh1;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		u.active_dev.epia_dvi = viafb_platform_epia_dvi;
52262306a36Sopenharmony_ci		u.active_dev.lcd_dual_edge = viafb_device_lcd_dualedge;
52362306a36Sopenharmony_ci		u.active_dev.bus_width = viafb_bus_width;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		if (copy_to_user(argp, &u.active_dev, sizeof(u.active_dev)))
52662306a36Sopenharmony_ci			return -EFAULT;
52762306a36Sopenharmony_ci		break;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	case VIAFB_GET_DRIVER_VERSION:
53062306a36Sopenharmony_ci		u.driver_version.iMajorNum = VERSION_MAJOR;
53162306a36Sopenharmony_ci		u.driver_version.iKernelNum = VERSION_KERNEL;
53262306a36Sopenharmony_ci		u.driver_version.iOSNum = VERSION_OS;
53362306a36Sopenharmony_ci		u.driver_version.iMinorNum = VERSION_MINOR;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		if (copy_to_user(argp, &u.driver_version,
53662306a36Sopenharmony_ci			sizeof(u.driver_version)))
53762306a36Sopenharmony_ci			return -EFAULT;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		break;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	case VIAFB_GET_DEVICE_INFO:
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		retrieve_device_setting(&u.viafb_setting);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		if (copy_to_user(argp, &u.viafb_setting,
54662306a36Sopenharmony_ci				 sizeof(u.viafb_setting)))
54762306a36Sopenharmony_ci			return -EFAULT;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	case VIAFB_GET_DEVICE_SUPPORT:
55262306a36Sopenharmony_ci		viafb_get_device_support_state(&state_info);
55362306a36Sopenharmony_ci		if (put_user(state_info, argp))
55462306a36Sopenharmony_ci			return -EFAULT;
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	case VIAFB_GET_DEVICE_CONNECT:
55862306a36Sopenharmony_ci		viafb_get_device_connect_state(&state_info);
55962306a36Sopenharmony_ci		if (put_user(state_info, argp))
56062306a36Sopenharmony_ci			return -EFAULT;
56162306a36Sopenharmony_ci		break;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	case VIAFB_GET_PANEL_SUPPORT_EXPAND:
56462306a36Sopenharmony_ci		state_info =
56562306a36Sopenharmony_ci		    viafb_lcd_get_support_expand_state(info->var.xres,
56662306a36Sopenharmony_ci						 info->var.yres);
56762306a36Sopenharmony_ci		if (put_user(state_info, argp))
56862306a36Sopenharmony_ci			return -EFAULT;
56962306a36Sopenharmony_ci		break;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	case VIAFB_GET_DRIVER_NAME:
57262306a36Sopenharmony_ci		if (copy_to_user(argp, driver_name, sizeof(driver_name)))
57362306a36Sopenharmony_ci			return -EFAULT;
57462306a36Sopenharmony_ci		break;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	case VIAFB_SET_GAMMA_LUT:
57762306a36Sopenharmony_ci		viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32));
57862306a36Sopenharmony_ci		if (IS_ERR(viafb_gamma_table))
57962306a36Sopenharmony_ci			return PTR_ERR(viafb_gamma_table);
58062306a36Sopenharmony_ci		viafb_set_gamma_table(viafb_bpp, viafb_gamma_table);
58162306a36Sopenharmony_ci		kfree(viafb_gamma_table);
58262306a36Sopenharmony_ci		break;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	case VIAFB_GET_GAMMA_LUT:
58562306a36Sopenharmony_ci		viafb_gamma_table = kmalloc_array(256, sizeof(u32),
58662306a36Sopenharmony_ci						  GFP_KERNEL);
58762306a36Sopenharmony_ci		if (!viafb_gamma_table)
58862306a36Sopenharmony_ci			return -ENOMEM;
58962306a36Sopenharmony_ci		viafb_get_gamma_table(viafb_gamma_table);
59062306a36Sopenharmony_ci		if (copy_to_user(argp, viafb_gamma_table,
59162306a36Sopenharmony_ci			256 * sizeof(u32))) {
59262306a36Sopenharmony_ci			kfree(viafb_gamma_table);
59362306a36Sopenharmony_ci			return -EFAULT;
59462306a36Sopenharmony_ci		}
59562306a36Sopenharmony_ci		kfree(viafb_gamma_table);
59662306a36Sopenharmony_ci		break;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	case VIAFB_GET_GAMMA_SUPPORT_STATE:
59962306a36Sopenharmony_ci		viafb_get_gamma_support_state(viafb_bpp, &state_info);
60062306a36Sopenharmony_ci		if (put_user(state_info, argp))
60162306a36Sopenharmony_ci			return -EFAULT;
60262306a36Sopenharmony_ci		break;
60362306a36Sopenharmony_ci	case VIAFB_SYNC_SURFACE:
60462306a36Sopenharmony_ci		DEBUG_MSG(KERN_INFO "lobo VIAFB_SYNC_SURFACE\n");
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci	case VIAFB_GET_DRIVER_CAPS:
60762306a36Sopenharmony_ci		break;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	case VIAFB_GET_PANEL_MAX_SIZE:
61062306a36Sopenharmony_ci		if (copy_from_user(&u.panel_pos_size_para, argp,
61162306a36Sopenharmony_ci				   sizeof(u.panel_pos_size_para)))
61262306a36Sopenharmony_ci			return -EFAULT;
61362306a36Sopenharmony_ci		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
61462306a36Sopenharmony_ci		if (copy_to_user(argp, &u.panel_pos_size_para,
61562306a36Sopenharmony_ci		     sizeof(u.panel_pos_size_para)))
61662306a36Sopenharmony_ci			return -EFAULT;
61762306a36Sopenharmony_ci		break;
61862306a36Sopenharmony_ci	case VIAFB_GET_PANEL_MAX_POSITION:
61962306a36Sopenharmony_ci		if (copy_from_user(&u.panel_pos_size_para, argp,
62062306a36Sopenharmony_ci				   sizeof(u.panel_pos_size_para)))
62162306a36Sopenharmony_ci			return -EFAULT;
62262306a36Sopenharmony_ci		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
62362306a36Sopenharmony_ci		if (copy_to_user(argp, &u.panel_pos_size_para,
62462306a36Sopenharmony_ci				 sizeof(u.panel_pos_size_para)))
62562306a36Sopenharmony_ci			return -EFAULT;
62662306a36Sopenharmony_ci		break;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	case VIAFB_GET_PANEL_POSITION:
62962306a36Sopenharmony_ci		if (copy_from_user(&u.panel_pos_size_para, argp,
63062306a36Sopenharmony_ci				   sizeof(u.panel_pos_size_para)))
63162306a36Sopenharmony_ci			return -EFAULT;
63262306a36Sopenharmony_ci		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
63362306a36Sopenharmony_ci		if (copy_to_user(argp, &u.panel_pos_size_para,
63462306a36Sopenharmony_ci				 sizeof(u.panel_pos_size_para)))
63562306a36Sopenharmony_ci			return -EFAULT;
63662306a36Sopenharmony_ci		break;
63762306a36Sopenharmony_ci	case VIAFB_GET_PANEL_SIZE:
63862306a36Sopenharmony_ci		if (copy_from_user(&u.panel_pos_size_para, argp,
63962306a36Sopenharmony_ci				   sizeof(u.panel_pos_size_para)))
64062306a36Sopenharmony_ci			return -EFAULT;
64162306a36Sopenharmony_ci		u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
64262306a36Sopenharmony_ci		if (copy_to_user(argp, &u.panel_pos_size_para,
64362306a36Sopenharmony_ci				 sizeof(u.panel_pos_size_para)))
64462306a36Sopenharmony_ci			return -EFAULT;
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	case VIAFB_SET_PANEL_POSITION:
64862306a36Sopenharmony_ci		if (copy_from_user(&u.panel_pos_size_para, argp,
64962306a36Sopenharmony_ci				   sizeof(u.panel_pos_size_para)))
65062306a36Sopenharmony_ci			return -EFAULT;
65162306a36Sopenharmony_ci		break;
65262306a36Sopenharmony_ci	case VIAFB_SET_PANEL_SIZE:
65362306a36Sopenharmony_ci		if (copy_from_user(&u.panel_pos_size_para, argp,
65462306a36Sopenharmony_ci				   sizeof(u.panel_pos_size_para)))
65562306a36Sopenharmony_ci			return -EFAULT;
65662306a36Sopenharmony_ci		break;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	default:
65962306a36Sopenharmony_ci		return -EINVAL;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	return 0;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic void viafb_fillrect(struct fb_info *info,
66662306a36Sopenharmony_ci	const struct fb_fillrect *rect)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
66962306a36Sopenharmony_ci	struct viafb_shared *shared = viapar->shared;
67062306a36Sopenharmony_ci	u32 fg_color;
67162306a36Sopenharmony_ci	u8 rop;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt) {
67462306a36Sopenharmony_ci		cfb_fillrect(info, rect);
67562306a36Sopenharmony_ci		return;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (!rect->width || !rect->height)
67962306a36Sopenharmony_ci		return;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
68262306a36Sopenharmony_ci		fg_color = ((u32 *)info->pseudo_palette)[rect->color];
68362306a36Sopenharmony_ci	else
68462306a36Sopenharmony_ci		fg_color = rect->color;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (rect->rop == ROP_XOR)
68762306a36Sopenharmony_ci		rop = 0x5A;
68862306a36Sopenharmony_ci	else
68962306a36Sopenharmony_ci		rop = 0xF0;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "viafb 2D engine: fillrect\n");
69262306a36Sopenharmony_ci	if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_FILL,
69362306a36Sopenharmony_ci		rect->width, rect->height, info->var.bits_per_pixel,
69462306a36Sopenharmony_ci		viapar->vram_addr, info->fix.line_length, rect->dx, rect->dy,
69562306a36Sopenharmony_ci		NULL, 0, 0, 0, 0, fg_color, 0, rop))
69662306a36Sopenharmony_ci		cfb_fillrect(info, rect);
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic void viafb_copyarea(struct fb_info *info,
70062306a36Sopenharmony_ci	const struct fb_copyarea *area)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
70362306a36Sopenharmony_ci	struct viafb_shared *shared = viapar->shared;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt) {
70662306a36Sopenharmony_ci		cfb_copyarea(info, area);
70762306a36Sopenharmony_ci		return;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (!area->width || !area->height)
71162306a36Sopenharmony_ci		return;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "viafb 2D engine: copyarea\n");
71462306a36Sopenharmony_ci	if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_COLOR,
71562306a36Sopenharmony_ci		area->width, area->height, info->var.bits_per_pixel,
71662306a36Sopenharmony_ci		viapar->vram_addr, info->fix.line_length, area->dx, area->dy,
71762306a36Sopenharmony_ci		NULL, viapar->vram_addr, info->fix.line_length,
71862306a36Sopenharmony_ci		area->sx, area->sy, 0, 0, 0))
71962306a36Sopenharmony_ci		cfb_copyarea(info, area);
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic void viafb_imageblit(struct fb_info *info,
72362306a36Sopenharmony_ci	const struct fb_image *image)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
72662306a36Sopenharmony_ci	struct viafb_shared *shared = viapar->shared;
72762306a36Sopenharmony_ci	u32 fg_color = 0, bg_color = 0;
72862306a36Sopenharmony_ci	u8 op;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED || !shared->hw_bitblt ||
73162306a36Sopenharmony_ci		(image->depth != 1 && image->depth != viapar->depth)) {
73262306a36Sopenharmony_ci		cfb_imageblit(info, image);
73362306a36Sopenharmony_ci		return;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (image->depth == 1) {
73762306a36Sopenharmony_ci		op = VIA_BITBLT_MONO;
73862306a36Sopenharmony_ci		if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
73962306a36Sopenharmony_ci			fg_color =
74062306a36Sopenharmony_ci				((u32 *)info->pseudo_palette)[image->fg_color];
74162306a36Sopenharmony_ci			bg_color =
74262306a36Sopenharmony_ci				((u32 *)info->pseudo_palette)[image->bg_color];
74362306a36Sopenharmony_ci		} else {
74462306a36Sopenharmony_ci			fg_color = image->fg_color;
74562306a36Sopenharmony_ci			bg_color = image->bg_color;
74662306a36Sopenharmony_ci		}
74762306a36Sopenharmony_ci	} else
74862306a36Sopenharmony_ci		op = VIA_BITBLT_COLOR;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	DEBUG_MSG(KERN_DEBUG "viafb 2D engine: imageblit\n");
75162306a36Sopenharmony_ci	if (shared->hw_bitblt(shared->vdev->engine_mmio, op,
75262306a36Sopenharmony_ci		image->width, image->height, info->var.bits_per_pixel,
75362306a36Sopenharmony_ci		viapar->vram_addr, info->fix.line_length, image->dx, image->dy,
75462306a36Sopenharmony_ci		(u32 *)image->data, 0, 0, 0, 0, fg_color, bg_color, 0))
75562306a36Sopenharmony_ci		cfb_imageblit(info, image);
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
76162306a36Sopenharmony_ci	void __iomem *engine = viapar->shared->vdev->engine_mmio;
76262306a36Sopenharmony_ci	u32 temp, xx, yy, bg_color = 0, fg_color = 0,
76362306a36Sopenharmony_ci		chip_name = viapar->shared->chip_info.gfx_chip_name;
76462306a36Sopenharmony_ci	int i, j = 0, cur_size = 64;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo)
76762306a36Sopenharmony_ci		return -ENODEV;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* LCD ouput does not support hw cursors (at least on VN896) */
77062306a36Sopenharmony_ci	if ((chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) ||
77162306a36Sopenharmony_ci		viafb_LCD_ON)
77262306a36Sopenharmony_ci		return -ENODEV;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	viafb_show_hw_cursor(info, HW_Cursor_OFF);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETHOT) {
77762306a36Sopenharmony_ci		temp = (cursor->hot.x << 16) + cursor->hot.y;
77862306a36Sopenharmony_ci		writel(temp, engine + VIA_REG_CURSOR_ORG);
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETPOS) {
78262306a36Sopenharmony_ci		yy = cursor->image.dy - info->var.yoffset;
78362306a36Sopenharmony_ci		xx = cursor->image.dx - info->var.xoffset;
78462306a36Sopenharmony_ci		temp = yy & 0xFFFF;
78562306a36Sopenharmony_ci		temp |= (xx << 16);
78662306a36Sopenharmony_ci		writel(temp, engine + VIA_REG_CURSOR_POS);
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (cursor->image.width <= 32 && cursor->image.height <= 32)
79062306a36Sopenharmony_ci		cur_size = 32;
79162306a36Sopenharmony_ci	else if (cursor->image.width <= 64 && cursor->image.height <= 64)
79262306a36Sopenharmony_ci		cur_size = 64;
79362306a36Sopenharmony_ci	else {
79462306a36Sopenharmony_ci		printk(KERN_WARNING "viafb_cursor: The cursor is too large "
79562306a36Sopenharmony_ci			"%dx%d", cursor->image.width, cursor->image.height);
79662306a36Sopenharmony_ci		return -ENXIO;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETSIZE) {
80062306a36Sopenharmony_ci		temp = readl(engine + VIA_REG_CURSOR_MODE);
80162306a36Sopenharmony_ci		if (cur_size == 32)
80262306a36Sopenharmony_ci			temp |= 0x2;
80362306a36Sopenharmony_ci		else
80462306a36Sopenharmony_ci			temp &= ~0x2;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci		writel(temp, engine + VIA_REG_CURSOR_MODE);
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETCMAP) {
81062306a36Sopenharmony_ci		fg_color = cursor->image.fg_color;
81162306a36Sopenharmony_ci		bg_color = cursor->image.bg_color;
81262306a36Sopenharmony_ci		if (chip_name == UNICHROME_CX700 ||
81362306a36Sopenharmony_ci			chip_name == UNICHROME_VX800 ||
81462306a36Sopenharmony_ci			chip_name == UNICHROME_VX855 ||
81562306a36Sopenharmony_ci			chip_name == UNICHROME_VX900) {
81662306a36Sopenharmony_ci			fg_color =
81762306a36Sopenharmony_ci				((info->cmap.red[fg_color] & 0xFFC0) << 14) |
81862306a36Sopenharmony_ci				((info->cmap.green[fg_color] & 0xFFC0) << 4) |
81962306a36Sopenharmony_ci				((info->cmap.blue[fg_color] & 0xFFC0) >> 6);
82062306a36Sopenharmony_ci			bg_color =
82162306a36Sopenharmony_ci				((info->cmap.red[bg_color] & 0xFFC0) << 14) |
82262306a36Sopenharmony_ci				((info->cmap.green[bg_color] & 0xFFC0) << 4) |
82362306a36Sopenharmony_ci				((info->cmap.blue[bg_color] & 0xFFC0) >> 6);
82462306a36Sopenharmony_ci		} else {
82562306a36Sopenharmony_ci			fg_color =
82662306a36Sopenharmony_ci				((info->cmap.red[fg_color] & 0xFF00) << 8) |
82762306a36Sopenharmony_ci				(info->cmap.green[fg_color] & 0xFF00) |
82862306a36Sopenharmony_ci				((info->cmap.blue[fg_color] & 0xFF00) >> 8);
82962306a36Sopenharmony_ci			bg_color =
83062306a36Sopenharmony_ci				((info->cmap.red[bg_color] & 0xFF00) << 8) |
83162306a36Sopenharmony_ci				(info->cmap.green[bg_color] & 0xFF00) |
83262306a36Sopenharmony_ci				((info->cmap.blue[bg_color] & 0xFF00) >> 8);
83362306a36Sopenharmony_ci		}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		writel(bg_color, engine + VIA_REG_CURSOR_BG);
83662306a36Sopenharmony_ci		writel(fg_color, engine + VIA_REG_CURSOR_FG);
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (cursor->set & FB_CUR_SETSHAPE) {
84062306a36Sopenharmony_ci		struct {
84162306a36Sopenharmony_ci			u8 data[CURSOR_SIZE];
84262306a36Sopenharmony_ci			u32 bak[CURSOR_SIZE / 4];
84362306a36Sopenharmony_ci		} *cr_data = kzalloc(sizeof(*cr_data), GFP_ATOMIC);
84462306a36Sopenharmony_ci		int size = ((cursor->image.width + 7) >> 3) *
84562306a36Sopenharmony_ci			cursor->image.height;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		if (!cr_data)
84862306a36Sopenharmony_ci			return -ENOMEM;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		if (cur_size == 32) {
85162306a36Sopenharmony_ci			for (i = 0; i < (CURSOR_SIZE / 4); i++) {
85262306a36Sopenharmony_ci				cr_data->bak[i] = 0x0;
85362306a36Sopenharmony_ci				cr_data->bak[i + 1] = 0xFFFFFFFF;
85462306a36Sopenharmony_ci				i += 1;
85562306a36Sopenharmony_ci			}
85662306a36Sopenharmony_ci		} else {
85762306a36Sopenharmony_ci			for (i = 0; i < (CURSOR_SIZE / 4); i++) {
85862306a36Sopenharmony_ci				cr_data->bak[i] = 0x0;
85962306a36Sopenharmony_ci				cr_data->bak[i + 1] = 0x0;
86062306a36Sopenharmony_ci				cr_data->bak[i + 2] = 0xFFFFFFFF;
86162306a36Sopenharmony_ci				cr_data->bak[i + 3] = 0xFFFFFFFF;
86262306a36Sopenharmony_ci				i += 3;
86362306a36Sopenharmony_ci			}
86462306a36Sopenharmony_ci		}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci		switch (cursor->rop) {
86762306a36Sopenharmony_ci		case ROP_XOR:
86862306a36Sopenharmony_ci			for (i = 0; i < size; i++)
86962306a36Sopenharmony_ci				cr_data->data[i] = cursor->mask[i];
87062306a36Sopenharmony_ci			break;
87162306a36Sopenharmony_ci		case ROP_COPY:
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci			for (i = 0; i < size; i++)
87462306a36Sopenharmony_ci				cr_data->data[i] = cursor->mask[i];
87562306a36Sopenharmony_ci			break;
87662306a36Sopenharmony_ci		default:
87762306a36Sopenharmony_ci			break;
87862306a36Sopenharmony_ci		}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci		if (cur_size == 32) {
88162306a36Sopenharmony_ci			for (i = 0; i < size; i++) {
88262306a36Sopenharmony_ci				cr_data->bak[j] = (u32) cr_data->data[i];
88362306a36Sopenharmony_ci				cr_data->bak[j + 1] = ~cr_data->bak[j];
88462306a36Sopenharmony_ci				j += 2;
88562306a36Sopenharmony_ci			}
88662306a36Sopenharmony_ci		} else {
88762306a36Sopenharmony_ci			for (i = 0; i < size; i++) {
88862306a36Sopenharmony_ci				cr_data->bak[j] = (u32) cr_data->data[i];
88962306a36Sopenharmony_ci				cr_data->bak[j + 1] = 0x0;
89062306a36Sopenharmony_ci				cr_data->bak[j + 2] = ~cr_data->bak[j];
89162306a36Sopenharmony_ci				cr_data->bak[j + 3] = ~cr_data->bak[j + 1];
89262306a36Sopenharmony_ci				j += 4;
89362306a36Sopenharmony_ci			}
89462306a36Sopenharmony_ci		}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		memcpy_toio(viafbinfo->screen_base + viapar->shared->
89762306a36Sopenharmony_ci			cursor_vram_addr, cr_data->bak, CURSOR_SIZE);
89862306a36Sopenharmony_ci		kfree(cr_data);
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (cursor->enable)
90262306a36Sopenharmony_ci		viafb_show_hw_cursor(info, HW_Cursor_ON);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	return 0;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int viafb_sync(struct fb_info *info)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	if (!(info->flags & FBINFO_HWACCEL_DISABLED))
91062306a36Sopenharmony_ci		viafb_wait_engine_idle(info);
91162306a36Sopenharmony_ci	return 0;
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic int get_primary_device(void)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	int primary_device = 0;
91762306a36Sopenharmony_ci	/* Rule: device on iga1 path are the primary device. */
91862306a36Sopenharmony_ci	if (viafb_SAMM_ON) {
91962306a36Sopenharmony_ci		if (viafb_CRT_ON) {
92062306a36Sopenharmony_ci			if (viaparinfo->shared->iga1_devices & VIA_CRT) {
92162306a36Sopenharmony_ci				DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n", IGA1);
92262306a36Sopenharmony_ci				primary_device = CRT_Device;
92362306a36Sopenharmony_ci			}
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci		if (viafb_DVI_ON) {
92662306a36Sopenharmony_ci			if (viaparinfo->tmds_setting_info->iga_path == IGA1) {
92762306a36Sopenharmony_ci				DEBUG_MSG(KERN_INFO "DVI IGA Path:%d\n",
92862306a36Sopenharmony_ci					viaparinfo->
92962306a36Sopenharmony_ci					tmds_setting_info->iga_path);
93062306a36Sopenharmony_ci				primary_device = DVI_Device;
93162306a36Sopenharmony_ci			}
93262306a36Sopenharmony_ci		}
93362306a36Sopenharmony_ci		if (viafb_LCD_ON) {
93462306a36Sopenharmony_ci			if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
93562306a36Sopenharmony_ci				DEBUG_MSG(KERN_INFO "LCD IGA Path:%d\n",
93662306a36Sopenharmony_ci					viaparinfo->
93762306a36Sopenharmony_ci					lvds_setting_info->iga_path);
93862306a36Sopenharmony_ci				primary_device = LCD_Device;
93962306a36Sopenharmony_ci			}
94062306a36Sopenharmony_ci		}
94162306a36Sopenharmony_ci		if (viafb_LCD2_ON) {
94262306a36Sopenharmony_ci			if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {
94362306a36Sopenharmony_ci				DEBUG_MSG(KERN_INFO "LCD2 IGA Path:%d\n",
94462306a36Sopenharmony_ci					viaparinfo->
94562306a36Sopenharmony_ci					lvds_setting_info2->iga_path);
94662306a36Sopenharmony_ci				primary_device = LCD2_Device;
94762306a36Sopenharmony_ci			}
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci	return primary_device;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic void retrieve_device_setting(struct viafb_ioctl_setting
95462306a36Sopenharmony_ci	*setting_info)
95562306a36Sopenharmony_ci{
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	/* get device status */
95862306a36Sopenharmony_ci	if (viafb_CRT_ON == 1)
95962306a36Sopenharmony_ci		setting_info->device_status = CRT_Device;
96062306a36Sopenharmony_ci	if (viafb_DVI_ON == 1)
96162306a36Sopenharmony_ci		setting_info->device_status |= DVI_Device;
96262306a36Sopenharmony_ci	if (viafb_LCD_ON == 1)
96362306a36Sopenharmony_ci		setting_info->device_status |= LCD_Device;
96462306a36Sopenharmony_ci	if (viafb_LCD2_ON == 1)
96562306a36Sopenharmony_ci		setting_info->device_status |= LCD2_Device;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	setting_info->samm_status = viafb_SAMM_ON;
96862306a36Sopenharmony_ci	setting_info->primary_device = get_primary_device();
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	setting_info->first_dev_bpp = viafb_bpp;
97162306a36Sopenharmony_ci	setting_info->second_dev_bpp = viafb_bpp1;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	setting_info->first_dev_refresh = viafb_refresh;
97462306a36Sopenharmony_ci	setting_info->second_dev_refresh = viafb_refresh1;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	setting_info->first_dev_hor_res = viafb_hotplug_Xres;
97762306a36Sopenharmony_ci	setting_info->first_dev_ver_res = viafb_hotplug_Yres;
97862306a36Sopenharmony_ci	setting_info->second_dev_hor_res = viafb_second_xres;
97962306a36Sopenharmony_ci	setting_info->second_dev_ver_res = viafb_second_yres;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/* Get lcd attributes */
98262306a36Sopenharmony_ci	setting_info->lcd_attributes.display_center = viafb_lcd_dsp_method;
98362306a36Sopenharmony_ci	setting_info->lcd_attributes.panel_id = viafb_lcd_panel_id;
98462306a36Sopenharmony_ci	setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic int __init parse_active_dev(void)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	viafb_CRT_ON = STATE_OFF;
99062306a36Sopenharmony_ci	viafb_DVI_ON = STATE_OFF;
99162306a36Sopenharmony_ci	viafb_LCD_ON = STATE_OFF;
99262306a36Sopenharmony_ci	viafb_LCD2_ON = STATE_OFF;
99362306a36Sopenharmony_ci	/* 1. Modify the active status of devices. */
99462306a36Sopenharmony_ci	/* 2. Keep the order of devices, so we can set corresponding
99562306a36Sopenharmony_ci	   IGA path to devices in SAMM case. */
99662306a36Sopenharmony_ci	/*    Note: The previous of active_dev is primary device,
99762306a36Sopenharmony_ci	   and the following is secondary device. */
99862306a36Sopenharmony_ci	if (!viafb_active_dev) {
99962306a36Sopenharmony_ci		if (machine_is_olpc()) { /* LCD only */
100062306a36Sopenharmony_ci			viafb_LCD_ON = STATE_ON;
100162306a36Sopenharmony_ci			viafb_SAMM_ON = STATE_OFF;
100262306a36Sopenharmony_ci		} else {
100362306a36Sopenharmony_ci			viafb_CRT_ON = STATE_ON;
100462306a36Sopenharmony_ci			viafb_SAMM_ON = STATE_OFF;
100562306a36Sopenharmony_ci		}
100662306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "CRT+DVI")) {
100762306a36Sopenharmony_ci		/* CRT+DVI */
100862306a36Sopenharmony_ci		viafb_CRT_ON = STATE_ON;
100962306a36Sopenharmony_ci		viafb_DVI_ON = STATE_ON;
101062306a36Sopenharmony_ci		viafb_primary_dev = CRT_Device;
101162306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "DVI+CRT")) {
101262306a36Sopenharmony_ci		/* DVI+CRT */
101362306a36Sopenharmony_ci		viafb_CRT_ON = STATE_ON;
101462306a36Sopenharmony_ci		viafb_DVI_ON = STATE_ON;
101562306a36Sopenharmony_ci		viafb_primary_dev = DVI_Device;
101662306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "CRT+LCD")) {
101762306a36Sopenharmony_ci		/* CRT+LCD */
101862306a36Sopenharmony_ci		viafb_CRT_ON = STATE_ON;
101962306a36Sopenharmony_ci		viafb_LCD_ON = STATE_ON;
102062306a36Sopenharmony_ci		viafb_primary_dev = CRT_Device;
102162306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "LCD+CRT")) {
102262306a36Sopenharmony_ci		/* LCD+CRT */
102362306a36Sopenharmony_ci		viafb_CRT_ON = STATE_ON;
102462306a36Sopenharmony_ci		viafb_LCD_ON = STATE_ON;
102562306a36Sopenharmony_ci		viafb_primary_dev = LCD_Device;
102662306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "DVI+LCD")) {
102762306a36Sopenharmony_ci		/* DVI+LCD */
102862306a36Sopenharmony_ci		viafb_DVI_ON = STATE_ON;
102962306a36Sopenharmony_ci		viafb_LCD_ON = STATE_ON;
103062306a36Sopenharmony_ci		viafb_primary_dev = DVI_Device;
103162306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "LCD+DVI")) {
103262306a36Sopenharmony_ci		/* LCD+DVI */
103362306a36Sopenharmony_ci		viafb_DVI_ON = STATE_ON;
103462306a36Sopenharmony_ci		viafb_LCD_ON = STATE_ON;
103562306a36Sopenharmony_ci		viafb_primary_dev = LCD_Device;
103662306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "LCD+LCD2")) {
103762306a36Sopenharmony_ci		viafb_LCD_ON = STATE_ON;
103862306a36Sopenharmony_ci		viafb_LCD2_ON = STATE_ON;
103962306a36Sopenharmony_ci		viafb_primary_dev = LCD_Device;
104062306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "LCD2+LCD")) {
104162306a36Sopenharmony_ci		viafb_LCD_ON = STATE_ON;
104262306a36Sopenharmony_ci		viafb_LCD2_ON = STATE_ON;
104362306a36Sopenharmony_ci		viafb_primary_dev = LCD2_Device;
104462306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "CRT")) {
104562306a36Sopenharmony_ci		/* CRT only */
104662306a36Sopenharmony_ci		viafb_CRT_ON = STATE_ON;
104762306a36Sopenharmony_ci		viafb_SAMM_ON = STATE_OFF;
104862306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "DVI")) {
104962306a36Sopenharmony_ci		/* DVI only */
105062306a36Sopenharmony_ci		viafb_DVI_ON = STATE_ON;
105162306a36Sopenharmony_ci		viafb_SAMM_ON = STATE_OFF;
105262306a36Sopenharmony_ci	} else if (!strcmp(viafb_active_dev, "LCD")) {
105362306a36Sopenharmony_ci		/* LCD only */
105462306a36Sopenharmony_ci		viafb_LCD_ON = STATE_ON;
105562306a36Sopenharmony_ci		viafb_SAMM_ON = STATE_OFF;
105662306a36Sopenharmony_ci	} else
105762306a36Sopenharmony_ci		return -EINVAL;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	return 0;
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic int parse_port(char *opt_str, int *output_interface)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	if (!strncmp(opt_str, "DVP0", 4))
106562306a36Sopenharmony_ci		*output_interface = INTERFACE_DVP0;
106662306a36Sopenharmony_ci	else if (!strncmp(opt_str, "DVP1", 4))
106762306a36Sopenharmony_ci		*output_interface = INTERFACE_DVP1;
106862306a36Sopenharmony_ci	else if (!strncmp(opt_str, "DFP_HIGHLOW", 11))
106962306a36Sopenharmony_ci		*output_interface = INTERFACE_DFP;
107062306a36Sopenharmony_ci	else if (!strncmp(opt_str, "DFP_HIGH", 8))
107162306a36Sopenharmony_ci		*output_interface = INTERFACE_DFP_HIGH;
107262306a36Sopenharmony_ci	else if (!strncmp(opt_str, "DFP_LOW", 7))
107362306a36Sopenharmony_ci		*output_interface = INTERFACE_DFP_LOW;
107462306a36Sopenharmony_ci	else
107562306a36Sopenharmony_ci		*output_interface = INTERFACE_NONE;
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic void parse_lcd_port(void)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info.
108262306a36Sopenharmony_ci		output_interface);
108362306a36Sopenharmony_ci	/*Initialize to avoid unexpected behavior */
108462306a36Sopenharmony_ci	viaparinfo->chip_info->lvds_chip_info2.output_interface =
108562306a36Sopenharmony_ci	INTERFACE_NONE;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "parse_lcd_port: viafb_lcd_port:%s,interface:%d\n",
108862306a36Sopenharmony_ci		  viafb_lcd_port, viaparinfo->chip_info->lvds_chip_info.
108962306a36Sopenharmony_ci		  output_interface);
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic void parse_dvi_port(void)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info.
109562306a36Sopenharmony_ci		output_interface);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "parse_dvi_port: viafb_dvi_port:%s,interface:%d\n",
109862306a36Sopenharmony_ci		  viafb_dvi_port, viaparinfo->chip_info->tmds_chip_info.
109962306a36Sopenharmony_ci		  output_interface);
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci/*
110562306a36Sopenharmony_ci * The proc filesystem read/write function, a simple proc implement to
110662306a36Sopenharmony_ci * get/set the value of DPA  DVP0,   DVP0DataDriving,  DVP0ClockDriving, DVP1,
110762306a36Sopenharmony_ci * DVP1Driving, DFPHigh, DFPLow CR96,   SR2A[5], SR1B[1], SR2A[4], SR1E[2],
110862306a36Sopenharmony_ci * CR9B,    SR65,    CR97,    CR99
110962306a36Sopenharmony_ci */
111062306a36Sopenharmony_cistatic int viafb_dvp0_proc_show(struct seq_file *m, void *v)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	u8 dvp0_data_dri = 0, dvp0_clk_dri = 0, dvp0 = 0;
111362306a36Sopenharmony_ci	dvp0_data_dri =
111462306a36Sopenharmony_ci	    (viafb_read_reg(VIASR, SR2A) & BIT5) >> 4 |
111562306a36Sopenharmony_ci	    (viafb_read_reg(VIASR, SR1B) & BIT1) >> 1;
111662306a36Sopenharmony_ci	dvp0_clk_dri =
111762306a36Sopenharmony_ci	    (viafb_read_reg(VIASR, SR2A) & BIT4) >> 3 |
111862306a36Sopenharmony_ci	    (viafb_read_reg(VIASR, SR1E) & BIT2) >> 2;
111962306a36Sopenharmony_ci	dvp0 = viafb_read_reg(VIACR, CR96) & 0x0f;
112062306a36Sopenharmony_ci	seq_printf(m, "%x %x %x\n", dvp0, dvp0_data_dri, dvp0_clk_dri);
112162306a36Sopenharmony_ci	return 0;
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cistatic int viafb_dvp0_proc_open(struct inode *inode, struct file *file)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	return single_open(file, viafb_dvp0_proc_show, NULL);
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic ssize_t viafb_dvp0_proc_write(struct file *file,
113062306a36Sopenharmony_ci	const char __user *buffer, size_t count, loff_t *pos)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	char buf[20], *value, *pbuf;
113362306a36Sopenharmony_ci	u8 reg_val = 0;
113462306a36Sopenharmony_ci	unsigned long length, i;
113562306a36Sopenharmony_ci	if (count < 1)
113662306a36Sopenharmony_ci		return -EINVAL;
113762306a36Sopenharmony_ci	length = count > 20 ? 20 : count;
113862306a36Sopenharmony_ci	if (copy_from_user(&buf[0], buffer, length))
113962306a36Sopenharmony_ci		return -EFAULT;
114062306a36Sopenharmony_ci	buf[length - 1] = '\0';	/*Ensure end string */
114162306a36Sopenharmony_ci	pbuf = &buf[0];
114262306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
114362306a36Sopenharmony_ci		value = strsep(&pbuf, " ");
114462306a36Sopenharmony_ci		if (value != NULL) {
114562306a36Sopenharmony_ci			if (kstrtou8(value, 0, &reg_val) < 0)
114662306a36Sopenharmony_ci				return -EINVAL;
114762306a36Sopenharmony_ci			DEBUG_MSG(KERN_INFO "DVP0:reg_val[%lu]=:%x\n", i,
114862306a36Sopenharmony_ci				  reg_val);
114962306a36Sopenharmony_ci			switch (i) {
115062306a36Sopenharmony_ci			case 0:
115162306a36Sopenharmony_ci				viafb_write_reg_mask(CR96, VIACR,
115262306a36Sopenharmony_ci					reg_val, 0x0f);
115362306a36Sopenharmony_ci				break;
115462306a36Sopenharmony_ci			case 1:
115562306a36Sopenharmony_ci				viafb_write_reg_mask(SR2A, VIASR,
115662306a36Sopenharmony_ci					reg_val << 4, BIT5);
115762306a36Sopenharmony_ci				viafb_write_reg_mask(SR1B, VIASR,
115862306a36Sopenharmony_ci					reg_val << 1, BIT1);
115962306a36Sopenharmony_ci				break;
116062306a36Sopenharmony_ci			case 2:
116162306a36Sopenharmony_ci				viafb_write_reg_mask(SR2A, VIASR,
116262306a36Sopenharmony_ci					reg_val << 3, BIT4);
116362306a36Sopenharmony_ci				viafb_write_reg_mask(SR1E, VIASR,
116462306a36Sopenharmony_ci					reg_val << 2, BIT2);
116562306a36Sopenharmony_ci				break;
116662306a36Sopenharmony_ci			default:
116762306a36Sopenharmony_ci				break;
116862306a36Sopenharmony_ci			}
116962306a36Sopenharmony_ci		} else {
117062306a36Sopenharmony_ci			break;
117162306a36Sopenharmony_ci		}
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci	return count;
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic const struct proc_ops viafb_dvp0_proc_ops = {
117762306a36Sopenharmony_ci	.proc_open	= viafb_dvp0_proc_open,
117862306a36Sopenharmony_ci	.proc_read	= seq_read,
117962306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
118062306a36Sopenharmony_ci	.proc_release	= single_release,
118162306a36Sopenharmony_ci	.proc_write	= viafb_dvp0_proc_write,
118262306a36Sopenharmony_ci};
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_cistatic int viafb_dvp1_proc_show(struct seq_file *m, void *v)
118562306a36Sopenharmony_ci{
118662306a36Sopenharmony_ci	u8 dvp1 = 0, dvp1_data_dri = 0, dvp1_clk_dri = 0;
118762306a36Sopenharmony_ci	dvp1 = viafb_read_reg(VIACR, CR9B) & 0x0f;
118862306a36Sopenharmony_ci	dvp1_data_dri = (viafb_read_reg(VIASR, SR65) & 0x0c) >> 2;
118962306a36Sopenharmony_ci	dvp1_clk_dri = viafb_read_reg(VIASR, SR65) & 0x03;
119062306a36Sopenharmony_ci	seq_printf(m, "%x %x %x\n", dvp1, dvp1_data_dri, dvp1_clk_dri);
119162306a36Sopenharmony_ci	return 0;
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistatic int viafb_dvp1_proc_open(struct inode *inode, struct file *file)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	return single_open(file, viafb_dvp1_proc_show, NULL);
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic ssize_t viafb_dvp1_proc_write(struct file *file,
120062306a36Sopenharmony_ci	const char __user *buffer, size_t count, loff_t *pos)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	char buf[20], *value, *pbuf;
120362306a36Sopenharmony_ci	u8 reg_val = 0;
120462306a36Sopenharmony_ci	unsigned long length, i;
120562306a36Sopenharmony_ci	if (count < 1)
120662306a36Sopenharmony_ci		return -EINVAL;
120762306a36Sopenharmony_ci	length = count > 20 ? 20 : count;
120862306a36Sopenharmony_ci	if (copy_from_user(&buf[0], buffer, length))
120962306a36Sopenharmony_ci		return -EFAULT;
121062306a36Sopenharmony_ci	buf[length - 1] = '\0';	/*Ensure end string */
121162306a36Sopenharmony_ci	pbuf = &buf[0];
121262306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
121362306a36Sopenharmony_ci		value = strsep(&pbuf, " ");
121462306a36Sopenharmony_ci		if (value != NULL) {
121562306a36Sopenharmony_ci			if (kstrtou8(value, 0, &reg_val) < 0)
121662306a36Sopenharmony_ci				return -EINVAL;
121762306a36Sopenharmony_ci			switch (i) {
121862306a36Sopenharmony_ci			case 0:
121962306a36Sopenharmony_ci				viafb_write_reg_mask(CR9B, VIACR,
122062306a36Sopenharmony_ci					reg_val, 0x0f);
122162306a36Sopenharmony_ci				break;
122262306a36Sopenharmony_ci			case 1:
122362306a36Sopenharmony_ci				viafb_write_reg_mask(SR65, VIASR,
122462306a36Sopenharmony_ci					reg_val << 2, 0x0c);
122562306a36Sopenharmony_ci				break;
122662306a36Sopenharmony_ci			case 2:
122762306a36Sopenharmony_ci				viafb_write_reg_mask(SR65, VIASR,
122862306a36Sopenharmony_ci					reg_val, 0x03);
122962306a36Sopenharmony_ci				break;
123062306a36Sopenharmony_ci			default:
123162306a36Sopenharmony_ci				break;
123262306a36Sopenharmony_ci			}
123362306a36Sopenharmony_ci		} else {
123462306a36Sopenharmony_ci			break;
123562306a36Sopenharmony_ci		}
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci	return count;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic const struct proc_ops viafb_dvp1_proc_ops = {
124162306a36Sopenharmony_ci	.proc_open	= viafb_dvp1_proc_open,
124262306a36Sopenharmony_ci	.proc_read	= seq_read,
124362306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
124462306a36Sopenharmony_ci	.proc_release	= single_release,
124562306a36Sopenharmony_ci	.proc_write	= viafb_dvp1_proc_write,
124662306a36Sopenharmony_ci};
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic int viafb_dfph_proc_show(struct seq_file *m, void *v)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	u8 dfp_high = 0;
125162306a36Sopenharmony_ci	dfp_high = viafb_read_reg(VIACR, CR97) & 0x0f;
125262306a36Sopenharmony_ci	seq_printf(m, "%x\n", dfp_high);
125362306a36Sopenharmony_ci	return 0;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic int viafb_dfph_proc_open(struct inode *inode, struct file *file)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	return single_open(file, viafb_dfph_proc_show, NULL);
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic ssize_t viafb_dfph_proc_write(struct file *file,
126262306a36Sopenharmony_ci	const char __user *buffer, size_t count, loff_t *pos)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	int err;
126562306a36Sopenharmony_ci	u8 reg_val;
126662306a36Sopenharmony_ci	err = kstrtou8_from_user(buffer, count, 0, &reg_val);
126762306a36Sopenharmony_ci	if (err)
126862306a36Sopenharmony_ci		return err;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f);
127162306a36Sopenharmony_ci	return count;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic const struct proc_ops viafb_dfph_proc_ops = {
127562306a36Sopenharmony_ci	.proc_open	= viafb_dfph_proc_open,
127662306a36Sopenharmony_ci	.proc_read	= seq_read,
127762306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
127862306a36Sopenharmony_ci	.proc_release	= single_release,
127962306a36Sopenharmony_ci	.proc_write	= viafb_dfph_proc_write,
128062306a36Sopenharmony_ci};
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int viafb_dfpl_proc_show(struct seq_file *m, void *v)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	u8 dfp_low = 0;
128562306a36Sopenharmony_ci	dfp_low = viafb_read_reg(VIACR, CR99) & 0x0f;
128662306a36Sopenharmony_ci	seq_printf(m, "%x\n", dfp_low);
128762306a36Sopenharmony_ci	return 0;
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cistatic int viafb_dfpl_proc_open(struct inode *inode, struct file *file)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	return single_open(file, viafb_dfpl_proc_show, NULL);
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic ssize_t viafb_dfpl_proc_write(struct file *file,
129662306a36Sopenharmony_ci	const char __user *buffer, size_t count, loff_t *pos)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	int err;
129962306a36Sopenharmony_ci	u8 reg_val;
130062306a36Sopenharmony_ci	err = kstrtou8_from_user(buffer, count, 0, &reg_val);
130162306a36Sopenharmony_ci	if (err)
130262306a36Sopenharmony_ci		return err;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f);
130562306a36Sopenharmony_ci	return count;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic const struct proc_ops viafb_dfpl_proc_ops = {
130962306a36Sopenharmony_ci	.proc_open	= viafb_dfpl_proc_open,
131062306a36Sopenharmony_ci	.proc_read	= seq_read,
131162306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
131262306a36Sopenharmony_ci	.proc_release	= single_release,
131362306a36Sopenharmony_ci	.proc_write	= viafb_dfpl_proc_write,
131462306a36Sopenharmony_ci};
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic int viafb_vt1636_proc_show(struct seq_file *m, void *v)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	u8 vt1636_08 = 0, vt1636_09 = 0;
131962306a36Sopenharmony_ci	switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
132062306a36Sopenharmony_ci	case VT1636_LVDS:
132162306a36Sopenharmony_ci		vt1636_08 =
132262306a36Sopenharmony_ci		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,
132362306a36Sopenharmony_ci		    &viaparinfo->chip_info->lvds_chip_info, 0x08) & 0x0f;
132462306a36Sopenharmony_ci		vt1636_09 =
132562306a36Sopenharmony_ci		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,
132662306a36Sopenharmony_ci		    &viaparinfo->chip_info->lvds_chip_info, 0x09) & 0x1f;
132762306a36Sopenharmony_ci		seq_printf(m, "%x %x\n", vt1636_08, vt1636_09);
132862306a36Sopenharmony_ci		break;
132962306a36Sopenharmony_ci	default:
133062306a36Sopenharmony_ci		break;
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci	switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
133362306a36Sopenharmony_ci	case VT1636_LVDS:
133462306a36Sopenharmony_ci		vt1636_08 =
133562306a36Sopenharmony_ci		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,
133662306a36Sopenharmony_ci			&viaparinfo->chip_info->lvds_chip_info2, 0x08) & 0x0f;
133762306a36Sopenharmony_ci		vt1636_09 =
133862306a36Sopenharmony_ci		    viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,
133962306a36Sopenharmony_ci			&viaparinfo->chip_info->lvds_chip_info2, 0x09) & 0x1f;
134062306a36Sopenharmony_ci		seq_printf(m, " %x %x\n", vt1636_08, vt1636_09);
134162306a36Sopenharmony_ci		break;
134262306a36Sopenharmony_ci	default:
134362306a36Sopenharmony_ci		break;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci	return 0;
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic int viafb_vt1636_proc_open(struct inode *inode, struct file *file)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	return single_open(file, viafb_vt1636_proc_show, NULL);
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_cistatic ssize_t viafb_vt1636_proc_write(struct file *file,
135462306a36Sopenharmony_ci	const char __user *buffer, size_t count, loff_t *pos)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	char buf[30], *value, *pbuf;
135762306a36Sopenharmony_ci	struct IODATA reg_val;
135862306a36Sopenharmony_ci	unsigned long length, i;
135962306a36Sopenharmony_ci	if (count < 1)
136062306a36Sopenharmony_ci		return -EINVAL;
136162306a36Sopenharmony_ci	length = count > 30 ? 30 : count;
136262306a36Sopenharmony_ci	if (copy_from_user(&buf[0], buffer, length))
136362306a36Sopenharmony_ci		return -EFAULT;
136462306a36Sopenharmony_ci	buf[length - 1] = '\0';	/*Ensure end string */
136562306a36Sopenharmony_ci	pbuf = &buf[0];
136662306a36Sopenharmony_ci	switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
136762306a36Sopenharmony_ci	case VT1636_LVDS:
136862306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
136962306a36Sopenharmony_ci			value = strsep(&pbuf, " ");
137062306a36Sopenharmony_ci			if (value != NULL) {
137162306a36Sopenharmony_ci				if (kstrtou8(value, 0, &reg_val.Data) < 0)
137262306a36Sopenharmony_ci					return -EINVAL;
137362306a36Sopenharmony_ci				switch (i) {
137462306a36Sopenharmony_ci				case 0:
137562306a36Sopenharmony_ci					reg_val.Index = 0x08;
137662306a36Sopenharmony_ci					reg_val.Mask = 0x0f;
137762306a36Sopenharmony_ci					viafb_gpio_i2c_write_mask_lvds
137862306a36Sopenharmony_ci					    (viaparinfo->lvds_setting_info,
137962306a36Sopenharmony_ci					    &viaparinfo->
138062306a36Sopenharmony_ci					    chip_info->lvds_chip_info,
138162306a36Sopenharmony_ci					     reg_val);
138262306a36Sopenharmony_ci					break;
138362306a36Sopenharmony_ci				case 1:
138462306a36Sopenharmony_ci					reg_val.Index = 0x09;
138562306a36Sopenharmony_ci					reg_val.Mask = 0x1f;
138662306a36Sopenharmony_ci					viafb_gpio_i2c_write_mask_lvds
138762306a36Sopenharmony_ci					    (viaparinfo->lvds_setting_info,
138862306a36Sopenharmony_ci					    &viaparinfo->
138962306a36Sopenharmony_ci					    chip_info->lvds_chip_info,
139062306a36Sopenharmony_ci					     reg_val);
139162306a36Sopenharmony_ci					break;
139262306a36Sopenharmony_ci				default:
139362306a36Sopenharmony_ci					break;
139462306a36Sopenharmony_ci				}
139562306a36Sopenharmony_ci			} else {
139662306a36Sopenharmony_ci				break;
139762306a36Sopenharmony_ci			}
139862306a36Sopenharmony_ci		}
139962306a36Sopenharmony_ci		break;
140062306a36Sopenharmony_ci	default:
140162306a36Sopenharmony_ci		break;
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci	switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
140462306a36Sopenharmony_ci	case VT1636_LVDS:
140562306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
140662306a36Sopenharmony_ci			value = strsep(&pbuf, " ");
140762306a36Sopenharmony_ci			if (value != NULL) {
140862306a36Sopenharmony_ci				if (kstrtou8(value, 0, &reg_val.Data) < 0)
140962306a36Sopenharmony_ci					return -EINVAL;
141062306a36Sopenharmony_ci				switch (i) {
141162306a36Sopenharmony_ci				case 0:
141262306a36Sopenharmony_ci					reg_val.Index = 0x08;
141362306a36Sopenharmony_ci					reg_val.Mask = 0x0f;
141462306a36Sopenharmony_ci					viafb_gpio_i2c_write_mask_lvds
141562306a36Sopenharmony_ci					    (viaparinfo->lvds_setting_info2,
141662306a36Sopenharmony_ci					    &viaparinfo->
141762306a36Sopenharmony_ci					    chip_info->lvds_chip_info2,
141862306a36Sopenharmony_ci					     reg_val);
141962306a36Sopenharmony_ci					break;
142062306a36Sopenharmony_ci				case 1:
142162306a36Sopenharmony_ci					reg_val.Index = 0x09;
142262306a36Sopenharmony_ci					reg_val.Mask = 0x1f;
142362306a36Sopenharmony_ci					viafb_gpio_i2c_write_mask_lvds
142462306a36Sopenharmony_ci					    (viaparinfo->lvds_setting_info2,
142562306a36Sopenharmony_ci					    &viaparinfo->
142662306a36Sopenharmony_ci					    chip_info->lvds_chip_info2,
142762306a36Sopenharmony_ci					     reg_val);
142862306a36Sopenharmony_ci					break;
142962306a36Sopenharmony_ci				default:
143062306a36Sopenharmony_ci					break;
143162306a36Sopenharmony_ci				}
143262306a36Sopenharmony_ci			} else {
143362306a36Sopenharmony_ci				break;
143462306a36Sopenharmony_ci			}
143562306a36Sopenharmony_ci		}
143662306a36Sopenharmony_ci		break;
143762306a36Sopenharmony_ci	default:
143862306a36Sopenharmony_ci		break;
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci	return count;
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cistatic const struct proc_ops viafb_vt1636_proc_ops = {
144462306a36Sopenharmony_ci	.proc_open	= viafb_vt1636_proc_open,
144562306a36Sopenharmony_ci	.proc_read	= seq_read,
144662306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
144762306a36Sopenharmony_ci	.proc_release	= single_release,
144862306a36Sopenharmony_ci	.proc_write	= viafb_vt1636_proc_write,
144962306a36Sopenharmony_ci};
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_cistatic int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	via_odev_to_seq(m, supported_odev_map[
145662306a36Sopenharmony_ci		viaparinfo->shared->chip_info.gfx_chip_name]);
145762306a36Sopenharmony_ci	return 0;
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	char buf[64], *ptr = buf;
146362306a36Sopenharmony_ci	u32 devices;
146462306a36Sopenharmony_ci	bool add, sub;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (count < 1 || count > 63)
146762306a36Sopenharmony_ci		return -EINVAL;
146862306a36Sopenharmony_ci	if (copy_from_user(&buf[0], buffer, count))
146962306a36Sopenharmony_ci		return -EFAULT;
147062306a36Sopenharmony_ci	buf[count] = '\0';
147162306a36Sopenharmony_ci	add = buf[0] == '+';
147262306a36Sopenharmony_ci	sub = buf[0] == '-';
147362306a36Sopenharmony_ci	if (add || sub)
147462306a36Sopenharmony_ci		ptr++;
147562306a36Sopenharmony_ci	devices = via_parse_odev(ptr, &ptr);
147662306a36Sopenharmony_ci	if (*ptr == '\n')
147762306a36Sopenharmony_ci		ptr++;
147862306a36Sopenharmony_ci	if (*ptr != 0)
147962306a36Sopenharmony_ci		return -EINVAL;
148062306a36Sopenharmony_ci	if (add)
148162306a36Sopenharmony_ci		*odev |= devices;
148262306a36Sopenharmony_ci	else if (sub)
148362306a36Sopenharmony_ci		*odev &= ~devices;
148462306a36Sopenharmony_ci	else
148562306a36Sopenharmony_ci		*odev = devices;
148662306a36Sopenharmony_ci	return count;
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cistatic int viafb_iga1_odev_proc_show(struct seq_file *m, void *v)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	via_odev_to_seq(m, viaparinfo->shared->iga1_devices);
149262306a36Sopenharmony_ci	return 0;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic int viafb_iga1_odev_proc_open(struct inode *inode, struct file *file)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	return single_open(file, viafb_iga1_odev_proc_show, NULL);
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_cistatic ssize_t viafb_iga1_odev_proc_write(struct file *file,
150162306a36Sopenharmony_ci	const char __user *buffer, size_t count, loff_t *pos)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	u32 dev_on, dev_off, dev_old, dev_new;
150462306a36Sopenharmony_ci	ssize_t res;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	dev_old = dev_new = viaparinfo->shared->iga1_devices;
150762306a36Sopenharmony_ci	res = odev_update(buffer, count, &dev_new);
150862306a36Sopenharmony_ci	if (res != count)
150962306a36Sopenharmony_ci		return res;
151062306a36Sopenharmony_ci	dev_off = dev_old & ~dev_new;
151162306a36Sopenharmony_ci	dev_on = dev_new & ~dev_old;
151262306a36Sopenharmony_ci	viaparinfo->shared->iga1_devices = dev_new;
151362306a36Sopenharmony_ci	viaparinfo->shared->iga2_devices &= ~dev_new;
151462306a36Sopenharmony_ci	via_set_state(dev_off, VIA_STATE_OFF);
151562306a36Sopenharmony_ci	via_set_source(dev_new, IGA1);
151662306a36Sopenharmony_ci	via_set_state(dev_on, VIA_STATE_ON);
151762306a36Sopenharmony_ci	return res;
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_cistatic const struct proc_ops viafb_iga1_odev_proc_ops = {
152162306a36Sopenharmony_ci	.proc_open	= viafb_iga1_odev_proc_open,
152262306a36Sopenharmony_ci	.proc_read	= seq_read,
152362306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
152462306a36Sopenharmony_ci	.proc_release	= single_release,
152562306a36Sopenharmony_ci	.proc_write	= viafb_iga1_odev_proc_write,
152662306a36Sopenharmony_ci};
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_cistatic int viafb_iga2_odev_proc_show(struct seq_file *m, void *v)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	via_odev_to_seq(m, viaparinfo->shared->iga2_devices);
153162306a36Sopenharmony_ci	return 0;
153262306a36Sopenharmony_ci}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic int viafb_iga2_odev_proc_open(struct inode *inode, struct file *file)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	return single_open(file, viafb_iga2_odev_proc_show, NULL);
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cistatic ssize_t viafb_iga2_odev_proc_write(struct file *file,
154062306a36Sopenharmony_ci	const char __user *buffer, size_t count, loff_t *pos)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	u32 dev_on, dev_off, dev_old, dev_new;
154362306a36Sopenharmony_ci	ssize_t res;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	dev_old = dev_new = viaparinfo->shared->iga2_devices;
154662306a36Sopenharmony_ci	res = odev_update(buffer, count, &dev_new);
154762306a36Sopenharmony_ci	if (res != count)
154862306a36Sopenharmony_ci		return res;
154962306a36Sopenharmony_ci	dev_off = dev_old & ~dev_new;
155062306a36Sopenharmony_ci	dev_on = dev_new & ~dev_old;
155162306a36Sopenharmony_ci	viaparinfo->shared->iga2_devices = dev_new;
155262306a36Sopenharmony_ci	viaparinfo->shared->iga1_devices &= ~dev_new;
155362306a36Sopenharmony_ci	via_set_state(dev_off, VIA_STATE_OFF);
155462306a36Sopenharmony_ci	via_set_source(dev_new, IGA2);
155562306a36Sopenharmony_ci	via_set_state(dev_on, VIA_STATE_ON);
155662306a36Sopenharmony_ci	return res;
155762306a36Sopenharmony_ci}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_cistatic const struct proc_ops viafb_iga2_odev_proc_ops = {
156062306a36Sopenharmony_ci	.proc_open	= viafb_iga2_odev_proc_open,
156162306a36Sopenharmony_ci	.proc_read	= seq_read,
156262306a36Sopenharmony_ci	.proc_lseek	= seq_lseek,
156362306a36Sopenharmony_ci	.proc_release	= single_release,
156462306a36Sopenharmony_ci	.proc_write	= viafb_iga2_odev_proc_write,
156562306a36Sopenharmony_ci};
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci#define IS_VT1636(lvds_chip)	((lvds_chip).lvds_chip_name == VT1636_LVDS)
156862306a36Sopenharmony_cistatic void viafb_init_proc(struct viafb_shared *shared)
156962306a36Sopenharmony_ci{
157062306a36Sopenharmony_ci	struct proc_dir_entry *iga1_entry, *iga2_entry,
157162306a36Sopenharmony_ci		*viafb_entry = proc_mkdir("viafb", NULL);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	shared->proc_entry = viafb_entry;
157462306a36Sopenharmony_ci	if (viafb_entry) {
157562306a36Sopenharmony_ci#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
157662306a36Sopenharmony_ci		proc_create("dvp0", 0, viafb_entry, &viafb_dvp0_proc_ops);
157762306a36Sopenharmony_ci		proc_create("dvp1", 0, viafb_entry, &viafb_dvp1_proc_ops);
157862306a36Sopenharmony_ci		proc_create("dfph", 0, viafb_entry, &viafb_dfph_proc_ops);
157962306a36Sopenharmony_ci		proc_create("dfpl", 0, viafb_entry, &viafb_dfpl_proc_ops);
158062306a36Sopenharmony_ci		if (IS_VT1636(shared->chip_info.lvds_chip_info)
158162306a36Sopenharmony_ci			|| IS_VT1636(shared->chip_info.lvds_chip_info2))
158262306a36Sopenharmony_ci			proc_create("vt1636", 0, viafb_entry,
158362306a36Sopenharmony_ci				    &viafb_vt1636_proc_ops);
158462306a36Sopenharmony_ci#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci		proc_create_single("supported_output_devices", 0, viafb_entry,
158762306a36Sopenharmony_ci			viafb_sup_odev_proc_show);
158862306a36Sopenharmony_ci		iga1_entry = proc_mkdir("iga1", viafb_entry);
158962306a36Sopenharmony_ci		shared->iga1_proc_entry = iga1_entry;
159062306a36Sopenharmony_ci		proc_create("output_devices", 0, iga1_entry,
159162306a36Sopenharmony_ci			    &viafb_iga1_odev_proc_ops);
159262306a36Sopenharmony_ci		iga2_entry = proc_mkdir("iga2", viafb_entry);
159362306a36Sopenharmony_ci		shared->iga2_proc_entry = iga2_entry;
159462306a36Sopenharmony_ci		proc_create("output_devices", 0, iga2_entry,
159562306a36Sopenharmony_ci			    &viafb_iga2_odev_proc_ops);
159662306a36Sopenharmony_ci	}
159762306a36Sopenharmony_ci}
159862306a36Sopenharmony_cistatic void viafb_remove_proc(struct viafb_shared *shared)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	struct proc_dir_entry *viafb_entry = shared->proc_entry;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	if (!viafb_entry)
160362306a36Sopenharmony_ci		return;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	remove_proc_entry("output_devices", shared->iga2_proc_entry);
160662306a36Sopenharmony_ci	remove_proc_entry("iga2", viafb_entry);
160762306a36Sopenharmony_ci	remove_proc_entry("output_devices", shared->iga1_proc_entry);
160862306a36Sopenharmony_ci	remove_proc_entry("iga1", viafb_entry);
160962306a36Sopenharmony_ci	remove_proc_entry("supported_output_devices", viafb_entry);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
161262306a36Sopenharmony_ci	remove_proc_entry("dvp0", viafb_entry);/* parent dir */
161362306a36Sopenharmony_ci	remove_proc_entry("dvp1", viafb_entry);
161462306a36Sopenharmony_ci	remove_proc_entry("dfph", viafb_entry);
161562306a36Sopenharmony_ci	remove_proc_entry("dfpl", viafb_entry);
161662306a36Sopenharmony_ci	if (IS_VT1636(shared->chip_info.lvds_chip_info)
161762306a36Sopenharmony_ci		|| IS_VT1636(shared->chip_info.lvds_chip_info2))
161862306a36Sopenharmony_ci		remove_proc_entry("vt1636", viafb_entry);
161962306a36Sopenharmony_ci#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	remove_proc_entry("viafb", NULL);
162262306a36Sopenharmony_ci}
162362306a36Sopenharmony_ci#undef IS_VT1636
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_cistatic int parse_mode(const char *str, u32 devices, u32 *xres, u32 *yres)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci	const struct fb_videomode *mode = NULL;
162862306a36Sopenharmony_ci	char *ptr;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	if (!str) {
163162306a36Sopenharmony_ci		if (devices == VIA_CRT)
163262306a36Sopenharmony_ci			mode = via_aux_get_preferred_mode(
163362306a36Sopenharmony_ci				viaparinfo->shared->i2c_26);
163462306a36Sopenharmony_ci		else if (devices == VIA_DVP1)
163562306a36Sopenharmony_ci			mode = via_aux_get_preferred_mode(
163662306a36Sopenharmony_ci				viaparinfo->shared->i2c_31);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci		if (mode) {
163962306a36Sopenharmony_ci			*xres = mode->xres;
164062306a36Sopenharmony_ci			*yres = mode->yres;
164162306a36Sopenharmony_ci		} else if (machine_is_olpc()) {
164262306a36Sopenharmony_ci			*xres = 1200;
164362306a36Sopenharmony_ci			*yres = 900;
164462306a36Sopenharmony_ci		} else {
164562306a36Sopenharmony_ci			*xres = 640;
164662306a36Sopenharmony_ci			*yres = 480;
164762306a36Sopenharmony_ci		}
164862306a36Sopenharmony_ci		return 0;
164962306a36Sopenharmony_ci	}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	*xres = simple_strtoul(str, &ptr, 10);
165262306a36Sopenharmony_ci	if (ptr[0] != 'x')
165362306a36Sopenharmony_ci		return -EINVAL;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	*yres = simple_strtoul(&ptr[1], &ptr, 10);
165662306a36Sopenharmony_ci	if (ptr[0])
165762306a36Sopenharmony_ci		return -EINVAL;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return 0;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci#ifdef CONFIG_PM
166462306a36Sopenharmony_cistatic int viafb_suspend(void *unused)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	console_lock();
166762306a36Sopenharmony_ci	fb_set_suspend(viafbinfo, 1);
166862306a36Sopenharmony_ci	viafb_sync(viafbinfo);
166962306a36Sopenharmony_ci	console_unlock();
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	return 0;
167262306a36Sopenharmony_ci}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_cistatic int viafb_resume(void *unused)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	console_lock();
167762306a36Sopenharmony_ci	if (viaparinfo->shared->vdev->engine_mmio)
167862306a36Sopenharmony_ci		viafb_reset_engine(viaparinfo);
167962306a36Sopenharmony_ci	viafb_set_par(viafbinfo);
168062306a36Sopenharmony_ci	if (viafb_dual_fb)
168162306a36Sopenharmony_ci		viafb_set_par(viafbinfo1);
168262306a36Sopenharmony_ci	fb_set_suspend(viafbinfo, 0);
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	console_unlock();
168562306a36Sopenharmony_ci	return 0;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_cistatic struct viafb_pm_hooks viafb_fb_pm_hooks = {
168962306a36Sopenharmony_ci	.suspend = viafb_suspend,
169062306a36Sopenharmony_ci	.resume = viafb_resume
169162306a36Sopenharmony_ci};
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci#endif
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_cistatic void i2c_bus_probe(struct viafb_shared *shared)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	/* should be always CRT */
169862306a36Sopenharmony_ci	printk(KERN_INFO "viafb: Probing I2C bus 0x26\n");
169962306a36Sopenharmony_ci	shared->i2c_26 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_26));
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	/* seems to be usually DVP1 */
170262306a36Sopenharmony_ci	printk(KERN_INFO "viafb: Probing I2C bus 0x31\n");
170362306a36Sopenharmony_ci	shared->i2c_31 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_31));
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	/* FIXME: what is this? */
170662306a36Sopenharmony_ci	if (!machine_is_olpc()) {
170762306a36Sopenharmony_ci		printk(KERN_INFO "viafb: Probing I2C bus 0x2C\n");
170862306a36Sopenharmony_ci		shared->i2c_2C = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_2C));
170962306a36Sopenharmony_ci	}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	printk(KERN_INFO "viafb: Finished I2C bus probing");
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic void i2c_bus_free(struct viafb_shared *shared)
171562306a36Sopenharmony_ci{
171662306a36Sopenharmony_ci	via_aux_free(shared->i2c_26);
171762306a36Sopenharmony_ci	via_aux_free(shared->i2c_31);
171862306a36Sopenharmony_ci	via_aux_free(shared->i2c_2C);
171962306a36Sopenharmony_ci}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ciint via_fb_pci_probe(struct viafb_dev *vdev)
172262306a36Sopenharmony_ci{
172362306a36Sopenharmony_ci	u32 default_xres, default_yres;
172462306a36Sopenharmony_ci	struct fb_var_screeninfo default_var;
172562306a36Sopenharmony_ci	int rc;
172662306a36Sopenharmony_ci	u32 viafb_par_length;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
172962306a36Sopenharmony_ci	memset(&default_var, 0, sizeof(default_var));
173062306a36Sopenharmony_ci	viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	/* Allocate fb_info and ***_par here, also including some other needed
173362306a36Sopenharmony_ci	 * variables
173462306a36Sopenharmony_ci	*/
173562306a36Sopenharmony_ci	viafbinfo = framebuffer_alloc(viafb_par_length +
173662306a36Sopenharmony_ci		ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8),
173762306a36Sopenharmony_ci		&vdev->pdev->dev);
173862306a36Sopenharmony_ci	if (!viafbinfo)
173962306a36Sopenharmony_ci		return -ENOMEM;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	viaparinfo = (struct viafb_par *)viafbinfo->par;
174262306a36Sopenharmony_ci	viaparinfo->shared = viafbinfo->par + viafb_par_length;
174362306a36Sopenharmony_ci	viaparinfo->shared->vdev = vdev;
174462306a36Sopenharmony_ci	viaparinfo->vram_addr = 0;
174562306a36Sopenharmony_ci	viaparinfo->tmds_setting_info = &viaparinfo->shared->tmds_setting_info;
174662306a36Sopenharmony_ci	viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info;
174762306a36Sopenharmony_ci	viaparinfo->lvds_setting_info2 =
174862306a36Sopenharmony_ci		&viaparinfo->shared->lvds_setting_info2;
174962306a36Sopenharmony_ci	viaparinfo->chip_info = &viaparinfo->shared->chip_info;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	i2c_bus_probe(viaparinfo->shared);
175262306a36Sopenharmony_ci	if (viafb_dual_fb)
175362306a36Sopenharmony_ci		viafb_SAMM_ON = 1;
175462306a36Sopenharmony_ci	parse_lcd_port();
175562306a36Sopenharmony_ci	parse_dvi_port();
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	viafb_init_chip_info(vdev->chip_type);
175862306a36Sopenharmony_ci	/*
175962306a36Sopenharmony_ci	 * The framebuffer will have been successfully mapped by
176062306a36Sopenharmony_ci	 * the core (or we'd not be here), but we still need to
176162306a36Sopenharmony_ci	 * set up our own accounting.
176262306a36Sopenharmony_ci	 */
176362306a36Sopenharmony_ci	viaparinfo->fbmem = vdev->fbmem_start;
176462306a36Sopenharmony_ci	viaparinfo->memsize = vdev->fbmem_len;
176562306a36Sopenharmony_ci	viaparinfo->fbmem_free = viaparinfo->memsize;
176662306a36Sopenharmony_ci	viaparinfo->fbmem_used = 0;
176762306a36Sopenharmony_ci	viafbinfo->screen_base = vdev->fbmem;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	viafbinfo->fix.mmio_start = vdev->engine_start;
177062306a36Sopenharmony_ci	viafbinfo->fix.mmio_len = vdev->engine_len;
177162306a36Sopenharmony_ci	viafbinfo->node = 0;
177262306a36Sopenharmony_ci	viafbinfo->fbops = &viafb_ops;
177362306a36Sopenharmony_ci	viafbinfo->flags = FBINFO_HWACCEL_YPAN;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	viafbinfo->pseudo_palette = pseudo_pal;
177662306a36Sopenharmony_ci	if (viafb_accel && !viafb_setup_engine(viafbinfo)) {
177762306a36Sopenharmony_ci		viafbinfo->flags |= FBINFO_HWACCEL_COPYAREA |
177862306a36Sopenharmony_ci			FBINFO_HWACCEL_FILLRECT |  FBINFO_HWACCEL_IMAGEBLIT;
177962306a36Sopenharmony_ci		default_var.accel_flags = FB_ACCELF_TEXT;
178062306a36Sopenharmony_ci	} else {
178162306a36Sopenharmony_ci		viafbinfo->flags |= FBINFO_HWACCEL_DISABLED;
178262306a36Sopenharmony_ci		default_var.accel_flags = 0;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	if (viafb_second_size && (viafb_second_size < 8)) {
178662306a36Sopenharmony_ci		viafb_second_offset = viaparinfo->fbmem_free -
178762306a36Sopenharmony_ci			viafb_second_size * 1024 * 1024;
178862306a36Sopenharmony_ci	} else {
178962306a36Sopenharmony_ci		viafb_second_size = 8;
179062306a36Sopenharmony_ci		viafb_second_offset = viaparinfo->fbmem_free -
179162306a36Sopenharmony_ci			viafb_second_size * 1024 * 1024;
179262306a36Sopenharmony_ci	}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	parse_mode(viafb_mode, viaparinfo->shared->iga1_devices,
179562306a36Sopenharmony_ci		&default_xres, &default_yres);
179662306a36Sopenharmony_ci	if (viafb_SAMM_ON == 1)
179762306a36Sopenharmony_ci		parse_mode(viafb_mode1, viaparinfo->shared->iga2_devices,
179862306a36Sopenharmony_ci			&viafb_second_xres, &viafb_second_yres);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	default_var.xres = default_xres;
180162306a36Sopenharmony_ci	default_var.yres = default_yres;
180262306a36Sopenharmony_ci	default_var.xres_virtual = default_xres;
180362306a36Sopenharmony_ci	default_var.yres_virtual = default_yres;
180462306a36Sopenharmony_ci	default_var.bits_per_pixel = viafb_bpp;
180562306a36Sopenharmony_ci	viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(
180662306a36Sopenharmony_ci		default_var.xres, default_var.yres, viafb_refresh));
180762306a36Sopenharmony_ci	viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
180862306a36Sopenharmony_ci	viafbinfo->var = default_var;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	if (viafb_dual_fb) {
181162306a36Sopenharmony_ci		viafbinfo1 = framebuffer_alloc(viafb_par_length,
181262306a36Sopenharmony_ci				&vdev->pdev->dev);
181362306a36Sopenharmony_ci		if (!viafbinfo1) {
181462306a36Sopenharmony_ci			rc = -ENOMEM;
181562306a36Sopenharmony_ci			goto out_fb_release;
181662306a36Sopenharmony_ci		}
181762306a36Sopenharmony_ci		viaparinfo1 = viafbinfo1->par;
181862306a36Sopenharmony_ci		memcpy(viaparinfo1, viaparinfo, viafb_par_length);
181962306a36Sopenharmony_ci		viaparinfo1->vram_addr = viafb_second_offset;
182062306a36Sopenharmony_ci		viaparinfo1->memsize = viaparinfo->memsize -
182162306a36Sopenharmony_ci			viafb_second_offset;
182262306a36Sopenharmony_ci		viaparinfo->memsize = viafb_second_offset;
182362306a36Sopenharmony_ci		viaparinfo1->fbmem = viaparinfo->fbmem + viafb_second_offset;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci		viaparinfo1->fbmem_used = viaparinfo->fbmem_used;
182662306a36Sopenharmony_ci		viaparinfo1->fbmem_free = viaparinfo1->memsize -
182762306a36Sopenharmony_ci			viaparinfo1->fbmem_used;
182862306a36Sopenharmony_ci		viaparinfo->fbmem_free = viaparinfo->memsize;
182962306a36Sopenharmony_ci		viaparinfo->fbmem_used = 0;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci		viaparinfo->iga_path = IGA1;
183262306a36Sopenharmony_ci		viaparinfo1->iga_path = IGA2;
183362306a36Sopenharmony_ci		memcpy(viafbinfo1, viafbinfo, sizeof(struct fb_info));
183462306a36Sopenharmony_ci		viafbinfo1->par = viaparinfo1;
183562306a36Sopenharmony_ci		viafbinfo1->screen_base = viafbinfo->screen_base +
183662306a36Sopenharmony_ci			viafb_second_offset;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci		default_var.xres = viafb_second_xres;
183962306a36Sopenharmony_ci		default_var.yres = viafb_second_yres;
184062306a36Sopenharmony_ci		default_var.xres_virtual = viafb_second_xres;
184162306a36Sopenharmony_ci		default_var.yres_virtual = viafb_second_yres;
184262306a36Sopenharmony_ci		default_var.bits_per_pixel = viafb_bpp1;
184362306a36Sopenharmony_ci		viafb_fill_var_timing_info(&default_var, viafb_get_best_mode(
184462306a36Sopenharmony_ci			default_var.xres, default_var.yres, viafb_refresh1));
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci		viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1);
184762306a36Sopenharmony_ci		viafb_check_var(&default_var, viafbinfo1);
184862306a36Sopenharmony_ci		viafbinfo1->var = default_var;
184962306a36Sopenharmony_ci		viafb_update_fix(viafbinfo1);
185062306a36Sopenharmony_ci		viaparinfo1->depth = fb_get_color_depth(&viafbinfo1->var,
185162306a36Sopenharmony_ci			&viafbinfo1->fix);
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	viafb_check_var(&viafbinfo->var, viafbinfo);
185562306a36Sopenharmony_ci	viafb_update_fix(viafbinfo);
185662306a36Sopenharmony_ci	viaparinfo->depth = fb_get_color_depth(&viafbinfo->var,
185762306a36Sopenharmony_ci		&viafbinfo->fix);
185862306a36Sopenharmony_ci	default_var.activate = FB_ACTIVATE_NOW;
185962306a36Sopenharmony_ci	rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
186062306a36Sopenharmony_ci	if (rc)
186162306a36Sopenharmony_ci		goto out_fb1_release;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
186462306a36Sopenharmony_ci	    && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) {
186562306a36Sopenharmony_ci		rc = register_framebuffer(viafbinfo1);
186662306a36Sopenharmony_ci		if (rc)
186762306a36Sopenharmony_ci			goto out_dealloc_cmap;
186862306a36Sopenharmony_ci	}
186962306a36Sopenharmony_ci	rc = register_framebuffer(viafbinfo);
187062306a36Sopenharmony_ci	if (rc)
187162306a36Sopenharmony_ci		goto out_fb1_unreg_lcd_cle266;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device)
187462306a36Sopenharmony_ci			|| (viaparinfo->chip_info->gfx_chip_name !=
187562306a36Sopenharmony_ci			UNICHROME_CLE266))) {
187662306a36Sopenharmony_ci		rc = register_framebuffer(viafbinfo1);
187762306a36Sopenharmony_ci		if (rc)
187862306a36Sopenharmony_ci			goto out_fb_unreg;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n",
188162306a36Sopenharmony_ci		  viafbinfo->node, viafbinfo->fix.id, default_var.xres,
188262306a36Sopenharmony_ci		  default_var.yres, default_var.bits_per_pixel);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	viafb_init_proc(viaparinfo->shared);
188562306a36Sopenharmony_ci	viafb_init_dac(IGA2);
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci#ifdef CONFIG_PM
188862306a36Sopenharmony_ci	viafb_pm_register(&viafb_fb_pm_hooks);
188962306a36Sopenharmony_ci#endif
189062306a36Sopenharmony_ci	return 0;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ciout_fb_unreg:
189362306a36Sopenharmony_ci	unregister_framebuffer(viafbinfo);
189462306a36Sopenharmony_ciout_fb1_unreg_lcd_cle266:
189562306a36Sopenharmony_ci	if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
189662306a36Sopenharmony_ci	    && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266))
189762306a36Sopenharmony_ci		unregister_framebuffer(viafbinfo1);
189862306a36Sopenharmony_ciout_dealloc_cmap:
189962306a36Sopenharmony_ci	fb_dealloc_cmap(&viafbinfo->cmap);
190062306a36Sopenharmony_ciout_fb1_release:
190162306a36Sopenharmony_ci	framebuffer_release(viafbinfo1);
190262306a36Sopenharmony_ciout_fb_release:
190362306a36Sopenharmony_ci	i2c_bus_free(viaparinfo->shared);
190462306a36Sopenharmony_ci	framebuffer_release(viafbinfo);
190562306a36Sopenharmony_ci	return rc;
190662306a36Sopenharmony_ci}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_civoid via_fb_pci_remove(struct pci_dev *pdev)
190962306a36Sopenharmony_ci{
191062306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "via_pci_remove!\n");
191162306a36Sopenharmony_ci	fb_dealloc_cmap(&viafbinfo->cmap);
191262306a36Sopenharmony_ci	unregister_framebuffer(viafbinfo);
191362306a36Sopenharmony_ci	if (viafb_dual_fb)
191462306a36Sopenharmony_ci		unregister_framebuffer(viafbinfo1);
191562306a36Sopenharmony_ci	viafb_remove_proc(viaparinfo->shared);
191662306a36Sopenharmony_ci	i2c_bus_free(viaparinfo->shared);
191762306a36Sopenharmony_ci	framebuffer_release(viafbinfo);
191862306a36Sopenharmony_ci	if (viafb_dual_fb)
191962306a36Sopenharmony_ci		framebuffer_release(viafbinfo1);
192062306a36Sopenharmony_ci}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci#ifndef MODULE
192362306a36Sopenharmony_cistatic int __init viafb_setup(void)
192462306a36Sopenharmony_ci{
192562306a36Sopenharmony_ci	char *this_opt;
192662306a36Sopenharmony_ci	char *options;
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_setup!\n");
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	if (fb_get_options("viafb", &options))
193162306a36Sopenharmony_ci		return -ENODEV;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	if (!options || !*options)
193462306a36Sopenharmony_ci		return 0;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
193762306a36Sopenharmony_ci		if (!*this_opt)
193862306a36Sopenharmony_ci			continue;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci		if (!strncmp(this_opt, "viafb_mode1=", 12)) {
194162306a36Sopenharmony_ci			viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL);
194262306a36Sopenharmony_ci			if (!viafb_mode1)
194362306a36Sopenharmony_ci				return -ENOMEM;
194462306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_mode=", 11)) {
194562306a36Sopenharmony_ci			viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL);
194662306a36Sopenharmony_ci			if (!viafb_mode)
194762306a36Sopenharmony_ci				return -ENOMEM;
194862306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_bpp1=", 11)) {
194962306a36Sopenharmony_ci			if (kstrtouint(this_opt + 11, 0, &viafb_bpp1) < 0)
195062306a36Sopenharmony_ci				return -EINVAL;
195162306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_bpp=", 10)) {
195262306a36Sopenharmony_ci			if (kstrtouint(this_opt + 10, 0, &viafb_bpp) < 0)
195362306a36Sopenharmony_ci				return -EINVAL;
195462306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_refresh1=", 15)) {
195562306a36Sopenharmony_ci			if (kstrtoint(this_opt + 15, 0, &viafb_refresh1) < 0)
195662306a36Sopenharmony_ci				return -EINVAL;
195762306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_refresh=", 14)) {
195862306a36Sopenharmony_ci			if (kstrtoint(this_opt + 14, 0, &viafb_refresh) < 0)
195962306a36Sopenharmony_ci				return -EINVAL;
196062306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21)) {
196162306a36Sopenharmony_ci			if (kstrtoint(this_opt + 21, 0,
196262306a36Sopenharmony_ci				      &viafb_lcd_dsp_method) < 0)
196362306a36Sopenharmony_ci				return -EINVAL;
196462306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19)) {
196562306a36Sopenharmony_ci			if (kstrtoint(this_opt + 19, 0,
196662306a36Sopenharmony_ci				      &viafb_lcd_panel_id) < 0)
196762306a36Sopenharmony_ci				return -EINVAL;
196862306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_accel=", 12)) {
196962306a36Sopenharmony_ci			if (kstrtoint(this_opt + 12, 0, &viafb_accel) < 0)
197062306a36Sopenharmony_ci				return -EINVAL;
197162306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14)) {
197262306a36Sopenharmony_ci			if (kstrtoint(this_opt + 14, 0, &viafb_SAMM_ON) < 0)
197362306a36Sopenharmony_ci				return -EINVAL;
197462306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_active_dev=", 17)) {
197562306a36Sopenharmony_ci			viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL);
197662306a36Sopenharmony_ci			if (!viafb_active_dev)
197762306a36Sopenharmony_ci				return -ENOMEM;
197862306a36Sopenharmony_ci		} else if (!strncmp(this_opt,
197962306a36Sopenharmony_ci			"viafb_display_hardware_layout=", 30)) {
198062306a36Sopenharmony_ci			if (kstrtoint(this_opt + 30, 0,
198162306a36Sopenharmony_ci				      &viafb_display_hardware_layout) < 0)
198262306a36Sopenharmony_ci				return -EINVAL;
198362306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_second_size=", 18)) {
198462306a36Sopenharmony_ci			if (kstrtoint(this_opt + 18, 0, &viafb_second_size) < 0)
198562306a36Sopenharmony_ci				return -EINVAL;
198662306a36Sopenharmony_ci		} else if (!strncmp(this_opt,
198762306a36Sopenharmony_ci			"viafb_platform_epia_dvi=", 24)) {
198862306a36Sopenharmony_ci			if (kstrtoint(this_opt + 24, 0,
198962306a36Sopenharmony_ci				      &viafb_platform_epia_dvi) < 0)
199062306a36Sopenharmony_ci				return -EINVAL;
199162306a36Sopenharmony_ci		} else if (!strncmp(this_opt,
199262306a36Sopenharmony_ci			"viafb_device_lcd_dualedge=", 26)) {
199362306a36Sopenharmony_ci			if (kstrtoint(this_opt + 26, 0,
199462306a36Sopenharmony_ci				      &viafb_device_lcd_dualedge) < 0)
199562306a36Sopenharmony_ci				return -EINVAL;
199662306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_bus_width=", 16)) {
199762306a36Sopenharmony_ci			if (kstrtoint(this_opt + 16, 0, &viafb_bus_width) < 0)
199862306a36Sopenharmony_ci				return -EINVAL;
199962306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_lcd_mode=", 15)) {
200062306a36Sopenharmony_ci			if (kstrtoint(this_opt + 15, 0, &viafb_lcd_mode) < 0)
200162306a36Sopenharmony_ci				return -EINVAL;
200262306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_lcd_port=", 15)) {
200362306a36Sopenharmony_ci			viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL);
200462306a36Sopenharmony_ci			if (!viafb_lcd_port)
200562306a36Sopenharmony_ci				return -ENOMEM;
200662306a36Sopenharmony_ci		} else if (!strncmp(this_opt, "viafb_dvi_port=", 15)) {
200762306a36Sopenharmony_ci			viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL);
200862306a36Sopenharmony_ci			if (!viafb_dvi_port)
200962306a36Sopenharmony_ci				return -ENOMEM;
201062306a36Sopenharmony_ci		}
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci	return 0;
201362306a36Sopenharmony_ci}
201462306a36Sopenharmony_ci#endif
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci/*
201762306a36Sopenharmony_ci * These are called out of via-core for now.
201862306a36Sopenharmony_ci */
201962306a36Sopenharmony_ciint __init viafb_init(void)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	u32 dummy_x, dummy_y;
202262306a36Sopenharmony_ci	int r = 0;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	if (machine_is_olpc())
202562306a36Sopenharmony_ci		/* Apply XO-1.5-specific configuration. */
202662306a36Sopenharmony_ci		viafb_lcd_panel_id = 23;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci#ifndef MODULE
202962306a36Sopenharmony_ci	r = viafb_setup();
203062306a36Sopenharmony_ci	if (r < 0)
203162306a36Sopenharmony_ci		return r;
203262306a36Sopenharmony_ci#endif
203362306a36Sopenharmony_ci	if (parse_mode(viafb_mode, 0, &dummy_x, &dummy_y)
203462306a36Sopenharmony_ci		|| !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh)
203562306a36Sopenharmony_ci		|| parse_mode(viafb_mode1, 0, &dummy_x, &dummy_y)
203662306a36Sopenharmony_ci		|| !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1)
203762306a36Sopenharmony_ci		|| viafb_bpp < 0 || viafb_bpp > 32
203862306a36Sopenharmony_ci		|| viafb_bpp1 < 0 || viafb_bpp1 > 32
203962306a36Sopenharmony_ci		|| parse_active_dev())
204062306a36Sopenharmony_ci		return -EINVAL;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	printk(KERN_INFO
204362306a36Sopenharmony_ci       "VIA Graphics Integration Chipset framebuffer %d.%d initializing\n",
204462306a36Sopenharmony_ci	       VERSION_MAJOR, VERSION_MINOR);
204562306a36Sopenharmony_ci	return r;
204662306a36Sopenharmony_ci}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_civoid __exit viafb_exit(void)
204962306a36Sopenharmony_ci{
205062306a36Sopenharmony_ci	DEBUG_MSG(KERN_INFO "viafb_exit!\n");
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_cistatic struct fb_ops viafb_ops = {
205462306a36Sopenharmony_ci	.owner = THIS_MODULE,
205562306a36Sopenharmony_ci	.fb_open = viafb_open,
205662306a36Sopenharmony_ci	.fb_release = viafb_release,
205762306a36Sopenharmony_ci	.fb_check_var = viafb_check_var,
205862306a36Sopenharmony_ci	.fb_set_par = viafb_set_par,
205962306a36Sopenharmony_ci	.fb_setcolreg = viafb_setcolreg,
206062306a36Sopenharmony_ci	.fb_pan_display = viafb_pan_display,
206162306a36Sopenharmony_ci	.fb_blank = viafb_blank,
206262306a36Sopenharmony_ci	.fb_fillrect = viafb_fillrect,
206362306a36Sopenharmony_ci	.fb_copyarea = viafb_copyarea,
206462306a36Sopenharmony_ci	.fb_imageblit = viafb_imageblit,
206562306a36Sopenharmony_ci	.fb_cursor = viafb_cursor,
206662306a36Sopenharmony_ci	.fb_ioctl = viafb_ioctl,
206762306a36Sopenharmony_ci	.fb_sync = viafb_sync,
206862306a36Sopenharmony_ci};
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci#ifdef MODULE
207262306a36Sopenharmony_cimodule_param(viafb_mode, charp, S_IRUSR);
207362306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)");
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_cimodule_param(viafb_mode1, charp, S_IRUSR);
207662306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_mode1, "Set resolution (default=640x480)");
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cimodule_param(viafb_bpp, int, S_IRUSR);
207962306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_bpp, "Set color depth (default=32bpp)");
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_cimodule_param(viafb_bpp1, int, S_IRUSR);
208262306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_bpp1, "Set color depth (default=32bpp)");
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cimodule_param(viafb_refresh, int, S_IRUSR);
208562306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_refresh,
208662306a36Sopenharmony_ci	"Set CRT viafb_refresh rate (default = 60)");
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_cimodule_param(viafb_refresh1, int, S_IRUSR);
208962306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_refresh1,
209062306a36Sopenharmony_ci	"Set CRT refresh rate (default = 60)");
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_cimodule_param(viafb_lcd_panel_id, int, S_IRUSR);
209362306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_lcd_panel_id,
209462306a36Sopenharmony_ci	"Set Flat Panel type(Default=1024x768)");
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_cimodule_param(viafb_lcd_dsp_method, int, S_IRUSR);
209762306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_lcd_dsp_method,
209862306a36Sopenharmony_ci	"Set Flat Panel display scaling method.(Default=Expansion)");
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_cimodule_param(viafb_SAMM_ON, int, S_IRUSR);
210162306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_SAMM_ON,
210262306a36Sopenharmony_ci	"Turn on/off flag of SAMM(Default=OFF)");
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_cimodule_param(viafb_accel, int, S_IRUSR);
210562306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_accel,
210662306a36Sopenharmony_ci	"Set 2D Hardware Acceleration: 0 = OFF, 1 = ON (default)");
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_cimodule_param(viafb_active_dev, charp, S_IRUSR);
210962306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_active_dev, "Specify active devices.");
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_cimodule_param(viafb_display_hardware_layout, int, S_IRUSR);
211262306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_display_hardware_layout,
211362306a36Sopenharmony_ci	"Display Hardware Layout (LCD Only, DVI Only...,etc)");
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_cimodule_param(viafb_second_size, int, S_IRUSR);
211662306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_second_size,
211762306a36Sopenharmony_ci	"Set secondary device memory size");
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_cimodule_param(viafb_dual_fb, int, S_IRUSR);
212062306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_dual_fb,
212162306a36Sopenharmony_ci	"Turn on/off flag of dual framebuffer devices.(Default = OFF)");
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_cimodule_param(viafb_platform_epia_dvi, int, S_IRUSR);
212462306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_platform_epia_dvi,
212562306a36Sopenharmony_ci	"Turn on/off flag of DVI devices on EPIA board.(Default = OFF)");
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cimodule_param(viafb_device_lcd_dualedge, int, S_IRUSR);
212862306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_device_lcd_dualedge,
212962306a36Sopenharmony_ci	"Turn on/off flag of dual edge panel.(Default = OFF)");
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cimodule_param(viafb_bus_width, int, S_IRUSR);
213262306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_bus_width,
213362306a36Sopenharmony_ci	"Set bus width of panel.(Default = 12)");
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_cimodule_param(viafb_lcd_mode, int, S_IRUSR);
213662306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_lcd_mode,
213762306a36Sopenharmony_ci	"Set Flat Panel mode(Default=OPENLDI)");
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_cimodule_param(viafb_lcd_port, charp, S_IRUSR);
214062306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_lcd_port, "Specify LCD output port.");
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_cimodule_param(viafb_dvi_port, charp, S_IRUSR);
214362306a36Sopenharmony_ciMODULE_PARM_DESC(viafb_dvi_port, "Specify DVI output port.");
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
214662306a36Sopenharmony_ci#endif
2147