s3c-fb.c revision bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9
1ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/* linux/drivers/video/s3c-fb.c
2ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
3ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Copyright 2008 Openmoko Inc.
450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * Copyright 2008-2010 Simtec Electronics
5ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *      Ben Dooks <ben@simtec.co.uk>
6ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *      http://armlinux.simtec.co.uk/
7ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
8ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Samsung SoC Framebuffer driver
9ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
10ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * This program is free software; you can redistribute it and/or modify
11ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * it under the terms of the GNU General Public License version 2 as
12c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * published by the Free Software FoundatIon.
13ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks*/
14ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
15ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/kernel.h>
16ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/module.h>
17ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/platform_device.h>
18ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/dma-mapping.h>
195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
20ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/init.h>
21ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/clk.h>
22ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/fb.h>
23ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <linux/io.h>
24ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
25ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <mach/map.h>
26c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks#include <plat/regs-fb-v4.h>
27ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#include <plat/fb.h>
28ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
29ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/* This driver will export a number of framebuffer interfaces depending
30ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * on the configuration passed in via the platform data. Each fb instance
31ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * maps to a hardware window. Currently there is no support for runtime
32ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * setting of the alpha-blending functions that each window has, so only
33ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * window 0 is actually useful.
34ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
35ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Window 0 is treated specially, it is used for the basis of the LCD
36ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * output timings and as the control for the output power-down state.
37ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks*/
38ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
3950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks/* note, the previous use of <mach/regs-fb.h> to get platform specific data
4050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * has been replaced by using the platform device name to pick the correct
4150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * configuration data for the system.
42ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks*/
43ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
44ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
45ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#undef writel
46ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#define writel(v, r) do { \
47ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
48ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	__raw_writel(v, r); } while(0)
49ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#endif /* FB_S3C_DEBUG_REGWRITE */
50ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
51ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstruct s3c_fb;
52ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
5350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks#define VALID_BPP(x) (1 << ((x) - 1))
5450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
55c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks#define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))
56c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks#define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00)
57c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks#define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04)
58c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks#define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
59c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks#define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
60c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
6150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks/**
6250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * struct s3c_fb_variant - fb variant information
63c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @is_2443: Set if S3C2443/S3C2416 style hardware.
6450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @nr_windows: The number of windows.
65c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @vidtcon: The base for the VIDTCONx registers
66c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @wincon: The base for the WINxCON registers.
67c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @winmap: The base for the WINxMAP registers.
68c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @keycon: The abse for the WxKEYCON registers.
69c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @buf_start: Offset of buffer start registers.
70c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @buf_size: Offset of buffer size registers.
71c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @buf_end: Offset of buffer end registers.
72c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks * @osd: The base for the OSD registers.
7350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @palette: Address of palette memory, or 0 if none.
7450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks */
7550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstruct s3c_fb_variant {
76c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned int	is_2443:1;
7750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	unsigned short	nr_windows;
78c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	vidtcon;
79c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	wincon;
80c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	winmap;
81c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	keycon;
82c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	buf_start;
83c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	buf_end;
84c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	buf_size;
85c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	osd;
86c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	unsigned short	osd_stride;
8750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	unsigned short	palette[S3C_FB_MAX_WIN];
8850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks};
8950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
9050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks/**
9150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * struct s3c_fb_win_variant
9250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @has_osd_c: Set if has OSD C register.
9350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @has_osd_d: Set if has OSD D register.
9450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @palette_sz: Size of palette in entries.
9550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @palette_16bpp: Set if palette is 16bits wide.
9650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
9750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks *
9850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * valid_bpp bit x is set if (x+1)BPP is supported.
9950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks */
10050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstruct s3c_fb_win_variant {
10150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	unsigned int	has_osd_c:1;
10250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	unsigned int	has_osd_d:1;
10350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	unsigned int	palette_16bpp:1;
10450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	unsigned short	palette_sz;
10550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	u32		valid_bpp;
10650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks};
10750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
10850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks/**
10950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * struct s3c_fb_driverdata - per-device type driver data for init time.
11050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @variant: The variant information for this driver.
11150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @win: The window information for each window.
11250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks */
11350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstruct s3c_fb_driverdata {
11450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	struct s3c_fb_variant	variant;
11550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];
11650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks};
11750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
118ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
119bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks * struct s3c_fb_palette - palette information
120bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks * @r: Red bitfield.
121bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks * @g: Green bitfield.
122bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks * @b: Blue bitfield.
123bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks * @a: Alpha bitfield.
124bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks */
125bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooksstruct s3c_fb_palette {
126bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks	struct fb_bitfield	r;
127bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks	struct fb_bitfield	g;
128bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks	struct fb_bitfield	b;
129bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks	struct fb_bitfield	a;
130bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks};
131bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks
132bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks/**
133ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * struct s3c_fb_win - per window private data for each framebuffer.
134ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @windata: The platform data supplied for the window configuration.
135ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @parent: The hardware that this window is part of.
136ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @fbinfo: Pointer pack to the framebuffer info for this window.
13750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @varint: The variant information for this window.
138ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @palette_buffer: Buffer/cache to hold palette entries.
139ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
140ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @index: The window number of this window.
141ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @palette: The bitfields for changing r/g/b into a hardware palette entry.
142ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
143ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstruct s3c_fb_win {
144ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_pd_win	*windata;
145ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb		*parent;
146ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct fb_info		*fbinfo;
147ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_palette	 palette;
14850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	struct s3c_fb_win_variant variant;
149ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
150ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	u32			*palette_buffer;
151ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	u32			 pseudo_palette[16];
152ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	unsigned int		 index;
153ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks};
154ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
155ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
156ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * struct s3c_fb - overall hardware state of the hardware
157ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @dev: The device that we bound to, for printing, etc.
158ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @regs_res: The resource we claimed for the IO registers.
159ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
160ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @regs: The mapped hardware registers.
16150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @variant: Variant information for this hardware.
162ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @enabled: A bitmask of enabled hardware windows.
163ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @pdata: The platform configuration data passed with the device.
164ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @windows: The hardware windows that have been claimed.
165ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
166ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstruct s3c_fb {
167ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct device		*dev;
168ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct resource		*regs_res;
169ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct clk		*bus_clk;
170ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	void __iomem		*regs;
17150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	struct s3c_fb_variant	 variant;
172ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
173ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	unsigned char		 enabled;
174ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
175ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_platdata	*pdata;
176ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win	*windows[S3C_FB_MAX_WIN];
177ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks};
178ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
179ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
18050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
18150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @win: The device window.
18250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @bpp: The bit depth.
183ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
18450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstatic bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
185ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
18650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	return win->variant.valid_bpp & VALID_BPP(bpp);
187ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
188ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
189ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
190ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
191ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @var: The screen information to verify.
192ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @info: The framebuffer device.
193ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
194ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Framebuffer layer call to verify the given information and allow us to
195ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * update various information depending on the hardware capabilities.
196ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
197ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int s3c_fb_check_var(struct fb_var_screeninfo *var,
198ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			    struct fb_info *info)
199ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
200ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win *win = info->par;
201ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_pd_win *windata = win->windata;
202ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb = win->parent;
203ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
204ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "checking parameters\n");
205ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
206ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres);
207ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres);
208ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
20950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
210ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
211ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			win->index, var->bits_per_pixel);
212ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return -EINVAL;
213ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
214ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
215ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* always ensure these are zero, for drop through cases below */
216ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	var->transp.offset = 0;
217ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	var->transp.length = 0;
218ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
219ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	switch (var->bits_per_pixel) {
220ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 1:
221ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 2:
222ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 4:
223ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 8:
22450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		if (sfb->variant.palette[win->index] != 0) {
225ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			/* non palletised, A:1,R:2,G:3,B:2 mode */
226ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->red.offset		= 4;
227ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->green.offset	= 2;
228ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->blue.offset	= 0;
229ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->red.length		= 5;
230ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->green.length	= 3;
231ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->blue.length	= 2;
232ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->transp.offset	= 7;
233ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->transp.length	= 1;
234ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		} else {
235ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->red.offset	= 0;
236ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->red.length	= var->bits_per_pixel;
237ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->green	= var->red;
238ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			var->blue	= var->red;
239ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		}
240ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
241ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
242ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 19:
243ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* 666 with one bit alpha/transparency */
244ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->transp.offset	= 18;
245ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->transp.length	= 1;
246ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 18:
247ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->bits_per_pixel	= 32;
248ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
249ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* 666 format */
250ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->red.offset		= 12;
251ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->green.offset	= 6;
252ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->blue.offset	= 0;
253ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->red.length		= 6;
254ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->green.length	= 6;
255ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->blue.length	= 6;
256ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
257ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
258ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 16:
259ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* 16 bpp, 565 format */
260ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->red.offset		= 11;
261ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->green.offset	= 5;
262ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->blue.offset	= 0;
263ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->red.length		= 5;
264ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->green.length	= 6;
265ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->blue.length	= 5;
266ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
267ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
268ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 28:
269ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 25:
270ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->transp.length	= var->bits_per_pixel - 24;
271ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->transp.offset	= 24;
272ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* drop through */
273ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 24:
274ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* our 24bpp is unpacked, so 32bpp */
275ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->bits_per_pixel	= 32;
276ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 32:
277ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->red.offset		= 16;
278ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->red.length		= 8;
279ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->green.offset	= 8;
280ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->green.length	= 8;
281ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->blue.offset	= 0;
282ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		var->blue.length	= 8;
283ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
284ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
285ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	default:
286ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(sfb->dev, "invalid bpp\n");
287ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
288ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
289ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
290ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
291ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
292ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
293ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
294ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
295ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @sfb: The hardware state.
296ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @pixclock: The pixel clock wanted, in picoseconds.
297ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
298ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Given the specified pixel clock, work out the necessary divider to get
299ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * close to the output frequency.
300ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
301eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brownstatic int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
302ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
303ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	unsigned long clk = clk_get_rate(sfb->bus_clk);
304eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brown	unsigned long long tmp;
305ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	unsigned int result;
306ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
307eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brown	tmp = (unsigned long long)clk;
308eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brown	tmp *= pixclk;
309eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brown
310eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brown	do_div(tmp, 1000000000UL);
311eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brown	result = (unsigned int)tmp / 1000;
312ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
313ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
314ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		pixclk, clk, result, clk / result);
315ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
316ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return result;
317ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
318ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
319ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
320ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_align_word() - align pixel count to word boundary
321ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @bpp: The number of bits per pixel
322ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @pix: The value to be aligned.
323ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
324ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Align the given pixel count so that it will start on an 32bit word
325ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * boundary.
326ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
327ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
328ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
329ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int pix_per_word;
330ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
331ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (bpp > 16)
332ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return pix;
333ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
334ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	pix_per_word = (8 * 32) / bpp;
335ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return ALIGN(pix, pix_per_word);
336ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
337ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
338ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
339ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
340ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @info: The framebuffer to change.
341ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
342ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Framebuffer layer request to set a new mode for the specified framebuffer
343ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
344ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int s3c_fb_set_par(struct fb_info *info)
345ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
346ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct fb_var_screeninfo *var = &info->var;
347ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win *win = info->par;
348ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb = win->parent;
349ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	void __iomem *regs = sfb->regs;
350c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	void __iomem *buf = regs;
351ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int win_no = win->index;
352600ce1a0faafeed1ce6bcfd421bc040b941cbbc1InKi Dae	u32 osdc_data = 0;
353ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	u32 data;
354ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	u32 pagewidth;
355ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int clkdiv;
356ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
357ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "setting framebuffer parameters\n");
358ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
359ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	switch (var->bits_per_pixel) {
360ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 32:
361ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 24:
362ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 16:
363ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 12:
364ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		info->fix.visual = FB_VISUAL_TRUECOLOR;
365ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
366ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 8:
36750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		if (win->variant.palette_sz >= 256)
368ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
369ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		else
370ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			info->fix.visual = FB_VISUAL_TRUECOLOR;
371ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
372ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 1:
373ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		info->fix.visual = FB_VISUAL_MONO01;
374ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
375ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	default:
376ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
377ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
378ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
379ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
380ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
381ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
382ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* disable the window whilst we update it */
383ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	writel(0, regs + WINCON(win_no));
384ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
385ad04490a171915737c9b99d2fa5cb813830f24c1InKi Dae	/* use platform specified window as the basis for the lcd timings */
386ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
387ad04490a171915737c9b99d2fa5cb813830f24c1InKi Dae	if (win_no == sfb->pdata->default_win) {
388eb29a5cc0b601c458bae9df2f6c3696d75c2d383Mark Brown		clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
389ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
390ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data = sfb->pdata->vidcon0;
391ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
392ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
393ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (clkdiv > 1)
394ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
395ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		else
396ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			data &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
397ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
398ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* write the timing data to the panel */
399ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
400c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		if (sfb->variant.is_2443)
401c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks			data |= (1 << 5);
402c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
403ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
404ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		writel(data, regs + VIDCON0);
405ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
406ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data = VIDTCON0_VBPD(var->upper_margin - 1) |
407ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		       VIDTCON0_VFPD(var->lower_margin - 1) |
408ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		       VIDTCON0_VSPW(var->vsync_len - 1);
409ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
410c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(data, regs + sfb->variant.vidtcon);
411ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
412ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data = VIDTCON1_HBPD(var->left_margin - 1) |
413ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		       VIDTCON1_HFPD(var->right_margin - 1) |
414ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		       VIDTCON1_HSPW(var->hsync_len - 1);
415ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
416c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		/* VIDTCON1 */
417c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(data, regs + sfb->variant.vidtcon + 4);
418ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
419ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data = VIDTCON2_LINEVAL(var->yres - 1) |
420ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		       VIDTCON2_HOZVAL(var->xres - 1);
421c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(data, regs +sfb->variant.vidtcon + 8 );
422ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
423ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
424ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* write the buffer address */
425ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
426c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	/* start and end registers stride is 8 */
427c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	buf = regs + win_no * 8;
428c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
429c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(info->fix.smem_start, buf + sfb->variant.buf_start);
430ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
431ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	data = info->fix.smem_start + info->fix.line_length * var->yres;
432c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(data, buf + sfb->variant.buf_end);
433ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
434ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	pagewidth = (var->xres * var->bits_per_pixel) >> 3;
435ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
436ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	       VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
437c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(data, regs + sfb->variant.buf_size + (win_no * 4));
438ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
439ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* write 'OSD' registers to control position of framebuffer */
440ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
441ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
442c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(data, regs + VIDOSD_A(win_no, sfb->variant));
443ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
444ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
445ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks						     var->xres - 1)) |
446ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	       VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
447ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
448c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(data, regs + VIDOSD_B(win_no, sfb->variant));
449ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
450ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	data = var->xres * var->yres;
45139000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae
45239000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae	osdc_data = VIDISD14C_ALPHA1_R(0xf) |
45339000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae		VIDISD14C_ALPHA1_G(0xf) |
45439000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae		VIDISD14C_ALPHA1_B(0xf);
45539000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae
45650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	if (win->variant.has_osd_d) {
457c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(data, regs + VIDOSD_D(win_no, sfb->variant));
458c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(osdc_data, regs + VIDOSD_C(win_no, sfb->variant));
459ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	} else
460c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(data, regs + VIDOSD_C(win_no, sfb->variant));
461ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
462ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	data = WINCONx_ENWIN;
463ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
464ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* note, since we have to round up the bits-per-pixel, we end up
465ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * relying on the bitfield information for r/g/b/a to work out
466ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * exactly which mode of operation is intended. */
467ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
468ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	switch (var->bits_per_pixel) {
469ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 1:
470ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCON0_BPPMODE_1BPP;
471ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BITSWP;
472ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BURSTLEN_4WORD;
473ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
474ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 2:
475ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCON0_BPPMODE_2BPP;
476ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BITSWP;
477ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BURSTLEN_8WORD;
478ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
479ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 4:
480ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCON0_BPPMODE_4BPP;
481ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BITSWP;
482ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BURSTLEN_8WORD;
483ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
484ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 8:
485ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (var->transp.length != 0)
486ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			data |= WINCON1_BPPMODE_8BPP_1232;
487ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		else
488ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			data |= WINCON0_BPPMODE_8BPP_PALETTE;
489ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BURSTLEN_8WORD;
490ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BYTSWP;
491ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
492ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 16:
493ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (var->transp.length != 0)
494ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			data |= WINCON1_BPPMODE_16BPP_A1555;
495ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		else
496ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			data |= WINCON0_BPPMODE_16BPP_565;
497ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_HAWSWP;
498ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BURSTLEN_16WORD;
499ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
500ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 24:
501ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case 32:
502ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (var->red.length == 6) {
503ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			if (var->transp.length != 0)
504ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				data |= WINCON1_BPPMODE_19BPP_A1666;
505ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			else
506ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				data |= WINCON1_BPPMODE_18BPP_666;
50739000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae		} else if (var->transp.length == 1)
50839000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae			data |= WINCON1_BPPMODE_25BPP_A1888
50939000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae				| WINCON1_BLD_PIX;
51039000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae		else if (var->transp.length == 4)
51139000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae			data |= WINCON1_BPPMODE_28BPP_A4888
51239000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae				| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
513ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		else
514ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			data |= WINCON0_BPPMODE_24BPP_888;
515ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
516dc8498c00f6a41a28f01111a3d2ed9f179356a71InKi Dae		data |= WINCONx_WSWP;
517ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		data |= WINCONx_BURSTLEN_16WORD;
518ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
519ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
520ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
521c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	/* Enable the colour keying for the window below this one */
52239000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae	if (win_no > 0) {
52339000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae		u32 keycon0_data = 0, keycon1_data = 0;
524c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		void __iomem *keycon = regs + sfb->variant.keycon;
52539000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae
52639000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae		keycon0_data = ~(WxKEYCON0_KEYBL_EN |
52739000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae				WxKEYCON0_KEYEN_F |
52839000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae				WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
52939000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae
53039000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae		keycon1_data = WxKEYCON1_COLVAL(0xffffff);
53139000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae
532c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		keycon += (win_no - 1) * 8;
533c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
534c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(keycon0_data, keycon + WKEYCON0);
535c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(keycon1_data, keycon + WKEYCON1);
53639000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae	}
53739000d654c2a22ca51fe92a39003d5fade59e9e4InKi Dae
538c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(data, regs + sfb->variant.wincon + (win_no * 4));
539c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
540ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
541ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
542ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
543ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
544ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
545ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_update_palette() - set or schedule a palette update.
546ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @sfb: The hardware information.
547ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @win: The window being updated.
548ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @reg: The palette index being changed.
549ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @value: The computed palette value.
550ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
551ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Change the value of a palette register, either by directly writing to
552ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * the palette (this requires the palette RAM to be disconnected from the
553ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * hardware whilst this is in progress) or schedule the update for later.
554ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
555ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * At the moment, since we have no VSYNC interrupt support, we simply set
556ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * the palette entry directly.
557ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
558ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic void s3c_fb_update_palette(struct s3c_fb *sfb,
559ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				  struct s3c_fb_win *win,
560ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				  unsigned int reg,
561ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				  u32 value)
562ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
563ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	void __iomem *palreg;
564ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	u32 palcon;
565ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
56650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	palreg = sfb->regs + sfb->variant.palette[win->index];
567ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
568ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
569ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		__func__, win->index, reg, palreg, value);
570ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
571ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	win->palette_buffer[reg] = value;
572ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
573ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	palcon = readl(sfb->regs + WPALCON);
574ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
575ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
57650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	if (win->variant.palette_16bpp)
57750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		writew(value, palreg + (reg * 2));
578ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	else
57950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		writel(value, palreg + (reg * 4));
580ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
581ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	writel(palcon, sfb->regs + WPALCON);
582ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
583ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
584ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic inline unsigned int chan_to_field(unsigned int chan,
585ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks					 struct fb_bitfield *bf)
586ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
587ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	chan &= 0xffff;
588ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	chan >>= 16 - bf->length;
589ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return chan << bf->offset;
590ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
591ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
592ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
593ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_setcolreg() - framebuffer layer request to change palette.
594ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @regno: The palette index to change.
595ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @red: The red field for the palette data.
596ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @green: The green field for the palette data.
597ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @blue: The blue field for the palette data.
598ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @trans: The transparency (alpha) field for the palette data.
599ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @info: The framebuffer being changed.
600ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
601ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int s3c_fb_setcolreg(unsigned regno,
602ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			    unsigned red, unsigned green, unsigned blue,
603ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			    unsigned transp, struct fb_info *info)
604ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
605ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win *win = info->par;
606ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb = win->parent;
607ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	unsigned int val;
608ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
609ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
610ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		__func__, win->index, regno, red, green, blue);
611ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
612ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	switch (info->fix.visual) {
613ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case FB_VISUAL_TRUECOLOR:
614ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* true-colour, use pseudo-palette */
615ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
616ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (regno < 16) {
617ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			u32 *pal = info->pseudo_palette;
618ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
619ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			val  = chan_to_field(red,   &info->var.red);
620ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			val |= chan_to_field(green, &info->var.green);
621ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			val |= chan_to_field(blue,  &info->var.blue);
622ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
623ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			pal[regno] = val;
624ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		}
625ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
626ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
627ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case FB_VISUAL_PSEUDOCOLOR:
62850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		if (regno < win->variant.palette_sz) {
629ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			val  = chan_to_field(red, &win->palette.r);
630ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			val |= chan_to_field(green, &win->palette.g);
631ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			val |= chan_to_field(blue, &win->palette.b);
632ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
633ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			s3c_fb_update_palette(sfb, win, regno, val);
634ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		}
635ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
636ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
637ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
638ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	default:
639ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return 1;	/* unknown type */
640ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
641ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
642ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
643ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
644ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
645ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
646ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_enable() - Set the state of the main LCD output
647ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @sfb: The main framebuffer state.
648ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @enable: The state to set.
649ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
650ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic void s3c_fb_enable(struct s3c_fb *sfb, int enable)
651ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
652ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	u32 vidcon0 = readl(sfb->regs + VIDCON0);
653ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
654ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (enable)
655ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
656ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	else {
657ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* see the note in the framebuffer datasheet about
658ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		 * why you cannot take both of these bits down at the
659ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		 * same time. */
660ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
661ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (!(vidcon0 & VIDCON0_ENVID))
662ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			return;
663ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
664ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		vidcon0 |= VIDCON0_ENVID;
665ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		vidcon0 &= ~VIDCON0_ENVID_F;
666ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
667ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
668ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	writel(vidcon0, sfb->regs + VIDCON0);
669ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
670ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
671ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
672ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_blank() - blank or unblank the given window
673ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @blank_mode: The blank state from FB_BLANK_*
674ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @info: The framebuffer to blank.
675ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
676ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Framebuffer layer request to change the power state.
677ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
678ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int s3c_fb_blank(int blank_mode, struct fb_info *info)
679ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
680ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win *win = info->par;
681ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb = win->parent;
682ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	unsigned int index = win->index;
683ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	u32 wincon;
684ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
685ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
686ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
687c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
688ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
689ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	switch (blank_mode) {
690ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case FB_BLANK_POWERDOWN:
691ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		wincon &= ~WINCONx_ENWIN;
692ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		sfb->enabled &= ~(1 << index);
693ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* fall through to FB_BLANK_NORMAL */
694ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
695ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case FB_BLANK_NORMAL:
696ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* disable the DMA and display 0x0 (black) */
697ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
698c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		       sfb->regs + sfb->variant.winmap + (index * 4));
699ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
700ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
701ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case FB_BLANK_UNBLANK:
702c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
703ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		wincon |= WINCONx_ENWIN;
704ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		sfb->enabled |= (1 << index);
705ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		break;
706ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
707ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case FB_BLANK_VSYNC_SUSPEND:
708ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	case FB_BLANK_HSYNC_SUSPEND:
709ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	default:
710ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return 1;
711ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
712ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
713c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
714ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
715ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* Check the enabled state to see if we need to be running the
716ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * main LCD interface, as if there are no active windows then
717ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * it is highly likely that we also do not need to output
718ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * anything.
719ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 */
720ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
721ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* We could do something like the following code, but the current
722ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * system of using framebuffer events means that we cannot make
723ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * the distinction between just window 0 being inactive and all
724ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * the windows being down.
725ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 *
726ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
727ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	*/
728ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
729ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* we're stuck with this until we can do something about overriding
730ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 * the power control using the blanking event for a single fb.
731ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	 */
732ad04490a171915737c9b99d2fa5cb813830f24c1InKi Dae	if (index == sfb->pdata->default_win)
733ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
734ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
735ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
736ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
737ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
738ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic struct fb_ops s3c_fb_ops = {
739ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.owner		= THIS_MODULE,
740ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.fb_check_var	= s3c_fb_check_var,
741ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.fb_set_par	= s3c_fb_set_par,
742ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.fb_blank	= s3c_fb_blank,
743ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.fb_setcolreg	= s3c_fb_setcolreg,
744ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.fb_fillrect	= cfb_fillrect,
745ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.fb_copyarea	= cfb_copyarea,
746ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.fb_imageblit	= cfb_imageblit,
747ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks};
748ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
749ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
750ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
751ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @sfb: The base resources for the hardware.
752ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @win: The window to initialise memory for.
753ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
754ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Allocate memory for the given framebuffer.
755ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
756ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
757ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks					 struct s3c_fb_win *win)
758ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
759ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_pd_win *windata = win->windata;
760ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	unsigned int real_size, virt_size, size;
761ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct fb_info *fbi = win->fbinfo;
762ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dma_addr_t map_dma;
763ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
764ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "allocating memory for display\n");
765ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
766ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	real_size = windata->win_mode.xres * windata->win_mode.yres;
767ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	virt_size = windata->virtual_x * windata->virtual_y;
768ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
769ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
770ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		real_size, windata->win_mode.xres, windata->win_mode.yres,
771ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		virt_size, windata->virtual_x, windata->virtual_y);
772ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
773ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	size = (real_size > virt_size) ? real_size : virt_size;
774ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
775ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	size /= 8;
776ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
777ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbi->fix.smem_len = size;
778ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	size = PAGE_ALIGN(size);
779ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
780ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "want %u bytes for window\n", size);
781ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
782ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
783ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks						  &map_dma, GFP_KERNEL);
784ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (!fbi->screen_base)
785ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return -ENOMEM;
786ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
787ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "mapped %x to %p\n",
788ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		(unsigned int)map_dma, fbi->screen_base);
789ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
790ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	memset(fbi->screen_base, 0x0, size);
791ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbi->fix.smem_start = map_dma;
792ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
793ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
794ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
795ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
796ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
797ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_free_memory() - free the display memory for the given window
798ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @sfb: The base resources for the hardware.
799ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @win: The window to free the display memory for.
800ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
801ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Free the display memory allocated by s3c_fb_alloc_memory().
802ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
803ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
804ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
805ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct fb_info *fbi = win->fbinfo;
806ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
807ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
808ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			      fbi->screen_base, fbi->fix.smem_start);
809ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
810ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
811ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
812ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_release_win() - release resources for a framebuffer window.
813ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @win: The window to cleanup the resources for.
814ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
815ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Release the resources that where claimed for the hardware window,
816ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * such as the framebuffer instance and any memory claimed for it.
817ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
818ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
819ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
820ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt	if (win->fbinfo) {
821ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt		unregister_framebuffer(win->fbinfo);
822ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt		fb_dealloc_cmap(&win->fbinfo->cmap);
823ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt		s3c_fb_free_memory(sfb, win);
824ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt		framebuffer_release(win->fbinfo);
825ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt	}
826ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
827ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
828ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
829ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_probe_win() - register an hardware window
830ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @sfb: The base resources for the hardware
83150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks * @variant: The variant information for this window.
832ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @res: Pointer to where to place the resultant window.
833ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
834ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Allocate and do the basic initialisation for one of the hardware's graphics
835ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * windows.
836ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
837ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
83850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				      struct s3c_fb_win_variant *variant,
839ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				      struct s3c_fb_win **res)
840ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
841ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct fb_var_screeninfo *var;
842ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct fb_videomode *initmode;
843ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_pd_win *windata;
844ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win *win;
845ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct fb_info *fbinfo;
846ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int palette_size;
847ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int ret;
848ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
849c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
850ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
85150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	palette_size = variant->palette_sz * 4;
852ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
853ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
854ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				   palette_size * sizeof(u32), sfb->dev);
855ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (!fbinfo) {
856ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(sfb->dev, "failed to allocate framebuffer\n");
857ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return -ENOENT;
858ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
859ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
860ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	windata = sfb->pdata->win[win_no];
861ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	initmode = &windata->win_mode;
862ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
863ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	WARN_ON(windata->max_bpp == 0);
864ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	WARN_ON(windata->win_mode.xres == 0);
865ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	WARN_ON(windata->win_mode.yres == 0);
866ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
867ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	win = fbinfo->par;
868ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	var = &fbinfo->var;
86950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	win->variant = *variant;
870ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	win->fbinfo = fbinfo;
871ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	win->parent = sfb;
872ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	win->windata = windata;
873ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	win->index = win_no;
874ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	win->palette_buffer = (u32 *)(win + 1);
875ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
876ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	ret = s3c_fb_alloc_memory(sfb, win);
877ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (ret) {
878ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(sfb->dev, "failed to allocate display memory\n");
879ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt		return ret;
880ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
881ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
882ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* setup the r/b/g positions for the window's palette */
883bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks	if (win->variant.palette_16bpp) {
884bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		/* Set RGB 5:6:5 as default */
885bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.r.offset = 11;
886bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.r.length = 5;
887bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.g.offset = 5;
888bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.g.length = 6;
889bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.b.offset = 0;
890bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.b.length = 5;
891bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks
892bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks	} else {
893bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		/* Set 8bpp or 8bpp and 1bit alpha */
894bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.r.offset = 16;
895bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.r.length = 8;
896bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.g.offset = 8;
897bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.g.length = 8;
898bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.b.offset = 0;
899bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks		win->palette.b.length = 8;
900bc2da1b6fb1a8af9a3226a4f5db3ce32a0a192c9Ben Dooks	}
901ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
902ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* setup the initial video mode from the window */
903ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fb_videomode_to_var(&fbinfo->var, initmode);
904ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
905ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->fix.type	= FB_TYPE_PACKED_PIXELS;
906ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->fix.accel	= FB_ACCEL_NONE;
907ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->var.activate	= FB_ACTIVATE_NOW;
908ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->var.vmode	= FB_VMODE_NONINTERLACED;
909ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->var.bits_per_pixel = windata->default_bpp;
910ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->fbops		= &s3c_fb_ops;
911ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->flags		= FBINFO_FLAG_DEFAULT;
912ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	fbinfo->pseudo_palette  = &win->pseudo_palette;
913ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
914ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* prepare to actually start the framebuffer */
915ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
916ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
917ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (ret < 0) {
918ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(sfb->dev, "check_var failed on initial video params\n");
919ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt		return ret;
920ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
921ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
922ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* create initial colour map */
923ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
92450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
925ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (ret == 0)
926ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		fb_set_cmap(&fbinfo->cmap, fbinfo);
927ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	else
928ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(sfb->dev, "failed to allocate fb cmap\n");
929ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
930ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	s3c_fb_set_par(fbinfo);
931ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
932ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(sfb->dev, "about to register framebuffer\n");
933ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
934ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* run the check_var and set_par on our configuration. */
935ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
936ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	ret = register_framebuffer(fbinfo);
937ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (ret < 0) {
938ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(sfb->dev, "failed to register framebuffer\n");
939ddc518d9f88d7cf82bd974737ce977193785335dKrzysztof Helt		return ret;
940ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
941ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
942ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	*res = win;
943ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
944ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
945ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
946ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
947ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
948ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
949ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_clear_win() - clear hardware window registers.
950ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @sfb: The base resources for the hardware.
951ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @win: The window to process.
952ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
953ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Reset the specific window registers to a known state.
954ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
955ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
956ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
957ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	void __iomem *regs = sfb->regs;
958ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
959c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(0, regs + sfb->variant.wincon + (win * 4));
960c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(0, regs + VIDOSD_A(win, sfb->variant));
961c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(0, regs + VIDOSD_B(win, sfb->variant));
962c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	writel(0, regs + VIDOSD_C(win, sfb->variant));
963ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
964ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
965ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int __devinit s3c_fb_probe(struct platform_device *pdev)
966ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
96750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	struct s3c_fb_driverdata *fbdrv;
968ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct device *dev = &pdev->dev;
969ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_platdata *pd;
970ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb;
971ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct resource *res;
972ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int win;
973ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int ret = 0;
974ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
97550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	fbdrv = (struct s3c_fb_driverdata *)platform_get_device_id(pdev)->driver_data;
97650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
97750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
97850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		dev_err(dev, "too many windows, cannot attach\n");
97950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		return -EINVAL;
98050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	}
98150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
982ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	pd = pdev->dev.platform_data;
983ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (!pd) {
984ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(dev, "no platform data specified\n");
985ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return -EINVAL;
986ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
987ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
988ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
989ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (!sfb) {
990ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(dev, "no memory for framebuffers\n");
991ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		return -ENOMEM;
992ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
993ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
994c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	dev_dbg(dev, "allocate new framebuffer %p\n", sfb);
995c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
996ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	sfb->dev = dev;
997ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	sfb->pdata = pd;
99850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	sfb->variant = fbdrv->variant;
999ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1000ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	sfb->bus_clk = clk_get(dev, "lcd");
1001ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (IS_ERR(sfb->bus_clk)) {
1002ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(dev, "failed to get bus clock\n");
1003ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		goto err_sfb;
1004ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
1005ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1006ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	clk_enable(sfb->bus_clk);
1007ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1008ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1009ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (!res) {
1010ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(dev, "failed to find registers\n");
1011ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		ret = -ENOENT;
1012ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		goto err_clk;
1013ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
1014ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1015ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	sfb->regs_res = request_mem_region(res->start, resource_size(res),
1016ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks					   dev_name(dev));
1017ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (!sfb->regs_res) {
1018ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(dev, "failed to claim register region\n");
1019ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		ret = -ENOENT;
1020ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		goto err_clk;
1021ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
1022ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1023ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	sfb->regs = ioremap(res->start, resource_size(res));
1024ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	if (!sfb->regs) {
1025ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_err(dev, "failed to map registers\n");
1026ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		ret = -ENXIO;
1027ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		goto err_req_region;
1028ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
1029ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1030ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
1031ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1032ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* setup gpio and output polarity controls */
1033ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1034ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	pd->setup_gpio();
1035ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1036ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	writel(pd->vidcon1, sfb->regs + VIDCON1);
1037ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1038ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* zero all windows before we do anything */
1039ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
104050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	for (win = 0; win < fbdrv->variant.nr_windows; win++)
1041ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		s3c_fb_clear_win(sfb, win);
1042ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1043949470375393e82dc9158d36d675180c8c250388Ben Dooks	/* initialise colour key controls */
104450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
1045c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		void __iomem *regs = sfb->regs + sfb->variant.keycon;
1046c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
1047c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		regs += (win * 8);
1048c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(0xffffff, regs + WKEYCON0);
1049c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(0xffffff, regs + WKEYCON1);
1050949470375393e82dc9158d36d675180c8c250388Ben Dooks	}
1051949470375393e82dc9158d36d675180c8c250388Ben Dooks
1052ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	/* we have the register setup, start allocating framebuffers */
1053ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
105450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	for (win = 0; win < fbdrv->variant.nr_windows; win++) {
1055ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (!pd->win[win])
1056ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			continue;
1057ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
105850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
105950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				       &sfb->windows[win]);
1060ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (ret < 0) {
1061ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			dev_err(dev, "failed to create window %d\n", win);
1062ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			for (; win >= 0; win--)
1063ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks				s3c_fb_release_win(sfb, sfb->windows[win]);
1064ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			goto err_ioremap;
1065ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		}
1066ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
1067ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1068ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	platform_set_drvdata(pdev, sfb);
1069ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1070ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
1071ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1072ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dookserr_ioremap:
1073ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	iounmap(sfb->regs);
1074ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1075ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dookserr_req_region:
1076ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	release_resource(sfb->regs_res);
1077ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	kfree(sfb->regs_res);
1078ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1079ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dookserr_clk:
1080ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	clk_disable(sfb->bus_clk);
1081ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	clk_put(sfb->bus_clk);
1082ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1083ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dookserr_sfb:
1084ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	kfree(sfb);
1085ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return ret;
1086ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
1087ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1088ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks/**
1089ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * s3c_fb_remove() - Cleanup on module finalisation
1090ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * @pdev: The platform device we are bound to.
1091ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks *
1092ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * Shutdown and then release all the resources that the driver allocated
1093ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks * on initialisation.
1094ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks */
1095ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int __devexit s3c_fb_remove(struct platform_device *pdev)
1096ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
1097ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb = platform_get_drvdata(pdev);
1098ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int win;
1099ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1100c42b110caeb128819104d057acdaa1ae564b7c8dPawel Osciak	for (win = 0; win < S3C_FB_MAX_WIN; win++)
110117663e59704bea838a9236f299104e30909a43b1Marek Szyprowski		if (sfb->windows[win])
110217663e59704bea838a9236f299104e30909a43b1Marek Szyprowski			s3c_fb_release_win(sfb, sfb->windows[win]);
1103ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1104ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	iounmap(sfb->regs);
1105ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1106ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	clk_disable(sfb->bus_clk);
1107ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	clk_put(sfb->bus_clk);
1108ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1109ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	release_resource(sfb->regs_res);
1110ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	kfree(sfb->regs_res);
1111ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1112ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	kfree(sfb);
1113ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1114ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
1115ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
1116ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1117ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#ifdef CONFIG_PM
1118ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state)
1119ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
1120ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb = platform_get_drvdata(pdev);
1121ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win *win;
1122ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int win_no;
1123ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1124c42b110caeb128819104d057acdaa1ae564b7c8dPawel Osciak	for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
1125ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		win = sfb->windows[win_no];
1126ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (!win)
1127ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			continue;
1128ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1129ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		/* use the blank function to push into power-down */
1130ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
1131ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
1132ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1133ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	clk_disable(sfb->bus_clk);
1134ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
1135ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
1136ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1137ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int s3c_fb_resume(struct platform_device *pdev)
1138ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
1139ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb *sfb = platform_get_drvdata(pdev);
114017663e59704bea838a9236f299104e30909a43b1Marek Szyprowski	struct s3c_fb_platdata *pd = sfb->pdata;
1141ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	struct s3c_fb_win *win;
1142ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	int win_no;
1143ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1144ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	clk_enable(sfb->bus_clk);
1145ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
114617663e59704bea838a9236f299104e30909a43b1Marek Szyprowski	/* setup registers */
114717663e59704bea838a9236f299104e30909a43b1Marek Szyprowski	writel(pd->vidcon1, sfb->regs + VIDCON1);
114817663e59704bea838a9236f299104e30909a43b1Marek Szyprowski
114917663e59704bea838a9236f299104e30909a43b1Marek Szyprowski	/* zero all windows before we do anything */
115050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
115117663e59704bea838a9236f299104e30909a43b1Marek Szyprowski		s3c_fb_clear_win(sfb, win_no);
115217663e59704bea838a9236f299104e30909a43b1Marek Szyprowski
115350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
1154c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		void __iomem *regs = sfb->regs + sfb->variant.keycon;
1155c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
1156c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		regs += (win_no * 8);
1157c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(0xffffff, regs + WKEYCON0);
1158c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		writel(0xffffff, regs + WKEYCON1);
1159949470375393e82dc9158d36d675180c8c250388Ben Dooks	}
1160949470375393e82dc9158d36d675180c8c250388Ben Dooks
116117663e59704bea838a9236f299104e30909a43b1Marek Szyprowski	/* restore framebuffers */
1162ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
1163ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		win = sfb->windows[win_no];
1164ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		if (!win)
1165ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks			continue;
1166ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1167ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
1168ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		s3c_fb_set_par(win->fbinfo);
1169ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	}
1170ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1171ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return 0;
1172ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
1173ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#else
1174ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#define s3c_fb_suspend NULL
1175ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#define s3c_fb_resume  NULL
1176ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks#endif
1177ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
117850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
117950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks#define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
118050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks#define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
118150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
118250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstatic struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = {
118350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	[0] = {
118450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_c	= 1,
118550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_sz	= 256,
118650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.valid_bpp	= VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
118750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
118850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	[1] = {
118950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_c	= 1,
119050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_d	= 1,
119150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_sz	= 256,
119250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
119350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(18) | VALID_BPP(19) |
119450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(24) | VALID_BPP(25)),
119550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
119650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	[2] = {
119750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_c	= 1,
119850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_d	= 1,
119950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_sz	= 16,
120050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_16bpp	= 1,
120150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
120250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(18) | VALID_BPP(19) |
120350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(24) | VALID_BPP(25)),
120450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
120550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	[3] = {
120650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_c	= 1,
120750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_d	= 1,
120850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_sz	= 16,
120950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_16bpp	= 1,
121050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.valid_bpp	= (VALID_BPP124  | VALID_BPP(16) |
121150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(18) | VALID_BPP(19) |
121250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(24) | VALID_BPP(25)),
121350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
121450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	[4] = {
121550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.has_osd_c	= 1,
121650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_sz	= 4,
121750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette_16bpp	= 1,
121850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.valid_bpp	= (VALID_BPP(1) | VALID_BPP(2) |
121950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(16) | VALID_BPP(18) |
122050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks				   VALID_BPP(24) | VALID_BPP(25)),
122150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
122250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks};
122350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
122450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstatic struct s3c_fb_driverdata s3c_fb_data_64xx __devinitdata = {
122550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.variant = {
122650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.nr_windows	= 5,
1227c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.vidtcon	= VIDTCON0,
1228c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.wincon		= WINCON(0),
1229c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.winmap		= WINxMAP(0),
1230c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.keycon		= WKEYCON,
1231c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.osd		= VIDOSD_BASE,
1232c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.osd_stride	= 16,
1233c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_start	= VIDW_BUF_START(0),
1234c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_size	= VIDW_BUF_SIZE(0),
1235c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_end	= VIDW_BUF_END(0),
123650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
123750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette = {
123850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[0] = 0x400,
123950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[1] = 0x800,
124050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[2] = 0x300,
124150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[3] = 0x320,
124250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[4] = 0x340,
124350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		},
124450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
124550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[0]	= &s3c_fb_data_64xx_wins[0],
124650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[1]	= &s3c_fb_data_64xx_wins[1],
124750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[2]	= &s3c_fb_data_64xx_wins[2],
124850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[3]	= &s3c_fb_data_64xx_wins[3],
124950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[4]	= &s3c_fb_data_64xx_wins[4],
125050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks};
125150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
125250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstatic struct s3c_fb_driverdata s3c_fb_data_s5p __devinitdata = {
125350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.variant = {
125450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.nr_windows	= 5,
1255c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.vidtcon	= VIDTCON0,
1256c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.wincon		= WINCON(0),
1257c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.winmap		= WINxMAP(0),
1258c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.keycon		= WKEYCON,
1259c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.osd		= VIDOSD_BASE,
1260c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.osd_stride	= 16,
1261c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_start	= VIDW_BUF_START(0),
1262c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_size	= VIDW_BUF_SIZE(0),
1263c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_end	= VIDW_BUF_END(0),
126450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
126550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.palette = {
126650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[0] = 0x2400,
126750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[1] = 0x2800,
126850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[2] = 0x2c00,
126950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[3] = 0x3000,
127050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks			[4] = 0x3400,
127150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		},
127250a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
127350a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[0]	= &s3c_fb_data_64xx_wins[0],
127450a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[1]	= &s3c_fb_data_64xx_wins[1],
127550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[2]	= &s3c_fb_data_64xx_wins[2],
127650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[3]	= &s3c_fb_data_64xx_wins[3],
127750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.win[4]	= &s3c_fb_data_64xx_wins[4],
127850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks};
127950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
1280c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks/* S3C2443/S3C2416 style hardware */
1281c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooksstatic struct s3c_fb_driverdata s3c_fb_data_s3c2443 __devinitdata = {
1282c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	.variant = {
1283c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.nr_windows	= 2,
1284c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.is_2443	= 1,
1285c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
1286c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.vidtcon	= 0x08,
1287c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.wincon		= 0x14,
1288c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.winmap		= 0xd0,
1289c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.keycon		= 0xb0,
1290c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.osd		= 0x28,
1291c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.osd_stride	= 12,
1292c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_start	= 0x64,
1293c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_size	= 0x94,
1294c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.buf_end	= 0x7c,
1295c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
1296c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.palette = {
1297c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks			[0] = 0x400,
1298c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks			[1] = 0x800,
1299c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		},
1300c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	},
1301c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	.win[0] = &(struct s3c_fb_win_variant) {
1302c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.palette_sz	= 256,
1303c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.valid_bpp	= VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
1304c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	},
1305c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	.win[1] = &(struct s3c_fb_win_variant) {
1306c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.has_osd_c	= 1,
1307c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.palette_sz	= 256,
1308c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.valid_bpp	= (VALID_BPP1248 | VALID_BPP(16) |
1309c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks				   VALID_BPP(18) | VALID_BPP(19) |
1310c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks				   VALID_BPP(24) | VALID_BPP(25) |
1311c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks				   VALID_BPP(28)),
1312c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	},
1313c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks};
1314c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks
131550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooksstatic struct platform_device_id s3c_fb_driver_ids[] = {
131650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	{
131750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.name		= "s3c-fb",
131850a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.driver_data	= (unsigned long)&s3c_fb_data_64xx,
131950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	}, {
132050a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.name		= "s5p-fb",
132150a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks		.driver_data	= (unsigned long)&s3c_fb_data_s5p,
1322c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks	}, {
1323c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.name		= "s3c2443-fb",
1324c4bb6ffa7754e8d0f8b24decd91de259b549fda1Ben Dooks		.driver_data	= (unsigned long)&s3c_fb_data_s3c2443,
132550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	},
132650a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	{},
132750a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks};
132850a5503a9208420e6c59d24504a5e9913d603cf7Ben DooksMODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
132950a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks
1330ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic struct platform_driver s3c_fb_driver = {
1331ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.probe		= s3c_fb_probe,
13323163eaba34943967aebb1eefa0d4bdc4e5dc197cPeter Korsgaard	.remove		= __devexit_p(s3c_fb_remove),
1333ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.suspend	= s3c_fb_suspend,
1334ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.resume		= s3c_fb_resume,
133550a5503a9208420e6c59d24504a5e9913d603cf7Ben Dooks	.id_table	= s3c_fb_driver_ids,
1336ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	.driver		= {
1337ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		.name	= "s3c-fb",
1338ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks		.owner	= THIS_MODULE,
1339ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	},
1340ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks};
1341ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1342ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic int __init s3c_fb_init(void)
1343ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
1344ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	return platform_driver_register(&s3c_fb_driver);
1345ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
1346ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1347ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksstatic void __exit s3c_fb_cleanup(void)
1348ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks{
1349ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks	platform_driver_unregister(&s3c_fb_driver);
1350ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks}
1351ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1352ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksmodule_init(s3c_fb_init);
1353ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooksmodule_exit(s3c_fb_cleanup);
1354ec549a0fdc32171b26677f1ef0b5309faa743362Ben Dooks
1355ec549a0fdc32171b26677f1ef0b5309faa743362Ben DooksMODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1356ec549a0fdc32171b26677f1ef0b5309faa743362Ben DooksMODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
1357ec549a0fdc32171b26677f1ef0b5309faa743362Ben DooksMODULE_LICENSE("GPL");
1358ec549a0fdc32171b26677f1ef0b5309faa743362Ben DooksMODULE_ALIAS("platform:s3c-fb");
1359