18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/drivers/video/w100fb.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Frame Buffer Device for ATI Imageon w100 (Wallaby)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2002, ATI Corp.
88c2ecf20Sopenharmony_ci * Copyright (C) 2004-2006 Richard Purdie
98c2ecf20Sopenharmony_ci * Copyright (c) 2005 Ian Molton
108c2ecf20Sopenharmony_ci * Copyright (c) 2006 Alberto Mardegan
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Generic platform support by Ian Molton <spyro@f2s.com>
158c2ecf20Sopenharmony_ci * and Richard Purdie <rpurdie@rpsys.net>
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * w32xx support by Ian Molton
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * Hardware acceleration support by Alberto Mardegan
208c2ecf20Sopenharmony_ci * <mardy@users.sourceforge.net>
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <linux/delay.h>
248c2ecf20Sopenharmony_ci#include <linux/fb.h>
258c2ecf20Sopenharmony_ci#include <linux/init.h>
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/mm.h>
288c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
298c2ecf20Sopenharmony_ci#include <linux/slab.h>
308c2ecf20Sopenharmony_ci#include <linux/string.h>
318c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
328c2ecf20Sopenharmony_ci#include <linux/module.h>
338c2ecf20Sopenharmony_ci#include <asm/io.h>
348c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
358c2ecf20Sopenharmony_ci#include <video/w100fb.h>
368c2ecf20Sopenharmony_ci#include "w100fb.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * Prototypes
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_cistatic void w100_suspend(u32 mode);
428c2ecf20Sopenharmony_cistatic void w100_vsync(void);
438c2ecf20Sopenharmony_cistatic void w100_hw_init(struct w100fb_par*);
448c2ecf20Sopenharmony_cistatic void w100_pwm_setup(struct w100fb_par*);
458c2ecf20Sopenharmony_cistatic void w100_init_clocks(struct w100fb_par*);
468c2ecf20Sopenharmony_cistatic void w100_setup_memory(struct w100fb_par*);
478c2ecf20Sopenharmony_cistatic void w100_init_lcd(struct w100fb_par*);
488c2ecf20Sopenharmony_cistatic void w100_set_dispregs(struct w100fb_par*);
498c2ecf20Sopenharmony_cistatic void w100_update_enable(void);
508c2ecf20Sopenharmony_cistatic void w100_update_disable(void);
518c2ecf20Sopenharmony_cistatic void calc_hsync(struct w100fb_par *par);
528c2ecf20Sopenharmony_cistatic void w100_init_graphic_engine(struct w100fb_par *par);
538c2ecf20Sopenharmony_cistruct w100_pll_info *w100_get_xtal_table(unsigned int freq);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Pseudo palette size */
568c2ecf20Sopenharmony_ci#define MAX_PALETTES      16
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define W100_SUSPEND_EXTMEM 0
598c2ecf20Sopenharmony_ci#define W100_SUSPEND_ALL    1
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define BITS_PER_PIXEL    16
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
648c2ecf20Sopenharmony_cistatic void __iomem *remapped_base;
658c2ecf20Sopenharmony_cistatic void __iomem *remapped_regs;
668c2ecf20Sopenharmony_cistatic void __iomem *remapped_fbuf;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define REMAPPED_FB_LEN   0x15ffff
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/* This is the offset in the w100's address space we map the current
718c2ecf20Sopenharmony_ci   framebuffer memory to. We use the position of external memory as
728c2ecf20Sopenharmony_ci   we can remap internal memory to there if external isn't present. */
738c2ecf20Sopenharmony_ci#define W100_FB_BASE MEM_EXT_BASE_VALUE
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/*
778c2ecf20Sopenharmony_ci * Sysfs functions
788c2ecf20Sopenharmony_ci */
798c2ecf20Sopenharmony_cistatic ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct fb_info *info = dev_get_drvdata(dev);
828c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n",par->flip);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	unsigned int flip;
908c2ecf20Sopenharmony_ci	struct fb_info *info = dev_get_drvdata(dev);
918c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	flip = simple_strtoul(buf, NULL, 10);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (flip > 0)
968c2ecf20Sopenharmony_ci		par->flip = 1;
978c2ecf20Sopenharmony_ci	else
988c2ecf20Sopenharmony_ci		par->flip = 0;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	w100_update_disable();
1018c2ecf20Sopenharmony_ci	w100_set_dispregs(par);
1028c2ecf20Sopenharmony_ci	w100_update_enable();
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	calc_hsync(par);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return count;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(flip);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	unsigned long regs, param;
1148c2ecf20Sopenharmony_ci	regs = simple_strtoul(buf, NULL, 16);
1158c2ecf20Sopenharmony_ci	param = readl(remapped_regs + regs);
1168c2ecf20Sopenharmony_ci	printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
1178c2ecf20Sopenharmony_ci	return count;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	unsigned long regs, param;
1258c2ecf20Sopenharmony_ci	sscanf(buf, "%lx %lx", &regs, &param);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (regs <= 0x2000) {
1288c2ecf20Sopenharmony_ci		printk("Write Register 0x%08lX: 0x%08lX\n", regs, param);
1298c2ecf20Sopenharmony_ci		writel(param, remapped_regs + regs);
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return count;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct fb_info *info = dev_get_drvdata(dev);
1418c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n",par->fastpll_mode);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct fb_info *info = dev_get_drvdata(dev);
1498c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (simple_strtoul(buf, NULL, 10) > 0) {
1528c2ecf20Sopenharmony_ci		par->fastpll_mode=1;
1538c2ecf20Sopenharmony_ci		printk("w100fb: Using fast system clock (if possible)\n");
1548c2ecf20Sopenharmony_ci	} else {
1558c2ecf20Sopenharmony_ci		par->fastpll_mode=0;
1568c2ecf20Sopenharmony_ci		printk("w100fb: Using normal system clock\n");
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	w100_init_clocks(par);
1608c2ecf20Sopenharmony_ci	calc_hsync(par);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	return count;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fastpllclk);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic struct attribute *w100fb_attrs[] = {
1688c2ecf20Sopenharmony_ci	&dev_attr_fastpllclk.attr,
1698c2ecf20Sopenharmony_ci	&dev_attr_reg_read.attr,
1708c2ecf20Sopenharmony_ci	&dev_attr_reg_write.attr,
1718c2ecf20Sopenharmony_ci	&dev_attr_flip.attr,
1728c2ecf20Sopenharmony_ci	NULL,
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(w100fb);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/*
1778c2ecf20Sopenharmony_ci * Some touchscreens need hsync information from the video driver to
1788c2ecf20Sopenharmony_ci * function correctly. We export it here.
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_ciunsigned long w100fb_get_hsynclen(struct device *dev)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct fb_info *info = dev_get_drvdata(dev);
1838c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/* If display is blanked/suspended, hsync isn't active */
1868c2ecf20Sopenharmony_ci	if (par->blanked)
1878c2ecf20Sopenharmony_ci		return 0;
1888c2ecf20Sopenharmony_ci	else
1898c2ecf20Sopenharmony_ci		return par->hsync_len;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(w100fb_get_hsynclen);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic void w100fb_clear_screen(struct w100fb_par *par)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/*
2008c2ecf20Sopenharmony_ci * Set a palette value from rgb components
2018c2ecf20Sopenharmony_ci */
2028c2ecf20Sopenharmony_cistatic int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
2038c2ecf20Sopenharmony_ci			     u_int trans, struct fb_info *info)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	unsigned int val;
2068c2ecf20Sopenharmony_ci	int ret = 1;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/*
2098c2ecf20Sopenharmony_ci	 * If greyscale is true, then we convert the RGB value
2108c2ecf20Sopenharmony_ci	 * to greyscale no matter what visual we are using.
2118c2ecf20Sopenharmony_ci	 */
2128c2ecf20Sopenharmony_ci	if (info->var.grayscale)
2138c2ecf20Sopenharmony_ci		red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/*
2168c2ecf20Sopenharmony_ci	 * 16-bit True Colour.  We encode the RGB value
2178c2ecf20Sopenharmony_ci	 * according to the RGB bitfield information.
2188c2ecf20Sopenharmony_ci	 */
2198c2ecf20Sopenharmony_ci	if (regno < MAX_PALETTES) {
2208c2ecf20Sopenharmony_ci		u32 *pal = info->pseudo_palette;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
2238c2ecf20Sopenharmony_ci		pal[regno] = val;
2248c2ecf20Sopenharmony_ci		ret = 0;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	return ret;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/*
2318c2ecf20Sopenharmony_ci * Blank the display based on value in blank_mode
2328c2ecf20Sopenharmony_ci */
2338c2ecf20Sopenharmony_cistatic int w100fb_blank(int blank_mode, struct fb_info *info)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct w100fb_par *par = info->par;
2368c2ecf20Sopenharmony_ci	struct w100_tg_info *tg = par->mach->tg;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	switch(blank_mode) {
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci 	case FB_BLANK_NORMAL:         /* Normal blanking */
2418c2ecf20Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:  /* VESA blank (vsync off) */
2428c2ecf20Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:  /* VESA blank (hsync off) */
2438c2ecf20Sopenharmony_ci 	case FB_BLANK_POWERDOWN:      /* Poweroff */
2448c2ecf20Sopenharmony_ci  		if (par->blanked == 0) {
2458c2ecf20Sopenharmony_ci			if(tg && tg->suspend)
2468c2ecf20Sopenharmony_ci				tg->suspend(par);
2478c2ecf20Sopenharmony_ci			par->blanked = 1;
2488c2ecf20Sopenharmony_ci  		}
2498c2ecf20Sopenharmony_ci  		break;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci 	case FB_BLANK_UNBLANK: /* Unblanking */
2528c2ecf20Sopenharmony_ci  		if (par->blanked != 0) {
2538c2ecf20Sopenharmony_ci			if(tg && tg->resume)
2548c2ecf20Sopenharmony_ci				tg->resume(par);
2558c2ecf20Sopenharmony_ci			par->blanked = 0;
2568c2ecf20Sopenharmony_ci  		}
2578c2ecf20Sopenharmony_ci  		break;
2588c2ecf20Sopenharmony_ci 	}
2598c2ecf20Sopenharmony_ci	return 0;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic void w100_fifo_wait(int entries)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	union rbbm_status_u status;
2668c2ecf20Sopenharmony_ci	int i;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	for (i = 0; i < 2000000; i++) {
2698c2ecf20Sopenharmony_ci		status.val = readl(remapped_regs + mmRBBM_STATUS);
2708c2ecf20Sopenharmony_ci		if (status.f.cmdfifo_avail >= entries)
2718c2ecf20Sopenharmony_ci			return;
2728c2ecf20Sopenharmony_ci		udelay(1);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci	printk(KERN_ERR "w100fb: FIFO Timeout!\n");
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic int w100fb_sync(struct fb_info *info)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	union rbbm_status_u status;
2818c2ecf20Sopenharmony_ci	int i;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	for (i = 0; i < 2000000; i++) {
2848c2ecf20Sopenharmony_ci		status.val = readl(remapped_regs + mmRBBM_STATUS);
2858c2ecf20Sopenharmony_ci		if (!status.f.gui_active)
2868c2ecf20Sopenharmony_ci			return 0;
2878c2ecf20Sopenharmony_ci		udelay(1);
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	printk(KERN_ERR "w100fb: Graphic engine timeout!\n");
2908c2ecf20Sopenharmony_ci	return -EBUSY;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic void w100_init_graphic_engine(struct w100fb_par *par)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	union dp_gui_master_cntl_u gmc;
2978c2ecf20Sopenharmony_ci	union dp_mix_u dp_mix;
2988c2ecf20Sopenharmony_ci	union dp_datatype_u dp_datatype;
2998c2ecf20Sopenharmony_ci	union dp_cntl_u dp_cntl;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	w100_fifo_wait(4);
3028c2ecf20Sopenharmony_ci	writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET);
3038c2ecf20Sopenharmony_ci	writel(par->xres, remapped_regs + mmDST_PITCH);
3048c2ecf20Sopenharmony_ci	writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET);
3058c2ecf20Sopenharmony_ci	writel(par->xres, remapped_regs + mmSRC_PITCH);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	w100_fifo_wait(3);
3088c2ecf20Sopenharmony_ci	writel(0, remapped_regs + mmSC_TOP_LEFT);
3098c2ecf20Sopenharmony_ci	writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT);
3108c2ecf20Sopenharmony_ci	writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	w100_fifo_wait(4);
3138c2ecf20Sopenharmony_ci	dp_cntl.val = 0;
3148c2ecf20Sopenharmony_ci	dp_cntl.f.dst_x_dir = 1;
3158c2ecf20Sopenharmony_ci	dp_cntl.f.dst_y_dir = 1;
3168c2ecf20Sopenharmony_ci	dp_cntl.f.src_x_dir = 1;
3178c2ecf20Sopenharmony_ci	dp_cntl.f.src_y_dir = 1;
3188c2ecf20Sopenharmony_ci	dp_cntl.f.dst_major_x = 1;
3198c2ecf20Sopenharmony_ci	dp_cntl.f.src_major_x = 1;
3208c2ecf20Sopenharmony_ci	writel(dp_cntl.val, remapped_regs + mmDP_CNTL);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	gmc.val = 0;
3238c2ecf20Sopenharmony_ci	gmc.f.gmc_src_pitch_offset_cntl = 1;
3248c2ecf20Sopenharmony_ci	gmc.f.gmc_dst_pitch_offset_cntl = 1;
3258c2ecf20Sopenharmony_ci	gmc.f.gmc_src_clipping = 1;
3268c2ecf20Sopenharmony_ci	gmc.f.gmc_dst_clipping = 1;
3278c2ecf20Sopenharmony_ci	gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
3288c2ecf20Sopenharmony_ci	gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */
3298c2ecf20Sopenharmony_ci	gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST;
3308c2ecf20Sopenharmony_ci	gmc.f.gmc_byte_pix_order = 1;
3318c2ecf20Sopenharmony_ci	gmc.f.gmc_default_sel = 0;
3328c2ecf20Sopenharmony_ci	gmc.f.gmc_rop3 = ROP3_SRCCOPY;
3338c2ecf20Sopenharmony_ci	gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR;
3348c2ecf20Sopenharmony_ci	gmc.f.gmc_clr_cmp_fcn_dis = 1;
3358c2ecf20Sopenharmony_ci	gmc.f.gmc_wr_msk_dis = 1;
3368c2ecf20Sopenharmony_ci	gmc.f.gmc_dp_op = DP_OP_ROP;
3378c2ecf20Sopenharmony_ci	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	dp_datatype.val = dp_mix.val = 0;
3408c2ecf20Sopenharmony_ci	dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype;
3418c2ecf20Sopenharmony_ci	dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype;
3428c2ecf20Sopenharmony_ci	dp_datatype.f.dp_src2_type = 0;
3438c2ecf20Sopenharmony_ci	dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype;
3448c2ecf20Sopenharmony_ci	dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype;
3458c2ecf20Sopenharmony_ci	dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order;
3468c2ecf20Sopenharmony_ci	writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source;
3498c2ecf20Sopenharmony_ci	dp_mix.f.dp_src2_source = 1;
3508c2ecf20Sopenharmony_ci	dp_mix.f.dp_rop3 = gmc.f.gmc_rop3;
3518c2ecf20Sopenharmony_ci	dp_mix.f.dp_op = gmc.f.gmc_dp_op;
3528c2ecf20Sopenharmony_ci	writel(dp_mix.val, remapped_regs + mmDP_MIX);
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void w100fb_fillrect(struct fb_info *info,
3578c2ecf20Sopenharmony_ci                            const struct fb_fillrect *rect)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	union dp_gui_master_cntl_u gmc;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
3628c2ecf20Sopenharmony_ci		return;
3638c2ecf20Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED) {
3648c2ecf20Sopenharmony_ci		cfb_fillrect(info, rect);
3658c2ecf20Sopenharmony_ci		return;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
3698c2ecf20Sopenharmony_ci	gmc.f.gmc_rop3 = ROP3_PATCOPY;
3708c2ecf20Sopenharmony_ci	gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR;
3718c2ecf20Sopenharmony_ci	w100_fifo_wait(2);
3728c2ecf20Sopenharmony_ci	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
3738c2ecf20Sopenharmony_ci	writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	w100_fifo_wait(2);
3768c2ecf20Sopenharmony_ci	writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X);
3778c2ecf20Sopenharmony_ci	writel((rect->width << 16) | (rect->height & 0xffff),
3788c2ecf20Sopenharmony_ci	       remapped_regs + mmDST_WIDTH_HEIGHT);
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void w100fb_copyarea(struct fb_info *info,
3838c2ecf20Sopenharmony_ci                            const struct fb_copyarea *area)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
3868c2ecf20Sopenharmony_ci	u32 h = area->height, w = area->width;
3878c2ecf20Sopenharmony_ci	union dp_gui_master_cntl_u gmc;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
3908c2ecf20Sopenharmony_ci		return;
3918c2ecf20Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED) {
3928c2ecf20Sopenharmony_ci		cfb_copyarea(info, area);
3938c2ecf20Sopenharmony_ci		return;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
3978c2ecf20Sopenharmony_ci	gmc.f.gmc_rop3 = ROP3_SRCCOPY;
3988c2ecf20Sopenharmony_ci	gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
3998c2ecf20Sopenharmony_ci	w100_fifo_wait(1);
4008c2ecf20Sopenharmony_ci	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	w100_fifo_wait(3);
4038c2ecf20Sopenharmony_ci	writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X);
4048c2ecf20Sopenharmony_ci	writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X);
4058c2ecf20Sopenharmony_ci	writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci/*
4108c2ecf20Sopenharmony_ci *  Change the resolution by calling the appropriate hardware functions
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_cistatic void w100fb_activate_var(struct w100fb_par *par)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct w100_tg_info *tg = par->mach->tg;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	w100_pwm_setup(par);
4178c2ecf20Sopenharmony_ci	w100_setup_memory(par);
4188c2ecf20Sopenharmony_ci	w100_init_clocks(par);
4198c2ecf20Sopenharmony_ci	w100fb_clear_screen(par);
4208c2ecf20Sopenharmony_ci	w100_vsync();
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	w100_update_disable();
4238c2ecf20Sopenharmony_ci	w100_init_lcd(par);
4248c2ecf20Sopenharmony_ci	w100_set_dispregs(par);
4258c2ecf20Sopenharmony_ci	w100_update_enable();
4268c2ecf20Sopenharmony_ci	w100_init_graphic_engine(par);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	calc_hsync(par);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (!par->blanked && tg && tg->change)
4318c2ecf20Sopenharmony_ci		tg->change(par);
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci/* Select the smallest mode that allows the desired resolution to be
4368c2ecf20Sopenharmony_ci * displayed. If desired, the x and y parameters can be rounded up to
4378c2ecf20Sopenharmony_ci * match the selected mode.
4388c2ecf20Sopenharmony_ci */
4398c2ecf20Sopenharmony_cistatic struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct w100_mode *mode = NULL;
4428c2ecf20Sopenharmony_ci	struct w100_mode *modelist = par->mach->modelist;
4438c2ecf20Sopenharmony_ci	unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
4448c2ecf20Sopenharmony_ci	unsigned int i;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	for (i = 0 ; i < par->mach->num_modes ; i++) {
4478c2ecf20Sopenharmony_ci		if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
4488c2ecf20Sopenharmony_ci				modelist[i].xres < best_x && modelist[i].yres < best_y) {
4498c2ecf20Sopenharmony_ci			best_x = modelist[i].xres;
4508c2ecf20Sopenharmony_ci			best_y = modelist[i].yres;
4518c2ecf20Sopenharmony_ci			mode = &modelist[i];
4528c2ecf20Sopenharmony_ci		} else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
4538c2ecf20Sopenharmony_ci		        modelist[i].xres < best_y && modelist[i].yres < best_x) {
4548c2ecf20Sopenharmony_ci			best_x = modelist[i].yres;
4558c2ecf20Sopenharmony_ci			best_y = modelist[i].xres;
4568c2ecf20Sopenharmony_ci			mode = &modelist[i];
4578c2ecf20Sopenharmony_ci		}
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (mode && saveval) {
4618c2ecf20Sopenharmony_ci		*x = best_x;
4628c2ecf20Sopenharmony_ci		*y = best_y;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return mode;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/*
4708c2ecf20Sopenharmony_ci *  w100fb_check_var():
4718c2ecf20Sopenharmony_ci *  Get the video params out of 'var'. If a value doesn't fit, round it up,
4728c2ecf20Sopenharmony_ci *  if it's too big, return -EINVAL.
4738c2ecf20Sopenharmony_ci */
4748c2ecf20Sopenharmony_cistatic int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
4798c2ecf20Sopenharmony_ci		return -EINVAL;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
4828c2ecf20Sopenharmony_ci		return -EINVAL;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
4858c2ecf20Sopenharmony_ci		return -EINVAL;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	var->xres_virtual = max(var->xres_virtual, var->xres);
4888c2ecf20Sopenharmony_ci	var->yres_virtual = max(var->yres_virtual, var->yres);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (var->bits_per_pixel > BITS_PER_PIXEL)
4918c2ecf20Sopenharmony_ci		return -EINVAL;
4928c2ecf20Sopenharmony_ci	else
4938c2ecf20Sopenharmony_ci		var->bits_per_pixel = BITS_PER_PIXEL;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	var->red.offset = 11;
4968c2ecf20Sopenharmony_ci	var->red.length = 5;
4978c2ecf20Sopenharmony_ci	var->green.offset = 5;
4988c2ecf20Sopenharmony_ci	var->green.length = 6;
4998c2ecf20Sopenharmony_ci	var->blue.offset = 0;
5008c2ecf20Sopenharmony_ci	var->blue.length = 5;
5018c2ecf20Sopenharmony_ci	var->transp.offset = var->transp.length = 0;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	var->nonstd = 0;
5048c2ecf20Sopenharmony_ci	var->height = -1;
5058c2ecf20Sopenharmony_ci	var->width = -1;
5068c2ecf20Sopenharmony_ci	var->vmode = FB_VMODE_NONINTERLACED;
5078c2ecf20Sopenharmony_ci	var->sync = 0;
5088c2ecf20Sopenharmony_ci	var->pixclock = 0x04;  /* 171521; */
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	return 0;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci/*
5158c2ecf20Sopenharmony_ci * w100fb_set_par():
5168c2ecf20Sopenharmony_ci *	Set the user defined part of the display for the specified console
5178c2ecf20Sopenharmony_ci *  by looking at the values in info.var
5188c2ecf20Sopenharmony_ci */
5198c2ecf20Sopenharmony_cistatic int w100fb_set_par(struct fb_info *info)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (par->xres != info->var.xres || par->yres != info->var.yres)	{
5248c2ecf20Sopenharmony_ci		par->xres = info->var.xres;
5258c2ecf20Sopenharmony_ci		par->yres = info->var.yres;
5268c2ecf20Sopenharmony_ci		par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		info->fix.visual = FB_VISUAL_TRUECOLOR;
5298c2ecf20Sopenharmony_ci		info->fix.ypanstep = 0;
5308c2ecf20Sopenharmony_ci		info->fix.ywrapstep = 0;
5318c2ecf20Sopenharmony_ci		info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci		mutex_lock(&info->mm_lock);
5348c2ecf20Sopenharmony_ci		if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
5358c2ecf20Sopenharmony_ci			par->extmem_active = 1;
5368c2ecf20Sopenharmony_ci			info->fix.smem_len = par->mach->mem->size+1;
5378c2ecf20Sopenharmony_ci		} else {
5388c2ecf20Sopenharmony_ci			par->extmem_active = 0;
5398c2ecf20Sopenharmony_ci			info->fix.smem_len = MEM_INT_SIZE+1;
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci		mutex_unlock(&info->mm_lock);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		w100fb_activate_var(par);
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci	return 0;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci/*
5508c2ecf20Sopenharmony_ci *  Frame buffer operations
5518c2ecf20Sopenharmony_ci */
5528c2ecf20Sopenharmony_cistatic const struct fb_ops w100fb_ops = {
5538c2ecf20Sopenharmony_ci	.owner        = THIS_MODULE,
5548c2ecf20Sopenharmony_ci	.fb_check_var = w100fb_check_var,
5558c2ecf20Sopenharmony_ci	.fb_set_par   = w100fb_set_par,
5568c2ecf20Sopenharmony_ci	.fb_setcolreg = w100fb_setcolreg,
5578c2ecf20Sopenharmony_ci	.fb_blank     = w100fb_blank,
5588c2ecf20Sopenharmony_ci	.fb_fillrect  = w100fb_fillrect,
5598c2ecf20Sopenharmony_ci	.fb_copyarea  = w100fb_copyarea,
5608c2ecf20Sopenharmony_ci	.fb_imageblit = cfb_imageblit,
5618c2ecf20Sopenharmony_ci	.fb_sync      = w100fb_sync,
5628c2ecf20Sopenharmony_ci};
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
5658c2ecf20Sopenharmony_cistatic void w100fb_save_vidmem(struct w100fb_par *par)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	int memsize;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (par->extmem_active) {
5708c2ecf20Sopenharmony_ci		memsize=par->mach->mem->size;
5718c2ecf20Sopenharmony_ci		par->saved_extmem = vmalloc(memsize);
5728c2ecf20Sopenharmony_ci		if (par->saved_extmem)
5738c2ecf20Sopenharmony_ci			memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci	memsize=MEM_INT_SIZE;
5768c2ecf20Sopenharmony_ci	par->saved_intmem = vmalloc(memsize);
5778c2ecf20Sopenharmony_ci	if (par->saved_intmem && par->extmem_active)
5788c2ecf20Sopenharmony_ci		memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
5798c2ecf20Sopenharmony_ci	else if (par->saved_intmem)
5808c2ecf20Sopenharmony_ci		memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cistatic void w100fb_restore_vidmem(struct w100fb_par *par)
5848c2ecf20Sopenharmony_ci{
5858c2ecf20Sopenharmony_ci	int memsize;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	if (par->extmem_active && par->saved_extmem) {
5888c2ecf20Sopenharmony_ci		memsize=par->mach->mem->size;
5898c2ecf20Sopenharmony_ci		memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
5908c2ecf20Sopenharmony_ci		vfree(par->saved_extmem);
5918c2ecf20Sopenharmony_ci		par->saved_extmem = NULL;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci	if (par->saved_intmem) {
5948c2ecf20Sopenharmony_ci		memsize=MEM_INT_SIZE;
5958c2ecf20Sopenharmony_ci		if (par->extmem_active)
5968c2ecf20Sopenharmony_ci			memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
5978c2ecf20Sopenharmony_ci		else
5988c2ecf20Sopenharmony_ci			memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
5998c2ecf20Sopenharmony_ci		vfree(par->saved_intmem);
6008c2ecf20Sopenharmony_ci		par->saved_intmem = NULL;
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int w100fb_suspend(struct platform_device *dev, pm_message_t state)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct fb_info *info = platform_get_drvdata(dev);
6078c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
6088c2ecf20Sopenharmony_ci	struct w100_tg_info *tg = par->mach->tg;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	w100fb_save_vidmem(par);
6118c2ecf20Sopenharmony_ci	if(tg && tg->suspend)
6128c2ecf20Sopenharmony_ci		tg->suspend(par);
6138c2ecf20Sopenharmony_ci	w100_suspend(W100_SUSPEND_ALL);
6148c2ecf20Sopenharmony_ci	par->blanked = 1;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return 0;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int w100fb_resume(struct platform_device *dev)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct fb_info *info = platform_get_drvdata(dev);
6228c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
6238c2ecf20Sopenharmony_ci	struct w100_tg_info *tg = par->mach->tg;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	w100_hw_init(par);
6268c2ecf20Sopenharmony_ci	w100fb_activate_var(par);
6278c2ecf20Sopenharmony_ci	w100fb_restore_vidmem(par);
6288c2ecf20Sopenharmony_ci	if(tg && tg->resume)
6298c2ecf20Sopenharmony_ci		tg->resume(par);
6308c2ecf20Sopenharmony_ci	par->blanked = 0;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	return 0;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci#else
6358c2ecf20Sopenharmony_ci#define w100fb_suspend  NULL
6368c2ecf20Sopenharmony_ci#define w100fb_resume   NULL
6378c2ecf20Sopenharmony_ci#endif
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistatic int w100fb_probe(struct platform_device *pdev)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	int err = -EIO;
6438c2ecf20Sopenharmony_ci	struct w100fb_mach_info *inf;
6448c2ecf20Sopenharmony_ci	struct fb_info *info = NULL;
6458c2ecf20Sopenharmony_ci	struct w100fb_par *par;
6468c2ecf20Sopenharmony_ci	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6478c2ecf20Sopenharmony_ci	unsigned int chip_id;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (!mem)
6508c2ecf20Sopenharmony_ci		return -EINVAL;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	/* Remap the chip base address */
6538c2ecf20Sopenharmony_ci	remapped_base = ioremap(mem->start+W100_CFG_BASE, W100_CFG_LEN);
6548c2ecf20Sopenharmony_ci	if (remapped_base == NULL)
6558c2ecf20Sopenharmony_ci		goto out;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/* Map the register space */
6588c2ecf20Sopenharmony_ci	remapped_regs = ioremap(mem->start+W100_REG_BASE, W100_REG_LEN);
6598c2ecf20Sopenharmony_ci	if (remapped_regs == NULL)
6608c2ecf20Sopenharmony_ci		goto out;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* Identify the chip */
6638c2ecf20Sopenharmony_ci	printk("Found ");
6648c2ecf20Sopenharmony_ci	chip_id = readl(remapped_regs + mmCHIP_ID);
6658c2ecf20Sopenharmony_ci	switch(chip_id) {
6668c2ecf20Sopenharmony_ci		case CHIP_ID_W100:  printk("w100");  break;
6678c2ecf20Sopenharmony_ci		case CHIP_ID_W3200: printk("w3200"); break;
6688c2ecf20Sopenharmony_ci		case CHIP_ID_W3220: printk("w3220"); break;
6698c2ecf20Sopenharmony_ci		default:
6708c2ecf20Sopenharmony_ci			printk("Unknown imageon chip ID\n");
6718c2ecf20Sopenharmony_ci			err = -ENODEV;
6728c2ecf20Sopenharmony_ci			goto out;
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci	printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	/* Remap the framebuffer */
6778c2ecf20Sopenharmony_ci	remapped_fbuf = ioremap(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
6788c2ecf20Sopenharmony_ci	if (remapped_fbuf == NULL)
6798c2ecf20Sopenharmony_ci		goto out;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
6828c2ecf20Sopenharmony_ci	if (!info) {
6838c2ecf20Sopenharmony_ci		err = -ENOMEM;
6848c2ecf20Sopenharmony_ci		goto out;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	par = info->par;
6888c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, info);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	inf = dev_get_platdata(&pdev->dev);
6918c2ecf20Sopenharmony_ci	par->chip_id = chip_id;
6928c2ecf20Sopenharmony_ci	par->mach = inf;
6938c2ecf20Sopenharmony_ci	par->fastpll_mode = 0;
6948c2ecf20Sopenharmony_ci	par->blanked = 0;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	par->pll_table=w100_get_xtal_table(inf->xtal_freq);
6978c2ecf20Sopenharmony_ci	if (!par->pll_table) {
6988c2ecf20Sopenharmony_ci		printk(KERN_ERR "No matching Xtal definition found\n");
6998c2ecf20Sopenharmony_ci		err = -EINVAL;
7008c2ecf20Sopenharmony_ci		goto out;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	info->pseudo_palette = kmalloc_array(MAX_PALETTES, sizeof(u32),
7048c2ecf20Sopenharmony_ci					     GFP_KERNEL);
7058c2ecf20Sopenharmony_ci	if (!info->pseudo_palette) {
7068c2ecf20Sopenharmony_ci		err = -ENOMEM;
7078c2ecf20Sopenharmony_ci		goto out;
7088c2ecf20Sopenharmony_ci	}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	info->fbops = &w100fb_ops;
7118c2ecf20Sopenharmony_ci	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
7128c2ecf20Sopenharmony_ci		FBINFO_HWACCEL_FILLRECT;
7138c2ecf20Sopenharmony_ci	info->node = -1;
7148c2ecf20Sopenharmony_ci	info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
7158c2ecf20Sopenharmony_ci	info->screen_size = REMAPPED_FB_LEN;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	strcpy(info->fix.id, "w100fb");
7188c2ecf20Sopenharmony_ci	info->fix.type = FB_TYPE_PACKED_PIXELS;
7198c2ecf20Sopenharmony_ci	info->fix.type_aux = 0;
7208c2ecf20Sopenharmony_ci	info->fix.accel = FB_ACCEL_NONE;
7218c2ecf20Sopenharmony_ci	info->fix.smem_start = mem->start+W100_FB_BASE;
7228c2ecf20Sopenharmony_ci	info->fix.mmio_start = mem->start+W100_REG_BASE;
7238c2ecf20Sopenharmony_ci	info->fix.mmio_len = W100_REG_LEN;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
7268c2ecf20Sopenharmony_ci		err = -ENOMEM;
7278c2ecf20Sopenharmony_ci		goto out;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	par->mode = &inf->modelist[0];
7318c2ecf20Sopenharmony_ci	if(inf->init_mode & INIT_MODE_ROTATED) {
7328c2ecf20Sopenharmony_ci		info->var.xres = par->mode->yres;
7338c2ecf20Sopenharmony_ci		info->var.yres = par->mode->xres;
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci	else {
7368c2ecf20Sopenharmony_ci		info->var.xres = par->mode->xres;
7378c2ecf20Sopenharmony_ci		info->var.yres = par->mode->yres;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if(inf->init_mode &= INIT_MODE_FLIPPED)
7418c2ecf20Sopenharmony_ci		par->flip = 1;
7428c2ecf20Sopenharmony_ci	else
7438c2ecf20Sopenharmony_ci		par->flip = 0;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	info->var.xres_virtual = info->var.xres;
7468c2ecf20Sopenharmony_ci	info->var.yres_virtual = info->var.yres;
7478c2ecf20Sopenharmony_ci	info->var.pixclock = 0x04;  /* 171521; */
7488c2ecf20Sopenharmony_ci	info->var.sync = 0;
7498c2ecf20Sopenharmony_ci	info->var.grayscale = 0;
7508c2ecf20Sopenharmony_ci	info->var.xoffset = info->var.yoffset = 0;
7518c2ecf20Sopenharmony_ci	info->var.accel_flags = 0;
7528c2ecf20Sopenharmony_ci	info->var.activate = FB_ACTIVATE_NOW;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	w100_hw_init(par);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (w100fb_check_var(&info->var, info) < 0) {
7578c2ecf20Sopenharmony_ci		err = -EINVAL;
7588c2ecf20Sopenharmony_ci		goto out;
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (register_framebuffer(info) < 0) {
7628c2ecf20Sopenharmony_ci		err = -EINVAL;
7638c2ecf20Sopenharmony_ci		goto out;
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	fb_info(info, "%s frame buffer device\n", info->fix.id);
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ciout:
7698c2ecf20Sopenharmony_ci	if (info) {
7708c2ecf20Sopenharmony_ci		fb_dealloc_cmap(&info->cmap);
7718c2ecf20Sopenharmony_ci		kfree(info->pseudo_palette);
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci	if (remapped_fbuf != NULL) {
7748c2ecf20Sopenharmony_ci		iounmap(remapped_fbuf);
7758c2ecf20Sopenharmony_ci		remapped_fbuf = NULL;
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci	if (remapped_regs != NULL) {
7788c2ecf20Sopenharmony_ci		iounmap(remapped_regs);
7798c2ecf20Sopenharmony_ci		remapped_regs = NULL;
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci	if (remapped_base != NULL) {
7828c2ecf20Sopenharmony_ci		iounmap(remapped_base);
7838c2ecf20Sopenharmony_ci		remapped_base = NULL;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci	if (info)
7868c2ecf20Sopenharmony_ci		framebuffer_release(info);
7878c2ecf20Sopenharmony_ci	return err;
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_cistatic int w100fb_remove(struct platform_device *pdev)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct fb_info *info = platform_get_drvdata(pdev);
7948c2ecf20Sopenharmony_ci	struct w100fb_par *par=info->par;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	unregister_framebuffer(info);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	vfree(par->saved_intmem);
7998c2ecf20Sopenharmony_ci	vfree(par->saved_extmem);
8008c2ecf20Sopenharmony_ci	kfree(info->pseudo_palette);
8018c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	iounmap(remapped_base);
8048c2ecf20Sopenharmony_ci	remapped_base = NULL;
8058c2ecf20Sopenharmony_ci	iounmap(remapped_regs);
8068c2ecf20Sopenharmony_ci	remapped_regs = NULL;
8078c2ecf20Sopenharmony_ci	iounmap(remapped_fbuf);
8088c2ecf20Sopenharmony_ci	remapped_fbuf = NULL;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	framebuffer_release(info);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	return 0;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci/* ------------------- chipset specific functions -------------------------- */
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic void w100_soft_reset(void)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	u16 val = readw((u16 __iomem *)remapped_base + cfgSTATUS);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	writew(val | 0x08, (u16 __iomem *)remapped_base + cfgSTATUS);
8248c2ecf20Sopenharmony_ci	udelay(100);
8258c2ecf20Sopenharmony_ci	writew(0x00, (u16 __iomem *)remapped_base + cfgSTATUS);
8268c2ecf20Sopenharmony_ci	udelay(100);
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic void w100_update_disable(void)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	/* Prevent display updates */
8348c2ecf20Sopenharmony_ci	disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
8358c2ecf20Sopenharmony_ci	disp_db_buf_wr_cntl.f.update_db_buf = 0;
8368c2ecf20Sopenharmony_ci	disp_db_buf_wr_cntl.f.en_db_buf = 0;
8378c2ecf20Sopenharmony_ci	writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic void w100_update_enable(void)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	/* Enable display updates */
8458c2ecf20Sopenharmony_ci	disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
8468c2ecf20Sopenharmony_ci	disp_db_buf_wr_cntl.f.update_db_buf = 1;
8478c2ecf20Sopenharmony_ci	disp_db_buf_wr_cntl.f.en_db_buf = 1;
8488c2ecf20Sopenharmony_ci	writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ciunsigned long w100fb_gpio_read(int port)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	unsigned long value;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (port==W100_GPIO_PORT_A)
8568c2ecf20Sopenharmony_ci		value = readl(remapped_regs + mmGPIO_DATA);
8578c2ecf20Sopenharmony_ci	else
8588c2ecf20Sopenharmony_ci		value = readl(remapped_regs + mmGPIO_DATA2);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	return value;
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_civoid w100fb_gpio_write(int port, unsigned long value)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	if (port==W100_GPIO_PORT_A)
8668c2ecf20Sopenharmony_ci		writel(value, remapped_regs + mmGPIO_DATA);
8678c2ecf20Sopenharmony_ci	else
8688c2ecf20Sopenharmony_ci		writel(value, remapped_regs + mmGPIO_DATA2);
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(w100fb_gpio_read);
8718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(w100fb_gpio_write);
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci/*
8748c2ecf20Sopenharmony_ci * Initialization of critical w100 hardware
8758c2ecf20Sopenharmony_ci */
8768c2ecf20Sopenharmony_cistatic void w100_hw_init(struct w100fb_par *par)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	u32 temp32;
8798c2ecf20Sopenharmony_ci	union cif_cntl_u cif_cntl;
8808c2ecf20Sopenharmony_ci	union intf_cntl_u intf_cntl;
8818c2ecf20Sopenharmony_ci	union cfgreg_base_u cfgreg_base;
8828c2ecf20Sopenharmony_ci	union wrap_top_dir_u wrap_top_dir;
8838c2ecf20Sopenharmony_ci	union cif_read_dbg_u cif_read_dbg;
8848c2ecf20Sopenharmony_ci	union cpu_defaults_u cpu_default;
8858c2ecf20Sopenharmony_ci	union cif_write_dbg_u cif_write_dbg;
8868c2ecf20Sopenharmony_ci	union wrap_start_dir_u wrap_start_dir;
8878c2ecf20Sopenharmony_ci	union cif_io_u cif_io;
8888c2ecf20Sopenharmony_ci	struct w100_gpio_regs *gpio = par->mach->gpio;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	w100_soft_reset();
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/* This is what the fpga_init code does on reset. May be wrong
8938c2ecf20Sopenharmony_ci	   but there is little info available */
8948c2ecf20Sopenharmony_ci	writel(0x31, remapped_regs + mmSCRATCH_UMSK);
8958c2ecf20Sopenharmony_ci	for (temp32 = 0; temp32 < 10000; temp32++)
8968c2ecf20Sopenharmony_ci		readl(remapped_regs + mmSCRATCH_UMSK);
8978c2ecf20Sopenharmony_ci	writel(0x30, remapped_regs + mmSCRATCH_UMSK);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	/* Set up CIF */
9008c2ecf20Sopenharmony_ci	cif_io.val = defCIF_IO;
9018c2ecf20Sopenharmony_ci	writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
9048c2ecf20Sopenharmony_ci	cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
9058c2ecf20Sopenharmony_ci	cif_write_dbg.f.en_dword_split_to_rbbm = 1;
9068c2ecf20Sopenharmony_ci	cif_write_dbg.f.dis_timeout_during_rbbm = 1;
9078c2ecf20Sopenharmony_ci	writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
9108c2ecf20Sopenharmony_ci	cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
9118c2ecf20Sopenharmony_ci	writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
9148c2ecf20Sopenharmony_ci	cif_cntl.f.dis_system_bits = 1;
9158c2ecf20Sopenharmony_ci	cif_cntl.f.dis_mr = 1;
9168c2ecf20Sopenharmony_ci	cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
9178c2ecf20Sopenharmony_ci	cif_cntl.f.intb_oe = 1;
9188c2ecf20Sopenharmony_ci	cif_cntl.f.interrupt_active_high = 1;
9198c2ecf20Sopenharmony_ci	writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* Setup cfgINTF_CNTL and cfgCPU defaults */
9228c2ecf20Sopenharmony_ci	intf_cntl.val = defINTF_CNTL;
9238c2ecf20Sopenharmony_ci	intf_cntl.f.ad_inc_a = 1;
9248c2ecf20Sopenharmony_ci	intf_cntl.f.ad_inc_b = 1;
9258c2ecf20Sopenharmony_ci	intf_cntl.f.rd_data_rdy_a = 0;
9268c2ecf20Sopenharmony_ci	intf_cntl.f.rd_data_rdy_b = 0;
9278c2ecf20Sopenharmony_ci	writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	cpu_default.val = defCPU_DEFAULTS;
9308c2ecf20Sopenharmony_ci	cpu_default.f.access_ind_addr_a = 1;
9318c2ecf20Sopenharmony_ci	cpu_default.f.access_ind_addr_b = 1;
9328c2ecf20Sopenharmony_ci	cpu_default.f.access_scratch_reg = 1;
9338c2ecf20Sopenharmony_ci	cpu_default.f.transition_size = 0;
9348c2ecf20Sopenharmony_ci	writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	/* set up the apertures */
9378c2ecf20Sopenharmony_ci	writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	cfgreg_base.val = defCFGREG_BASE;
9408c2ecf20Sopenharmony_ci	cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
9418c2ecf20Sopenharmony_ci	writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	wrap_start_dir.val = defWRAP_START_DIR;
9448c2ecf20Sopenharmony_ci	wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
9458c2ecf20Sopenharmony_ci	writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	wrap_top_dir.val = defWRAP_TOP_DIR;
9488c2ecf20Sopenharmony_ci	wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
9498c2ecf20Sopenharmony_ci	writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	/* Set the hardware to 565 colour */
9548c2ecf20Sopenharmony_ci	temp32 = readl(remapped_regs + mmDISP_DEBUG2);
9558c2ecf20Sopenharmony_ci	temp32 &= 0xff7fffff;
9568c2ecf20Sopenharmony_ci	temp32 |= 0x00800000;
9578c2ecf20Sopenharmony_ci	writel(temp32, remapped_regs + mmDISP_DEBUG2);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	/* Initialise the GPIO lines */
9608c2ecf20Sopenharmony_ci	if (gpio) {
9618c2ecf20Sopenharmony_ci		writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
9628c2ecf20Sopenharmony_ci		writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
9638c2ecf20Sopenharmony_ci		writel(gpio->gpio_dir1,  remapped_regs + mmGPIO_CNTL1);
9648c2ecf20Sopenharmony_ci		writel(gpio->gpio_oe1,   remapped_regs + mmGPIO_CNTL2);
9658c2ecf20Sopenharmony_ci		writel(gpio->gpio_dir2,  remapped_regs + mmGPIO_CNTL3);
9668c2ecf20Sopenharmony_ci		writel(gpio->gpio_oe2,   remapped_regs + mmGPIO_CNTL4);
9678c2ecf20Sopenharmony_ci	}
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistruct power_state {
9728c2ecf20Sopenharmony_ci	union clk_pin_cntl_u clk_pin_cntl;
9738c2ecf20Sopenharmony_ci	union pll_ref_fb_div_u pll_ref_fb_div;
9748c2ecf20Sopenharmony_ci	union pll_cntl_u pll_cntl;
9758c2ecf20Sopenharmony_ci	union sclk_cntl_u sclk_cntl;
9768c2ecf20Sopenharmony_ci	union pclk_cntl_u pclk_cntl;
9778c2ecf20Sopenharmony_ci	union pwrmgt_cntl_u pwrmgt_cntl;
9788c2ecf20Sopenharmony_ci	int auto_mode;  /* system clock auto changing? */
9798c2ecf20Sopenharmony_ci};
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cistatic struct power_state w100_pwr_state;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci/* 12.5MHz Crystal PLL Table */
9878c2ecf20Sopenharmony_cistatic struct w100_pll_info xtal_12500000[] = {
9888c2ecf20Sopenharmony_ci	/*freq     M   N_int    N_fac  tfgoal  lock_time */
9898c2ecf20Sopenharmony_ci	{ 50,      0,   1,       0,     0xe0,        56},  /*  50.00 MHz */
9908c2ecf20Sopenharmony_ci	{ 75,      0,   5,       0,     0xde,        37},  /*  75.00 MHz */
9918c2ecf20Sopenharmony_ci	{100,      0,   7,       0,     0xe0,        28},  /* 100.00 MHz */
9928c2ecf20Sopenharmony_ci	{125,      0,   9,       0,     0xe0,        22},  /* 125.00 MHz */
9938c2ecf20Sopenharmony_ci	{150,      0,   11,      0,     0xe0,        17},  /* 150.00 MHz */
9948c2ecf20Sopenharmony_ci	{  0,      0,   0,       0,        0,         0},  /* Terminator */
9958c2ecf20Sopenharmony_ci};
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci/* 14.318MHz Crystal PLL Table */
9988c2ecf20Sopenharmony_cistatic struct w100_pll_info xtal_14318000[] = {
9998c2ecf20Sopenharmony_ci	/*freq     M   N_int    N_fac  tfgoal  lock_time */
10008c2ecf20Sopenharmony_ci	{ 40,      4,   13,      0,     0xe0,        80}, /* tfgoal guessed */
10018c2ecf20Sopenharmony_ci	{ 50,      1,   6,       0,     0xe0,	     64}, /*  50.05 MHz */
10028c2ecf20Sopenharmony_ci	{ 57,      2,   11,      0,     0xe0,        53}, /* tfgoal guessed */
10038c2ecf20Sopenharmony_ci	{ 75,      0,   4,       3,     0xe0,	     43}, /*  75.08 MHz */
10048c2ecf20Sopenharmony_ci	{100,      0,   6,       0,     0xe0,        32}, /* 100.10 MHz */
10058c2ecf20Sopenharmony_ci	{  0,      0,   0,       0,        0,         0},
10068c2ecf20Sopenharmony_ci};
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci/* 16MHz Crystal PLL Table */
10098c2ecf20Sopenharmony_cistatic struct w100_pll_info xtal_16000000[] = {
10108c2ecf20Sopenharmony_ci	/*freq     M   N_int    N_fac  tfgoal  lock_time */
10118c2ecf20Sopenharmony_ci	{ 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
10128c2ecf20Sopenharmony_ci	{ 80,      1,   9,       0,     0xe0,        13}, /* tfgoal guessed */
10138c2ecf20Sopenharmony_ci	{ 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
10148c2ecf20Sopenharmony_ci	{ 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
10158c2ecf20Sopenharmony_ci	{  0,      0,   0,       0,        0,         0},
10168c2ecf20Sopenharmony_ci};
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic struct pll_entries {
10198c2ecf20Sopenharmony_ci	int xtal_freq;
10208c2ecf20Sopenharmony_ci	struct w100_pll_info *pll_table;
10218c2ecf20Sopenharmony_ci} w100_pll_tables[] = {
10228c2ecf20Sopenharmony_ci	{ 12500000, &xtal_12500000[0] },
10238c2ecf20Sopenharmony_ci	{ 14318000, &xtal_14318000[0] },
10248c2ecf20Sopenharmony_ci	{ 16000000, &xtal_16000000[0] },
10258c2ecf20Sopenharmony_ci	{ 0 },
10268c2ecf20Sopenharmony_ci};
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistruct w100_pll_info *w100_get_xtal_table(unsigned int freq)
10298c2ecf20Sopenharmony_ci{
10308c2ecf20Sopenharmony_ci	struct pll_entries *pll_entry = w100_pll_tables;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	do {
10338c2ecf20Sopenharmony_ci		if (freq == pll_entry->xtal_freq)
10348c2ecf20Sopenharmony_ci			return pll_entry->pll_table;
10358c2ecf20Sopenharmony_ci		pll_entry++;
10368c2ecf20Sopenharmony_ci	} while (pll_entry->xtal_freq);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	return NULL;
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_cistatic unsigned int w100_get_testcount(unsigned int testclk_sel)
10438c2ecf20Sopenharmony_ci{
10448c2ecf20Sopenharmony_ci	union clk_test_cntl_u clk_test_cntl;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	udelay(5);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	/* Select the test clock source and reset */
10498c2ecf20Sopenharmony_ci	clk_test_cntl.f.start_check_freq = 0x0;
10508c2ecf20Sopenharmony_ci	clk_test_cntl.f.testclk_sel = testclk_sel;
10518c2ecf20Sopenharmony_ci	clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
10528c2ecf20Sopenharmony_ci	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
10558c2ecf20Sopenharmony_ci	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	/* Run clock test */
10588c2ecf20Sopenharmony_ci	clk_test_cntl.f.start_check_freq = 0x1;
10598c2ecf20Sopenharmony_ci	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	/* Give the test time to complete */
10628c2ecf20Sopenharmony_ci	udelay(20);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	/* Return the result */
10658c2ecf20Sopenharmony_ci	clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
10668c2ecf20Sopenharmony_ci	clk_test_cntl.f.start_check_freq = 0x0;
10678c2ecf20Sopenharmony_ci	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	return clk_test_cntl.f.test_count;
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic int w100_pll_adjust(struct w100_pll_info *pll)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	unsigned int tf80;
10768c2ecf20Sopenharmony_ci	unsigned int tf20;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	/* Initial Settings */
10798c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0;     /* power down */
10808c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_reset = 0x0;    /* not reset */
10818c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1;   /* Hi-Z */
10828c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;      /* VCO gain = 0 */
10838c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;    /* VCO frequency range control = off */
10848c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;  /* current offset inside VCO = 0 */
10858c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	/* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
10888c2ecf20Sopenharmony_ci	 * therefore, commented out the following lines
10898c2ecf20Sopenharmony_ci	 * tf80 meant tf100
10908c2ecf20Sopenharmony_ci	 */
10918c2ecf20Sopenharmony_ci	do {
10928c2ecf20Sopenharmony_ci		/* set VCO input = 0.8 * VDD */
10938c2ecf20Sopenharmony_ci		w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
10948c2ecf20Sopenharmony_ci		writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci		tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
10978c2ecf20Sopenharmony_ci		if (tf80 >= (pll->tfgoal)) {
10988c2ecf20Sopenharmony_ci			/* set VCO input = 0.2 * VDD */
10998c2ecf20Sopenharmony_ci			w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
11008c2ecf20Sopenharmony_ci			writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci			tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
11038c2ecf20Sopenharmony_ci			if (tf20 <= (pll->tfgoal))
11048c2ecf20Sopenharmony_ci				return 1;  /* Success */
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci			if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
11078c2ecf20Sopenharmony_ci				((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
11088c2ecf20Sopenharmony_ci				(w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
11098c2ecf20Sopenharmony_ci				/* slow VCO config */
11108c2ecf20Sopenharmony_ci				w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
11118c2ecf20Sopenharmony_ci				w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
11128c2ecf20Sopenharmony_ci				w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
11138c2ecf20Sopenharmony_ci				continue;
11148c2ecf20Sopenharmony_ci			}
11158c2ecf20Sopenharmony_ci		}
11168c2ecf20Sopenharmony_ci		if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
11178c2ecf20Sopenharmony_ci			w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
11188c2ecf20Sopenharmony_ci		} else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
11198c2ecf20Sopenharmony_ci			w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
11208c2ecf20Sopenharmony_ci			w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
11218c2ecf20Sopenharmony_ci		} else {
11228c2ecf20Sopenharmony_ci			return 0;  /* Error */
11238c2ecf20Sopenharmony_ci		}
11248c2ecf20Sopenharmony_ci	} while(1);
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci/*
11298c2ecf20Sopenharmony_ci * w100_pll_calibration
11308c2ecf20Sopenharmony_ci */
11318c2ecf20Sopenharmony_cistatic int w100_pll_calibration(struct w100_pll_info *pll)
11328c2ecf20Sopenharmony_ci{
11338c2ecf20Sopenharmony_ci	int status;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	status = w100_pll_adjust(pll);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	/* PLL Reset And Lock */
11388c2ecf20Sopenharmony_ci	/* set VCO input = 0.5 * VDD */
11398c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
11408c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	udelay(1);  /* reset time */
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	/* enable charge pump */
11458c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;  /* normal */
11468c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	/* set VCO input = Hi-Z, disable DAC */
11498c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
11508c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	udelay(400);  /* lock time */
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	/* PLL locked */
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	return status;
11578c2ecf20Sopenharmony_ci}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_cistatic int w100_pll_set_clk(struct w100_pll_info *pll)
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	int status;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	if (w100_pwr_state.auto_mode == 1)  /* auto mode */
11658c2ecf20Sopenharmony_ci	{
11668c2ecf20Sopenharmony_ci		w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;  /* disable fast to normal */
11678c2ecf20Sopenharmony_ci		w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;  /* disable normal to fast */
11688c2ecf20Sopenharmony_ci		writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	/* Set system clock source to XTAL whilst adjusting the PLL! */
11728c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
11738c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
11768c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
11778c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
11788c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
11798c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
11828c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	status = w100_pll_calibration(pll);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	if (w100_pwr_state.auto_mode == 1)  /* auto mode */
11878c2ecf20Sopenharmony_ci	{
11888c2ecf20Sopenharmony_ci		w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1;  /* reenable fast to normal */
11898c2ecf20Sopenharmony_ci		w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1;  /* reenable normal to fast  */
11908c2ecf20Sopenharmony_ci		writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
11918c2ecf20Sopenharmony_ci	}
11928c2ecf20Sopenharmony_ci	return status;
11938c2ecf20Sopenharmony_ci}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci/* freq = target frequency of the PLL */
11968c2ecf20Sopenharmony_cistatic int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	struct w100_pll_info *pll = par->pll_table;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	do {
12018c2ecf20Sopenharmony_ci		if (freq == pll->freq) {
12028c2ecf20Sopenharmony_ci			return w100_pll_set_clk(pll);
12038c2ecf20Sopenharmony_ci		}
12048c2ecf20Sopenharmony_ci		pll++;
12058c2ecf20Sopenharmony_ci	} while(pll->freq);
12068c2ecf20Sopenharmony_ci	return 0;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci/* Set up an initial state.  Some values/fields set
12108c2ecf20Sopenharmony_ci   here will be overwritten. */
12118c2ecf20Sopenharmony_cistatic void w100_pwm_setup(struct w100fb_par *par)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
12148c2ecf20Sopenharmony_ci	w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
12158c2ecf20Sopenharmony_ci	w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
12168c2ecf20Sopenharmony_ci	w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
12178c2ecf20Sopenharmony_ci	w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
12188c2ecf20Sopenharmony_ci	w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
12198c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
12228c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0;  /* Pfast = 1 */
12238c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
12248c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;  /* Pslow = 1 */
12258c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
12268c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0;    /* Dynamic */
12278c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0;   /* Dynamic */
12288c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0;     /* Dynamic */
12298c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0;  /* Dynamic */
12308c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0;     /* Dynamic */
12318c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0;     /* Dynamic */
12328c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0;     /* Dynamic */
12338c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0;   /* Dynamic */
12348c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0;   /* Dynamic */
12358c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
12368c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
12378c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
12388c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
12398c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
12428c2ecf20Sopenharmony_ci	w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1;    /* P = 2 */
12438c2ecf20Sopenharmony_ci	w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0;  /* Dynamic */
12448c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0;     /* M = 1 */
12478c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0;  /* N = 1.0 */
12488c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
12498c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
12508c2ecf20Sopenharmony_ci	w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
12518c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
12548c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
12558c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
12568c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_mode = 0x0;  /* uses VCO clock */
12578c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
12588c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
12598c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
12608c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pcp = 0x4;
12618c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
12628c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;
12638c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
12648c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
12658c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
12668c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;  /* Hi-Z */
12678c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
12688c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
12698c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
12708c2ecf20Sopenharmony_ci	w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
12718c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
12748c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;  /* normal mode (0, 1, 3) */
12758c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
12768c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
12778c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
12788c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1;  /* PM4,ENG */
12798c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1;  /* PM4,ENG */
12808c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
12818c2ecf20Sopenharmony_ci	w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
12828c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	w100_pwr_state.auto_mode = 0;  /* manual mode */
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci/*
12898c2ecf20Sopenharmony_ci * Setup the w100 clocks for the specified mode
12908c2ecf20Sopenharmony_ci */
12918c2ecf20Sopenharmony_cistatic void w100_init_clocks(struct w100fb_par *par)
12928c2ecf20Sopenharmony_ci{
12938c2ecf20Sopenharmony_ci	struct w100_mode *mode = par->mode;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
12968c2ecf20Sopenharmony_ci		w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
12998c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
13008c2ecf20Sopenharmony_ci	w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
13018c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cistatic void w100_init_lcd(struct w100fb_par *par)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	u32 temp32;
13078c2ecf20Sopenharmony_ci	struct w100_mode *mode = par->mode;
13088c2ecf20Sopenharmony_ci	struct w100_gen_regs *regs = par->mach->regs;
13098c2ecf20Sopenharmony_ci	union active_h_disp_u active_h_disp;
13108c2ecf20Sopenharmony_ci	union active_v_disp_u active_v_disp;
13118c2ecf20Sopenharmony_ci	union graphic_h_disp_u graphic_h_disp;
13128c2ecf20Sopenharmony_ci	union graphic_v_disp_u graphic_v_disp;
13138c2ecf20Sopenharmony_ci	union crtc_total_u crtc_total;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	/* w3200 doesn't like undefined bits being set so zero register values first */
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	active_h_disp.val = 0;
13188c2ecf20Sopenharmony_ci	active_h_disp.f.active_h_start=mode->left_margin;
13198c2ecf20Sopenharmony_ci	active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
13208c2ecf20Sopenharmony_ci	writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	active_v_disp.val = 0;
13238c2ecf20Sopenharmony_ci	active_v_disp.f.active_v_start=mode->upper_margin;
13248c2ecf20Sopenharmony_ci	active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
13258c2ecf20Sopenharmony_ci	writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	graphic_h_disp.val = 0;
13288c2ecf20Sopenharmony_ci	graphic_h_disp.f.graphic_h_start=mode->left_margin;
13298c2ecf20Sopenharmony_ci	graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
13308c2ecf20Sopenharmony_ci	writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	graphic_v_disp.val = 0;
13338c2ecf20Sopenharmony_ci	graphic_v_disp.f.graphic_v_start=mode->upper_margin;
13348c2ecf20Sopenharmony_ci	graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
13358c2ecf20Sopenharmony_ci	writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	crtc_total.val = 0;
13388c2ecf20Sopenharmony_ci	crtc_total.f.crtc_h_total=mode->left_margin  + mode->xres + mode->right_margin;
13398c2ecf20Sopenharmony_ci	crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
13408c2ecf20Sopenharmony_ci	writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
13438c2ecf20Sopenharmony_ci	writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
13448c2ecf20Sopenharmony_ci	writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
13458c2ecf20Sopenharmony_ci	writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
13468c2ecf20Sopenharmony_ci	writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
13478c2ecf20Sopenharmony_ci	writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
13488c2ecf20Sopenharmony_ci	writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
13498c2ecf20Sopenharmony_ci	writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
13508c2ecf20Sopenharmony_ci	writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
13538c2ecf20Sopenharmony_ci	writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
13548c2ecf20Sopenharmony_ci	writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
13558c2ecf20Sopenharmony_ci	writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
13568c2ecf20Sopenharmony_ci	writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
13578c2ecf20Sopenharmony_ci	writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	writel(0x00000000, remapped_regs + mmCRTC_FRAME);
13608c2ecf20Sopenharmony_ci	writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
13618c2ecf20Sopenharmony_ci	writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
13628c2ecf20Sopenharmony_ci	writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	/* Hack for overlay in ext memory */
13658c2ecf20Sopenharmony_ci	temp32 = readl(remapped_regs + mmDISP_DEBUG2);
13668c2ecf20Sopenharmony_ci	temp32 |= 0xc0000000;
13678c2ecf20Sopenharmony_ci	writel(temp32, remapped_regs + mmDISP_DEBUG2);
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_cistatic void w100_setup_memory(struct w100fb_par *par)
13728c2ecf20Sopenharmony_ci{
13738c2ecf20Sopenharmony_ci	union mc_ext_mem_location_u extmem_location;
13748c2ecf20Sopenharmony_ci	union mc_fb_location_u intmem_location;
13758c2ecf20Sopenharmony_ci	struct w100_mem_info *mem = par->mach->mem;
13768c2ecf20Sopenharmony_ci	struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (!par->extmem_active) {
13798c2ecf20Sopenharmony_ci		w100_suspend(W100_SUSPEND_EXTMEM);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		/* Map Internal Memory at FB Base */
13828c2ecf20Sopenharmony_ci		intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
13838c2ecf20Sopenharmony_ci		intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
13848c2ecf20Sopenharmony_ci		writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		/* Unmap External Memory - value is *probably* irrelevant but may have meaning
13878c2ecf20Sopenharmony_ci		   to acceleration libraries */
13888c2ecf20Sopenharmony_ci		extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
13898c2ecf20Sopenharmony_ci		extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
13908c2ecf20Sopenharmony_ci		writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
13918c2ecf20Sopenharmony_ci	} else {
13928c2ecf20Sopenharmony_ci		/* Map Internal Memory to its default location */
13938c2ecf20Sopenharmony_ci		intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
13948c2ecf20Sopenharmony_ci		intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
13958c2ecf20Sopenharmony_ci		writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci		/* Map External Memory at FB Base */
13988c2ecf20Sopenharmony_ci		extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
13998c2ecf20Sopenharmony_ci		extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
14008c2ecf20Sopenharmony_ci		writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci		writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
14038c2ecf20Sopenharmony_ci		writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
14048c2ecf20Sopenharmony_ci		writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
14058c2ecf20Sopenharmony_ci		udelay(100);
14068c2ecf20Sopenharmony_ci		writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
14078c2ecf20Sopenharmony_ci		udelay(100);
14088c2ecf20Sopenharmony_ci		writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
14098c2ecf20Sopenharmony_ci		udelay(100);
14108c2ecf20Sopenharmony_ci		writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
14118c2ecf20Sopenharmony_ci		writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
14128c2ecf20Sopenharmony_ci		if (bm_mem) {
14138c2ecf20Sopenharmony_ci			writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
14148c2ecf20Sopenharmony_ci			writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
14158c2ecf20Sopenharmony_ci			writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
14168c2ecf20Sopenharmony_ci			writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
14178c2ecf20Sopenharmony_ci			writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
14188c2ecf20Sopenharmony_ci			writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
14198c2ecf20Sopenharmony_ci			writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
14208c2ecf20Sopenharmony_ci		}
14218c2ecf20Sopenharmony_ci	}
14228c2ecf20Sopenharmony_ci}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_cistatic void w100_set_dispregs(struct w100fb_par *par)
14258c2ecf20Sopenharmony_ci{
14268c2ecf20Sopenharmony_ci	unsigned long rot=0, divider, offset=0;
14278c2ecf20Sopenharmony_ci	union graphic_ctrl_u graphic_ctrl;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	/* See if the mode has been rotated */
14308c2ecf20Sopenharmony_ci	if (par->xres == par->mode->xres) {
14318c2ecf20Sopenharmony_ci		if (par->flip) {
14328c2ecf20Sopenharmony_ci			rot=3; /* 180 degree */
14338c2ecf20Sopenharmony_ci			offset=(par->xres * par->yres) - 1;
14348c2ecf20Sopenharmony_ci		} /* else 0 degree */
14358c2ecf20Sopenharmony_ci		divider = par->mode->pixclk_divider;
14368c2ecf20Sopenharmony_ci	} else {
14378c2ecf20Sopenharmony_ci		if (par->flip) {
14388c2ecf20Sopenharmony_ci			rot=2; /* 270 degree */
14398c2ecf20Sopenharmony_ci			offset=par->xres - 1;
14408c2ecf20Sopenharmony_ci		} else {
14418c2ecf20Sopenharmony_ci			rot=1; /* 90 degree */
14428c2ecf20Sopenharmony_ci			offset=par->xres * (par->yres - 1);
14438c2ecf20Sopenharmony_ci		}
14448c2ecf20Sopenharmony_ci		divider = par->mode->pixclk_divider_rotated;
14458c2ecf20Sopenharmony_ci	}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
14488c2ecf20Sopenharmony_ci	switch (par->chip_id) {
14498c2ecf20Sopenharmony_ci		case CHIP_ID_W100:
14508c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.color_depth=6;
14518c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.en_crtc=1;
14528c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.en_graphic_req=1;
14538c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.en_graphic_crtc=1;
14548c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.lcd_pclk_on=1;
14558c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.lcd_sclk_on=1;
14568c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.low_power_on=0;
14578c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.req_freq=0;
14588c2ecf20Sopenharmony_ci			graphic_ctrl.f_w100.portrait_mode=rot;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci			/* Zaurus needs this */
14618c2ecf20Sopenharmony_ci			switch(par->xres) {
14628c2ecf20Sopenharmony_ci				case 240:
14638c2ecf20Sopenharmony_ci				case 320:
14648c2ecf20Sopenharmony_ci				default:
14658c2ecf20Sopenharmony_ci					graphic_ctrl.f_w100.total_req_graphic=0xa0;
14668c2ecf20Sopenharmony_ci					break;
14678c2ecf20Sopenharmony_ci				case 480:
14688c2ecf20Sopenharmony_ci				case 640:
14698c2ecf20Sopenharmony_ci					switch(rot) {
14708c2ecf20Sopenharmony_ci						case 0:  /* 0 */
14718c2ecf20Sopenharmony_ci						case 3:  /* 180 */
14728c2ecf20Sopenharmony_ci							graphic_ctrl.f_w100.low_power_on=1;
14738c2ecf20Sopenharmony_ci							graphic_ctrl.f_w100.req_freq=5;
14748c2ecf20Sopenharmony_ci						break;
14758c2ecf20Sopenharmony_ci						case 1:  /* 90 */
14768c2ecf20Sopenharmony_ci						case 2:  /* 270 */
14778c2ecf20Sopenharmony_ci							graphic_ctrl.f_w100.req_freq=4;
14788c2ecf20Sopenharmony_ci							break;
14798c2ecf20Sopenharmony_ci						default:
14808c2ecf20Sopenharmony_ci							break;
14818c2ecf20Sopenharmony_ci					}
14828c2ecf20Sopenharmony_ci					graphic_ctrl.f_w100.total_req_graphic=0xf0;
14838c2ecf20Sopenharmony_ci					break;
14848c2ecf20Sopenharmony_ci			}
14858c2ecf20Sopenharmony_ci			break;
14868c2ecf20Sopenharmony_ci		case CHIP_ID_W3200:
14878c2ecf20Sopenharmony_ci		case CHIP_ID_W3220:
14888c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.color_depth=6;
14898c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.en_crtc=1;
14908c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.en_graphic_req=1;
14918c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.en_graphic_crtc=1;
14928c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.lcd_pclk_on=1;
14938c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.lcd_sclk_on=1;
14948c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.low_power_on=0;
14958c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.req_freq=0;
14968c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
14978c2ecf20Sopenharmony_ci			graphic_ctrl.f_w32xx.portrait_mode=rot;
14988c2ecf20Sopenharmony_ci			break;
14998c2ecf20Sopenharmony_ci	}
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	/* Set the pixel clock source and divider */
15028c2ecf20Sopenharmony_ci	w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
15038c2ecf20Sopenharmony_ci	w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
15048c2ecf20Sopenharmony_ci	writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
15078c2ecf20Sopenharmony_ci	writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
15088c2ecf20Sopenharmony_ci	writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci/*
15138c2ecf20Sopenharmony_ci * Work out how long the sync pulse lasts
15148c2ecf20Sopenharmony_ci * Value is 1/(time in seconds)
15158c2ecf20Sopenharmony_ci */
15168c2ecf20Sopenharmony_cistatic void calc_hsync(struct w100fb_par *par)
15178c2ecf20Sopenharmony_ci{
15188c2ecf20Sopenharmony_ci	unsigned long hsync;
15198c2ecf20Sopenharmony_ci	struct w100_mode *mode = par->mode;
15208c2ecf20Sopenharmony_ci	union crtc_ss_u crtc_ss;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	if (mode->pixclk_src == CLK_SRC_XTAL)
15238c2ecf20Sopenharmony_ci		hsync=par->mach->xtal_freq;
15248c2ecf20Sopenharmony_ci	else
15258c2ecf20Sopenharmony_ci		hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
15308c2ecf20Sopenharmony_ci	if (crtc_ss.val)
15318c2ecf20Sopenharmony_ci		par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
15328c2ecf20Sopenharmony_ci	else
15338c2ecf20Sopenharmony_ci		par->hsync_len = 0;
15348c2ecf20Sopenharmony_ci}
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_cistatic void w100_suspend(u32 mode)
15378c2ecf20Sopenharmony_ci{
15388c2ecf20Sopenharmony_ci	u32 val;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
15418c2ecf20Sopenharmony_ci	writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
15448c2ecf20Sopenharmony_ci	val &= ~(0x00100000);  /* bit20=0 */
15458c2ecf20Sopenharmony_ci	val |= 0xFF000000;     /* bit31:24=0xff */
15468c2ecf20Sopenharmony_ci	writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	val = readl(remapped_regs + mmMEM_EXT_CNTL);
15498c2ecf20Sopenharmony_ci	val &= ~(0x00040000);  /* bit18=0 */
15508c2ecf20Sopenharmony_ci	val |= 0x00080000;     /* bit19=1 */
15518c2ecf20Sopenharmony_ci	writel(val, remapped_regs + mmMEM_EXT_CNTL);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	udelay(1);  /* wait 1us */
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	if (mode == W100_SUSPEND_EXTMEM) {
15568c2ecf20Sopenharmony_ci		/* CKE: Tri-State */
15578c2ecf20Sopenharmony_ci		val = readl(remapped_regs + mmMEM_EXT_CNTL);
15588c2ecf20Sopenharmony_ci		val |= 0x40000000;  /* bit30=1 */
15598c2ecf20Sopenharmony_ci		writel(val, remapped_regs + mmMEM_EXT_CNTL);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci		/* CLK: Stop */
15628c2ecf20Sopenharmony_ci		val = readl(remapped_regs + mmMEM_EXT_CNTL);
15638c2ecf20Sopenharmony_ci		val &= ~(0x00000001);  /* bit0=0 */
15648c2ecf20Sopenharmony_ci		writel(val, remapped_regs + mmMEM_EXT_CNTL);
15658c2ecf20Sopenharmony_ci	} else {
15668c2ecf20Sopenharmony_ci		writel(0x00000000, remapped_regs + mmSCLK_CNTL);
15678c2ecf20Sopenharmony_ci		writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
15688c2ecf20Sopenharmony_ci		writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci		udelay(5);
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci		val = readl(remapped_regs + mmPLL_CNTL);
15738c2ecf20Sopenharmony_ci		val |= 0x00000004;  /* bit2=1 */
15748c2ecf20Sopenharmony_ci		writel(val, remapped_regs + mmPLL_CNTL);
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci		writel(0x00000000, remapped_regs + mmLCDD_CNTL1);
15778c2ecf20Sopenharmony_ci		writel(0x00000000, remapped_regs + mmLCDD_CNTL2);
15788c2ecf20Sopenharmony_ci		writel(0x00000000, remapped_regs + mmGENLCD_CNTL1);
15798c2ecf20Sopenharmony_ci		writel(0x00000000, remapped_regs + mmGENLCD_CNTL2);
15808c2ecf20Sopenharmony_ci		writel(0x00000000, remapped_regs + mmGENLCD_CNTL3);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci		val = readl(remapped_regs + mmMEM_EXT_CNTL);
15838c2ecf20Sopenharmony_ci		val |= 0xF0000000;
15848c2ecf20Sopenharmony_ci		val &= ~(0x00000001);
15858c2ecf20Sopenharmony_ci		writel(val, remapped_regs + mmMEM_EXT_CNTL);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci		writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
15888c2ecf20Sopenharmony_ci	}
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_cistatic void w100_vsync(void)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	u32 tmp;
15948c2ecf20Sopenharmony_ci	int timeout = 30000;  /* VSync timeout = 30[ms] > 16.8[ms] */
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	tmp = readl(remapped_regs + mmACTIVE_V_DISP);
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	/* set vline pos  */
15998c2ecf20Sopenharmony_ci	writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL);
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	/* disable vline irq */
16028c2ecf20Sopenharmony_ci	tmp = readl(remapped_regs + mmGEN_INT_CNTL);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	tmp &= ~0x00000002;
16058c2ecf20Sopenharmony_ci	writel(tmp, remapped_regs + mmGEN_INT_CNTL);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	/* clear vline irq status */
16088c2ecf20Sopenharmony_ci	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	/* enable vline irq */
16118c2ecf20Sopenharmony_ci	writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	/* clear vline irq status */
16148c2ecf20Sopenharmony_ci	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	while(timeout > 0) {
16178c2ecf20Sopenharmony_ci		if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002)
16188c2ecf20Sopenharmony_ci			break;
16198c2ecf20Sopenharmony_ci		udelay(1);
16208c2ecf20Sopenharmony_ci		timeout--;
16218c2ecf20Sopenharmony_ci	}
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	/* disable vline irq */
16248c2ecf20Sopenharmony_ci	writel(tmp, remapped_regs + mmGEN_INT_CNTL);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	/* clear vline irq status */
16278c2ecf20Sopenharmony_ci	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
16288c2ecf20Sopenharmony_ci}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_cistatic struct platform_driver w100fb_driver = {
16318c2ecf20Sopenharmony_ci	.probe		= w100fb_probe,
16328c2ecf20Sopenharmony_ci	.remove		= w100fb_remove,
16338c2ecf20Sopenharmony_ci	.suspend	= w100fb_suspend,
16348c2ecf20Sopenharmony_ci	.resume		= w100fb_resume,
16358c2ecf20Sopenharmony_ci	.driver		= {
16368c2ecf20Sopenharmony_ci		.name	= "w100fb",
16378c2ecf20Sopenharmony_ci		.dev_groups	= w100fb_groups,
16388c2ecf20Sopenharmony_ci	},
16398c2ecf20Sopenharmony_ci};
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_cimodule_platform_driver(w100fb_driver);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
16448c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1645